Bug Summary

File:dev/usb/udcf.c
Warning:line 198, column 7
Although the value stored to 'err' is used in the enclosing expression, the value is never actually read from 'err'

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple amd64-unknown-openbsd7.4 -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name udcf.c -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 -ffp-contract=on -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 -target-feature +retpoline-external-thunk -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/llvm16/lib/clang/16 -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/legacy-dpm -I /usr/src/sys/dev/pci/drm/amd/pm/swsmu -I /usr/src/sys/dev/pci/drm/amd/pm/swsmu/inc -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/swsmu/smu13 -I /usr/src/sys/dev/pci/drm/amd/pm/powerplay/inc -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/pm/swsmu/inc -I /usr/src/sys/dev/pci/drm/amd/pm/swsmu/inc/pmfw_if -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 SUSPEND -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 -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 -fcf-protection=branch -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 /home/ben/Projects/scan/2024-01-11-110808-61670-1 -x c /usr/src/sys/dev/usb/udcf.c
1/* $OpenBSD: udcf.c,v 1.65 2022/07/02 08:50:42 visa Exp $ */
2
3/*
4 * Copyright (c) 2006, 2007, 2008 Marc Balmer <mbalmer@openbsd.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 DISCLAIMS 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#include <sys/param.h>
20#include <sys/systm.h>
21#include <sys/kernel.h>
22#include <sys/device.h>
23#include <sys/time.h>
24#include <sys/sensors.h>
25#include <sys/timeout.h>
26
27#include <dev/usb/usb.h>
28#include <dev/usb/usbdi.h>
29#include <dev/usb/usbdi_util.h>
30#include <dev/usb/usbdevs.h>
31
32#ifdef UDCF_DEBUG
33#define DPRINTFN(n, x) do { if (udcfdebug > (n)) printf x; } while (0)
34int udcfdebug = 0;
35#else
36#define DPRINTFN(n, x)
37#endif
38#define DPRINTF(x) DPRINTFN(0, x)
39
40#define UDCF_READ_IDX0x1f 0x1f
41
42#define UDCF_CTRL_IDX0x33 0x33
43#define UDCF_CTRL_VAL0x98 0x98
44
45#define FT232R_RESET0x00 0x00 /* reset USB request */
46#define FT232R_STATUS0x05 0x05 /* get modem status USB request */
47#define FT232R_RI0x40 0x40 /* ring indicator */
48
49/* max. skew of received time diff vs. measured time diff in percent. */
50#define MAX_SKEW5 5
51
52#define CLOCK_DCF77"DCF77" "DCF77"
53
54struct udcf_softc {
55 struct device sc_dev; /* base device */
56 struct usbd_device *sc_udev; /* USB device */
57 struct usbd_interface *sc_iface; /* data interface */
58
59 struct timeout sc_to;
60 struct usb_task sc_task;
61
62 struct timeout sc_bv_to; /* bit-value detect */
63 struct timeout sc_db_to; /* debounce */
64 struct timeout sc_mg_to; /* minute-gap detect */
65 struct timeout sc_sl_to; /* signal-loss detect */
66 struct timeout sc_it_to; /* invalidate time */
67 struct usb_task sc_bv_task;
68 struct usb_task sc_mg_task;
69 struct usb_task sc_sl_task;
70
71 usb_device_request_t sc_req;
72
73 int sc_sync; /* 1 during sync */
74 u_int64_t sc_mask; /* 64 bit mask */
75 u_int64_t sc_tbits; /* Time bits */
76 int sc_minute;
77 int sc_level;
78 time_t sc_last_mg;
79 int (*sc_signal)(struct udcf_softc *);
80
81 time_t sc_current; /* current time */
82 time_t sc_next; /* time to become valid next */
83 time_t sc_last;
84 int sc_nrecv; /* consecutive valid times */
85 struct timeval sc_last_tv; /* uptime of last valid time */
86 struct ksensor sc_sensor;
87#ifdef UDCF_DEBUG
88 struct ksensor sc_skew; /* recv vs local skew */
89#endif
90 struct ksensordev sc_sensordev;
91};
92
93/* timeouts in milliseconds: */
94#define T_BV150 150 /* bit value detection (150ms) */
95#define T_SYNC950 950 /* sync (950ms) */
96#define T_MG1500 1500 /* minute gap detection (1500ms) */
97#define T_MGSYNC450 450 /* resync after a minute gap (450ms) */
98#define T_SL3000 3000 /* detect signal loss (3sec) */
99#define T_WAIT5000 5000 /* wait (5sec) */
100#define T_WARN300000 300000 /* degrade sensor status to warning (5min) */
101#define T_CRIT900000 900000 /* degrade sensor status to critical (15min) */
102
103void udcf_intr(void *);
104void udcf_probe(void *);
105
106void udcf_bv_intr(void *);
107void udcf_mg_intr(void *);
108void udcf_sl_intr(void *);
109void udcf_it_intr(void *);
110void udcf_bv_probe(void *);
111void udcf_mg_probe(void *);
112void udcf_sl_probe(void *);
113
114int udcf_match(struct device *, void *, void *);
115void udcf_attach(struct device *, struct device *, void *);
116int udcf_detach(struct device *, int);
117
118int udcf_nc_signal(struct udcf_softc *);
119int udcf_nc_init_hw(struct udcf_softc *);
120int udcf_ft232r_signal(struct udcf_softc *);
121int udcf_ft232r_init_hw(struct udcf_softc *);
122
123struct cfdriver udcf_cd = {
124 NULL((void *)0), "udcf", DV_DULL
125};
126
127const struct cfattach udcf_ca = {
128 sizeof(struct udcf_softc), udcf_match, udcf_attach, udcf_detach,
129};
130
131static const struct usb_devno udcf_devs[] = {
132 { USB_VENDOR_GUDE0x0959, USB_PRODUCT_GUDE_DCF0xdcf7 },
133 { USB_VENDOR_FTDI0x0403, USB_PRODUCT_FTDI_DCF0xe88a }
134};
135
136int
137udcf_match(struct device *parent, void *match, void *aux)
138{
139 struct usb_attach_arg *uaa = aux;
140
141 if (uaa->iface == NULL((void *)0))
142 return UMATCH_NONE0;
143
144 return (usb_lookup(udcf_devs, uaa->vendor, uaa->product)usbd_match_device((const struct usb_devno *)(udcf_devs), sizeof
(udcf_devs) / sizeof ((udcf_devs)[0]), sizeof ((udcf_devs)[0
]), (uaa->vendor), (uaa->product))
!= NULL((void *)0) ?
145 UMATCH_VENDOR_PRODUCT13 : UMATCH_NONE0);
146}
147
148void
149udcf_attach(struct device *parent, struct device *self, void *aux)
150{
151 struct udcf_softc *sc = (struct udcf_softc *)self;
152 struct usb_attach_arg *uaa = aux;
153 struct usbd_device *dev = uaa->device;
154 struct usbd_interface *iface;
155 usbd_status err;
156
157 switch (uaa->product) {
158 case USB_PRODUCT_GUDE_DCF0xdcf7:
159 sc->sc_signal = udcf_nc_signal;
160 strlcpy(sc->sc_sensor.desc, "DCF77",
161 sizeof(sc->sc_sensor.desc));
162 break;
163 case USB_PRODUCT_FTDI_DCF0xe88a:
164 sc->sc_signal = udcf_ft232r_signal;
165 strlcpy(sc->sc_sensor.desc, "DCF77",
166 sizeof(sc->sc_sensor.desc));
167 break;
168 }
169
170 usb_init_task(&sc->sc_task, udcf_probe, sc, USB_TASK_TYPE_GENERIC)((&sc->sc_task)->fun = (udcf_probe), (&sc->sc_task
)->arg = (sc), (&sc->sc_task)->type = (0), (&
sc->sc_task)->state = 0x0)
;
171 usb_init_task(&sc->sc_bv_task, udcf_bv_probe, sc, USB_TASK_TYPE_GENERIC)((&sc->sc_bv_task)->fun = (udcf_bv_probe), (&sc
->sc_bv_task)->arg = (sc), (&sc->sc_bv_task)->
type = (0), (&sc->sc_bv_task)->state = 0x0)
;
172 usb_init_task(&sc->sc_mg_task, udcf_mg_probe, sc, USB_TASK_TYPE_GENERIC)((&sc->sc_mg_task)->fun = (udcf_mg_probe), (&sc
->sc_mg_task)->arg = (sc), (&sc->sc_mg_task)->
type = (0), (&sc->sc_mg_task)->state = 0x0)
;
173 usb_init_task(&sc->sc_sl_task, udcf_sl_probe, sc, USB_TASK_TYPE_GENERIC)((&sc->sc_sl_task)->fun = (udcf_sl_probe), (&sc
->sc_sl_task)->arg = (sc), (&sc->sc_sl_task)->
type = (0), (&sc->sc_sl_task)->state = 0x0)
;
174
175 timeout_set(&sc->sc_to, udcf_intr, sc);
176 timeout_set(&sc->sc_bv_to, udcf_bv_intr, sc);
177 timeout_set(&sc->sc_mg_to, udcf_mg_intr, sc);
178 timeout_set(&sc->sc_sl_to, udcf_sl_intr, sc);
179 timeout_set(&sc->sc_it_to, udcf_it_intr, sc);
180
181 strlcpy(sc->sc_sensordev.xname, sc->sc_dev.dv_xname,
182 sizeof(sc->sc_sensordev.xname));
183
184 sc->sc_sensor.type = SENSOR_TIMEDELTA;
185 sc->sc_sensor.status = SENSOR_S_UNKNOWN;
186 sensor_attach(&sc->sc_sensordev, &sc->sc_sensor);
187
188#ifdef UDCF_DEBUG
189 sc->sc_skew.type = SENSOR_TIMEDELTA;
190 sc->sc_skew.status = SENSOR_S_UNKNOWN;
191 strlcpy(sc->sc_skew.desc, "local clock skew",
192 sizeof(sc->sc_skew.desc));
193 sensor_attach(&sc->sc_sensordev, &sc->sc_skew);
194#endif
195 sensordev_install(&sc->sc_sensordev);
196
197 sc->sc_udev = dev;
198 if ((err = usbd_device2interface_handle(dev, 0, &iface))) {
Although the value stored to 'err' is used in the enclosing expression, the value is never actually read from 'err'
199 DPRINTF(("%s: failed to get interface, err=%s\n",
200 sc->sc_dev.dv_xname, usbd_errstr(err)));
201 goto fishy;
202 }
203
204 sc->sc_iface = iface;
205
206 sc->sc_level = 0;
207 sc->sc_minute = 0;
208 sc->sc_last_mg = 0L;
209
210 sc->sc_sync = 1;
211
212 sc->sc_current = 0L;
213 sc->sc_next = 0L;
214 sc->sc_nrecv = 0;
215 sc->sc_last = 0L;
216 sc->sc_last_tv.tv_sec = 0L;
217
218 switch (uaa->product) {
219 case USB_PRODUCT_GUDE_DCF0xdcf7:
220 if (udcf_nc_init_hw(sc))
221 goto fishy;
222 break;
223 case USB_PRODUCT_FTDI_DCF0xe88a:
224 if (udcf_ft232r_init_hw(sc))
225 goto fishy;
226 break;
227 }
228
229 /* Give the receiver some slack to stabilize */
230 timeout_add_msec(&sc->sc_to, T_WAIT5000);
231
232 /* Detect signal loss */
233 timeout_add_msec(&sc->sc_sl_to, T_WAIT5000 + T_SL3000);
234
235 DPRINTF(("synchronizing\n"));
236 return;
237
238fishy:
239 DPRINTF(("udcf_attach failed\n"));
240 usbd_deactivate(sc->sc_udev);
241}
242
243int
244udcf_detach(struct device *self, int flags)
245{
246 struct udcf_softc *sc = (struct udcf_softc *)self;
247
248 if (timeout_initialized(&sc->sc_to)((&sc->sc_to)->to_flags & 0x04))
249 timeout_del(&sc->sc_to);
250 if (timeout_initialized(&sc->sc_bv_to)((&sc->sc_bv_to)->to_flags & 0x04))
251 timeout_del(&sc->sc_bv_to);
252 if (timeout_initialized(&sc->sc_mg_to)((&sc->sc_mg_to)->to_flags & 0x04))
253 timeout_del(&sc->sc_mg_to);
254 if (timeout_initialized(&sc->sc_sl_to)((&sc->sc_sl_to)->to_flags & 0x04))
255 timeout_del(&sc->sc_sl_to);
256 if (timeout_initialized(&sc->sc_it_to)((&sc->sc_it_to)->to_flags & 0x04))
257 timeout_del(&sc->sc_it_to);
258
259 /* Unregister the clock with the kernel */
260 sensordev_deinstall(&sc->sc_sensordev);
261 usb_rem_task(sc->sc_udev, &sc->sc_task);
262 usb_rem_task(sc->sc_udev, &sc->sc_bv_task);
263 usb_rem_task(sc->sc_udev, &sc->sc_mg_task);
264 usb_rem_task(sc->sc_udev, &sc->sc_sl_task);
265
266 return 0;
267}
268
269/* udcf_intr runs in an interrupt context */
270void
271udcf_intr(void *xsc)
272{
273 struct udcf_softc *sc = xsc;
274 usb_add_task(sc->sc_udev, &sc->sc_task);
275}
276
277/* bit value detection */
278void
279udcf_bv_intr(void *xsc)
280{
281 struct udcf_softc *sc = xsc;
282 usb_add_task(sc->sc_udev, &sc->sc_bv_task);
283}
284
285/* minute gap detection */
286void
287udcf_mg_intr(void *xsc)
288{
289 struct udcf_softc *sc = xsc;
290 usb_add_task(sc->sc_udev, &sc->sc_mg_task);
291}
292
293/* signal loss detection */
294void
295udcf_sl_intr(void *xsc)
296{
297 struct udcf_softc *sc = xsc;
298 usb_add_task(sc->sc_udev, &sc->sc_sl_task);
299}
300
301/*
302 * initialize the Expert mouseCLOCK USB devices, they use a NetCologne
303 * chip to interface the receiver. Power must be supplied to the
304 * receiver and the receiver must be turned on.
305 */
306int
307udcf_nc_init_hw(struct udcf_softc *sc)
308{
309 usbd_status err;
310 usb_device_request_t req;
311 uWord result;
312 int actlen;
313
314 /* Prepare the USB request to probe the value */
315 sc->sc_req.bmRequestType = UT_READ_VENDOR_DEVICE(0x80 | 0x40 | 0x00);
316 sc->sc_req.bRequest = 1;
317 USETW(sc->sc_req.wValue, 0)(*(u_int16_t *)(sc->sc_req.wValue) = (0));
318 USETW(sc->sc_req.wIndex, UDCF_READ_IDX)(*(u_int16_t *)(sc->sc_req.wIndex) = (0x1f));
319 USETW(sc->sc_req.wLength, 1)(*(u_int16_t *)(sc->sc_req.wLength) = (1));
320
321 req.bmRequestType = UT_WRITE_VENDOR_DEVICE(0x00 | 0x40 | 0x00);
322 req.bRequest = 0;
323 USETW(req.wValue, 0)(*(u_int16_t *)(req.wValue) = (0));
324 USETW(req.wIndex, 0)(*(u_int16_t *)(req.wIndex) = (0));
325 USETW(req.wLength, 0)(*(u_int16_t *)(req.wLength) = (0));
326 if ((err = usbd_do_request_flags(sc->sc_udev, &req, &result,
327 USBD_SHORT_XFER_OK0x04, &actlen, USBD_DEFAULT_TIMEOUT5000))) {
328 DPRINTF(("failed to turn on power for receiver\n"));
329 return -1;
330 }
331
332 req.bmRequestType = UT_WRITE_VENDOR_DEVICE(0x00 | 0x40 | 0x00);
333 req.bRequest = 0;
334 USETW(req.wValue, UDCF_CTRL_VAL)(*(u_int16_t *)(req.wValue) = (0x98));
335 USETW(req.wIndex, UDCF_CTRL_IDX)(*(u_int16_t *)(req.wIndex) = (0x33));
336 USETW(req.wLength, 0)(*(u_int16_t *)(req.wLength) = (0));
337 if ((err = usbd_do_request_flags(sc->sc_udev, &req, &result,
338 USBD_SHORT_XFER_OK0x04, &actlen, USBD_DEFAULT_TIMEOUT5000))) {
339 DPRINTF(("failed to turn on receiver\n"));
340 return -1;
341 }
342 return 0;
343}
344
345/*
346 * initialize the Expert mouseCLOCK USB II devices, they use an FTDI
347 * FT232R chip to interface the receiver. Only reset the chip.
348 */
349int
350udcf_ft232r_init_hw(struct udcf_softc *sc)
351{
352 usbd_status err;
353 usb_device_request_t req;
354
355 req.bmRequestType = UT_WRITE_VENDOR_DEVICE(0x00 | 0x40 | 0x00);
356 req.bRequest = FT232R_RESET0x00;
357 /* 0 resets the SIO */
358 USETW(req.wValue,FT232R_RESET)(*(u_int16_t *)(req.wValue) = (0x00));
359 USETW(req.wIndex, 0)(*(u_int16_t *)(req.wIndex) = (0));
360 USETW(req.wLength, 0)(*(u_int16_t *)(req.wLength) = (0));
361 err = usbd_do_request(sc->sc_udev, &req, NULL((void *)0));
362 if (err) {
363 DPRINTF(("failed to reset ftdi\n"));
364 return -1;
365 }
366 return 0;
367}
368
369/*
370 * return 1 during high-power-, 0 during low-power-emission
371 * If bit 0 is set, the transmitter emits at full power.
372 * During the low-power emission we decode a zero bit.
373 */
374int
375udcf_nc_signal(struct udcf_softc *sc)
376{
377 int actlen;
378 unsigned char data;
379
380 if (usbd_do_request_flags(sc->sc_udev, &sc->sc_req, &data,
381 USBD_SHORT_XFER_OK0x04, &actlen, USBD_DEFAULT_TIMEOUT5000))
382 /* This happens if we pull the receiver */
383 return -1;
384 return data & 0x01;
385}
386
387/* pick up the signal level through the FTDI FT232R chip */
388int
389udcf_ft232r_signal(struct udcf_softc *sc)
390{
391 usb_device_request_t req;
392 int actlen;
393 u_int16_t data;
394
395 req.bmRequestType = UT_READ_VENDOR_DEVICE(0x80 | 0x40 | 0x00);
396 req.bRequest = FT232R_STATUS0x05;
397 USETW(req.wValue, 0)(*(u_int16_t *)(req.wValue) = (0));
398 USETW(req.wIndex, 0)(*(u_int16_t *)(req.wIndex) = (0));
399 USETW(req.wLength, 2)(*(u_int16_t *)(req.wLength) = (2));
400 if (usbd_do_request_flags(sc->sc_udev, &req, &data,
401 USBD_SHORT_XFER_OK0x04, &actlen, USBD_DEFAULT_TIMEOUT5000)) {
402 DPRINTFN(2, ("error reading ftdi modem status\n"));
403 return -1;
404 }
405 DPRINTFN(2, ("ftdi status 0x%04x\n", data));
406 return data & FT232R_RI0x40 ? 0 : 1;
407}
408
409/* udcf_probe runs in a process context. */
410void
411udcf_probe(void *xsc)
412{
413 struct udcf_softc *sc = xsc;
414 struct timespec now;
415 int data;
416
417 if (usbd_is_dying(sc->sc_udev))
418 return;
419
420 data = sc->sc_signal(sc);
421 if (data == -1)
422 return;
423
424 if (data) {
425 sc->sc_level = 1;
426 timeout_add(&sc->sc_to, 1);
427 return;
428 }
429
430 if (sc->sc_level == 0)
431 return;
432
433 /* the beginning of a second */
434 sc->sc_level = 0;
435 if (sc->sc_minute == 1) {
436 if (sc->sc_sync) {
437 DPRINTF(("start collecting bits\n"));
438 sc->sc_sync = 0;
439 } else {
440 /* provide the timedelta */
441 microtime(&sc->sc_sensor.tv);
442 nanotime(&now);
443 sc->sc_current = sc->sc_next;
444 sc->sc_sensor.value = (int64_t)(now.tv_sec -
445 sc->sc_current) * 1000000000LL + now.tv_nsec;
446
447 sc->sc_sensor.status = SENSOR_S_OK;
448
449 /*
450 * if no valid time information is received
451 * during the next 5 minutes, the sensor state
452 * will be degraded to SENSOR_S_WARN
453 */
454 timeout_add_msec(&sc->sc_it_to, T_WARN300000);
455 }
456 sc->sc_minute = 0;
457 }
458
459 timeout_add_msec(&sc->sc_to, T_SYNC950); /* resync in 950 ms */
460
461 /* no clock and bit detection during sync */
462 if (!sc->sc_sync) {
463 /* detect bit value */
464 timeout_add_msec(&sc->sc_bv_to, T_BV150);
465 }
466 timeout_add_msec(&sc->sc_mg_to, T_MG1500); /* detect minute gap */
467 timeout_add_msec(&sc->sc_sl_to, T_SL3000); /* detect signal loss */
468}
469
470/* detect the bit value */
471void
472udcf_bv_probe(void *xsc)
473{
474 struct udcf_softc *sc = xsc;
475 int data;
476
477 if (usbd_is_dying(sc->sc_udev))
478 return;
479
480 data = sc->sc_signal(sc);
481 if (data == -1) {
482 DPRINTF(("bit detection failed\n"));
483 return;
484 }
485
486 DPRINTFN(1, (data ? "0" : "1"));
487 if (!(data))
488 sc->sc_tbits |= sc->sc_mask;
489 sc->sc_mask <<= 1;
490}
491
492/* detect the minute gap */
493void
494udcf_mg_probe(void *xsc)
495{
496 struct udcf_softc *sc = xsc;
497 struct clock_ymdhms ymdhm;
498 struct timeval monotime;
499 int tdiff_recv, tdiff_local;
500 int skew;
501 int minute_bits, hour_bits, day_bits;
502 int month_bits, year_bits, wday;
503 int p1, p2, p3;
504 int p1_bit, p2_bit, p3_bit;
505 int r_bit, a1_bit, a2_bit, z1_bit, z2_bit;
506 int s_bit, m_bit;
507 u_int32_t parity = 0x6996;
508
509 if (sc->sc_sync) {
510 sc->sc_minute = 1;
511 goto cleanbits;
512 }
513
514 if (gettime() - sc->sc_last_mg < 57) {
515 DPRINTF(("\nunexpected gap, resync\n"));
516 sc->sc_sync = sc->sc_minute = 1;
517 goto cleanbits;
518 }
519
520 /* extract bits w/o parity */
521 m_bit = sc->sc_tbits & 1;
522 r_bit = sc->sc_tbits >> 15 & 1;
523 a1_bit = sc->sc_tbits >> 16 & 1;
524 z1_bit = sc->sc_tbits >> 17 & 1;
525 z2_bit = sc->sc_tbits >> 18 & 1;
526 a2_bit = sc->sc_tbits >> 19 & 1;
527 s_bit = sc->sc_tbits >> 20 & 1;
528 p1_bit = sc->sc_tbits >> 28 & 1;
529 p2_bit = sc->sc_tbits >> 35 & 1;
530 p3_bit = sc->sc_tbits >> 58 & 1;
531
532 minute_bits = sc->sc_tbits >> 21 & 0x7f;
533 hour_bits = sc->sc_tbits >> 29 & 0x3f;
534 day_bits = sc->sc_tbits >> 36 & 0x3f;
535 wday = (sc->sc_tbits >> 42) & 0x07;
536 month_bits = sc->sc_tbits >> 45 & 0x1f;
537 year_bits = sc->sc_tbits >> 50 & 0xff;
538
539 /* validate time information */
540 p1 = (parity >> (minute_bits & 0x0f) & 1) ^
541 (parity >> (minute_bits >> 4) & 1);
542
543 p2 = (parity >> (hour_bits & 0x0f) & 1) ^
544 (parity >> (hour_bits >> 4) & 1);
545
546 p3 = (parity >> (day_bits & 0x0f) & 1) ^
547 (parity >> (day_bits >> 4) & 1) ^
548 ((parity >> wday) & 1) ^ (parity >> (month_bits & 0x0f) & 1) ^
549 (parity >> (month_bits >> 4) & 1) ^
550 (parity >> (year_bits & 0x0f) & 1) ^
551 (parity >> (year_bits >> 4) & 1);
552
553 if (m_bit == 0 && s_bit == 1 && p1 == p1_bit && p2 == p2_bit &&
554 p3 == p3_bit && (z1_bit ^ z2_bit)) {
555
556 /* Decode time */
557 if ((ymdhm.dt_year = 2000 + FROMBCD(year_bits)(((year_bits) >> 4) * 10 + ((year_bits) & 0xf))) > 2037) {
558 DPRINTF(("year out of range, resync\n"));
559 sc->sc_sync = 1;
560 goto cleanbits;
561 }
562 ymdhm.dt_min = FROMBCD(minute_bits)(((minute_bits) >> 4) * 10 + ((minute_bits) & 0xf));
563 ymdhm.dt_hour = FROMBCD(hour_bits)(((hour_bits) >> 4) * 10 + ((hour_bits) & 0xf));
564 ymdhm.dt_day = FROMBCD(day_bits)(((day_bits) >> 4) * 10 + ((day_bits) & 0xf));
565 ymdhm.dt_mon = FROMBCD(month_bits)(((month_bits) >> 4) * 10 + ((month_bits) & 0xf));
566 ymdhm.dt_sec = 0;
567
568 sc->sc_next = clock_ymdhms_to_secs(&ymdhm);
569 getmicrouptime(&monotime);
570
571 /* convert to coordinated universal time */
572 sc->sc_next -= z1_bit ? 7200 : 3600;
573
574 DPRINTF(("\n%02d.%02d.%04d %02d:%02d:00 %s",
575 ymdhm.dt_day, ymdhm.dt_mon, ymdhm.dt_year,
576 ymdhm.dt_hour, ymdhm.dt_min, z1_bit ? "CEST" : "CET"));
577 DPRINTF((r_bit ? ", call bit" : ""));
578 DPRINTF((a1_bit ? ", dst chg ann." : ""));
579 DPRINTF((a2_bit ? ", leap sec ann." : ""));
580 DPRINTF(("\n"));
581
582 if (sc->sc_last) {
583 tdiff_recv = sc->sc_next - sc->sc_last;
584 tdiff_local = monotime.tv_sec - sc->sc_last_tv.tv_sec;
585 skew = abs(tdiff_local - tdiff_recv);
586#ifdef UDCF_DEBUG
587 if (sc->sc_skew.status == SENSOR_S_UNKNOWN)
588 sc->sc_skew.status = SENSOR_S_CRIT;
589 sc->sc_skew.value = skew * 1000000000LL;
590 getmicrotime(&sc->sc_skew.tv);
591#endif
592 DPRINTF(("local = %d, recv = %d, skew = %d\n",
593 tdiff_local, tdiff_recv, skew));
594
595 if (skew && skew * 100LL / tdiff_local > MAX_SKEW5) {
596 DPRINTF(("skew out of tolerated range\n"));
597 goto cleanbits;
598 } else {
599 if (sc->sc_nrecv < 2) {
600 sc->sc_nrecv++;
601 DPRINTF(("got frame %d\n",
602 sc->sc_nrecv));
603 } else {
604 DPRINTF(("data is valid\n"));
605 sc->sc_minute = 1;
606 }
607 }
608 } else {
609 DPRINTF(("received the first frame\n"));
610 sc->sc_nrecv = 1;
611 }
612
613 /* record the time received and when it was received */
614 sc->sc_last = sc->sc_next;
615 sc->sc_last_tv.tv_sec = monotime.tv_sec;
616 } else {
617 DPRINTF(("\nparity error, resync\n"));
618 sc->sc_sync = sc->sc_minute = 1;
619 }
620
621cleanbits:
622 timeout_add_msec(&sc->sc_to, T_MGSYNC450); /* re-sync in 450 ms */
623 sc->sc_last_mg = gettime();
624 sc->sc_tbits = 0LL;
625 sc->sc_mask = 1LL;
626}
627
628/* detect signal loss */
629void
630udcf_sl_probe(void *xsc)
631{
632 struct udcf_softc *sc = xsc;
633
634 if (usbd_is_dying(sc->sc_udev))
635 return;
636
637 DPRINTF(("no signal\n"));
638 sc->sc_sync = 1;
639 timeout_add_msec(&sc->sc_to, T_WAIT5000);
640 timeout_add_msec(&sc->sc_sl_to, T_WAIT5000 + T_SL3000);
641}
642
643/* invalidate timedelta (called in an interrupt context) */
644void
645udcf_it_intr(void *xsc)
646{
647 struct udcf_softc *sc = xsc;
648
649 if (usbd_is_dying(sc->sc_udev))
650 return;
651
652 if (sc->sc_sensor.status == SENSOR_S_OK) {
653 sc->sc_sensor.status = SENSOR_S_WARN;
654 /*
655 * further degrade in 15 minutes if we dont receive any new
656 * time information
657 */
658 timeout_add_msec(&sc->sc_it_to, T_CRIT900000);
659 } else {
660 sc->sc_sensor.status = SENSOR_S_CRIT;
661 sc->sc_nrecv = 0;
662 }
663}