This source file includes following definitions.
- mbg_probe
- mbg_attach
- mbg_task
- mbg_read_amcc_s5933
- mbg_read_asic
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 #include <sys/types.h>
20 #include <sys/param.h>
21 #include <sys/device.h>
22 #include <sys/kernel.h>
23 #include <sys/proc.h>
24 #include <sys/systm.h>
25 #include <sys/sensors.h>
26 #include <sys/syslog.h>
27 #include <sys/time.h>
28
29 #include <machine/bus.h>
30
31 #include <dev/pci/pcivar.h>
32 #include <dev/pci/pcireg.h>
33 #include <dev/pci/pcidevs.h>
34
35 struct mbg_softc {
36 struct device sc_dev;
37 bus_space_tag_t sc_iot;
38 bus_space_handle_t sc_ioh;
39
40 struct ksensor sc_timedelta;
41 struct ksensor sc_signal;
42 struct ksensordev sc_sensordev;
43 u_int8_t sc_status;
44
45 int (*sc_read)(struct mbg_softc *, int cmd,
46 char *buf, size_t len,
47 struct timespec *tstamp);
48 };
49
50 struct mbg_time {
51 u_int8_t hundreds;
52 u_int8_t sec;
53 u_int8_t min;
54 u_int8_t hour;
55 u_int8_t mday;
56 u_int8_t wday;
57 u_int8_t mon;
58 u_int8_t year;
59 u_int8_t status;
60 u_int8_t signal;
61 int8_t utc_off;
62 };
63
64
65 #define MBG_FREERUN 0x01
66 #define MBG_DST_ENA 0x02
67 #define MBG_SYNC 0x04
68 #define MBG_DST_CHG 0x08
69 #define MBG_UTC 0x10
70 #define MBG_LEAP 0x20
71 #define MBG_IFTM 0x40
72 #define MBG_INVALID 0x80
73
74
75 #define AMCC_OMB1 0x00
76 #define AMCC_IMB4 0x1c
77 #define AMCC_FIFO 0x20
78 #define AMCC_INTCSR 0x38
79 #define AMCC_MCSR 0x3c
80
81
82 #define ASIC_CFG 0x00
83 #define ASIC_FEATURES 0x08
84 #define ASIC_STATUS 0x10
85 #define ASIC_CTLSTATUS 0x14
86 #define ASIC_DATA 0x18
87 #define ASIC_RES1 0x1c
88 #define ASIC_ADDON 0x20
89
90
91 #define MBG_GET_TIME 0x00
92 #define MBG_GET_SYNC_TIME 0x02
93 #define MBG_GET_HR_TIME 0x03
94 #define MBG_GET_FW_ID_1 0x40
95 #define MBG_GET_FW_ID_2 0x41
96 #define MBG_GET_SERNUM 0x42
97
98
99 #define MBG_FIFO_LEN 16
100 #define MBG_ID_LEN (2 * MBG_FIFO_LEN + 1)
101 #define MBG_BUSY 0x01
102 #define MBG_SIG_BIAS 55
103 #define MBG_SIG_MAX 68
104
105 int mbg_probe(struct device *, void *, void *);
106 void mbg_attach(struct device *, struct device *, void *);
107 void mbg_task(void *);
108 int mbg_read_amcc_s5933(struct mbg_softc *, int cmd, char *buf, size_t len,
109 struct timespec *tstamp);
110 int mbg_read_asic(struct mbg_softc *, int cmd, char *buf, size_t len,
111 struct timespec *tstamp);
112
113 struct cfattach mbg_ca = {
114 sizeof(struct mbg_softc), mbg_probe, mbg_attach
115 };
116
117 struct cfdriver mbg_cd = {
118 NULL, "mbg", DV_DULL
119 };
120
121 const struct pci_matchid mbg_devices[] = {
122 { PCI_VENDOR_MEINBERG, PCI_PRODUCT_MEINBERG_GPS170 },
123 { PCI_VENDOR_MEINBERG, PCI_PRODUCT_MEINBERG_PCI32 },
124 { PCI_VENDOR_MEINBERG, PCI_PRODUCT_MEINBERG_PCI511 }
125 };
126
127 int
128 mbg_probe(struct device *parent, void *match, void *aux)
129 {
130 return pci_matchbyid((struct pci_attach_args *)aux, mbg_devices,
131 sizeof(mbg_devices) / sizeof(mbg_devices[0]));
132 }
133
134 void
135 mbg_attach(struct device *parent, struct device *self, void *aux)
136 {
137 struct mbg_softc *sc = (struct mbg_softc *)self;
138 struct pci_attach_args *const pa = (struct pci_attach_args *)aux;
139 struct mbg_time tframe;
140 pcireg_t memtype;
141 bus_size_t iosize;
142 char fw_id[MBG_ID_LEN];
143 const char *desc;
144
145 memtype = pci_mapreg_type(pa->pa_pc, pa->pa_tag, PCI_MAPREG_START);
146 if (pci_mapreg_map(pa, PCI_MAPREG_START, memtype, 0, &sc->sc_iot,
147 &sc->sc_ioh, NULL, &iosize, 0)) {
148 printf(": PCI %s region not found\n",
149 memtype == PCI_MAPREG_TYPE_IO ? "I/O" : "memory");
150 return;
151 }
152
153 if ((desc = pci_findproduct(pa->pa_id)) == NULL)
154 desc = "Radio clock";
155 strlcpy(sc->sc_timedelta.desc, desc, sizeof(sc->sc_timedelta.desc));
156
157 switch (PCI_PRODUCT(pa->pa_id)) {
158 case PCI_PRODUCT_MEINBERG_PCI32:
159 sc->sc_read = mbg_read_amcc_s5933;
160 break;
161 case PCI_PRODUCT_MEINBERG_PCI511:
162
163 case PCI_PRODUCT_MEINBERG_GPS170:
164 sc->sc_read = mbg_read_asic;
165 break;
166 default:
167
168 panic(": unsupported product 0x%04x", PCI_PRODUCT(pa->pa_id));
169 break;
170 }
171 if (sc->sc_read(sc, MBG_GET_FW_ID_1, fw_id, MBG_FIFO_LEN, NULL) ||
172 sc->sc_read(sc, MBG_GET_FW_ID_2, &fw_id[MBG_FIFO_LEN], MBG_FIFO_LEN,
173 NULL))
174 printf(": firmware unknown, ");
175 else {
176 fw_id[MBG_ID_LEN - 1] = '\0';
177 printf(": firmware %s, ", fw_id);
178 }
179
180 if (sc->sc_read(sc, MBG_GET_TIME, (char *)&tframe,
181 sizeof(struct mbg_time), NULL)) {
182 printf("unknown status\n");
183 sc->sc_status = 0;
184 } else {
185 if (tframe.status & MBG_FREERUN)
186 printf("free running on xtal\n");
187 else if (tframe.status & MBG_SYNC)
188 printf("synchronised\n");
189 else if (tframe.status & MBG_INVALID)
190 printf("invalid\n");
191 sc->sc_status = tframe.status;
192 }
193
194 strlcpy(sc->sc_sensordev.xname, sc->sc_dev.dv_xname,
195 sizeof(sc->sc_sensordev.xname));
196
197 sc->sc_timedelta.type = SENSOR_TIMEDELTA;
198 sc->sc_timedelta.status = SENSOR_S_UNKNOWN;
199 sc->sc_timedelta.value = 0LL;
200 sc->sc_timedelta.flags = 0;
201 sensor_attach(&sc->sc_sensordev, &sc->sc_timedelta);
202
203 sc->sc_signal.type = SENSOR_PERCENT;
204 sc->sc_signal.status = SENSOR_S_UNKNOWN;
205 sc->sc_signal.value = 0LL;
206 sc->sc_signal.flags = 0;
207 strlcpy(sc->sc_signal.desc, "Signal strength",
208 sizeof(sc->sc_signal.desc));
209 sensor_attach(&sc->sc_sensordev, &sc->sc_signal);
210
211 sensor_task_register(sc, mbg_task, 10);
212 sensordev_install(&sc->sc_sensordev);
213 }
214
215 void
216 mbg_task(void *arg)
217 {
218 struct mbg_softc *sc = (struct mbg_softc *)arg;
219 struct mbg_time tframe;
220 struct clock_ymdhms ymdhms;
221 struct timespec tstamp;
222 time_t trecv;
223 int signal;
224
225 if (sc->sc_read(sc, MBG_GET_TIME, (char *)&tframe, sizeof(tframe),
226 &tstamp)) {
227 log(LOG_ERR, "%s: error reading time\n", sc->sc_dev.dv_xname);
228 return;
229 }
230 if (tframe.status & MBG_INVALID) {
231 log(LOG_INFO, "%s: invalid time, battery was disconnected\n",
232 sc->sc_dev.dv_xname);
233 return;
234 }
235 ymdhms.dt_year = tframe.year + 2000;
236 ymdhms.dt_mon = tframe.mon;
237 ymdhms.dt_day = tframe.mday;
238 ymdhms.dt_hour = tframe.hour;
239 ymdhms.dt_min = tframe.min;
240 ymdhms.dt_sec = tframe.sec;
241 trecv = clock_ymdhms_to_secs(&ymdhms) - tframe.utc_off * 3600;
242
243 sc->sc_timedelta.value = (int64_t)((tstamp.tv_sec - trecv) * 100
244 - tframe.hundreds) * 10000000LL + tstamp.tv_nsec;
245 sc->sc_timedelta.status = SENSOR_S_OK;
246 sc->sc_timedelta.tv.tv_sec = tstamp.tv_sec;
247 sc->sc_timedelta.tv.tv_usec = tstamp.tv_nsec / 1000;
248
249 signal = tframe.signal - MBG_SIG_BIAS;
250 if (signal < 0)
251 signal = 0;
252 else if (signal > MBG_SIG_MAX)
253 signal = MBG_SIG_MAX;
254
255 sc->sc_signal.value = signal * 100000 / MBG_SIG_MAX;
256 sc->sc_signal.status = SENSOR_S_OK;
257 sc->sc_signal.tv.tv_sec = sc->sc_timedelta.tv.tv_sec;
258 sc->sc_signal.tv.tv_usec = sc->sc_timedelta.tv.tv_usec;
259
260 if (tframe.status != sc->sc_status) {
261 if (tframe.status & MBG_SYNC)
262 log(LOG_INFO, "%s: clock is synchronized",
263 sc->sc_dev.dv_xname);
264 else if (tframe.status & MBG_FREERUN)
265 log(LOG_INFO, "%s: clock is free running on xtal",
266 sc->sc_dev.dv_xname);
267 sc->sc_status = tframe.status;
268 }
269 }
270
271
272
273
274
275 int
276 mbg_read_amcc_s5933(struct mbg_softc *sc, int cmd, char *buf, size_t len,
277 struct timespec *tstamp)
278 {
279 long timer, tmax;
280 size_t n;
281 u_int8_t status;
282
283
284 bus_space_write_1(sc->sc_iot, sc->sc_ioh, AMCC_MCSR + 3, 0x0c);
285
286
287 bus_space_write_1(sc->sc_iot, sc->sc_ioh, AMCC_INTCSR + 3, 0x3c);
288
289
290 if (tstamp)
291 nanotime(tstamp);
292 bus_space_write_1(sc->sc_iot, sc->sc_ioh, AMCC_OMB1, cmd);
293
294
295 timer = 0;
296 tmax = cold ? 50 : hz / 10;
297 do {
298 if (cold)
299 delay(20);
300 else
301 tsleep(tstamp, 0, "mbg", 1);
302 status = bus_space_read_1(sc->sc_iot, sc->sc_ioh,
303 AMCC_IMB4 + 3);
304 } while ((status & MBG_BUSY) && timer++ < tmax);
305
306 if (status & MBG_BUSY)
307 return -1;
308
309
310 for (n = 0; n < len; n++) {
311 if (bus_space_read_2(sc->sc_iot, sc->sc_ioh, AMCC_MCSR)
312 & 0x20) {
313 printf("%s: FIFO error\n", sc->sc_dev.dv_xname);
314 return -1;
315 }
316 buf[n] = bus_space_read_1(sc->sc_iot, sc->sc_ioh,
317 AMCC_FIFO + (n % 4));
318 }
319 return 0;
320 }
321
322
323
324
325
326 int
327 mbg_read_asic(struct mbg_softc *sc, int cmd, char *buf, size_t len,
328 struct timespec *tstamp)
329 {
330 long timer, tmax;
331 size_t n;
332 u_int32_t data;
333 char *p = buf;
334 u_int16_t port;
335 u_int8_t status;
336 int s;
337
338
339 if (tstamp) {
340 s = splhigh();
341 nanotime(tstamp);
342 bus_space_write_4(sc->sc_iot, sc->sc_ioh, ASIC_DATA, cmd);
343 splx(s);
344 } else
345 bus_space_write_4(sc->sc_iot, sc->sc_ioh, ASIC_DATA, cmd);
346
347
348 timer = 0;
349 tmax = cold ? 50 : hz / 10;
350 do {
351 if (cold)
352 delay(20);
353 else
354 tsleep(tstamp, 0, "mbg", 1);
355 status = bus_space_read_1(sc->sc_iot, sc->sc_ioh, ASIC_STATUS);
356 } while ((status & MBG_BUSY) && timer++ < tmax);
357
358 if (status & MBG_BUSY)
359 return -1;
360
361
362 port = ASIC_ADDON;
363 for (n = 0; n < len / 4; n++) {
364 data = bus_space_read_4(sc->sc_iot, sc->sc_ioh, port);
365 *(u_int32_t *)p = data;
366 p += sizeof(data);
367 port += sizeof(data);
368 }
369
370 if (len % 4) {
371 data = bus_space_read_4(sc->sc_iot, sc->sc_ioh, port);
372 for (n = 0; n < len % 4; n++) {
373 *p++ = data & 0xff;
374 data >>= 8;
375 }
376 }
377 return 0;
378 }