File: | dev/usb/udcf.c |
Warning: | line 526, column 2 Value stored to 'a2_bit' is never read |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
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) |
34 | int 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 | |
54 | struct 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 | |
103 | void udcf_intr(void *); |
104 | void udcf_probe(void *); |
105 | |
106 | void udcf_bv_intr(void *); |
107 | void udcf_mg_intr(void *); |
108 | void udcf_sl_intr(void *); |
109 | void udcf_it_intr(void *); |
110 | void udcf_bv_probe(void *); |
111 | void udcf_mg_probe(void *); |
112 | void udcf_sl_probe(void *); |
113 | |
114 | int udcf_match(struct device *, void *, void *); |
115 | void udcf_attach(struct device *, struct device *, void *); |
116 | int udcf_detach(struct device *, int); |
117 | |
118 | int udcf_nc_signal(struct udcf_softc *); |
119 | int udcf_nc_init_hw(struct udcf_softc *); |
120 | int udcf_ft232r_signal(struct udcf_softc *); |
121 | int udcf_ft232r_init_hw(struct udcf_softc *); |
122 | |
123 | struct cfdriver udcf_cd = { |
124 | NULL((void *)0), "udcf", DV_DULL |
125 | }; |
126 | |
127 | const struct cfattach udcf_ca = { |
128 | sizeof(struct udcf_softc), udcf_match, udcf_attach, udcf_detach, |
129 | }; |
130 | |
131 | static const struct usb_devno udcf_devs[] = { |
132 | { USB_VENDOR_GUDE0x0959, USB_PRODUCT_GUDE_DCF0xdcf7 }, |
133 | { USB_VENDOR_FTDI0x0403, USB_PRODUCT_FTDI_DCF0xe88a } |
134 | }; |
135 | |
136 | int |
137 | udcf_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 | |
148 | void |
149 | udcf_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))) { |
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 | |
238 | fishy: |
239 | DPRINTF(("udcf_attach failed\n")); |
240 | usbd_deactivate(sc->sc_udev); |
241 | } |
242 | |
243 | int |
244 | udcf_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 */ |
270 | void |
271 | udcf_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 */ |
278 | void |
279 | udcf_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 */ |
286 | void |
287 | udcf_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 */ |
294 | void |
295 | udcf_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 | */ |
306 | int |
307 | udcf_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 | */ |
349 | int |
350 | udcf_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 | */ |
374 | int |
375 | udcf_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 */ |
388 | int |
389 | udcf_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. */ |
410 | void |
411 | udcf_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 */ |
471 | void |
472 | udcf_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 */ |
493 | void |
494 | udcf_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; |
Value stored to 'a2_bit' is never read | |
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 | |
621 | cleanbits: |
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 */ |
629 | void |
630 | udcf_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) */ |
644 | void |
645 | udcf_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 | } |