File: | dev/usb/uoakv.c |
Warning: | line 237, column 2 Value stored to 'frame' is never read |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* $OpenBSD: uoakv.c,v 1.17 2022/04/09 20:09:03 naddy Exp $ */ |
2 | |
3 | /* |
4 | * Copyright (c) 2012 Yojiro UO <yuo@nui.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 DISCAIMS 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 | /* TORADEX OAK series sensors: 8channel +/-10V ADC driver */ |
20 | /* http://developer.toradex.com/files/toradex-dev/uploads/media/Oak/Oak_ProgrammingGuide.pdf */ |
21 | |
22 | #include <sys/param.h> |
23 | #include <sys/systm.h> |
24 | #include <sys/kernel.h> |
25 | #include <sys/malloc.h> |
26 | #include <sys/device.h> |
27 | #include <sys/conf.h> |
28 | #include <sys/sensors.h> |
29 | |
30 | #include <dev/usb/usb.h> |
31 | #include <dev/usb/usbhid.h> |
32 | #include <dev/usb/usbdi.h> |
33 | #include <dev/usb/usbdevs.h> |
34 | #include <dev/usb/uhidev.h> |
35 | |
36 | #include "uoak.h" |
37 | |
38 | #ifdef UOAKV_DEBUG |
39 | int uoakvdebug = 0; |
40 | #define DPRINTFN(n, x) do { if (uoakvdebug > (n)) printf x; } while (0) |
41 | #else |
42 | #define DPRINTFN(n, x) |
43 | #endif |
44 | |
45 | #define DPRINTF(x) DPRINTFN(0, x) |
46 | |
47 | #define UOAKV_SAMPLE_RATE100 100 /* ms */ |
48 | #define UOAKV_REFRESH_PERIOD1 1 /* 1 sec : 1Hz */ |
49 | |
50 | struct uoakv_sensor { |
51 | struct uoak_sensor v; |
52 | /* ADC setting */ |
53 | unsigned int offset[OAK_V_TARGET_MAX2]; /* absolute offset (mV) */ |
54 | }; |
55 | |
56 | struct uoakv_softc { |
57 | struct uhidev sc_hdev; |
58 | |
59 | /* uoak common */ |
60 | struct uoak_softc sc_uoak_softc; |
61 | |
62 | /* sensor framework */ |
63 | struct uoakv_sensor sc_sensor[OAK_V_MAXSENSORS8]; |
64 | struct ksensordev sc_sensordev; |
65 | struct sensor_task *sc_sensortask; |
66 | |
67 | /* sensor setting */ |
68 | int sc_inputmode[OAK_V_TARGET_MAX2]; |
69 | |
70 | }; |
71 | |
72 | const struct usb_devno uoakv_devs[] = { |
73 | { USB_VENDOR_TORADEX0x1b67, USB_PRODUCT_TORADEX_10V0x000e}, |
74 | }; |
75 | #define uoakv_lookup(v, p)usbd_match_device((const struct usb_devno *)(uoakv_devs), sizeof (uoakv_devs) / sizeof ((uoakv_devs)[0]), sizeof ((uoakv_devs )[0]), (v), (p)) usb_lookup(uoakv_devs, v, p)usbd_match_device((const struct usb_devno *)(uoakv_devs), sizeof (uoakv_devs) / sizeof ((uoakv_devs)[0]), sizeof ((uoakv_devs )[0]), (v), (p)) |
76 | |
77 | int uoakv_match(struct device *, void *, void *); |
78 | void uoakv_attach(struct device *, struct device *, void *); |
79 | int uoakv_detach(struct device *, int); |
80 | |
81 | void uoakv_intr(struct uhidev *, void *, u_int); |
82 | void uoakv_refresh(void *); |
83 | |
84 | int uoakv_get_channel_setting(struct uoakv_softc *, enum uoak_target, int); |
85 | int uoakv_get_sensor_setting(struct uoakv_softc *, enum uoak_target); |
86 | |
87 | void uoakv_dev_setting(void *, enum uoak_target); |
88 | void uoakv_dev_print(void *, enum uoak_target); |
89 | |
90 | |
91 | struct cfdriver uoakv_cd = { |
92 | NULL((void *)0), "uoakv", DV_DULL |
93 | }; |
94 | |
95 | const struct cfattach uoakv_ca = { |
96 | sizeof(struct uoakv_softc), |
97 | uoakv_match, |
98 | uoakv_attach, |
99 | uoakv_detach, |
100 | |
101 | }; |
102 | |
103 | const struct uoak_methods uoakv_methods = { |
104 | uoakv_dev_print, |
105 | uoakv_dev_setting |
106 | }; |
107 | |
108 | int |
109 | uoakv_match(struct device *parent, void *match, void *aux) |
110 | { |
111 | struct uhidev_attach_arg *uha = aux; |
112 | |
113 | if (UHIDEV_CLAIM_MULTIPLE_REPORTID(uha)((uha)->claimed != ((void *)0))) |
114 | return (UMATCH_NONE0); |
115 | |
116 | if (uoakv_lookup(uha->uaa->vendor, uha->uaa->product)usbd_match_device((const struct usb_devno *)(uoakv_devs), sizeof (uoakv_devs) / sizeof ((uoakv_devs)[0]), sizeof ((uoakv_devs )[0]), (uha->uaa->vendor), (uha->uaa->product)) == NULL((void *)0)) |
117 | return UMATCH_NONE0; |
118 | |
119 | return (UMATCH_VENDOR_PRODUCT13); |
120 | } |
121 | |
122 | void |
123 | uoakv_attach(struct device *parent, struct device *self, void *aux) |
124 | { |
125 | struct uoakv_softc *sc = (struct uoakv_softc *)self; |
126 | struct usb_attach_arg *uaa = aux; |
127 | struct uhidev_attach_arg *uha = (struct uhidev_attach_arg *)uaa; |
128 | struct usbd_device *dev = uha->parent->sc_udev; |
129 | |
130 | struct uoak_softc *scc = &sc->sc_uoak_softc; |
131 | int i, err, size, repid; |
132 | void *desc; |
133 | |
134 | sc->sc_hdev.sc_intr = uoakv_intr; |
135 | sc->sc_hdev.sc_parent = uha->parent; |
136 | sc->sc_hdev.sc_report_id = uha->reportid; |
137 | |
138 | scc->sc_parent = sc; |
139 | scc->sc_udev = dev; |
140 | scc->sc_hdev = &sc->sc_hdev; |
141 | scc->sc_methods = &uoakv_methods; |
142 | scc->sc_sensordev = &sc->sc_sensordev; |
143 | |
144 | uhidev_get_report_desc(uha->parent, &desc, &size); |
145 | repid = uha->reportid; |
146 | scc->sc_ilen = hid_report_size(desc, size, hid_input, repid); |
147 | scc->sc_olen = hid_report_size(desc, size, hid_output, repid); |
148 | scc->sc_flen = hid_report_size(desc, size, hid_feature, repid); |
149 | |
150 | /* device initialize */ |
151 | (void)uoak_led_ctrl(scc, OAK_TARGET_RAM, OAK_LED_ON0x1); |
152 | err = uoak_set_sample_rate(scc, OAK_TARGET_RAM, UOAKV_SAMPLE_RATE100); |
153 | if (err) { |
154 | printf("%s: could not set sampling rate. exit\n", |
155 | sc->sc_hdev.sc_dev.dv_xname); |
156 | return; |
157 | } |
158 | |
159 | /* query and print device setting */ |
160 | uoak_get_devinfo(scc); |
161 | uoak_print_devinfo(scc); |
162 | |
163 | DPRINTF((" config in RAM\n")); |
164 | uoak_get_setting(scc, OAK_TARGET_RAM); |
165 | uoak_print_setting(scc, OAK_TARGET_RAM); |
166 | #ifdef UOAKV_DEBUG |
167 | DPRINTF((" config in FRASH\n")); |
168 | uoak_get_setting(scc, OAK_TARGET_FLASH); |
169 | uoak_print_setting(scc, OAK_TARGET_FLASH); |
170 | #endif |
171 | |
172 | /* attach sensor */ |
173 | strlcpy(sc->sc_sensordev.xname, sc->sc_hdev.sc_dev.dv_xname, |
174 | sizeof(sc->sc_sensordev.xname)); |
175 | for (i = 0; i < OAK_V_MAXSENSORS8; i++) |
176 | uoak_sensor_attach(scc, &sc->sc_sensor[i].v, SENSOR_VOLTS_DC); |
177 | |
178 | /* start sensor */ |
179 | sc->sc_sensortask = sensor_task_register(sc, uoakv_refresh, |
180 | UOAKV_REFRESH_PERIOD1); |
181 | if (sc->sc_sensortask == NULL((void *)0)) { |
182 | printf(", unable to register update task\n"); |
183 | return; |
184 | } |
185 | sensordev_install(&sc->sc_sensordev); |
186 | |
187 | err = uhidev_open(&sc->sc_hdev); |
188 | if (err) { |
189 | printf("%s: could not open interrupt pipe, quit\n", |
190 | sc->sc_hdev.sc_dev.dv_xname); |
191 | return; |
192 | } |
193 | scc->sc_ibuf = malloc(scc->sc_ilen, M_USBDEV102, M_WAITOK0x0001); |
194 | |
195 | DPRINTF(("uoakv_attach: complete\n")); |
196 | } |
197 | |
198 | int |
199 | uoakv_detach(struct device *self, int flags) |
200 | { |
201 | struct uoakv_softc *sc = (struct uoakv_softc *)self; |
202 | struct uoak_softc *scc = &sc->sc_uoak_softc; |
203 | int i, rv = 0; |
204 | |
205 | wakeup(&sc->sc_sensortask); |
206 | sensordev_deinstall(&sc->sc_sensordev); |
207 | |
208 | for (i = 0; i < OAK_V_MAXSENSORS8; i++) |
209 | uoak_sensor_detach(scc, &sc->sc_sensor[i].v); |
210 | |
211 | if (sc->sc_sensortask != NULL((void *)0)) |
212 | sensor_task_unregister(sc->sc_sensortask); |
213 | |
214 | if (sc->sc_hdev.sc_state & UHIDEV_OPEN0x01) |
215 | uhidev_close(&sc->sc_hdev); |
216 | |
217 | if (scc->sc_ibuf != NULL((void *)0)) { |
218 | free(scc->sc_ibuf, M_USBDEV102, scc->sc_ilen); |
219 | scc->sc_ibuf = NULL((void *)0); |
220 | } |
221 | |
222 | return (rv); |
223 | } |
224 | |
225 | void |
226 | uoakv_intr(struct uhidev *addr, void *ibuf, u_int len) |
227 | { |
228 | struct uoakv_softc *sc = (struct uoakv_softc *)addr; |
229 | struct uoak_softc *scc = &sc->sc_uoak_softc; |
230 | int i, idx, frame; |
231 | int16_t val; |
232 | |
233 | if (scc->sc_ibuf == NULL((void *)0)) |
234 | return; |
235 | |
236 | memcpy(scc->sc_ibuf, ibuf, len)__builtin_memcpy((scc->sc_ibuf), (ibuf), (len)); |
237 | frame = (scc->sc_ibuf[1] << 8) + scc->sc_ibuf[0]; |
Value stored to 'frame' is never read | |
238 | |
239 | for (i = 0; i < OAK_V_MAXSENSORS8; i++) { |
240 | idx = (i + 1) * 2; |
241 | val = (int16_t)((scc->sc_ibuf[idx+1] << 8) | scc->sc_ibuf[idx]); |
242 | uoak_sensor_update(&sc->sc_sensor[i].v, val); |
243 | } |
244 | } |
245 | |
246 | void |
247 | uoakv_refresh(void *arg) |
248 | { |
249 | struct uoakv_softc *sc = arg; |
250 | struct uoak_softc *scc = &sc->sc_uoak_softc; |
251 | uint8_t led; |
252 | int i; |
253 | |
254 | /* blink LED for each cycle */ |
255 | if (uoak_led_status(scc, OAK_TARGET_RAM, &led) < 0) |
256 | DPRINTF(("status query error\n")); |
257 | if (led == OAK_LED_OFF0x0) |
258 | (void)uoak_led_ctrl(scc, OAK_TARGET_RAM, OAK_LED_ON0x1); |
259 | else |
260 | (void)uoak_led_ctrl(scc, OAK_TARGET_RAM, OAK_LED_OFF0x0); |
261 | |
262 | for (i = 0; i < OAK_V_MAXSENSORS8; i++) |
263 | uoak_sensor_refresh(&sc->sc_sensor[i].v, 1000, 0); |
264 | } |
265 | |
266 | int |
267 | uoakv_get_channel_setting(struct uoakv_softc *sc, enum uoak_target target, |
268 | int ch) |
269 | { |
270 | struct uoak_softc *scc = &sc->sc_uoak_softc; |
271 | uint16_t cmd, result; |
272 | |
273 | memset(&scc->sc_rcmd, 0, sizeof(struct uoak_rcmd))__builtin_memset((&scc->sc_rcmd), (0), (sizeof(struct uoak_rcmd ))); |
274 | scc->sc_rcmd.target = target; |
275 | scc->sc_rcmd.datasize = 0x2; |
276 | |
277 | #define OAK_V_CHANNEL_IDX_OFFSET3 3 |
278 | cmd = (ch + OAK_V_CHANNEL_IDX_OFFSET3); |
279 | USETW(&scc->sc_rcmd.cmd, cmd)(*(u_int16_t *)(&scc->sc_rcmd.cmd) = (cmd)); |
280 | |
281 | if (uoak_get_cmd(scc) < 0) |
282 | return EIO5; |
283 | |
284 | result = (scc->sc_buf[2] << 8) + scc->sc_buf[1]; |
285 | sc->sc_sensor[ch].offset[target] = result; |
286 | |
287 | return 0; |
288 | } |
289 | |
290 | int |
291 | uoakv_get_sensor_setting(struct uoakv_softc *sc, enum uoak_target target) |
292 | { |
293 | struct uoak_softc *scc = &sc->sc_uoak_softc; |
294 | uint8_t result; |
295 | |
296 | memset(&scc->sc_rcmd, 0, sizeof(struct uoak_rcmd))__builtin_memset((&scc->sc_rcmd), (0), (sizeof(struct uoak_rcmd ))); |
297 | scc->sc_rcmd.target = target; |
298 | scc->sc_rcmd.datasize = 0x1; |
299 | USETW(&scc->sc_rcmd.cmd, OAK_CMD_SENSORSETTING)(*(u_int16_t *)(&scc->sc_rcmd.cmd) = (0x0002)); |
300 | |
301 | if (uoak_get_cmd(scc) < 0) |
302 | return EIO5; |
303 | |
304 | result = scc->sc_buf[1]; |
305 | sc->sc_inputmode[target] = (result & OAK_V_SENSOR_INPUTMODEMASK(0x1 << 0)); |
306 | |
307 | return 0; |
308 | } |
309 | |
310 | /* device specific functions */ |
311 | void |
312 | uoakv_dev_setting(void *parent, enum uoak_target target) |
313 | { |
314 | struct uoakv_softc *sc = (struct uoakv_softc *)parent; |
315 | int i; |
316 | |
317 | /* get device specific configuration */ |
318 | (void)uoakv_get_sensor_setting(sc, target); |
319 | for (i = 0; i < OAK_V_MAXSENSORS8; i++) |
320 | (void)uoakv_get_channel_setting(sc, target, i); |
321 | } |
322 | |
323 | void |
324 | uoakv_dev_print(void *parent, enum uoak_target target) |
325 | { |
326 | struct uoakv_softc *sc = (struct uoakv_softc *)parent; |
327 | int i; |
328 | |
329 | printf(", %s", (sc->sc_inputmode[target] ? |
330 | "Pseudo-Differential" : "Single-Ended")); |
331 | |
332 | printf(", ADC channel offsets:\n"); |
333 | printf("%s: ", sc->sc_hdev.sc_dev.dv_xname); |
334 | for (i = 0; i < OAK_V_MAXSENSORS8; i++) |
335 | printf("ch%02d %2d.%02d, ", i, |
336 | sc->sc_sensor[i].offset[target] / 100, |
337 | sc->sc_sensor[i].offset[target] % 100); |
338 | } |