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