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