| @@ -1,90 +1,119 @@ | | | @@ -1,90 +1,119 @@ |
1 | /* $NetBSD: gpio.c,v 1.18 2009/04/02 00:09:33 dyoung Exp $ */ | | 1 | /* $NetBSD: gpio.c,v 1.19 2009/07/25 16:17:10 mbalmer Exp $ */ |
2 | /* $OpenBSD: gpio.c,v 1.6 2006/01/14 12:33:49 grange Exp $ */ | | 2 | /* $OpenBSD: gpio.c,v 1.6 2006/01/14 12:33:49 grange Exp $ */ |
3 | | | 3 | |
4 | /* | | 4 | /* |
| | | 5 | * Copyright (c) 2008, 2009 Marc Balmer <marc@msys.ch> |
5 | * Copyright (c) 2004, 2006 Alexander Yurchenko <grange@openbsd.org> | | 6 | * Copyright (c) 2004, 2006 Alexander Yurchenko <grange@openbsd.org> |
6 | * | | 7 | * |
7 | * Permission to use, copy, modify, and distribute this software for any | | 8 | * Permission to use, copy, modify, and distribute this software for any |
8 | * purpose with or without fee is hereby granted, provided that the above | | 9 | * purpose with or without fee is hereby granted, provided that the above |
9 | * copyright notice and this permission notice appear in all copies. | | 10 | * copyright notice and this permission notice appear in all copies. |
10 | * | | 11 | * |
11 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | | 12 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
12 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | | 13 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
13 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | | 14 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR |
14 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | | 15 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
15 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | | 16 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN |
16 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | | 17 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF |
17 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | | 18 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
18 | */ | | 19 | */ |
19 | | | 20 | |
20 | #include <sys/cdefs.h> | | 21 | #include <sys/cdefs.h> |
21 | __KERNEL_RCSID(0, "$NetBSD: gpio.c,v 1.18 2009/04/02 00:09:33 dyoung Exp $"); | | 22 | __KERNEL_RCSID(0, "$NetBSD: gpio.c,v 1.19 2009/07/25 16:17:10 mbalmer Exp $"); |
22 | | | 23 | |
23 | /* | | 24 | /* |
24 | * General Purpose Input/Output framework. | | 25 | * General Purpose Input/Output framework. |
25 | */ | | 26 | */ |
26 | | | 27 | |
27 | #include <sys/param.h> | | 28 | #include <sys/param.h> |
28 | #include <sys/systm.h> | | 29 | #include <sys/systm.h> |
29 | #include <sys/conf.h> | | 30 | #include <sys/conf.h> |
30 | #include <sys/device.h> | | 31 | #include <sys/device.h> |
| | | 32 | #include <sys/fcntl.h> |
31 | #include <sys/ioctl.h> | | 33 | #include <sys/ioctl.h> |
32 | #include <sys/gpio.h> | | 34 | #include <sys/gpio.h> |
33 | #include <sys/vnode.h> | | 35 | #include <sys/vnode.h> |
| | | 36 | #include <sys/kmem.h> |
| | | 37 | #include <sys/queue.h> |
| | | 38 | #include <sys/kauth.h> |
34 | | | 39 | |
35 | #include <dev/gpio/gpiovar.h> | | 40 | #include <dev/gpio/gpiovar.h> |
36 | | | 41 | |
37 | #include "locators.h" | | 42 | #include "locators.h" |
38 | | | 43 | |
39 | struct gpio_softc { | | 44 | #ifdef GPIO_DEBUG |
40 | device_t sc_dev; | | 45 | #define DPRINTF(n, x) do { if (gpiodebug > (n)) printf x; } while (0) |
| | | 46 | int gpiodebug = 0; |
| | | 47 | #else |
| | | 48 | #define DPRINTFN(n, x) |
| | | 49 | #endif |
| | | 50 | #define DPRINTF(x) DPRINTFN(0, x) |
41 | | | 51 | |
42 | gpio_chipset_tag_t sc_gc; /* our GPIO controller */ | | 52 | struct gpio_softc { |
43 | gpio_pin_t *sc_pins; /* pins array */ | | 53 | device_t sc_dev; |
44 | int sc_npins; /* total number of pins */ | | | |
45 | | | 54 | |
46 | int sc_opened; | | 55 | gpio_chipset_tag_t sc_gc; /* GPIO controller */ |
47 | int sc_dying; | | 56 | gpio_pin_t *sc_pins; /* pins array */ |
| | | 57 | int sc_npins; /* number of pins */ |
| | | 58 | |
| | | 59 | int sc_opened; |
| | | 60 | LIST_HEAD(, gpio_dev) sc_devs; /* devices */ |
| | | 61 | LIST_HEAD(, gpio_name) sc_names; /* named pins */ |
48 | }; | | 62 | }; |
49 | | | 63 | |
50 | int gpio_match(device_t, cfdata_t, void *); | | 64 | int gpio_match(device_t, cfdata_t, void *); |
| | | 65 | int gpio_submatch(device_t, cfdata_t, const int *, void *); |
51 | void gpio_attach(device_t, device_t, void *); | | 66 | void gpio_attach(device_t, device_t, void *); |
52 | bool gpio_resume(device_t PMF_FN_PROTO); | | 67 | bool gpio_resume(device_t PMF_FN_PROTO); |
53 | int gpio_detach(device_t, int); | | 68 | int gpio_detach(device_t, int); |
54 | int gpio_activate(device_t, enum devact); | | 69 | int gpio_activate(device_t, enum devact); |
55 | int gpio_search(device_t, cfdata_t, const int *, void *); | | 70 | int gpio_search(device_t, cfdata_t, const int *, void *); |
56 | int gpio_print(void *, const char *); | | 71 | int gpio_print(void *, const char *); |
| | | 72 | int gpio_pinbyname(struct gpio_softc *, char *); |
| | | 73 | |
| | | 74 | /* Old API */ |
| | | 75 | int gpio_ioctl_oapi(struct gpio_softc *, u_long, void *, int, kauth_cred_t); |
57 | | | 76 | |
58 | CFATTACH_DECL3_NEW(gpio, sizeof(struct gpio_softc), | | 77 | CFATTACH_DECL3_NEW(gpio, sizeof(struct gpio_softc), |
59 | gpio_match, gpio_attach, gpio_detach, gpio_activate, NULL, NULL, | | 78 | gpio_match, gpio_attach, gpio_detach, gpio_activate, NULL, NULL, |
60 | DVF_DETACH_SHUTDOWN); | | 79 | DVF_DETACH_SHUTDOWN); |
61 | | | 80 | |
62 | dev_type_open(gpioopen); | | 81 | dev_type_open(gpioopen); |
63 | dev_type_close(gpioclose); | | 82 | dev_type_close(gpioclose); |
64 | dev_type_ioctl(gpioioctl); | | 83 | dev_type_ioctl(gpioioctl); |
65 | | | 84 | |
66 | const struct cdevsw gpio_cdevsw = { | | 85 | const struct cdevsw gpio_cdevsw = { |
67 | gpioopen, gpioclose, noread, nowrite, gpioioctl, | | 86 | gpioopen, gpioclose, noread, nowrite, gpioioctl, |
68 | nostop, notty, nopoll, nommap, nokqfilter, D_OTHER, | | 87 | nostop, notty, nopoll, nommap, nokqfilter, D_OTHER, |
69 | }; | | 88 | }; |
70 | | | 89 | |
71 | extern struct cfdriver gpio_cd; | | 90 | extern struct cfdriver gpio_cd; |
72 | | | 91 | |
73 | int | | 92 | int |
74 | gpio_match(device_t parent, cfdata_t cf, void *aux) | | 93 | gpio_match(device_t parent, cfdata_t cf, void *aux) |
75 | { | | 94 | { |
| | | 95 | return 1; |
| | | 96 | } |
| | | 97 | |
| | | 98 | int |
| | | 99 | gpio_submatch(device_t parent, cfdata_t cf, const int *ip, void *aux) |
| | | 100 | { |
| | | 101 | struct gpio_attach_args *ga = aux; |
76 | | | 102 | |
77 | return (1); | | 103 | if (ga->ga_offset == -1) |
| | | 104 | return 0; |
| | | 105 | |
| | | 106 | return strcmp(ga->ga_dvname, cf->cf_name) == 0; |
78 | } | | 107 | } |
79 | | | 108 | |
80 | bool | | 109 | bool |
81 | gpio_resume(device_t self PMF_FN_ARGS) | | 110 | gpio_resume(device_t self PMF_FN_ARGS) |
82 | { | | 111 | { |
83 | struct gpio_softc *sc = device_private(self); | | 112 | struct gpio_softc *sc = device_private(self); |
84 | int pin; | | 113 | int pin; |
85 | | | 114 | |
86 | for (pin = 0; pin < sc->sc_npins; pin++) { | | 115 | for (pin = 0; pin < sc->sc_npins; pin++) { |
87 | gpiobus_pin_ctl(sc->sc_gc, pin, sc->sc_pins[pin].pin_flags); | | 116 | gpiobus_pin_ctl(sc->sc_gc, pin, sc->sc_pins[pin].pin_flags); |
88 | gpiobus_pin_write(sc->sc_gc, pin, sc->sc_pins[pin].pin_state); | | 117 | gpiobus_pin_write(sc->sc_gc, pin, sc->sc_pins[pin].pin_state); |
89 | } | | 118 | } |
90 | return true; | | 119 | return true; |
| @@ -118,290 +147,586 @@ gpio_detach(device_t self, int flags) | | | @@ -118,290 +147,586 @@ gpio_detach(device_t self, int flags) |
118 | { | | 147 | { |
119 | #if 0 | | 148 | #if 0 |
120 | int maj, mn; | | 149 | int maj, mn; |
121 | | | 150 | |
122 | /* Locate the major number */ | | 151 | /* Locate the major number */ |
123 | for (maj = 0; maj < nchrdev; maj++) | | 152 | for (maj = 0; maj < nchrdev; maj++) |
124 | if (cdevsw[maj].d_open == gpioopen) | | 153 | if (cdevsw[maj].d_open == gpioopen) |
125 | break; | | 154 | break; |
126 | | | 155 | |
127 | /* Nuke the vnodes for any open instances (calls close) */ | | 156 | /* Nuke the vnodes for any open instances (calls close) */ |
128 | mn = device_unit(self); | | 157 | mn = device_unit(self); |
129 | vdevgone(maj, mn, mn, VCHR); | | 158 | vdevgone(maj, mn, mn, VCHR); |
130 | #endif | | 159 | #endif |
131 | | | 160 | return 0; |
132 | return (0); | | | |
133 | } | | 161 | } |
134 | | | 162 | |
135 | int | | 163 | int |
136 | gpio_activate(device_t self, enum devact act) | | 164 | gpio_activate(device_t self, enum devact act) |
137 | { | | 165 | { |
138 | struct gpio_softc *sc = device_private(self); | | 166 | printf("gpio_active: "); |
139 | | | | |
140 | switch (act) { | | 167 | switch (act) { |
141 | case DVACT_ACTIVATE: | | 168 | case DVACT_ACTIVATE: |
142 | return (EOPNOTSUPP); | | 169 | DPRINTF(("ACTIVATE\n")); |
| | | 170 | return EOPNOTSUPP; |
143 | case DVACT_DEACTIVATE: | | 171 | case DVACT_DEACTIVATE: |
144 | sc->sc_dying = 1; | | 172 | DPRINTF(("DEACTIVATE\n")); |
145 | break; | | 173 | break; |
146 | } | | 174 | } |
147 | | | 175 | return 0; |
148 | return (0); | | | |
149 | } | | 176 | } |
150 | | | 177 | |
151 | int | | 178 | int |
152 | gpio_search(device_t parent, cfdata_t cf, | | 179 | gpio_search(device_t parent, cfdata_t cf, |
153 | const int *ldesc, void *aux) | | 180 | const int *ldesc, void *aux) |
154 | { | | 181 | { |
155 | struct gpio_attach_args ga; | | 182 | struct gpio_attach_args ga; |
156 | | | 183 | |
157 | ga.ga_gpio = aux; | | 184 | ga.ga_gpio = aux; |
158 | ga.ga_offset = cf->cf_loc[GPIOCF_OFFSET]; | | 185 | ga.ga_offset = cf->cf_loc[GPIOCF_OFFSET]; |
159 | ga.ga_mask = cf->cf_loc[GPIOCF_MASK]; | | 186 | ga.ga_mask = cf->cf_loc[GPIOCF_MASK]; |
160 | | | 187 | |
161 | if (config_match(parent, cf, &ga) > 0) | | 188 | if (config_match(parent, cf, &ga) > 0) |
162 | config_attach(parent, cf, &ga, gpio_print); | | 189 | config_attach(parent, cf, &ga, gpio_print); |
163 | | | 190 | |
164 | return (0); | | 191 | return 0; |
165 | } | | 192 | } |
166 | | | 193 | |
167 | int | | 194 | int |
168 | gpio_print(void *aux, const char *pnp) | | 195 | gpio_print(void *aux, const char *pnp) |
169 | { | | 196 | { |
170 | struct gpio_attach_args *ga = aux; | | 197 | struct gpio_attach_args *ga = aux; |
171 | int i; | | 198 | int i; |
172 | | | 199 | |
173 | printf(" pins"); | | 200 | printf(" pins"); |
174 | for (i = 0; i < 32; i++) | | 201 | for (i = 0; i < 32; i++) |
175 | if (ga->ga_mask & (1 << i)) | | 202 | if (ga->ga_mask & (1 << i)) |
176 | printf(" %d", ga->ga_offset + i); | | 203 | printf(" %d", ga->ga_offset + i); |
177 | | | 204 | |
178 | return (UNCONF); | | 205 | return UNCONF; |
179 | } | | 206 | } |
180 | | | 207 | |
181 | int | | 208 | int |
182 | gpiobus_print(void *aux, const char *pnp) | | 209 | gpiobus_print(void *aux, const char *pnp) |
183 | { | | 210 | { |
184 | #if 0 | | 211 | #if 0 |
185 | struct gpiobus_attach_args *gba = aux; | | 212 | struct gpiobus_attach_args *gba = aux; |
186 | #endif | | 213 | #endif |
187 | if (pnp != NULL) | | 214 | if (pnp != NULL) |
188 | printf("%s at %s", "gpiobus", pnp); | | 215 | printf("gpiobus at %s", pnp); |
189 | | | 216 | |
190 | return (UNCONF); | | 217 | return UNCONF; |
191 | } | | 218 | } |
192 | | | 219 | |
193 | int | | 220 | int |
194 | gpio_pin_map(void *gpio, int offset, u_int32_t mask, struct gpio_pinmap *map) | | 221 | gpio_pin_map(void *gpio, int offset, u_int32_t mask, struct gpio_pinmap *map) |
195 | { | | 222 | { |
196 | struct gpio_softc *sc = gpio; | | 223 | struct gpio_softc *sc = gpio; |
197 | int npins, pin, i; | | 224 | int npins, pin, i; |
198 | | | 225 | |
199 | npins = gpio_npins(mask); | | 226 | npins = gpio_npins(mask); |
200 | if (npins > sc->sc_npins) | | 227 | if (npins > sc->sc_npins) |
201 | return (1); | | 228 | return 1; |
202 | | | 229 | |
203 | for (npins = 0, i = 0; i < 32; i++) | | 230 | for (npins = 0, i = 0; i < 32; i++) |
204 | if (mask & (1 << i)) { | | 231 | if (mask & (1 << i)) { |
205 | pin = offset + i; | | 232 | pin = offset + i; |
206 | if (pin < 0 || pin >= sc->sc_npins) | | 233 | if (pin < 0 || pin >= sc->sc_npins) |
207 | return (1); | | 234 | return 1; |
208 | if (sc->sc_pins[pin].pin_mapped) | | 235 | if (sc->sc_pins[pin].pin_mapped) |
209 | return (1); | | 236 | return 1; |
210 | sc->sc_pins[pin].pin_mapped = 1; | | 237 | sc->sc_pins[pin].pin_mapped = 1; |
211 | map->pm_map[npins++] = pin; | | 238 | map->pm_map[npins++] = pin; |
212 | } | | 239 | } |
213 | map->pm_size = npins; | | 240 | map->pm_size = npins; |
214 | | | 241 | |
215 | return (0); | | 242 | return 0; |
216 | } | | 243 | } |
217 | | | 244 | |
218 | void | | 245 | void |
219 | gpio_pin_unmap(void *gpio, struct gpio_pinmap *map) | | 246 | gpio_pin_unmap(void *gpio, struct gpio_pinmap *map) |
220 | { | | 247 | { |
221 | struct gpio_softc *sc = gpio; | | 248 | struct gpio_softc *sc = gpio; |
222 | int pin, i; | | 249 | int pin, i; |
223 | | | 250 | |
224 | for (i = 0; i < map->pm_size; i++) { | | 251 | for (i = 0; i < map->pm_size; i++) { |
225 | pin = map->pm_map[i]; | | 252 | pin = map->pm_map[i]; |
226 | sc->sc_pins[pin].pin_mapped = 0; | | 253 | sc->sc_pins[pin].pin_mapped = 0; |
227 | } | | 254 | } |
228 | } | | 255 | } |
229 | | | 256 | |
230 | int | | 257 | int |
231 | gpio_pin_read(void *gpio, struct gpio_pinmap *map, int pin) | | 258 | gpio_pin_read(void *gpio, struct gpio_pinmap *map, int pin) |
232 | { | | 259 | { |
233 | struct gpio_softc *sc = gpio; | | 260 | struct gpio_softc *sc = gpio; |
234 | | | 261 | |
235 | return (gpiobus_pin_read(sc->sc_gc, map->pm_map[pin])); | | 262 | return gpiobus_pin_read(sc->sc_gc, map->pm_map[pin]); |
236 | } | | 263 | } |
237 | | | 264 | |
238 | void | | 265 | void |
239 | gpio_pin_write(void *gpio, struct gpio_pinmap *map, int pin, int value) | | 266 | gpio_pin_write(void *gpio, struct gpio_pinmap *map, int pin, int value) |
240 | { | | 267 | { |
241 | struct gpio_softc *sc = gpio; | | 268 | struct gpio_softc *sc = gpio; |
242 | | | 269 | |
243 | gpiobus_pin_write(sc->sc_gc, map->pm_map[pin], value); | | 270 | gpiobus_pin_write(sc->sc_gc, map->pm_map[pin], value); |
244 | sc->sc_pins[map->pm_map[pin]].pin_state = value; | | 271 | sc->sc_pins[map->pm_map[pin]].pin_state = value; |
245 | } | | 272 | } |
246 | | | 273 | |
247 | void | | 274 | void |
248 | gpio_pin_ctl(void *gpio, struct gpio_pinmap *map, int pin, int flags) | | 275 | gpio_pin_ctl(void *gpio, struct gpio_pinmap *map, int pin, int flags) |
249 | { | | 276 | { |
250 | struct gpio_softc *sc = gpio; | | 277 | struct gpio_softc *sc = gpio; |
251 | | | 278 | |
252 | return (gpiobus_pin_ctl(sc->sc_gc, map->pm_map[pin], flags)); | | 279 | return gpiobus_pin_ctl(sc->sc_gc, map->pm_map[pin], flags); |
253 | } | | 280 | } |
254 | | | 281 | |
255 | int | | 282 | int |
256 | gpio_pin_caps(void *gpio, struct gpio_pinmap *map, int pin) | | 283 | gpio_pin_caps(void *gpio, struct gpio_pinmap *map, int pin) |
257 | { | | 284 | { |
258 | struct gpio_softc *sc = gpio; | | 285 | struct gpio_softc *sc = gpio; |
259 | | | 286 | |
260 | return (sc->sc_pins[map->pm_map[pin]].pin_caps); | | 287 | return sc->sc_pins[map->pm_map[pin]].pin_caps; |
261 | } | | 288 | } |
262 | | | 289 | |
263 | int | | 290 | int |
264 | gpio_npins(u_int32_t mask) | | 291 | gpio_npins(u_int32_t mask) |
265 | { | | 292 | { |
266 | int npins, i; | | 293 | int npins, i; |
267 | | | 294 | |
268 | for (npins = 0, i = 0; i < 32; i++) | | 295 | for (npins = 0, i = 0; i < 32; i++) |
269 | if (mask & (1 << i)) | | 296 | if (mask & (1 << i)) |
270 | npins++; | | 297 | npins++; |
271 | | | 298 | |
272 | return (npins); | | 299 | return npins; |
273 | } | | 300 | } |
274 | | | 301 | |
275 | int | | 302 | int |
276 | gpioopen(dev_t dev, int flag, int mode, | | 303 | gpioopen(dev_t dev, int flag, int mode, |
277 | struct lwp *l) | | 304 | struct lwp *l) |
278 | { | | 305 | { |
279 | struct gpio_softc *sc; | | 306 | struct gpio_softc *sc; |
280 | int ret; | | 307 | int ret; |
281 | | | 308 | |
282 | sc = device_lookup_private(&gpio_cd, minor(dev)); | | 309 | sc = device_lookup_private(&gpio_cd, minor(dev)); |
283 | if (sc == NULL) | | 310 | if (sc == NULL) |
284 | return (ENXIO); | | 311 | return ENXIO; |
285 | | | 312 | DPRINTF(("%s: opening\n", sc->sc_dev->dv_xname)); |
286 | if (sc->sc_opened) | | 313 | if (sc->sc_opened) { |
287 | return (EBUSY); | | 314 | DPRINTF(("%s: already opened\n", sc->sc_dev->dv_xname)); |
| | | 315 | return EBUSY; |
| | | 316 | } |
288 | | | 317 | |
289 | if ((ret = gpiobus_open(sc->sc_gc, sc->sc_dev))) | | 318 | if ((ret = gpiobus_open(sc->sc_gc, sc->sc_dev))) { |
| | | 319 | DPRINTF(("%s: gpiobus_open returned %d\n", sc->sc_dev->dv_xname, |
| | | 320 | ret)); |
290 | return ret; | | 321 | return ret; |
| | | 322 | } |
291 | | | 323 | |
292 | sc->sc_opened = 1; | | 324 | sc->sc_opened = 1; |
293 | | | 325 | |
294 | return (0); | | 326 | return 0; |
295 | } | | 327 | } |
296 | | | 328 | |
297 | int | | 329 | int |
298 | gpioclose(dev_t dev, int flag, int mode, | | 330 | gpioclose(dev_t dev, int flag, int mode, |
299 | struct lwp *l) | | 331 | struct lwp *l) |
300 | { | | 332 | { |
301 | struct gpio_softc *sc; | | 333 | struct gpio_softc *sc; |
302 | | | 334 | |
303 | sc = device_lookup_private(&gpio_cd, minor(dev)); | | 335 | sc = device_lookup_private(&gpio_cd, minor(dev)); |
| | | 336 | DPRINTF(("%s: closing\n", sc->sc_dev->dv_xname)); |
304 | gpiobus_close(sc->sc_gc, sc->sc_dev); | | 337 | gpiobus_close(sc->sc_gc, sc->sc_dev); |
305 | sc->sc_opened = 0; | | 338 | sc->sc_opened = 0; |
306 | | | 339 | |
307 | return (0); | | 340 | return 0; |
| | | 341 | } |
| | | 342 | |
| | | 343 | int |
| | | 344 | gpio_pinbyname(struct gpio_softc *sc, char *gp_name) |
| | | 345 | { |
| | | 346 | struct gpio_name *nm; |
| | | 347 | |
| | | 348 | LIST_FOREACH(nm, &sc->sc_names, gp_next) |
| | | 349 | if (!strcmp(nm->gp_name, gp_name)) |
| | | 350 | return nm->gp_pin; |
| | | 351 | return -1; |
308 | } | | 352 | } |
309 | | | 353 | |
310 | int | | 354 | int |
311 | gpioioctl(dev_t dev, u_long cmd, void *data, int flag, | | 355 | gpioioctl(dev_t dev, u_long cmd, void *data, int flag, |
312 | struct lwp *l) | | 356 | struct lwp *l) |
313 | { | | 357 | { |
314 | struct gpio_softc *sc; | | 358 | struct gpio_softc *sc; |
315 | gpio_chipset_tag_t gc; | | 359 | gpio_chipset_tag_t gc; |
316 | struct gpio_info *info; | | 360 | struct gpio_info *info; |
317 | struct gpio_pin_op *op; | | 361 | struct gpio_attach *attach; |
318 | struct gpio_pin_ctl *ctl; | | 362 | struct gpio_attach_args ga; |
319 | int pin, value, flags; | | 363 | struct gpio_dev *gdev; |
| | | 364 | struct gpio_req *req; |
| | | 365 | struct gpio_name *nm; |
| | | 366 | struct gpio_set *set; |
| | | 367 | struct device *dv; |
| | | 368 | kauth_cred_t cred; |
| | | 369 | int locs[GPIOCF_NLOCS]; |
| | | 370 | int pin, value, flags, npins, found; |
320 | | | 371 | |
321 | sc = device_lookup_private(&gpio_cd, minor(dev)); | | 372 | sc = device_lookup_private(&gpio_cd, minor(dev)); |
322 | gc = sc->sc_gc; | | 373 | gc = sc->sc_gc; |
323 | | | 374 | |
324 | if (cmd != GPIOINFO && !device_is_active(sc->sc_dev)) | | 375 | if (cmd != GPIOINFO && !device_is_active(sc->sc_dev)) { |
| | | 376 | DPRINTF(("%s: device is not active\n", sc->sc_dev->dv_xname)); |
325 | return EBUSY; | | 377 | return EBUSY; |
| | | 378 | } |
| | | 379 | |
| | | 380 | cred = kauth_cred_get(); |
326 | | | 381 | |
327 | switch (cmd) { | | 382 | switch (cmd) { |
328 | case GPIOINFO: | | 383 | case GPIOINFO: |
329 | info = (struct gpio_info *)data; | | 384 | info = (struct gpio_info *)data; |
| | | 385 | if (!kauth_authorize_device(cred, KAUTH_DEVICE_GPIO_PINSET, |
| | | 386 | NULL, NULL, NULL, NULL)) |
| | | 387 | info->gpio_npins = sc->sc_npins; |
| | | 388 | else { |
| | | 389 | for (pin = npins = 0; pin < sc->sc_npins; pin++) |
| | | 390 | if (sc->sc_pins[pin].pin_flags & GPIO_PIN_SET) |
| | | 391 | ++npins; |
| | | 392 | info->gpio_npins = npins; |
| | | 393 | } |
| | | 394 | break; |
| | | 395 | case GPIOREAD: |
| | | 396 | req = (struct gpio_req *)data; |
| | | 397 | |
| | | 398 | if (req->gp_name[0] != '\0') { |
| | | 399 | pin = gpio_pinbyname(sc, req->gp_name); |
| | | 400 | if (pin == -1) |
| | | 401 | return EINVAL; |
| | | 402 | } else |
| | | 403 | pin = req->gp_pin; |
| | | 404 | |
| | | 405 | if (pin < 0 || pin >= sc->sc_npins) |
| | | 406 | return EINVAL; |
| | | 407 | |
| | | 408 | if (!(sc->sc_pins[pin].pin_flags & GPIO_PIN_SET) && |
| | | 409 | kauth_authorize_device(cred, KAUTH_DEVICE_GPIO_PINSET, |
| | | 410 | NULL, NULL, NULL, NULL)) |
| | | 411 | return EPERM; |
| | | 412 | |
| | | 413 | /* return read value */ |
| | | 414 | req->gp_value = gpiobus_pin_read(gc, pin); |
| | | 415 | break; |
| | | 416 | case GPIOWRITE: |
| | | 417 | if ((flag & FWRITE) == 0) |
| | | 418 | return EBADF; |
| | | 419 | |
| | | 420 | req = (struct gpio_req *)data; |
| | | 421 | |
| | | 422 | if (req->gp_name[0] != '\0') { |
| | | 423 | pin = gpio_pinbyname(sc, req->gp_name); |
| | | 424 | if (pin == -1) |
| | | 425 | return EINVAL; |
| | | 426 | } else |
| | | 427 | pin = req->gp_pin; |
| | | 428 | |
| | | 429 | if (pin < 0 || pin >= sc->sc_npins) |
| | | 430 | return EINVAL; |
| | | 431 | |
| | | 432 | if (sc->sc_pins[pin].pin_mapped) |
| | | 433 | return EBUSY; |
| | | 434 | |
| | | 435 | if (!(sc->sc_pins[pin].pin_flags & GPIO_PIN_SET) && |
| | | 436 | kauth_authorize_device(cred, KAUTH_DEVICE_GPIO_PINSET, |
| | | 437 | NULL, NULL, NULL, NULL)) |
| | | 438 | return EPERM; |
330 | | | 439 | |
331 | info->gpio_npins = sc->sc_npins; | | 440 | value = req->gp_value; |
| | | 441 | if (value != GPIO_PIN_LOW && value != GPIO_PIN_HIGH) |
| | | 442 | return EINVAL; |
| | | 443 | |
| | | 444 | gpiobus_pin_write(gc, pin, value); |
| | | 445 | /* return old value */ |
| | | 446 | req->gp_value = sc->sc_pins[pin].pin_state; |
| | | 447 | /* update current value */ |
| | | 448 | sc->sc_pins[pin].pin_state = value; |
332 | break; | | 449 | break; |
| | | 450 | case GPIOTOGGLE: |
| | | 451 | if ((flag & FWRITE) == 0) |
| | | 452 | return EBADF; |
| | | 453 | |
| | | 454 | req = (struct gpio_req *)data; |
| | | 455 | |
| | | 456 | if (req->gp_name[0] != '\0') { |
| | | 457 | pin = gpio_pinbyname(sc, req->gp_name); |
| | | 458 | if (pin == -1) |
| | | 459 | return EINVAL; |
| | | 460 | } else |
| | | 461 | pin = req->gp_pin; |
| | | 462 | |
| | | 463 | if (pin < 0 || pin >= sc->sc_npins) |
| | | 464 | return EINVAL; |
| | | 465 | |
| | | 466 | if (sc->sc_pins[pin].pin_mapped) |
| | | 467 | return EBUSY; |
| | | 468 | |
| | | 469 | if (!(sc->sc_pins[pin].pin_flags & GPIO_PIN_SET) && |
| | | 470 | kauth_authorize_device(cred, KAUTH_DEVICE_GPIO_PINSET, |
| | | 471 | NULL, NULL, NULL, NULL)) |
| | | 472 | return EPERM; |
| | | 473 | |
| | | 474 | value = (sc->sc_pins[pin].pin_state == GPIO_PIN_LOW ? |
| | | 475 | GPIO_PIN_HIGH : GPIO_PIN_LOW); |
| | | 476 | gpiobus_pin_write(gc, pin, value); |
| | | 477 | /* return old value */ |
| | | 478 | req->gp_value = sc->sc_pins[pin].pin_state; |
| | | 479 | /* update current value */ |
| | | 480 | sc->sc_pins[pin].pin_state = value; |
| | | 481 | break; |
| | | 482 | case GPIOATTACH: |
| | | 483 | if (kauth_authorize_device(cred, KAUTH_DEVICE_GPIO_PINSET, |
| | | 484 | NULL, NULL, NULL, NULL)) |
| | | 485 | return EPERM; |
| | | 486 | |
| | | 487 | attach = (struct gpio_attach *)data; |
| | | 488 | ga.ga_gpio = sc; |
| | | 489 | ga.ga_dvname = attach->ga_dvname; |
| | | 490 | ga.ga_offset = attach->ga_offset; |
| | | 491 | ga.ga_mask = attach->ga_mask; |
| | | 492 | DPRINTF(("%s: attach %s with offset %d and mask 0x%02x\n", |
| | | 493 | sc->sc_dev->dv_xname, ga.ga_dvname, ga.ga_offset, |
| | | 494 | ga.ga_mask)); |
| | | 495 | |
| | | 496 | locs[GPIOCF_OFFSET] = ga.ga_offset; |
| | | 497 | locs[GPIOCF_MASK] = ga.ga_mask; |
| | | 498 | |
| | | 499 | dv = config_found_sm_loc(sc->sc_dev, "gpio", locs, &ga, |
| | | 500 | gpiobus_print, gpio_submatch); |
| | | 501 | if (dv != NULL) { |
| | | 502 | gdev = kmem_alloc(sizeof(struct gpio_dev), KM_SLEEP); |
| | | 503 | gdev->sc_dev = dv; |
| | | 504 | LIST_INSERT_HEAD(&sc->sc_devs, gdev, sc_next); |
| | | 505 | } else |
| | | 506 | return EINVAL; |
| | | 507 | break; |
| | | 508 | case GPIODETACH: |
| | | 509 | if (kauth_authorize_device(cred, KAUTH_DEVICE_GPIO_PINSET, |
| | | 510 | NULL, NULL, NULL, NULL)) |
| | | 511 | return EPERM; |
| | | 512 | |
| | | 513 | attach = (struct gpio_attach *)data; |
| | | 514 | LIST_FOREACH(gdev, &sc->sc_devs, sc_next) { |
| | | 515 | if (strcmp(gdev->sc_dev->dv_xname, attach->ga_dvname) |
| | | 516 | == 0) { |
| | | 517 | if (config_detach(gdev->sc_dev, 0) == 0) { |
| | | 518 | LIST_REMOVE(gdev, sc_next); |
| | | 519 | kmem_free(gdev, |
| | | 520 | sizeof(struct gpio_dev)); |
| | | 521 | return 0; |
| | | 522 | } |
| | | 523 | break; |
| | | 524 | } |
| | | 525 | } |
| | | 526 | return EINVAL; |
| | | 527 | break; |
| | | 528 | case GPIOSET: |
| | | 529 | if (kauth_authorize_device(cred, KAUTH_DEVICE_GPIO_PINSET, |
| | | 530 | NULL, NULL, NULL, NULL)) |
| | | 531 | return EPERM; |
| | | 532 | |
| | | 533 | set = (struct gpio_set *)data; |
| | | 534 | |
| | | 535 | if (set->gp_name[0] != '\0') { |
| | | 536 | pin = gpio_pinbyname(sc, set->gp_name); |
| | | 537 | if (pin == -1) |
| | | 538 | return EINVAL; |
| | | 539 | } else |
| | | 540 | pin = set->gp_pin; |
| | | 541 | if (pin < 0 || pin >= sc->sc_npins) |
| | | 542 | return EINVAL; |
| | | 543 | flags = set->gp_flags; |
| | | 544 | |
| | | 545 | /* check that the controller supports all requested flags */ |
| | | 546 | if ((flags & sc->sc_pins[pin].pin_caps) != flags) |
| | | 547 | return ENODEV; |
| | | 548 | flags = set->gp_flags | GPIO_PIN_SET; |
| | | 549 | |
| | | 550 | set->gp_caps = sc->sc_pins[pin].pin_caps; |
| | | 551 | /* return old value */ |
| | | 552 | set->gp_flags = sc->sc_pins[pin].pin_flags; |
| | | 553 | if (flags > 0) { |
| | | 554 | gpiobus_pin_ctl(gc, pin, flags); |
| | | 555 | /* update current value */ |
| | | 556 | sc->sc_pins[pin].pin_flags = flags; |
| | | 557 | } |
| | | 558 | |
| | | 559 | /* rename pin or new pin? */ |
| | | 560 | if (set->gp_name2[0] != '\0') { |
| | | 561 | found = 0; |
| | | 562 | LIST_FOREACH(nm, &sc->sc_names, gp_next) |
| | | 563 | if (nm->gp_pin == pin) { |
| | | 564 | strlcpy(nm->gp_name, set->gp_name2, |
| | | 565 | sizeof(nm->gp_name)); |
| | | 566 | found = 1; |
| | | 567 | break; |
| | | 568 | } |
| | | 569 | if (!found) { |
| | | 570 | nm = kmem_alloc(sizeof(struct gpio_name), |
| | | 571 | KM_SLEEP); |
| | | 572 | strlcpy(nm->gp_name, set->gp_name2, |
| | | 573 | sizeof(nm->gp_name)); |
| | | 574 | nm->gp_pin = set->gp_pin; |
| | | 575 | LIST_INSERT_HEAD(&sc->sc_names, nm, gp_next); |
| | | 576 | } |
| | | 577 | } |
| | | 578 | break; |
| | | 579 | case GPIOUNSET: |
| | | 580 | if (kauth_authorize_device(cred, KAUTH_DEVICE_GPIO_PINSET, |
| | | 581 | NULL, NULL, NULL, NULL)) |
| | | 582 | return EPERM; |
| | | 583 | |
| | | 584 | set = (struct gpio_set *)data; |
| | | 585 | if (set->gp_name[0] != '\0') { |
| | | 586 | pin = gpio_pinbyname(sc, set->gp_name); |
| | | 587 | if (pin == -1) |
| | | 588 | return EINVAL; |
| | | 589 | } else |
| | | 590 | pin = set->gp_pin; |
| | | 591 | |
| | | 592 | if (pin < 0 || pin >= sc->sc_npins) |
| | | 593 | return EINVAL; |
| | | 594 | if (sc->sc_pins[pin].pin_mapped) |
| | | 595 | return EBUSY; |
| | | 596 | if (!(sc->sc_pins[pin].pin_flags & GPIO_PIN_SET)) |
| | | 597 | return EINVAL; |
| | | 598 | |
| | | 599 | LIST_FOREACH(nm, &sc->sc_names, gp_next) { |
| | | 600 | if (nm->gp_pin == pin) { |
| | | 601 | LIST_REMOVE(nm, gp_next); |
| | | 602 | kmem_free(nm, sizeof(struct gpio_name)); |
| | | 603 | break; |
| | | 604 | } |
| | | 605 | } |
| | | 606 | sc->sc_pins[pin].pin_flags &= ~GPIO_PIN_SET; |
| | | 607 | break; |
| | | 608 | default: |
| | | 609 | /* Try the old API */ |
| | | 610 | DPRINTF(("%s: trying the old API\n", sc->sc_dev->dv_xname)); |
| | | 611 | return gpio_ioctl_oapi(sc, cmd, data, flag, cred); |
| | | 612 | } |
| | | 613 | return 0; |
| | | 614 | } |
| | | 615 | |
| | | 616 | int |
| | | 617 | gpio_ioctl_oapi(struct gpio_softc *sc, u_long cmd, void *data, int flag, |
| | | 618 | kauth_cred_t cred) |
| | | 619 | { |
| | | 620 | gpio_chipset_tag_t gc; |
| | | 621 | struct gpio_pin_op *op; |
| | | 622 | struct gpio_pin_ctl *ctl; |
| | | 623 | int pin, value, flags; |
| | | 624 | |
| | | 625 | gc = sc->sc_gc; |
| | | 626 | |
| | | 627 | switch (cmd) { |
333 | case GPIOPINREAD: | | 628 | case GPIOPINREAD: |
334 | op = (struct gpio_pin_op *)data; | | 629 | op = (struct gpio_pin_op *)data; |
335 | | | 630 | |
336 | pin = op->gp_pin; | | 631 | pin = op->gp_pin; |
| | | 632 | |
337 | if (pin < 0 || pin >= sc->sc_npins) | | 633 | if (pin < 0 || pin >= sc->sc_npins) |
338 | return (EINVAL); | | 634 | return EINVAL; |
| | | 635 | |
| | | 636 | if (!(sc->sc_pins[pin].pin_flags & GPIO_PIN_SET) && |
| | | 637 | kauth_authorize_device(cred, KAUTH_DEVICE_GPIO_PINSET, |
| | | 638 | NULL, NULL, NULL, NULL)) |
| | | 639 | return EPERM; |
339 | | | 640 | |
340 | /* return read value */ | | 641 | /* return read value */ |
341 | op->gp_value = gpiobus_pin_read(gc, pin); | | 642 | op->gp_value = gpiobus_pin_read(gc, pin); |
342 | break; | | 643 | break; |
343 | case GPIOPINWRITE: | | 644 | case GPIOPINWRITE: |
| | | 645 | if ((flag & FWRITE) == 0) |
| | | 646 | return EBADF; |
| | | 647 | |
344 | op = (struct gpio_pin_op *)data; | | 648 | op = (struct gpio_pin_op *)data; |
345 | | | 649 | |
346 | pin = op->gp_pin; | | 650 | pin = op->gp_pin; |
| | | 651 | |
347 | if (pin < 0 || pin >= sc->sc_npins) | | 652 | if (pin < 0 || pin >= sc->sc_npins) |
348 | return (EINVAL); | | 653 | return EINVAL; |
| | | 654 | |
349 | if (sc->sc_pins[pin].pin_mapped) | | 655 | if (sc->sc_pins[pin].pin_mapped) |
350 | return (EBUSY); | | 656 | return EBUSY; |
| | | 657 | |
| | | 658 | if (!(sc->sc_pins[pin].pin_flags & GPIO_PIN_SET) && |
| | | 659 | kauth_authorize_device(cred, KAUTH_DEVICE_GPIO_PINSET, |
| | | 660 | NULL, NULL, NULL, NULL)) |
| | | 661 | return EPERM; |
351 | | | 662 | |
352 | value = op->gp_value; | | 663 | value = op->gp_value; |
353 | if (value != GPIO_PIN_LOW && value != GPIO_PIN_HIGH) | | 664 | if (value != GPIO_PIN_LOW && value != GPIO_PIN_HIGH) |
354 | return (EINVAL); | | 665 | return EINVAL; |
355 | | | 666 | |
356 | gpiobus_pin_write(gc, pin, value); | | 667 | gpiobus_pin_write(gc, pin, value); |
357 | /* return old value */ | | 668 | /* return old value */ |
358 | op->gp_value = sc->sc_pins[pin].pin_state; | | 669 | op->gp_value = sc->sc_pins[pin].pin_state; |
359 | /* update current value */ | | 670 | /* update current value */ |
360 | sc->sc_pins[pin].pin_state = value; | | 671 | sc->sc_pins[pin].pin_state = value; |
361 | break; | | 672 | break; |
362 | case GPIOPINTOGGLE: | | 673 | case GPIOPINTOGGLE: |
| | | 674 | if ((flag & FWRITE) == 0) |
| | | 675 | return EBADF; |
| | | 676 | |
363 | op = (struct gpio_pin_op *)data; | | 677 | op = (struct gpio_pin_op *)data; |
364 | | | 678 | |
365 | pin = op->gp_pin; | | 679 | pin = op->gp_pin; |
| | | 680 | |
366 | if (pin < 0 || pin >= sc->sc_npins) | | 681 | if (pin < 0 || pin >= sc->sc_npins) |
367 | return (EINVAL); | | 682 | return EINVAL; |
| | | 683 | |
368 | if (sc->sc_pins[pin].pin_mapped) | | 684 | if (sc->sc_pins[pin].pin_mapped) |
369 | return (EBUSY); | | 685 | return EBUSY; |
| | | 686 | |
| | | 687 | if (!(sc->sc_pins[pin].pin_flags & GPIO_PIN_SET) && |
| | | 688 | kauth_authorize_device(cred, KAUTH_DEVICE_GPIO_PINSET, |
| | | 689 | NULL, NULL, NULL, NULL)) |
| | | 690 | return EPERM; |
370 | | | 691 | |
371 | value = (sc->sc_pins[pin].pin_state == GPIO_PIN_LOW ? | | 692 | value = (sc->sc_pins[pin].pin_state == GPIO_PIN_LOW ? |
372 | GPIO_PIN_HIGH : GPIO_PIN_LOW); | | 693 | GPIO_PIN_HIGH : GPIO_PIN_LOW); |
373 | gpiobus_pin_write(gc, pin, value); | | 694 | gpiobus_pin_write(gc, pin, value); |
374 | /* return old value */ | | 695 | /* return old value */ |
375 | op->gp_value = sc->sc_pins[pin].pin_state; | | 696 | op->gp_value = sc->sc_pins[pin].pin_state; |
376 | /* update current value */ | | 697 | /* update current value */ |
377 | sc->sc_pins[pin].pin_state = value; | | 698 | sc->sc_pins[pin].pin_state = value; |
378 | break; | | 699 | break; |
379 | case GPIOPINCTL: | | 700 | case GPIOPINCTL: |
380 | ctl = (struct gpio_pin_ctl *)data; | | 701 | ctl = (struct gpio_pin_ctl *) data; |
| | | 702 | |
| | | 703 | if (kauth_authorize_device(cred, KAUTH_DEVICE_GPIO_PINSET, |
| | | 704 | NULL, NULL, NULL, NULL)) |
| | | 705 | return EPERM; |
381 | | | 706 | |
382 | pin = ctl->gp_pin; | | 707 | pin = ctl->gp_pin; |
| | | 708 | |
383 | if (pin < 0 || pin >= sc->sc_npins) | | 709 | if (pin < 0 || pin >= sc->sc_npins) |
384 | return (EINVAL); | | 710 | return EINVAL; |
385 | if (sc->sc_pins[pin].pin_mapped) | | 711 | if (sc->sc_pins[pin].pin_mapped) |
386 | return (EBUSY); | | 712 | return EBUSY; |
387 | | | | |
388 | flags = ctl->gp_flags; | | 713 | flags = ctl->gp_flags; |
| | | 714 | |
389 | /* check that the controller supports all requested flags */ | | 715 | /* check that the controller supports all requested flags */ |
390 | if ((flags & sc->sc_pins[pin].pin_caps) != flags) | | 716 | if ((flags & sc->sc_pins[pin].pin_caps) != flags) |
391 | return (ENODEV); | | 717 | return ENODEV; |
392 | | | 718 | |
393 | ctl->gp_caps = sc->sc_pins[pin].pin_caps; | | 719 | ctl->gp_caps = sc->sc_pins[pin].pin_caps; |
394 | /* return old value */ | | 720 | /* return old value */ |
395 | ctl->gp_flags = sc->sc_pins[pin].pin_flags; | | 721 | ctl->gp_flags = sc->sc_pins[pin].pin_flags; |
396 | if (flags > 0) { | | 722 | if (flags > 0) { |
397 | gpiobus_pin_ctl(gc, pin, flags); | | 723 | gpiobus_pin_ctl(gc, pin, flags); |
398 | /* update current value */ | | 724 | /* update current value */ |
399 | sc->sc_pins[pin].pin_flags = flags; | | 725 | sc->sc_pins[pin].pin_flags = flags; |
400 | } | | 726 | } |
401 | break; | | 727 | break; |
402 | default: | | 728 | default: |
403 | return (ENOTTY); | | 729 | return ENOTTY; |
404 | } | | 730 | } |
405 | | | 731 | return 0; |
406 | return (0); | | | |
407 | } | | 732 | } |