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