xref: /openbsd-src/sys/dev/usb/umbg.c (revision 2b0358df1d88d06ef4139321dd05bd5e05d91eaf)
1 /*	$OpenBSD: umbg.c,v 1.8 2008/11/21 11:38:12 mbalmer Exp $ */
2 
3 /*
4  * Copyright (c) 2007 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/conf.h>
23 #include <sys/file.h>
24 #include <sys/select.h>
25 #include <sys/proc.h>
26 #include <sys/vnode.h>
27 #include <sys/device.h>
28 #include <sys/poll.h>
29 #include <sys/syslog.h>
30 #include <sys/time.h>
31 #include <sys/sensors.h>
32 
33 #include <dev/usb/usb.h>
34 #include <dev/usb/usbdi.h>
35 #include <dev/usb/usbdi_util.h>
36 #include <dev/usb/usbdevs.h>
37 
38 #ifdef UMBG_DEBUG
39 #define DPRINTFN(n, x)	do { if (umbgdebug > (n)) printf x; } while (0)
40 int umbgdebug = 0;
41 #else
42 #define DPRINTFN(n, x)
43 #endif
44 #define DPRINTF(x)	DPRINTFN(0, x)
45 
46 #ifdef UMBG_DEBUG
47 #define TRUSTTIME	((long) 60)
48 #else
49 #define TRUSTTIME	((long) 12 * 60 * 60)	/* degrade OK > WARN > CRIT */
50 #endif
51 
52 struct umbg_softc {
53 	struct device		sc_dev;		/* base device */
54 	usbd_device_handle	sc_udev;	/* USB device */
55 	usbd_interface_handle	sc_iface;	/* data interface */
56 	u_char			sc_dying;	/* disconnecting */
57 
58 	int			sc_bulkin_no;
59 	usbd_pipe_handle	sc_bulkin_pipe;
60 	int			sc_bulkout_no;
61 	usbd_pipe_handle	sc_bulkout_pipe;
62 
63 	struct timeout		sc_to;		/* get time from device */
64 	struct usb_task		sc_task;
65 
66 	struct timeout		sc_it_to;	/* invalidate sensor */
67 
68 	usb_device_request_t	sc_req;
69 
70 	struct ksensor		sc_timedelta;	/* timedelta */
71 	struct ksensor		sc_signal;	/* signal quality and status */
72 	struct ksensordev	sc_sensordev;
73 };
74 
75 struct mbg_time {
76 	u_int8_t		hundreds;
77 	u_int8_t		sec;
78 	u_int8_t		min;
79 	u_int8_t		hour;
80 	u_int8_t		mday;
81 	u_int8_t		wday;	/* 1 (monday) - 7 (sunday) */
82 	u_int8_t		mon;
83 	u_int8_t		year;	/* 0 - 99 */
84 	u_int8_t		status;
85 	u_int8_t		signal;
86 	int8_t			utc_off;
87 };
88 
89 struct mbg_time_hr {
90 	u_int32_t		sec;		/* always UTC */
91 	u_int32_t		frac;		/* fractions of second */
92 	int32_t			utc_off;	/* informal only, in seconds */
93 	u_int16_t		status;
94 	u_int8_t		signal;
95 };
96 
97 /* mbg_time.status bits */
98 #define MBG_FREERUN		0x01	/* clock running on xtal */
99 #define MBG_DST_ENA		0x02	/* DST enabled */
100 #define MBG_SYNC		0x04	/* clock synced at least once */
101 #define MBG_DST_CHG		0x08	/* DST change announcement */
102 #define MBG_UTC			0x10	/* special UTC firmware is installed */
103 #define MBG_LEAP		0x20	/* announcement of a leap second */
104 #define MBG_IFTM		0x40	/* current time was set from host */
105 #define MBG_INVALID		0x80	/* time invalid, batt. was disconn. */
106 
107 /* commands */
108 #define MBG_GET_TIME		0x00
109 #define MBG_GET_SYNC_TIME	0x02
110 #define MBG_GET_TIME_HR		0x03
111 #define MBG_SET_TIME		0x10
112 #define MBG_GET_TZCODE		0x32
113 #define MBG_SET_TZCODE		0x33
114 #define MBG_GET_FW_ID_1		0x40
115 #define MBG_GET_FW_ID_2		0x41
116 #define MBG_GET_SERNUM		0x42
117 
118 /* timezone codes (for MBG_{GET|SET}_TZCODE) */
119 #define MBG_TZCODE_CET_CEST	0x00
120 #define MBG_TZCODE_CET		0x01
121 #define MBG_TZCODE_UTC		0x02
122 #define MBG_TZCODE_EET_EEST	0x03
123 
124 /* misc. constants */
125 #define MBG_FIFO_LEN		16
126 #define MBG_ID_LEN		(2 * MBG_FIFO_LEN + 1)
127 #define MBG_BUSY		0x01
128 #define MBG_SIG_BIAS		55
129 #define MBG_SIG_MAX		68
130 #define NSECPERSEC		1000000000LL	/* nanoseconds per second */
131 #define HRDIVISOR		0x100000000LL	/* for hi-res timestamp */
132 
133 static int t_wait, t_trust;
134 
135 void umbg_intr(void *);
136 void umbg_it_intr(void *);
137 
138 int umbg_match(struct device *, void *, void *);
139 void umbg_attach(struct device *, struct device *, void *);
140 int umbg_detach(struct device *, int);
141 int umbg_activate(struct device *, enum devact);
142 
143 void umbg_task(void *);
144 
145 int umbg_read(struct umbg_softc *, u_int8_t cmd, char *buf, size_t len,
146     struct timespec *tstamp);
147 
148 struct cfdriver umbg_cd = {
149 	NULL, "umbg", DV_DULL
150 };
151 
152 const struct cfattach umbg_ca = {
153 	sizeof(struct umbg_softc),
154 	umbg_match,
155 	umbg_attach,
156 	umbg_detach,
157 	umbg_activate
158 };
159 
160 int
161 umbg_match(struct device *parent, void *match, void *aux)
162 {
163 	struct usb_attach_arg *uaa = aux;
164 
165 	if (uaa->iface != NULL)
166 		return UMATCH_NONE;
167 
168 	return uaa->vendor == USB_VENDOR_MEINBERG &&
169 	    uaa->product == USB_PRODUCT_MEINBERG_USB5131 ?
170 	    UMATCH_VENDOR_PRODUCT : UMATCH_NONE;
171 }
172 
173 void
174 umbg_attach(struct device *parent, struct device *self, void *aux)
175 {
176 	struct umbg_softc *sc = (struct umbg_softc *)self;
177 	struct usb_attach_arg *uaa = aux;
178 	usbd_device_handle dev = uaa->device;
179 	usbd_interface_handle iface = uaa->iface;
180 	struct mbg_time tframe;
181 	usb_endpoint_descriptor_t *ed;
182 	usbd_status err;
183 	int signal;
184 #ifdef UMBG_DEBUG
185 	char fw_id[MBG_ID_LEN];
186 #endif
187 	sc->sc_udev = dev;
188 
189 	strlcpy(sc->sc_sensordev.xname, sc->sc_dev.dv_xname,
190 	    sizeof(sc->sc_sensordev.xname));
191 
192 	sc->sc_timedelta.type = SENSOR_TIMEDELTA;
193 	sc->sc_timedelta.status = SENSOR_S_UNKNOWN;
194 	sc->sc_timedelta.value = 0LL;
195 	sc->sc_timedelta.flags = 0;
196 	strlcpy(sc->sc_timedelta.desc, "USB5131",
197 	    sizeof(sc->sc_timedelta.desc));
198 	sensor_attach(&sc->sc_sensordev, &sc->sc_timedelta);
199 
200 	sc->sc_signal.type = SENSOR_PERCENT;
201 	sc->sc_signal.value = 0LL;
202 	sc->sc_signal.flags = 0;
203 	strlcpy(sc->sc_signal.desc, "Signal", sizeof(sc->sc_signal.desc));
204 	sensor_attach(&sc->sc_sensordev, &sc->sc_signal);
205 	sensordev_install(&sc->sc_sensordev);
206 
207 	usb_init_task(&sc->sc_task, umbg_task, sc);
208 	timeout_set(&sc->sc_to, umbg_intr, sc);
209 	timeout_set(&sc->sc_it_to, umbg_it_intr, sc);
210 
211 	if ((err = usbd_set_config_index(dev, 0, 1))) {
212 		printf("%s: failed to set configuration, err=%s\n",
213 		    sc->sc_dev.dv_xname, usbd_errstr(err));
214 		goto fishy;
215 	}
216 
217 	if ((err = usbd_device2interface_handle(dev, 0, &iface))) {
218 		printf("%s: failed to get interface, err=%s\n",
219 		    sc->sc_dev.dv_xname, usbd_errstr(err));
220 		goto fishy;
221 	}
222 
223 	ed = usbd_interface2endpoint_descriptor(iface, 0);
224 	sc->sc_bulkin_no = ed->bEndpointAddress;
225 	ed = usbd_interface2endpoint_descriptor(iface, 1);
226 	sc->sc_bulkout_no = ed->bEndpointAddress;
227 
228 	sc->sc_iface = iface;
229 
230 	err = usbd_open_pipe(sc->sc_iface, sc->sc_bulkin_no,
231 	    USBD_EXCLUSIVE_USE, &sc->sc_bulkin_pipe);
232 	if (err) {
233 		printf("%s: open rx pipe failed: %s\n", sc->sc_dev.dv_xname,
234 		    usbd_errstr(err));
235 		goto fishy;
236 	}
237 
238 	err = usbd_open_pipe(sc->sc_iface, sc->sc_bulkout_no,
239 	    USBD_EXCLUSIVE_USE, &sc->sc_bulkout_pipe);
240 	if (err) {
241 		printf("%s: open tx pipe failed: %s\n", sc->sc_dev.dv_xname,
242 		    usbd_errstr(err));
243 		goto fishy;
244 	}
245 
246 	printf("%s: ", sc->sc_dev.dv_xname);
247 	if (umbg_read(sc, MBG_GET_TIME, (char *)&tframe,
248 	    sizeof(struct mbg_time), NULL)) {
249 		sc->sc_signal.status = SENSOR_S_CRIT;
250 		printf("unknown status");
251 	} else {
252 		sc->sc_signal.status = SENSOR_S_OK;
253 		signal = tframe.signal - MBG_SIG_BIAS;
254 		if (signal < 0)
255 			signal = 0;
256 		else if (signal > MBG_SIG_MAX)
257 			signal = MBG_SIG_MAX;
258 		sc->sc_signal.value = signal;
259 
260 		if (tframe.status & MBG_SYNC)
261 			printf("synchronized");
262 		else
263 			printf("not synchronized");
264 		if (tframe.status & MBG_FREERUN) {
265 			sc->sc_signal.status = SENSOR_S_WARN;
266 			printf(", freerun");
267 		}
268 		if (tframe.status & MBG_IFTM)
269 			printf(", time set from host");
270 	}
271 #ifdef UMBG_DEBUG
272 	if (umbg_read(sc, MBG_GET_FW_ID_1, fw_id, MBG_FIFO_LEN, NULL) ||
273 	    umbg_read(sc, MBG_GET_FW_ID_2, &fw_id[MBG_FIFO_LEN], MBG_FIFO_LEN,
274 	    NULL))
275 		printf(", firmware unknown");
276 	else {
277 		fw_id[MBG_ID_LEN - 1] = '\0';
278 		printf(", firmware %s", fw_id);
279 	}
280 #endif
281 	printf("\n");
282 
283 	usbd_add_drv_event(USB_EVENT_DRIVER_ATTACH, sc->sc_udev,
284 	    &sc->sc_dev);
285 
286 	t_wait = 5;
287 
288 	t_trust = TRUSTTIME;
289 
290 	usb_add_task(sc->sc_udev, &sc->sc_task);
291 	return;
292 
293 fishy:
294 	sc->sc_dying = 1;
295 }
296 
297 int
298 umbg_detach(struct device *self, int flags)
299 {
300 	struct umbg_softc *sc = (struct umbg_softc *)self;
301 	usbd_status err;
302 
303 	sc->sc_dying = 1;
304 
305 	timeout_del(&sc->sc_to);
306 	timeout_del(&sc->sc_it_to);
307 
308 	if (sc->sc_bulkin_pipe != NULL) {
309 		err = usbd_abort_pipe(sc->sc_bulkin_pipe);
310 		if (err)
311 			printf("%s: abort rx pipe failed: %s\n",
312 			    sc->sc_dev.dv_xname, usbd_errstr(err));
313 		err = usbd_close_pipe(sc->sc_bulkin_pipe);
314 		if (err)
315 			printf("%s: close rx pipe failed: %s\n",
316 			    sc->sc_dev.dv_xname, usbd_errstr(err));
317 		sc->sc_bulkin_pipe = NULL;
318 	}
319 	if (sc->sc_bulkout_pipe != NULL) {
320 		err = usbd_abort_pipe(sc->sc_bulkout_pipe);
321 		if (err)
322 			printf("%s: abort tx pipe failed: %s\n",
323 			    sc->sc_dev.dv_xname, usbd_errstr(err));
324 		err = usbd_close_pipe(sc->sc_bulkout_pipe);
325 		if (err)
326 			printf("%s: close tx pipe failed: %s\n",
327 			    sc->sc_dev.dv_xname, usbd_errstr(err));
328 		sc->sc_bulkout_pipe = NULL;
329 	}
330 
331 	usb_rem_task(sc->sc_udev, &sc->sc_task);
332 
333 	/* Unregister the clock with the kernel */
334 	sensordev_deinstall(&sc->sc_sensordev);
335 
336 	usbd_add_drv_event(USB_EVENT_DRIVER_DETACH, sc->sc_udev, &sc->sc_dev);
337 	return 0;
338 }
339 
340 void
341 umbg_intr(void *xsc)
342 {
343 	struct umbg_softc *sc = xsc;
344 	usb_add_task(sc->sc_udev, &sc->sc_task);
345 }
346 
347 /* umbg_task_hr() read a high resolution timestamp from the device. */
348 void
349 umbg_task(void *arg)
350 {
351 	struct umbg_softc *sc = (struct umbg_softc *)arg;
352 	struct mbg_time_hr tframe;
353 	struct timespec tstamp;
354 	int64_t tlocal, trecv;
355 	int signal;
356 
357 	if (sc->sc_dying)
358 		return;
359 
360 	if (umbg_read(sc, MBG_GET_TIME_HR, (char *)&tframe, sizeof(tframe),
361 	    &tstamp)) {
362 		sc->sc_signal.status = SENSOR_S_CRIT;
363 		goto bail_out;
364 	}
365 	if (tframe.status & MBG_INVALID) {
366 		sc->sc_signal.status = SENSOR_S_CRIT;
367 		goto bail_out;
368 	}
369 
370 	tlocal = tstamp.tv_sec * NSECPERSEC + tstamp.tv_nsec;
371 	trecv = letoh32(tframe.sec) * NSECPERSEC +
372 	    (letoh32(tframe.frac) * NSECPERSEC >> 32);
373 
374 	sc->sc_timedelta.value = tlocal - trecv;
375 	if (sc->sc_timedelta.status == SENSOR_S_UNKNOWN ||
376 		!(letoh16(tframe.status) & MBG_FREERUN)) {
377 		sc->sc_timedelta.status = SENSOR_S_OK;
378 		timeout_add_sec(&sc->sc_it_to, t_trust);
379 	}
380 
381 	sc->sc_timedelta.tv.tv_sec = tstamp.tv_sec;
382 	sc->sc_timedelta.tv.tv_usec = tstamp.tv_nsec / 1000;
383 
384 	signal = tframe.signal - MBG_SIG_BIAS;
385 	if (signal < 0)
386 		signal = 0;
387 	else if (signal > MBG_SIG_MAX)
388 		signal = MBG_SIG_MAX;
389 
390 	sc->sc_signal.value = signal * 100000 / MBG_SIG_MAX;
391 	sc->sc_signal.status = letoh16(tframe.status) & MBG_FREERUN ?
392 	    SENSOR_S_WARN : SENSOR_S_OK;
393 	sc->sc_signal.tv.tv_sec = sc->sc_timedelta.tv.tv_sec;
394 	sc->sc_signal.tv.tv_usec = sc->sc_timedelta.tv.tv_usec;
395 
396 bail_out:
397 	timeout_add_sec(&sc->sc_to, t_wait);
398 
399 }
400 
401 /* send a command and read back results */
402 int
403 umbg_read(struct umbg_softc *sc, u_int8_t cmd, char *buf, size_t len,
404     struct timespec *tstamp)
405 {
406 	usbd_status err;
407 	usbd_xfer_handle xfer;
408 
409 	xfer = usbd_alloc_xfer(sc->sc_udev);
410 	if (xfer == NULL) {
411 		DPRINTF(("%s: alloc xfer failed\n", sc->sc_dev.dv_xname));
412 		return -1;
413 	}
414 
415 	usbd_setup_xfer(xfer, sc->sc_bulkout_pipe, NULL, &cmd, sizeof(cmd),
416 	    USBD_SHORT_XFER_OK, USBD_DEFAULT_TIMEOUT, NULL);
417 	if (tstamp)
418 		nanotime(tstamp);
419 	err = usbd_sync_transfer(xfer);
420 	if (err) {
421 		DPRINTF(("%s: sending of command failed: %s\n",
422 		    sc->sc_dev.dv_xname, usbd_errstr(err)));
423 		usbd_free_xfer(xfer);
424 		return -1;
425 	}
426 
427 	usbd_setup_xfer(xfer, sc->sc_bulkin_pipe, NULL, buf, len,
428 	    USBD_SHORT_XFER_OK, USBD_DEFAULT_TIMEOUT, NULL);
429 
430 	err = usbd_sync_transfer(xfer);
431 	usbd_free_xfer(xfer);
432 	if (err) {
433 		DPRINTF(("%s: reading data failed: %s\n",
434 		    sc->sc_dev.dv_xname, usbd_errstr(err)));
435 		return -1;
436 	}
437 	return 0;
438 }
439 
440 void
441 umbg_it_intr(void *xsc)
442 {
443 	struct umbg_softc *sc = xsc;
444 
445 	if (sc->sc_dying)
446 		return;
447 
448 	if (sc->sc_timedelta.status == SENSOR_S_OK) {
449 		sc->sc_timedelta.status = SENSOR_S_WARN;
450 		/*
451 		 * further degrade in TRUSTTIME seconds if the clocks remains
452 		 * free running.
453 		 */
454 		timeout_add_sec(&sc->sc_it_to, t_trust);
455 	} else
456 		sc->sc_timedelta.status = SENSOR_S_CRIT;
457 }
458 
459 int
460 umbg_activate(struct device *self, enum devact act)
461 {
462 	struct umbg_softc *sc = (struct umbg_softc *)self;
463 
464 	switch (act) {
465 	case DVACT_ACTIVATE:
466 		break;
467 	case DVACT_DEACTIVATE:
468 		sc->sc_dying = 1;
469 		break;
470 	}
471 	return 0;
472 }
473