Bug Summary

File:dev/usb/uthum.c
Warning:line 691, column 13
The left operand of '!=' is a garbage value

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple amd64-unknown-openbsd7.0 -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name uthum.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model static -mframe-pointer=all -relaxed-aliasing -fno-rounding-math -mconstructor-aliases -ffreestanding -mcmodel=kernel -target-cpu x86-64 -target-feature +retpoline-indirect-calls -target-feature +retpoline-indirect-branches -target-feature -sse2 -target-feature -sse -target-feature -3dnow -target-feature -mmx -target-feature +save-args -disable-red-zone -no-implicit-float -tune-cpu generic -debugger-tuning=gdb -fcoverage-compilation-dir=/usr/src/sys/arch/amd64/compile/GENERIC.MP/obj -nostdsysteminc -nobuiltininc -resource-dir /usr/local/lib/clang/13.0.0 -I /usr/src/sys -I /usr/src/sys/arch/amd64/compile/GENERIC.MP/obj -I /usr/src/sys/arch -I /usr/src/sys/dev/pci/drm/include -I /usr/src/sys/dev/pci/drm/include/uapi -I /usr/src/sys/dev/pci/drm/amd/include/asic_reg -I /usr/src/sys/dev/pci/drm/amd/include -I /usr/src/sys/dev/pci/drm/amd/amdgpu -I /usr/src/sys/dev/pci/drm/amd/display -I /usr/src/sys/dev/pci/drm/amd/display/include -I /usr/src/sys/dev/pci/drm/amd/display/dc -I /usr/src/sys/dev/pci/drm/amd/display/amdgpu_dm -I /usr/src/sys/dev/pci/drm/amd/pm/inc -I /usr/src/sys/dev/pci/drm/amd/pm/swsmu -I /usr/src/sys/dev/pci/drm/amd/pm/swsmu/smu11 -I /usr/src/sys/dev/pci/drm/amd/pm/swsmu/smu12 -I /usr/src/sys/dev/pci/drm/amd/pm/powerplay -I /usr/src/sys/dev/pci/drm/amd/pm/powerplay/hwmgr -I /usr/src/sys/dev/pci/drm/amd/pm/powerplay/smumgr -I /usr/src/sys/dev/pci/drm/amd/display/dc/inc -I /usr/src/sys/dev/pci/drm/amd/display/dc/inc/hw -I /usr/src/sys/dev/pci/drm/amd/display/dc/clk_mgr -I /usr/src/sys/dev/pci/drm/amd/display/modules/inc -I /usr/src/sys/dev/pci/drm/amd/display/modules/hdcp -I /usr/src/sys/dev/pci/drm/amd/display/dmub/inc -I /usr/src/sys/dev/pci/drm/i915 -D DDB -D DIAGNOSTIC -D KTRACE -D ACCOUNTING -D KMEMSTATS -D PTRACE -D POOL_DEBUG -D CRYPTO -D SYSVMSG -D SYSVSEM -D SYSVSHM -D UVM_SWAP_ENCRYPT -D FFS -D FFS2 -D FFS_SOFTUPDATES -D UFS_DIRHASH -D QUOTA -D EXT2FS -D MFS -D NFSCLIENT -D NFSSERVER -D CD9660 -D UDF -D MSDOSFS -D FIFO -D FUSE -D SOCKET_SPLICE -D TCP_ECN -D TCP_SIGNATURE -D INET6 -D IPSEC -D PPP_BSDCOMP -D PPP_DEFLATE -D PIPEX -D MROUTING -D MPLS -D BOOT_CONFIG -D USER_PCICONF -D APERTURE -D MTRR -D NTFS -D HIBERNATE -D PCIVERBOSE -D USBVERBOSE -D WSDISPLAY_COMPAT_USL -D WSDISPLAY_COMPAT_RAWKBD -D WSDISPLAY_DEFAULTSCREENS=6 -D X86EMU -D ONEWIREVERBOSE -D MULTIPROCESSOR -D MAXUSERS=80 -D _KERNEL -D CONFIG_DRM_AMD_DC_DCN3_0 -O2 -Wno-pointer-sign -Wno-address-of-packed-member -Wno-constant-conversion -Wno-unused-but-set-variable -Wno-gnu-folding-constant -fdebug-compilation-dir=/usr/src/sys/arch/amd64/compile/GENERIC.MP/obj -ferror-limit 19 -fwrapv -D_RET_PROTECTOR -ret-protector -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -fno-builtin-malloc -fno-builtin-calloc -fno-builtin-realloc -fno-builtin-valloc -fno-builtin-free -fno-builtin-strdup -fno-builtin-strndup -analyzer-output=html -faddrsig -o /usr/obj/sys/arch/amd64/compile/GENERIC.MP/scan-build/2022-01-12-131800-47421-1 -x c /usr/src/sys/dev/usb/uthum.c
1/* $OpenBSD: uthum.c,v 1.38 2022/01/09 05:43:02 jsg Exp $ */
2
3/*
4 * Copyright (c) 2009, 2010 Yojiro UO <yuo@nui.org>
5 *
6 * Permission to use, copy, modify, and distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
9 *
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 */
18
19/* Driver for HID based TEMPer series Temperature(/Humidity) sensors */
20
21#include <sys/param.h>
22#include <sys/systm.h>
23#include <sys/kernel.h>
24#include <sys/device.h>
25#include <sys/conf.h>
26#include <sys/sensors.h>
27
28#include <dev/usb/usb.h>
29#include <dev/usb/usbhid.h>
30#include <dev/usb/usbdi.h>
31#include <dev/usb/usbdi_util.h>
32#include <dev/usb/usbdevs.h>
33#include <dev/usb/uhidev.h>
34
35#ifdef UTHUM_DEBUG
36#define DPRINTF(x) do { printf x; } while (0)
37#else
38#define DPRINTF(x)
39#endif
40
41/* Device types */
42#define UTHUM_TYPE_TEMPERHUM0x535a 0x535a
43#define UTHUM_TYPE_TEMPERHUM_20x575a 0x575a /* alternative TEMPerHUM */
44#define UTHUM_TYPE_TEMPER10x5758 0x5758 /* TEMPer1 and HID TEMPer */
45#define UTHUM_TYPE_TEMPER20x5759 0x5759
46#define UTHUM_TYPE_TEMPERNTC0x575b 0x575b
47#define UTHUM_TYPE_TEMPERHUM_30x5f5a 0x5f5a
48#define UTHUM_TYPE_UNKNOWN0xffff 0xffff
49
50/* Common */
51#define UTHUM_CAL_OFFSET0x14 0x14
52#define UTHUM_MAX_SENSORS2 2
53#define CMD_DEVTYPE0x52 0x52
54#define DEVTYPE_EOF0x53 0x53
55
56/* query commands */
57#define CMD_GETDATA_NTC0x41 0x41 /* TEMPerNTC NTC part */
58#define CMD_RESET00x43 0x43 /* TEMPer, TEMPer[12], TEMPerNTC */
59#define CMD_RESET10x44 0x44 /* TEMPer, TEMPer[12] */
60#define CMD_GETDATA0x48 0x48 /* TEMPerHUM */
61#define CMD_GETDATA_OUTER0x53 0x53 /* TEMPer, TEMPer[12], TEMPerNTC */
62#define CMD_GETDATA_INNER0x54 0x54 /* TEMPer, TEMPer[12], TEMPerNTC */
63#define CMD_GETDATA_EOF0x31 0x31
64#define CMD_GETDATA_EOF20xaa 0xaa
65
66/* temperntc mode */
67#define TEMPERNTC_MODE_BASE0x61 0x61 /* 0x61 - 0x68 */
68#define TEMPERNTC_MODE_MAX0x68 0x68
69#define CMD_TEMPERNTC_MODE_DONE0x69 0x69
70#define UTHUM_NTC_MIN_THRESHOLD0xb300 0xb300
71#define UTHUM_NTC_MAX_THRESHOLD0xf200 0xf200
72
73/* sensor name */
74#define UTHUM_TEMPER_INNER0 0
75#define UTHUM_TEMPER_OUTER1 1
76#define UTHUM_TEMPER_NTC1 1
77#define UTHUM_TEMPERHUM_TEMP0 0
78#define UTHUM_TEMPERHUM_HUM1 1
79
80enum uthum_sensor_type {
81 UTHUM_SENSOR_UNKNOWN,
82 UTHUM_SENSOR_SHT1X,
83 UTHUM_SENSOR_DS75,
84 UTHUM_SENSOR_NTC,
85 UTHUM_SENSOR_MAXTYPES,
86};
87
88static const char * const uthum_sensor_type_s[UTHUM_SENSOR_MAXTYPES] = {
89 "unknown",
90 "sht1x",
91 "ds75/12bit",
92 "NTC"
93};
94
95static uint8_t cmd_issue[8] =
96 { 0x0a, 0x0b, 0x0c, 0x0d, 0x00, 0x00, 0x02, 0x00 };
97static uint8_t cmd_query[8] =
98 { 0x0a, 0x0b, 0x0c, 0x0d, 0x00, 0x00, 0x01, 0x00 };
99
100struct uthum_sensor {
101 struct ksensor sensor;
102 int cal_offset; /* mC or m%RH */
103 int attached;
104 enum uthum_sensor_type dev_type;
105 int cur_state; /* for TEMPerNTC */
106};
107
108struct uthum_softc {
109 struct uhidev sc_hdev;
110 struct usbd_device *sc_udev;
111 int sc_device_type;
112 int sc_num_sensors;
113
114 /* uhidev parameters */
115 size_t sc_flen; /* feature report length */
116 size_t sc_ilen; /* input report length */
117 size_t sc_olen; /* output report length */
118
119 /* sensor framework */
120 struct uthum_sensor sc_sensor[UTHUM_MAX_SENSORS2];
121 struct ksensordev sc_sensordev;
122 struct sensor_task *sc_sensortask;
123};
124
125const struct usb_devno uthum_devs[] = {
126 /* XXX: various TEMPer variants are using same VID/PID */
127 { USB_VENDOR_TENX0x1130, USB_PRODUCT_TENX_TEMPER0x660c},
128};
129#define uthum_lookup(v, p)usbd_match_device((const struct usb_devno *)(uthum_devs), sizeof
(uthum_devs) / sizeof ((uthum_devs)[0]), sizeof ((uthum_devs
)[0]), (v), (p))
usb_lookup(uthum_devs, v, p)usbd_match_device((const struct usb_devno *)(uthum_devs), sizeof
(uthum_devs) / sizeof ((uthum_devs)[0]), sizeof ((uthum_devs
)[0]), (v), (p))
130
131int uthum_match(struct device *, void *, void *);
132void uthum_attach(struct device *, struct device *, void *);
133int uthum_detach(struct device *, int);
134
135int uthum_issue_cmd(struct uthum_softc *, uint8_t, int);
136int uthum_read_data(struct uthum_softc *, uint8_t, uint8_t *, size_t, int);
137int uthum_check_device_info(struct uthum_softc *);
138void uthum_reset_device(struct uthum_softc *);
139void uthum_setup_sensors(struct uthum_softc *);
140
141void uthum_intr(struct uhidev *, void *, u_int);
142void uthum_refresh(void *);
143void uthum_refresh_temper(struct uthum_softc *, int);
144void uthum_refresh_temperhum(struct uthum_softc *);
145void uthum_refresh_temperntc(struct uthum_softc *, int);
146
147int uthum_ntc_getdata(struct uthum_softc *, int *);
148int uthum_ntc_tuning(struct uthum_softc *, int, int *);
149int64_t uthum_ntc_temp(int64_t, int);
150int uthum_sht1x_temp(uint8_t, uint8_t);
151int uthum_sht1x_rh(uint8_t, uint8_t, int);
152int uthum_ds75_temp(uint8_t, uint8_t);
153void uthum_print_sensorinfo(struct uthum_softc *, int);
154
155struct cfdriver uthum_cd = {
156 NULL((void *)0), "uthum", DV_DULL
157};
158
159const struct cfattach uthum_ca = {
160 sizeof(struct uthum_softc),
161 uthum_match,
162 uthum_attach,
163 uthum_detach
164};
165
166int
167uthum_match(struct device *parent, void *match, void *aux)
168{
169 struct uhidev_attach_arg *uha = aux;
170
171 if (UHIDEV_CLAIM_MULTIPLE_REPORTID(uha)((uha)->claimed != ((void *)0)))
172 return (UMATCH_NONE0);
173
174 if (uthum_lookup(uha->uaa->vendor, uha->uaa->product)usbd_match_device((const struct usb_devno *)(uthum_devs), sizeof
(uthum_devs) / sizeof ((uthum_devs)[0]), sizeof ((uthum_devs
)[0]), (uha->uaa->vendor), (uha->uaa->product))
== NULL((void *)0))
175 return UMATCH_NONE0;
176
177#if 0 /* attach only sensor part of HID as uthum* */
178#define HUG_UNKNOWN_3 0x0003
179 void *desc;
180 int size;
181 uhidev_get_report_desc(uha->parent, &desc, &size);
182 if (!hid_is_collection(desc, size, uha->reportid,
183 HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_UNKNOWN_3)(((0x0001) << 16) | HUG_UNKNOWN_3)))
184 return (UMATCH_NONE0);
185#undef HUG_UNKNOWN_3
186#endif
187
188 return (UMATCH_VENDOR_PRODUCT13);
189}
190
191void
192uthum_attach(struct device *parent, struct device *self, void *aux)
193{
194 struct uthum_softc *sc = (struct uthum_softc *)self;
195 struct usb_attach_arg *uaa = aux;
196 struct uhidev_attach_arg *uha = (struct uhidev_attach_arg *)uaa;
197 struct usbd_device *dev = uha->parent->sc_udev;
198 int i, size, repid;
199 void *desc;
200
201 sc->sc_udev = dev;
202 sc->sc_hdev.sc_intr = uthum_intr;
203 sc->sc_hdev.sc_parent = uha->parent;
204 sc->sc_hdev.sc_report_id = uha->reportid;
205 sc->sc_num_sensors = 0;
206
207 uhidev_get_report_desc(uha->parent, &desc, &size);
208 repid = uha->reportid;
209 sc->sc_ilen = hid_report_size(desc, size, hid_input, repid);
210 sc->sc_olen = hid_report_size(desc, size, hid_output, repid);
211 sc->sc_flen = hid_report_size(desc, size, hid_feature, repid);
212
213 printf("\n");
214
215 if (sc->sc_flen < 32) {
216 /* not sensor interface, just attach */
217 return;
218 }
219
220 /* maybe unsupported device */
221 if (uthum_check_device_info(sc) < 0) {
222 DPRINTF(("uthum: unknown device\n"));
223 return;
224 };
225
226 /* attach sensor */
227 strlcpy(sc->sc_sensordev.xname, sc->sc_hdev.sc_dev.dv_xname,
228 sizeof(sc->sc_sensordev.xname));
229 uthum_setup_sensors(sc);
230
231 /* attach sensors */
232 for (i = 0; i < UTHUM_MAX_SENSORS2; i++) {
233 if (sc->sc_sensor[i].dev_type == UTHUM_SENSOR_UNKNOWN)
234 continue;
235 uthum_print_sensorinfo(sc, i);
236 sc->sc_sensor[i].sensor.flags |= SENSOR_FINVALID0x0001;
237 sensor_attach(&sc->sc_sensordev, &sc->sc_sensor[i].sensor);
238 sc->sc_sensor[i].attached = 1;
239 sc->sc_num_sensors++;
240 }
241
242 if (sc->sc_num_sensors > 0) {
243 /* 0.1Hz */
244 sc->sc_sensortask = sensor_task_register(sc, uthum_refresh, 6);
245 if (sc->sc_sensortask == NULL((void *)0)) {
246 printf(", unable to register update task\n");
247 return;
248 }
249 sensordev_install(&sc->sc_sensordev);
250 }
251
252 DPRINTF(("uthum_attach: complete\n"));
253}
254
255int
256uthum_detach(struct device *self, int flags)
257{
258 struct uthum_softc *sc = (struct uthum_softc *)self;
259 int i, rv = 0;
260
261 if (sc->sc_num_sensors > 0) {
262 wakeup(&sc->sc_sensortask);
263 sensordev_deinstall(&sc->sc_sensordev);
264 for (i = 0; i < UTHUM_MAX_SENSORS2; i++) {
265 if (sc->sc_sensor[i].attached)
266 sensor_detach(&sc->sc_sensordev,
267 &sc->sc_sensor[i].sensor);
268 }
269 if (sc->sc_sensortask != NULL((void *)0))
270 sensor_task_unregister(sc->sc_sensortask);
271 }
272
273 uthum_reset_device(sc);
274
275 return (rv);
276}
277
278void
279uthum_intr(struct uhidev *addr, void *ibuf, u_int len)
280{
281 /* do nothing */
282}
283
284int
285uthum_issue_cmd(struct uthum_softc *sc, uint8_t target_cmd, int delay)
286{
287 uint8_t cmdbuf[32];
288 int i, actlen, olen;
289
290 olen = MIN(sc->sc_olen, sizeof(cmdbuf))(((sc->sc_olen)<(sizeof(cmdbuf)))?(sc->sc_olen):(sizeof
(cmdbuf)))
;
291
292 bzero(cmdbuf, sizeof(cmdbuf))__builtin_bzero((cmdbuf), (sizeof(cmdbuf)));
293 memcpy(cmdbuf, cmd_issue, sizeof(cmd_issue))__builtin_memcpy((cmdbuf), (cmd_issue), (sizeof(cmd_issue)));
294 actlen = uhidev_set_report(sc->sc_hdev.sc_parent, UHID_OUTPUT_REPORT0x02,
295 sc->sc_hdev.sc_report_id, cmdbuf, olen);
296 if (actlen != olen)
297 return EIO5;
298
299 bzero(cmdbuf, sizeof(cmdbuf))__builtin_bzero((cmdbuf), (sizeof(cmdbuf)));
300 cmdbuf[0] = target_cmd;
301 actlen = uhidev_set_report(sc->sc_hdev.sc_parent, UHID_OUTPUT_REPORT0x02,
302 sc->sc_hdev.sc_report_id, cmdbuf, olen);
303 if (actlen != olen)
304 return EIO5;
305
306 bzero(cmdbuf, sizeof(cmdbuf))__builtin_bzero((cmdbuf), (sizeof(cmdbuf)));
307 for (i = 0; i < 7; i++) {
308 actlen = uhidev_set_report(sc->sc_hdev.sc_parent,
309 UHID_OUTPUT_REPORT0x02, sc->sc_hdev.sc_report_id, cmdbuf, olen);
310 if (actlen != olen)
311 return EIO5;
312 }
313
314 /* wait if required */
315 if (delay > 0)
316 tsleep_nsec(&sc->sc_sensortask, 0, "uthum",
317 MSEC_TO_NSEC(delay));
318
319 return 0;
320}
321
322int
323uthum_read_data(struct uthum_softc *sc, uint8_t target_cmd, uint8_t *buf,
324 size_t len, int delay)
325{
326 uint8_t cmdbuf[32], report[256];
327 int olen, flen;
328
329 /* if return buffer is null, do nothing */
330 if ((buf
8.1
'buf' is not equal to NULL
== NULL((void *)0)) || len
8.2
'len' is not equal to 0
== 0)
9
Taking false branch
331 return 0;
332
333 if (uthum_issue_cmd(sc, target_cmd, 50))
10
Assuming the condition is true
11
Taking true branch
334 return 0;
335
336 olen = MIN(sc->sc_olen, sizeof(cmdbuf))(((sc->sc_olen)<(sizeof(cmdbuf)))?(sc->sc_olen):(sizeof
(cmdbuf)))
;
337
338 bzero(cmdbuf, sizeof(cmdbuf))__builtin_bzero((cmdbuf), (sizeof(cmdbuf)));
339 memcpy(cmdbuf, cmd_query, sizeof(cmd_query))__builtin_memcpy((cmdbuf), (cmd_query), (sizeof(cmd_query)));
340 if (uhidev_set_report(sc->sc_hdev.sc_parent, UHID_OUTPUT_REPORT0x02,
341 sc->sc_hdev.sc_report_id, cmdbuf, olen) != olen)
342 return EIO5;
343
344 /* wait if required */
345 if (delay > 0)
346 tsleep_nsec(&sc->sc_sensortask, 0, "uthum",
347 MSEC_TO_NSEC(delay));
348
349 /* get answer */
350 flen = MIN(sc->sc_flen, sizeof(report))(((sc->sc_flen)<(sizeof(report)))?(sc->sc_flen):(sizeof
(report)))
;
351 if (uhidev_get_report(sc->sc_hdev.sc_parent, UHID_FEATURE_REPORT0x03,
352 sc->sc_hdev.sc_report_id, report, flen) != flen)
353 return EIO5;
354 memcpy(buf, report, len)__builtin_memcpy((buf), (report), (len));
355 return 0;
356}
357
358int
359uthum_check_device_info(struct uthum_softc *sc)
360{
361 struct uthum_dev_info {
362 uint16_t dev_type;
363 uint8_t cal[2][2]; /* calibration offsets */
364 uint8_t footer;
365 uint8_t padding[25];
366 } dinfo;
367 int val, dev_type;
368 int retry = 3;
369
370 /* issue query to device */
371 while (retry) {
372 if (uthum_read_data(sc, CMD_DEVTYPE0x52, (void *)&dinfo,
373 sizeof(struct uthum_dev_info), 0) != 0) {
374 DPRINTF(("uthum: device information query fail.\n"));
375 retry--;
376 continue;
377 }
378 if (dinfo.footer != DEVTYPE_EOF0x53) {
379 /* it will be a bogus entry, retry. */
380 retry--;
381 } else
382 break;
383 }
384
385 if (retry <= 0)
386 return EIO5;
387
388 dev_type = betoh16(dinfo.dev_type)(__uint16_t)(__builtin_constant_p(dinfo.dev_type) ? (__uint16_t
)(((__uint16_t)(dinfo.dev_type) & 0xffU) << 8 | ((__uint16_t
)(dinfo.dev_type) & 0xff00U) >> 8) : __swap16md(dinfo
.dev_type))
;
389 /* TEMPerHUM has 3 different device identifiers, unify them */
390 if (dev_type == UTHUM_TYPE_TEMPERHUM_20x575a ||
391 dev_type == UTHUM_TYPE_TEMPERHUM_30x5f5a)
392 dev_type = UTHUM_TYPE_TEMPERHUM0x535a;
393
394 /* check device type and calibration offset*/
395 switch (dev_type) {
396 case UTHUM_TYPE_TEMPER20x5759:
397 case UTHUM_TYPE_TEMPERHUM0x535a:
398 case UTHUM_TYPE_TEMPERNTC0x575b:
399 val = (dinfo.cal[1][0] - UTHUM_CAL_OFFSET0x14) * 100;
400 val += dinfo.cal[1][1] * 10;
401 sc->sc_sensor[1].cal_offset = val;
402 /* fall down, don't break */
403 case UTHUM_TYPE_TEMPER10x5758:
404 val = (dinfo.cal[0][0] - UTHUM_CAL_OFFSET0x14) * 100;
405 val += dinfo.cal[0][1] * 10;
406 sc->sc_sensor[0].cal_offset = val;
407 sc->sc_device_type = dev_type;
408 break;
409 default:
410 sc->sc_device_type = UTHUM_TYPE_UNKNOWN0xffff;
411 printf("uthum: unknown device (devtype = 0x%.2x)\n",
412 dev_type);
413 return EIO5;
414 }
415
416 /* device specific init process */
417 switch (dev_type) {
418 case UTHUM_TYPE_TEMPERHUM0x535a:
419 sc->sc_sensor[UTHUM_TEMPER_NTC1].cur_state = 0;
420 break;
421 };
422
423 uthum_reset_device(sc);
424
425 return 0;
426};
427
428void
429uthum_reset_device(struct uthum_softc *sc)
430{
431 switch (sc->sc_device_type) {
432 case UTHUM_TYPE_TEMPER10x5758:
433 case UTHUM_TYPE_TEMPERNTC0x575b:
434 uthum_issue_cmd(sc, CMD_RESET00x43, 200);
435 break;
436 case UTHUM_TYPE_TEMPER20x5759:
437 uthum_issue_cmd(sc, CMD_RESET00x43, 200);
438 uthum_issue_cmd(sc, CMD_RESET10x44, 200);
439 break;
440 }
441}
442
443void
444uthum_setup_sensors(struct uthum_softc *sc)
445{
446 int i;
447
448 for (i = 0; i < UTHUM_MAX_SENSORS2; i++)
449 sc->sc_sensor[i].dev_type = UTHUM_SENSOR_UNKNOWN;
450
451 switch (sc->sc_device_type) {
452 case UTHUM_TYPE_TEMPER20x5759: /* 2 temperature sensors */
453 sc->sc_sensor[UTHUM_TEMPER_OUTER1].dev_type =
454 UTHUM_SENSOR_DS75;
455 sc->sc_sensor[UTHUM_TEMPER_OUTER1].sensor.type =
456 SENSOR_TEMP;
457 strlcpy(sc->sc_sensor[UTHUM_TEMPER_OUTER1].sensor.desc,
458 "outer",
459 sizeof(sc->sc_sensor[UTHUM_TEMPER_OUTER1].sensor.desc));
460 /* fall down */
461 case UTHUM_TYPE_TEMPER10x5758: /* 1 temperature sensor */
462 sc->sc_sensor[UTHUM_TEMPER_INNER0].dev_type =
463 UTHUM_SENSOR_DS75;
464 sc->sc_sensor[UTHUM_TEMPER_INNER0].sensor.type =
465 SENSOR_TEMP;
466 strlcpy(sc->sc_sensor[UTHUM_TEMPER_INNER0].sensor.desc,
467 "inner",
468 sizeof(sc->sc_sensor[UTHUM_TEMPER_INNER0].sensor.desc));
469 break;
470 case UTHUM_TYPE_TEMPERHUM0x535a:
471 /* 1 temperature sensor and 1 humidity sensor */
472 for (i = 0; i < 2; i++)
473 sc->sc_sensor[i].dev_type = UTHUM_SENSOR_SHT1X;
474 sc->sc_sensor[UTHUM_TEMPERHUM_TEMP0].sensor.type = SENSOR_TEMP;
475 sc->sc_sensor[UTHUM_TEMPERHUM_HUM1].sensor.type =
476 SENSOR_HUMIDITY;
477 strlcpy(sc->sc_sensor[UTHUM_TEMPERHUM_HUM1].sensor.desc,
478 "RH",
479 sizeof(sc->sc_sensor[UTHUM_TEMPERHUM_HUM1].sensor.desc));
480 break;
481 case UTHUM_TYPE_TEMPERNTC0x575b:
482 /* 2 temperature sensors */
483 for (i = 0; i < 2; i++)
484 sc->sc_sensor[i].sensor.type = SENSOR_TEMP;
485 sc->sc_sensor[UTHUM_TEMPER_INNER0].dev_type =
486 UTHUM_SENSOR_DS75;
487 sc->sc_sensor[UTHUM_TEMPER_NTC1].dev_type =
488 UTHUM_SENSOR_NTC;
489 strlcpy(sc->sc_sensor[UTHUM_TEMPER_INNER0].sensor.desc,
490 "inner",
491 sizeof(sc->sc_sensor[UTHUM_TEMPER_INNER0].sensor.desc));
492 strlcpy(sc->sc_sensor[UTHUM_TEMPER_NTC1].sensor.desc,
493 "outer/ntc",
494 sizeof(sc->sc_sensor[UTHUM_TEMPER_NTC1].sensor.desc));
495
496 /* sensor state tuning */
497 for (i = 0; i < 4; i++)
498 uthum_issue_cmd(sc, TEMPERNTC_MODE_BASE0x61, 50);
499 sc->sc_sensor[UTHUM_TEMPER_NTC1].cur_state = TEMPERNTC_MODE_BASE0x61;
500 if (uthum_ntc_tuning(sc, UTHUM_TEMPER_NTC1, NULL((void *)0)))
501 DPRINTF(("uthum: NTC sensor tuning failed\n"));
502 uthum_issue_cmd(sc, CMD_TEMPERNTC_MODE_DONE0x69, 100);
503 break;
504 default:
505 /* do nothing */
506 break;
507 }
508}
509
510int
511uthum_ntc_getdata(struct uthum_softc *sc, int *val)
512{
513 uint8_t buf[8];
514
515 if (val == NULL((void *)0))
516 return EIO5;
517
518 /* get sensor value */
519 if (uthum_read_data(sc, CMD_GETDATA_NTC0x41, buf, sizeof(buf), 10) != 0) {
520 DPRINTF(("uthum: data read fail\n"));
521 return EIO5;
522 }
523
524 /* check data integrity */
525 if (buf[2] != CMD_GETDATA_EOF20xaa) {
526 DPRINTF(("uthum: broken ntc data 0x%.2x 0x%.2x 0x%.2x\n",
527 buf[0], buf[1], buf[2]));
528 return EIO5;
529 }
530
531 *val = (buf[0] << 8) + buf[1];
532 return 0;
533}
534
535int
536uthum_ntc_tuning(struct uthum_softc *sc, int sensor, int *val)
537{
538 struct uthum_sensor *s;
539 int done, state, ostate, curval;
540 int retry = 3;
541
542 s = &sc->sc_sensor[sensor];
543 state = s->cur_state;
544
545 /* get current sensor value */
546 if (val == NULL((void *)0)) {
547 while (retry) {
548 if (uthum_ntc_getdata(sc, &curval)) {
549 retry--;
550 continue;
551 } else
552 break;
553 }
554 if (retry <= 0)
555 return EIO5;
556 } else {
557 curval = *val;
558 }
559
560 /* no state change is required */
561 if ((curval >= UTHUM_NTC_MIN_THRESHOLD0xb300) &&
562 (curval <= UTHUM_NTC_MAX_THRESHOLD0xf200)) {
563 return 0;
564 }
565
566 if (((curval < UTHUM_NTC_MIN_THRESHOLD0xb300) &&
567 (state == TEMPERNTC_MODE_MAX0x68)) ||
568 ((curval > UTHUM_NTC_MAX_THRESHOLD0xf200) &&
569 (state == TEMPERNTC_MODE_BASE0x61)))
570 return 0;
571
572 DPRINTF(("uthum: ntc tuning start. cur state = 0x%.2x, val = 0x%.4x\n",
573 state, curval));
574
575 /* tuning loop */
576 ostate = state;
577 done = 0;
578 while (!done) {
579 if (curval < UTHUM_NTC_MIN_THRESHOLD0xb300) {
580 if (state == TEMPERNTC_MODE_MAX0x68)
581 done++;
582 else
583 state++;
584 } else if (curval > UTHUM_NTC_MAX_THRESHOLD0xf200) {
585 if (state == TEMPERNTC_MODE_BASE0x61)
586 done++;
587 else
588 state--;
589 } else {
590 uthum_ntc_getdata(sc, &curval);
591 if ((curval >= UTHUM_NTC_MIN_THRESHOLD0xb300) &&
592 (curval <= UTHUM_NTC_MAX_THRESHOLD0xf200))
593 done++;
594 }
595
596 /* update state */
597 if (state != ostate) {
598 uthum_issue_cmd(sc, state, 50);
599 uthum_issue_cmd(sc, state, 50);
600 uthum_ntc_getdata(sc, &curval);
601 }
602 ostate = state;
603 }
604
605 DPRINTF(("uthum: ntc tuning done. state change: 0x%.2x->0x%.2x\n",
606 s->cur_state, state));
607 s->cur_state = state;
608 if (val != NULL((void *)0))
609 *val = curval;
610
611 return 0;
612}
613
614void
615uthum_refresh(void *arg)
616{
617 struct uthum_softc *sc = arg;
618 int i;
619
620 switch (sc->sc_device_type) {
1
Control jumps to 'case 22363:' at line 623
621 case UTHUM_TYPE_TEMPER10x5758:
622 case UTHUM_TYPE_TEMPER20x5759:
623 case UTHUM_TYPE_TEMPERNTC0x575b:
624 for (i = 0; i < sc->sc_num_sensors; i++) {
2
Assuming 'i' is < field 'sc_num_sensors'
3
Loop condition is true. Entering loop body
625 if (sc->sc_sensor[i].dev_type == UTHUM_SENSOR_DS75)
4
Assuming field 'dev_type' is equal to UTHUM_SENSOR_DS75
5
Taking true branch
626 uthum_refresh_temper(sc, i);
6
Calling 'uthum_refresh_temper'
627 else if (sc->sc_sensor[i].dev_type == UTHUM_SENSOR_NTC)
628 uthum_refresh_temperntc(sc, i);
629 }
630 break;
631 case UTHUM_TYPE_TEMPERHUM0x535a:
632 uthum_refresh_temperhum(sc);
633 break;
634 default:
635 break;
636 /* never reach */
637 }
638}
639
640void
641uthum_refresh_temperhum(struct uthum_softc *sc)
642{
643 uint8_t buf[8];
644 int temp, rh;
645
646 if (uthum_read_data(sc, CMD_GETDATA0x48, buf, sizeof(buf), 1000) != 0) {
647 DPRINTF(("uthum: data read fail\n"));
648 sc->sc_sensor[UTHUM_TEMPERHUM_TEMP0].sensor.flags
649 |= SENSOR_FINVALID0x0001;
650 sc->sc_sensor[UTHUM_TEMPERHUM_HUM1].sensor.flags
651 |= SENSOR_FINVALID0x0001;
652 return;
653 }
654
655 temp = uthum_sht1x_temp(buf[0], buf[1]);
656 rh = uthum_sht1x_rh(buf[2], buf[3], temp);
657
658 /* apply calibration offsets */
659 temp += sc->sc_sensor[UTHUM_TEMPERHUM_TEMP0].cal_offset;
660 rh += sc->sc_sensor[UTHUM_TEMPERHUM_HUM1].cal_offset;
661
662 sc->sc_sensor[UTHUM_TEMPERHUM_TEMP0].sensor.value =
663 (temp * 10000) + 273150000;
664 sc->sc_sensor[UTHUM_TEMPERHUM_TEMP0].sensor.flags &= ~SENSOR_FINVALID0x0001;
665 sc->sc_sensor[UTHUM_TEMPERHUM_HUM1].sensor.value = rh;
666 sc->sc_sensor[UTHUM_TEMPERHUM_HUM1].sensor.flags &= ~SENSOR_FINVALID0x0001;
667}
668
669void
670uthum_refresh_temper(struct uthum_softc *sc, int sensor)
671{
672 uint8_t buf[8];
673 uint8_t cmd;
674 int temp;
675
676 if (sensor
6.1
'sensor' is equal to UTHUM_TEMPER_INNER
== UTHUM_TEMPER_INNER0)
7
Taking true branch
677 cmd = CMD_GETDATA_INNER0x54;
678 else if (sensor == UTHUM_TEMPER_OUTER1)
679 cmd = CMD_GETDATA_OUTER0x53;
680 else
681 return;
682
683 /* get sensor value */
684 if (uthum_read_data(sc, cmd, buf, sizeof(buf), 1000) != 0) {
8
Calling 'uthum_read_data'
12
Returning from 'uthum_read_data'
13
Taking false branch
685 DPRINTF(("uthum: data read fail\n"));
686 sc->sc_sensor[sensor].sensor.flags |= SENSOR_FINVALID0x0001;
687 return;
688 }
689
690 /* check integrity */
691 if (buf[2] != CMD_GETDATA_EOF0x31) {
14
The left operand of '!=' is a garbage value
692 DPRINTF(("uthum: broken ds75 data: 0x%.2x 0x%.2x 0x%.2x\n",
693 buf[0], buf[1], buf[2]));
694 sc->sc_sensor[sensor].sensor.flags |= SENSOR_FINVALID0x0001;
695 return;
696 }
697 temp = uthum_ds75_temp(buf[0], buf[1]);
698
699 /* apply calibration offset */
700 temp += sc->sc_sensor[sensor].cal_offset;
701
702 sc->sc_sensor[sensor].sensor.value = (temp * 10000) + 273150000;
703 sc->sc_sensor[sensor].sensor.flags &= ~SENSOR_FINVALID0x0001;
704}
705
706void
707uthum_refresh_temperntc(struct uthum_softc *sc, int sensor)
708{
709 int val;
710 int64_t temp;
711
712 /* get sensor data */
713 if (uthum_ntc_getdata(sc, &val)) {
714 DPRINTF(("uthum: ntc data read fail\n"));
715 sc->sc_sensor[sensor].sensor.flags |= SENSOR_FINVALID0x0001;
716 return;
717 }
718
719 /* adjust sensor state */
720 if ((val < UTHUM_NTC_MIN_THRESHOLD0xb300) ||
721 (val > UTHUM_NTC_MAX_THRESHOLD0xf200)) {
722 if (uthum_ntc_tuning(sc, UTHUM_TEMPER_NTC1, &val)) {
723 DPRINTF(("uthum: NTC sensor tuning failed\n"));
724 sc->sc_sensor[sensor].sensor.flags |= SENSOR_FINVALID0x0001;
725 return;
726 }
727 }
728
729 temp = uthum_ntc_temp(val, sc->sc_sensor[sensor].cur_state);
730 if (temp == 0) {
731 /* XXX: work around. */
732 sc->sc_sensor[sensor].sensor.flags |= SENSOR_FINVALID0x0001;
733 } else {
734 /* apply calibration offset */
735 temp += sc->sc_sensor[sensor].cal_offset * 10000;
736 sc->sc_sensor[sensor].sensor.value = temp;
737 sc->sc_sensor[sensor].sensor.flags &= ~SENSOR_FINVALID0x0001;
738 }
739}
740
741/* return C-degree * 100 value */
742int
743uthum_ds75_temp(uint8_t msb, uint8_t lsb)
744{
745 /* DS75: 12bit precision mode : 0.0625 degrees Celsius ticks */
746 return (msb * 100) + ((lsb >> 4) * 25 / 4);
747}
748
749/* return C-degree * 100 value */
750int
751uthum_sht1x_temp(uint8_t msb, uint8_t lsb)
752{
753 int nticks;
754
755 /* sensor device VDD-bias value table
756 * ----------------------------------------------
757 * VDD 2.5V 3.0V 3.5V 4.0V 5.0V
758 * bias -3940 -3960 -3970 -3980 -4010
759 * ----------------------------------------------
760 *
761 * as the VDD of the SHT10 on my TEMPerHUM is 3.43V +/- 0.05V,
762 * bias -3970 will be best for that device.
763 */
764
765 nticks = (msb * 256 + lsb) & 0x3fff;
766 return (nticks - 3970);
767}
768
769/* return %RH * 1000 */
770int
771uthum_sht1x_rh(uint8_t msb, uint8_t lsb, int temp)
772{
773 int nticks, rh_l;
774
775 nticks = (msb * 256 + lsb) & 0x0fff;
776 rh_l = (-40000 + 405 * nticks) - ((7 * nticks * nticks) / 250);
777
778 return ((temp - 2500) * (1 + (nticks >> 7)) + rh_l) / 10;
779}
780
781/* return muK */
782int64_t
783uthum_ntc_temp(int64_t val, int state)
784{
785 int64_t temp = 0;
786
787 switch (state) {
788 case TEMPERNTC_MODE_BASE0x61: /* 0x61 */
789 case TEMPERNTC_MODE_BASE0x61+1: /* 0x62 */
790 case TEMPERNTC_MODE_BASE0x61+2: /* 0x63 */
791 case TEMPERNTC_MODE_BASE0x61+3: /* 0x64 */
792 /* XXX, no data */
793 temp = -273150000;
794 break;
795 case TEMPERNTC_MODE_BASE0x61+4: /* 0x65 */
796 temp = ((val * val * 2977) / 100000) - (val * 4300) + 152450000;
797 break;
798 case TEMPERNTC_MODE_BASE0x61+5: /* 0x66 */
799 temp = ((val * val * 3887) / 100000) - (val * 5300) + 197590000;
800 break;
801 case TEMPERNTC_MODE_BASE0x61+6: /* 0x67 */
802 temp = ((val * val * 3495) / 100000) - (val * 5000) + 210590000;
803 break;
804 case TEMPERNTC_MODE_BASE0x61+7: /* 0x68 */
805 if (val < UTHUM_NTC_MIN_THRESHOLD0xb300)
806 temp = (val * -1700) + 149630000;
807 else
808 temp = ((val * val * 3257) / 100000) - (val * 4900) +
809 230470000;
810 break;
811 default:
812 DPRINTF(("NTC state error, unknown state 0x%.2x\n", state));
813 break;
814 }
815
816 /* convert muC->muK value */
817 return temp + 273150000;
818}
819
820void
821uthum_print_sensorinfo(struct uthum_softc *sc, int num)
822{
823 struct uthum_sensor *s;
824 s = &sc->sc_sensor[num];
825
826 printf("%s: ", sc->sc_hdev.sc_dev.dv_xname);
827 switch (s->sensor.type) {
828 case SENSOR_TEMP:
829 printf("type %s (temperature)",
830 uthum_sensor_type_s[s->dev_type]);
831 if (s->cal_offset)
832 printf(", calibration offset %c%d.%d degC",
833 (s->cal_offset < 0) ? '-' : '+',
834 abs(s->cal_offset / 100),
835 abs(s->cal_offset % 100));
836 break;
837 case SENSOR_HUMIDITY:
838 printf("type %s (humidity)",
839 uthum_sensor_type_s[s->dev_type]);
840 if (s->cal_offset)
841 printf("calibration offset %c%d.%d %%RH",
842 (s->cal_offset < 0) ? '-' : '+',
843 abs(s->cal_offset / 100),
844 abs(s->cal_offset % 100));
845 break;
846 default:
847 printf("unknown");
848 }
849 printf("\n");
850}