| @@ -1,680 +1,879 @@ | | | @@ -1,680 +1,879 @@ |
1 | /* $NetBSD: i2c.c,v 1.60 2018/06/07 05:56:18 thorpej Exp $ */ | | 1 | /* $NetBSD: i2c.c,v 1.61 2018/06/07 13:30:49 thorpej Exp $ */ |
2 | | | 2 | |
3 | /* | | 3 | /* |
4 | * Copyright (c) 2003 Wasabi Systems, Inc. | | 4 | * Copyright (c) 2003 Wasabi Systems, Inc. |
5 | * All rights reserved. | | 5 | * All rights reserved. |
6 | * | | 6 | * |
7 | * Written by Jason R. Thorpe for Wasabi Systems, Inc. | | 7 | * Written by Jason R. Thorpe for Wasabi Systems, Inc. |
8 | * | | 8 | * |
9 | * Redistribution and use in source and binary forms, with or without | | 9 | * Redistribution and use in source and binary forms, with or without |
10 | * modification, are permitted provided that the following conditions | | 10 | * modification, are permitted provided that the following conditions |
11 | * are met: | | 11 | * are met: |
12 | * 1. Redistributions of source code must retain the above copyright | | 12 | * 1. Redistributions of source code must retain the above copyright |
13 | * notice, this list of conditions and the following disclaimer. | | 13 | * notice, this list of conditions and the following disclaimer. |
14 | * 2. Redistributions in binary form must reproduce the above copyright | | 14 | * 2. Redistributions in binary form must reproduce the above copyright |
15 | * notice, this list of conditions and the following disclaimer in the | | 15 | * notice, this list of conditions and the following disclaimer in the |
16 | * documentation and/or other materials provided with the distribution. | | 16 | * documentation and/or other materials provided with the distribution. |
17 | * 3. All advertising materials mentioning features or use of this software | | 17 | * 3. All advertising materials mentioning features or use of this software |
18 | * must display the following acknowledgement: | | 18 | * must display the following acknowledgement: |
19 | * This product includes software developed for the NetBSD Project by | | 19 | * This product includes software developed for the NetBSD Project by |
20 | * Wasabi Systems, Inc. | | 20 | * Wasabi Systems, Inc. |
21 | * 4. The name of Wasabi Systems, Inc. may not be used to endorse | | 21 | * 4. The name of Wasabi Systems, Inc. may not be used to endorse |
22 | * or promote products derived from this software without specific prior | | 22 | * or promote products derived from this software without specific prior |
23 | * written permission. | | 23 | * written permission. |
24 | * | | 24 | * |
25 | * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND | | 25 | * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND |
26 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED | | 26 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED |
27 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | | 27 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
28 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC | | 28 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC |
29 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | | 29 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
30 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | | 30 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
31 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | | 31 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
32 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | | 32 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
33 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | | 33 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
34 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | | 34 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
35 | * POSSIBILITY OF SUCH DAMAGE. | | 35 | * POSSIBILITY OF SUCH DAMAGE. |
36 | */ | | 36 | */ |
37 | | | 37 | |
38 | #ifdef _KERNEL_OPT | | 38 | #ifdef _KERNEL_OPT |
39 | #include "opt_i2c.h" | | 39 | #include "opt_i2c.h" |
40 | #endif | | 40 | #endif |
41 | | | 41 | |
42 | #include <sys/cdefs.h> | | 42 | #include <sys/cdefs.h> |
43 | __KERNEL_RCSID(0, "$NetBSD: i2c.c,v 1.60 2018/06/07 05:56:18 thorpej Exp $"); | | 43 | __KERNEL_RCSID(0, "$NetBSD: i2c.c,v 1.61 2018/06/07 13:30:49 thorpej Exp $"); |
44 | | | 44 | |
45 | #include <sys/param.h> | | 45 | #include <sys/param.h> |
46 | #include <sys/systm.h> | | 46 | #include <sys/systm.h> |
47 | #include <sys/device.h> | | 47 | #include <sys/device.h> |
48 | #include <sys/event.h> | | 48 | #include <sys/event.h> |
49 | #include <sys/conf.h> | | 49 | #include <sys/conf.h> |
50 | #include <sys/malloc.h> | | 50 | #include <sys/malloc.h> |
51 | #include <sys/kmem.h> | | 51 | #include <sys/kmem.h> |
52 | #include <sys/kthread.h> | | 52 | #include <sys/kthread.h> |
53 | #include <sys/proc.h> | | 53 | #include <sys/proc.h> |
54 | #include <sys/kernel.h> | | 54 | #include <sys/kernel.h> |
55 | #include <sys/fcntl.h> | | 55 | #include <sys/fcntl.h> |
56 | #include <sys/module.h> | | 56 | #include <sys/module.h> |
57 | #include <sys/once.h> | | 57 | #include <sys/once.h> |
58 | #include <sys/mutex.h> | | 58 | #include <sys/mutex.h> |
59 | | | 59 | |
60 | #include <dev/i2c/i2cvar.h> | | 60 | #include <dev/i2c/i2cvar.h> |
61 | | | 61 | |
62 | #include "ioconf.h" | | 62 | #include "ioconf.h" |
63 | #include "locators.h" | | 63 | #include "locators.h" |
64 | | | 64 | |
65 | #ifndef I2C_MAX_ADDR | | 65 | #ifndef I2C_MAX_ADDR |
66 | #define I2C_MAX_ADDR 0x3ff /* 10-bit address, max */ | | 66 | #define I2C_MAX_ADDR 0x3ff /* 10-bit address, max */ |
67 | #endif | | 67 | #endif |
68 | | | 68 | |
69 | struct iic_softc { | | 69 | struct iic_softc { |
| | | 70 | device_t sc_dev; |
70 | i2c_tag_t sc_tag; | | 71 | i2c_tag_t sc_tag; |
71 | int sc_type; | | 72 | int sc_type; |
72 | device_t sc_devices[I2C_MAX_ADDR + 1]; | | 73 | device_t sc_devices[I2C_MAX_ADDR + 1]; |
73 | }; | | 74 | }; |
74 | | | 75 | |
75 | static dev_type_open(iic_open); | | 76 | static dev_type_open(iic_open); |
76 | static dev_type_close(iic_close); | | 77 | static dev_type_close(iic_close); |
77 | static dev_type_ioctl(iic_ioctl); | | 78 | static dev_type_ioctl(iic_ioctl); |
78 | | | 79 | |
79 | int iic_init(void); | | 80 | int iic_init(void); |
80 | | | 81 | |
81 | kmutex_t iic_mtx; | | 82 | kmutex_t iic_mtx; |
82 | int iic_refcnt; | | 83 | int iic_refcnt; |
83 | | | 84 | |
84 | ONCE_DECL(iic_once); | | 85 | ONCE_DECL(iic_once); |
85 | | | 86 | |
86 | const struct cdevsw iic_cdevsw = { | | 87 | const struct cdevsw iic_cdevsw = { |
87 | .d_open = iic_open, | | 88 | .d_open = iic_open, |
88 | .d_close = iic_close, | | 89 | .d_close = iic_close, |
89 | .d_read = noread, | | 90 | .d_read = noread, |
90 | .d_write = nowrite, | | 91 | .d_write = nowrite, |
91 | .d_ioctl = iic_ioctl, | | 92 | .d_ioctl = iic_ioctl, |
92 | .d_stop = nostop, | | 93 | .d_stop = nostop, |
93 | .d_tty = notty, | | 94 | .d_tty = notty, |
94 | .d_poll = nopoll, | | 95 | .d_poll = nopoll, |
95 | .d_mmap = nommap, | | 96 | .d_mmap = nommap, |
96 | .d_kqfilter = nokqfilter, | | 97 | .d_kqfilter = nokqfilter, |
97 | .d_discard = nodiscard, | | 98 | .d_discard = nodiscard, |
98 | .d_flag = D_OTHER | | 99 | .d_flag = D_OTHER |
99 | }; | | 100 | }; |
100 | | | 101 | |
101 | static void iic_smbus_intr_thread(void *); | | 102 | static void iic_smbus_intr_thread(void *); |
102 | static void iic_fill_compat(struct i2c_attach_args*, const char*, | | 103 | static void iic_fill_compat(struct i2c_attach_args*, const char*, |
103 | size_t, char **); | | 104 | size_t, char **); |
104 | | | 105 | |
105 | static int | | 106 | static int |
106 | iic_print_direct(void *aux, const char *pnp) | | 107 | iic_print_direct(void *aux, const char *pnp) |
107 | { | | 108 | { |
108 | struct i2c_attach_args *ia = aux; | | 109 | struct i2c_attach_args *ia = aux; |
109 | | | 110 | |
110 | if (pnp != NULL) | | 111 | if (pnp != NULL) |
111 | aprint_normal("%s at %s addr 0x%02x", ia->ia_name, pnp, | | 112 | aprint_normal("%s at %s addr 0x%02x", ia->ia_name, pnp, |
112 | ia->ia_addr); | | 113 | ia->ia_addr); |
113 | else | | 114 | else |
114 | aprint_normal(" addr 0x%02x", ia->ia_addr); | | 115 | aprint_normal(" addr 0x%02x", ia->ia_addr); |
115 | | | 116 | |
116 | return UNCONF; | | 117 | return UNCONF; |
117 | } | | 118 | } |
118 | | | 119 | |
119 | static int | | 120 | static int |
120 | iic_print(void *aux, const char *pnp) | | 121 | iic_print(void *aux, const char *pnp) |
121 | { | | 122 | { |
122 | struct i2c_attach_args *ia = aux; | | 123 | struct i2c_attach_args *ia = aux; |
123 | | | 124 | |
124 | if (ia->ia_addr != (i2c_addr_t)IICCF_ADDR_DEFAULT) | | 125 | if (ia->ia_addr != (i2c_addr_t)IICCF_ADDR_DEFAULT) |
125 | aprint_normal(" addr 0x%x", ia->ia_addr); | | 126 | aprint_normal(" addr 0x%x", ia->ia_addr); |
126 | | | 127 | |
127 | return UNCONF; | | 128 | return UNCONF; |
128 | } | | 129 | } |
129 | | | 130 | |
| | | 131 | static bool |
| | | 132 | iic_is_special_address(i2c_addr_t addr) |
| | | 133 | { |
| | | 134 | |
| | | 135 | /* |
| | | 136 | * See: https://www.i2c-bus.org/addressing/ |
| | | 137 | */ |
| | | 138 | |
| | | 139 | /* General Call (read) / Start Byte (write) */ |
| | | 140 | if (addr == 0x00) |
| | | 141 | return (true); |
| | | 142 | |
| | | 143 | /* CBUS Addresses */ |
| | | 144 | if (addr == 0x01) |
| | | 145 | return (true); |
| | | 146 | |
| | | 147 | /* Reserved for Different Bus Formats */ |
| | | 148 | if (addr == 0x02) |
| | | 149 | return (true); |
| | | 150 | |
| | | 151 | /* Reserved for future purposes */ |
| | | 152 | if (addr == 0x03) |
| | | 153 | return (true); |
| | | 154 | |
| | | 155 | /* High Speed Master Code */ |
| | | 156 | if ((addr & 0x7c) == 0x04) |
| | | 157 | return (true); |
| | | 158 | |
| | | 159 | /* 10-bit Slave Addressing prefix */ |
| | | 160 | if ((addr & 0x7c) == 0x78) |
| | | 161 | return (true); |
| | | 162 | |
| | | 163 | /* Reserved for future purposes */ |
| | | 164 | if ((addr & 0x7c) == 0x7c) |
| | | 165 | return (true); |
| | | 166 | |
| | | 167 | return (false); |
| | | 168 | } |
| | | 169 | |
| | | 170 | static int |
| | | 171 | iic_probe_none(struct iic_softc *sc, |
| | | 172 | const struct i2c_attach_args *ia, int flags) |
| | | 173 | { |
| | | 174 | |
| | | 175 | return (0); |
| | | 176 | } |
| | | 177 | |
| | | 178 | static int |
| | | 179 | iic_probe_smbus_quick_write(struct iic_softc *sc, |
| | | 180 | const struct i2c_attach_args *ia, int flags) |
| | | 181 | { |
| | | 182 | int error; |
| | | 183 | |
| | | 184 | if ((error = iic_acquire_bus(ia->ia_tag, flags)) == 0) { |
| | | 185 | error = iic_smbus_quick_write(ia->ia_tag, ia->ia_addr, flags); |
| | | 186 | } |
| | | 187 | (void) iic_release_bus(ia->ia_tag, flags); |
| | | 188 | |
| | | 189 | return (error); |
| | | 190 | } |
| | | 191 | |
| | | 192 | static int |
| | | 193 | iic_probe_smbus_receive_byte(struct iic_softc *sc, |
| | | 194 | const struct i2c_attach_args *ia, int flags) |
| | | 195 | { |
| | | 196 | int error; |
| | | 197 | |
| | | 198 | if ((error = iic_acquire_bus(ia->ia_tag, flags)) == 0) { |
| | | 199 | uint8_t dummy; |
| | | 200 | |
| | | 201 | error = iic_smbus_receive_byte(ia->ia_tag, ia->ia_addr, |
| | | 202 | &dummy, flags); |
| | | 203 | } |
| | | 204 | (void) iic_release_bus(ia->ia_tag, flags); |
| | | 205 | |
| | | 206 | return (error); |
| | | 207 | } |
| | | 208 | |
| | | 209 | static bool |
| | | 210 | iic_indirect_driver_is_whitelisted(struct iic_softc *sc, cfdata_t cf) |
| | | 211 | { |
| | | 212 | prop_object_iterator_t iter; |
| | | 213 | prop_array_t whitelist; |
| | | 214 | prop_string_t pstr; |
| | | 215 | prop_type_t ptype; |
| | | 216 | bool rv = false; |
| | | 217 | |
| | | 218 | whitelist = prop_dictionary_get(device_properties(sc->sc_dev), |
| | | 219 | I2C_PROP_INDIRECT_DEVICE_WHITELIST); |
| | | 220 | if (whitelist == NULL) { |
| | | 221 | /* No whitelist -> everything allowed */ |
| | | 222 | return (true); |
| | | 223 | } |
| | | 224 | |
| | | 225 | if ((ptype = prop_object_type(whitelist)) != PROP_TYPE_ARRAY) { |
| | | 226 | aprint_error_dev(sc->sc_dev, |
| | | 227 | "invalid property type (%d) for '%s'; must be array (%d)\n", |
| | | 228 | ptype, I2C_PROP_INDIRECT_DEVICE_WHITELIST, PROP_TYPE_ARRAY); |
| | | 229 | return (false); |
| | | 230 | } |
| | | 231 | |
| | | 232 | iter = prop_array_iterator(whitelist); |
| | | 233 | while ((pstr = prop_object_iterator_next(iter)) != NULL) { |
| | | 234 | if (prop_string_equals_cstring(pstr, cf->cf_name)) { |
| | | 235 | rv = true; |
| | | 236 | break; |
| | | 237 | } |
| | | 238 | } |
| | | 239 | prop_object_iterator_release(iter); |
| | | 240 | |
| | | 241 | return (rv); |
| | | 242 | } |
| | | 243 | |
130 | static int | | 244 | static int |
131 | iic_search(device_t parent, cfdata_t cf, const int *ldesc, void *aux) | | 245 | iic_search(device_t parent, cfdata_t cf, const int *ldesc, void *aux) |
132 | { | | 246 | { |
133 | struct iic_softc *sc = device_private(parent); | | 247 | struct iic_softc *sc = device_private(parent); |
134 | struct i2c_attach_args ia; | | 248 | struct i2c_attach_args ia; |
| | | 249 | int (*probe_func)(struct iic_softc *, |
| | | 250 | const struct i2c_attach_args *, int); |
| | | 251 | prop_string_t pstr; |
| | | 252 | i2c_addr_t first_addr, last_addr; |
135 | | | 253 | |
136 | /* | | 254 | /* |
137 | * I2C doesn't have any regular probing capability. If we | | 255 | * Before we do any more work, consult the allowed-driver |
138 | * encounter a cfdata with a wild-carded address or a wild- | | 256 | * white-list for this bus (if any). |
139 | * carded parent spec, we skip them because they can only | | | |
140 | * be used for direct-coniguration. | | | |
141 | */ | | 257 | */ |
142 | if (cf->cf_loc[IICCF_ADDR] == IICCF_ADDR_DEFAULT || | | 258 | if (iic_indirect_driver_is_whitelisted(sc, cf) == false) |
143 | cf->cf_pspec->cfp_unit == DVUNIT_ANY) | | 259 | return (0); |
144 | return 0; | | 260 | |
| | | 261 | /* default to "quick write". */ |
| | | 262 | probe_func = iic_probe_smbus_quick_write; |
| | | 263 | |
| | | 264 | pstr = prop_dictionary_get(device_properties(sc->sc_dev), |
| | | 265 | I2C_PROP_INDIRECT_PROBE_STRATEGY); |
| | | 266 | if (pstr == NULL) { |
| | | 267 | /* Use the default. */ |
| | | 268 | } else if (prop_string_equals_cstring(pstr, |
| | | 269 | I2C_PROBE_STRATEGY_QUICK_WRITE)) { |
| | | 270 | probe_func = iic_probe_smbus_quick_write; |
| | | 271 | } else if (prop_string_equals_cstring(pstr, |
| | | 272 | I2C_PROBE_STRATEGY_RECEIVE_BYTE)) { |
| | | 273 | probe_func = iic_probe_smbus_receive_byte; |
| | | 274 | } else if (prop_string_equals_cstring(pstr, |
| | | 275 | I2C_PROBE_STRATEGY_NONE)) { |
| | | 276 | probe_func = iic_probe_none; |
| | | 277 | } else { |
| | | 278 | aprint_error_dev(sc->sc_dev, |
| | | 279 | "unknown probe strategy '%s'; defaulting to '%s'\n", |
| | | 280 | prop_string_cstring_nocopy(pstr), |
| | | 281 | I2C_PROBE_STRATEGY_QUICK_WRITE); |
| | | 282 | |
| | | 283 | /* Use the default. */ |
| | | 284 | } |
145 | | | 285 | |
146 | ia.ia_tag = sc->sc_tag; | | 286 | ia.ia_tag = sc->sc_tag; |
147 | ia.ia_size = cf->cf_loc[IICCF_SIZE]; | | 287 | ia.ia_size = cf->cf_loc[IICCF_SIZE]; |
148 | ia.ia_type = sc->sc_type; | | 288 | ia.ia_type = sc->sc_type; |
149 | | | 289 | |
150 | ia.ia_name = NULL; | | 290 | ia.ia_name = NULL; |
151 | ia.ia_ncompat = 0; | | 291 | ia.ia_ncompat = 0; |
152 | ia.ia_compat = NULL; | | 292 | ia.ia_compat = NULL; |
153 | ia.ia_prop = NULL; | | 293 | ia.ia_prop = NULL; |
154 | | | 294 | |
155 | for (ia.ia_addr = 0; ia.ia_addr <= I2C_MAX_ADDR; ia.ia_addr++) { | | 295 | if (cf->cf_loc[IICCF_ADDR] == IICCF_ADDR_DEFAULT) { |
| | | 296 | /* |
| | | 297 | * This particular config directive has |
| | | 298 | * wildcarded the address, so we will |
| | | 299 | * scan the entire bus for it. |
| | | 300 | */ |
| | | 301 | first_addr = 0; |
| | | 302 | last_addr = I2C_MAX_ADDR; |
| | | 303 | } else { |
| | | 304 | /* |
| | | 305 | * This config directive hard-wires the i2c |
| | | 306 | * bus address for the device, so there is |
| | | 307 | * no need to go poking around at any other |
| | | 308 | * addresses. |
| | | 309 | */ |
| | | 310 | if (cf->cf_loc[IICCF_ADDR] < 0 || |
| | | 311 | cf->cf_loc[IICCF_ADDR] > I2C_MAX_ADDR) { |
| | | 312 | /* Invalid config directive! */ |
| | | 313 | return (0); |
| | | 314 | } |
| | | 315 | first_addr = last_addr = cf->cf_loc[IICCF_ADDR]; |
| | | 316 | } |
| | | 317 | |
| | | 318 | for (ia.ia_addr = first_addr; ia.ia_addr <= last_addr; ia.ia_addr++) { |
| | | 319 | int error, match_result; |
| | | 320 | |
| | | 321 | /* |
| | | 322 | * Skip I2C addresses that are reserved for |
| | | 323 | * special purposes. |
| | | 324 | */ |
| | | 325 | if (iic_is_special_address(ia.ia_addr)) |
| | | 326 | continue; |
| | | 327 | |
| | | 328 | /* |
| | | 329 | * Skip addresses where a device is already attached. |
| | | 330 | */ |
156 | if (sc->sc_devices[ia.ia_addr] != NULL) | | 331 | if (sc->sc_devices[ia.ia_addr] != NULL) |
157 | continue; | | 332 | continue; |
158 | | | 333 | |
159 | if (cf->cf_loc[IICCF_ADDR] != ia.ia_addr) | | 334 | /* |
| | | 335 | * Call the "match" routine for the device. If that |
| | | 336 | * returns success, then call the probe strategy |
| | | 337 | * function. |
| | | 338 | * |
| | | 339 | * We do it in this order because i2c devices tend |
| | | 340 | * to be found at a small number of possible addresses |
| | | 341 | * (e.g. read-time clocks that are only ever found at |
| | | 342 | * 0x68). This gives the driver a chance to skip any |
| | | 343 | * address that are not valid for the device, saving |
| | | 344 | * us from having to poke at the bus to see if anything |
| | | 345 | * is there. |
| | | 346 | */ |
| | | 347 | match_result = config_match(parent, cf, &ia); |
| | | 348 | if (match_result <= 0) |
| | | 349 | continue; |
| | | 350 | |
| | | 351 | /* |
| | | 352 | * If the quality of the match by the driver was low |
| | | 353 | * (i.e. matched on being a valid address only, didn't |
| | | 354 | * perform any hardware probe), invoke our probe routine |
| | | 355 | * to see if it looks like something is really there. |
| | | 356 | */ |
| | | 357 | if (match_result == I2C_MATCH_ADDRESS_ONLY && |
| | | 358 | (error = (*probe_func)(sc, &ia, I2C_F_POLL)) != 0) |
160 | continue; | | 359 | continue; |
161 | | | 360 | |
162 | if (config_match(parent, cf, &ia) > 0) | | 361 | sc->sc_devices[ia.ia_addr] = |
163 | sc->sc_devices[ia.ia_addr] = | | 362 | config_attach(parent, cf, &ia, iic_print); |
164 | config_attach(parent, cf, &ia, iic_print); | | | |
165 | } | | 363 | } |
166 | | | 364 | |
167 | return 0; | | 365 | return 0; |
168 | } | | 366 | } |
169 | | | 367 | |
170 | static void | | 368 | static void |
171 | iic_child_detach(device_t parent, device_t child) | | 369 | iic_child_detach(device_t parent, device_t child) |
172 | { | | 370 | { |
173 | struct iic_softc *sc = device_private(parent); | | 371 | struct iic_softc *sc = device_private(parent); |
174 | int i; | | 372 | int i; |
175 | | | 373 | |
176 | for (i = 0; i <= I2C_MAX_ADDR; i++) | | 374 | for (i = 0; i <= I2C_MAX_ADDR; i++) |
177 | if (sc->sc_devices[i] == child) { | | 375 | if (sc->sc_devices[i] == child) { |
178 | sc->sc_devices[i] = NULL; | | 376 | sc->sc_devices[i] = NULL; |
179 | break; | | 377 | break; |
180 | } | | 378 | } |
181 | } | | 379 | } |
182 | | | 380 | |
183 | static int | | 381 | static int |
184 | iic_rescan(device_t self, const char *ifattr, const int *locators) | | 382 | iic_rescan(device_t self, const char *ifattr, const int *locators) |
185 | { | | 383 | { |
186 | config_search_ia(iic_search, self, ifattr, NULL); | | 384 | config_search_ia(iic_search, self, ifattr, NULL); |
187 | return 0; | | 385 | return 0; |
188 | } | | 386 | } |
189 | | | 387 | |
190 | static int | | 388 | static int |
191 | iic_match(device_t parent, cfdata_t cf, void *aux) | | 389 | iic_match(device_t parent, cfdata_t cf, void *aux) |
192 | { | | 390 | { |
193 | | | 391 | |
194 | return 1; | | 392 | return 1; |
195 | } | | 393 | } |
196 | | | 394 | |
197 | static void | | 395 | static void |
198 | iic_attach(device_t parent, device_t self, void *aux) | | 396 | iic_attach(device_t parent, device_t self, void *aux) |
199 | { | | 397 | { |
200 | struct iic_softc *sc = device_private(self); | | 398 | struct iic_softc *sc = device_private(self); |
201 | struct i2cbus_attach_args *iba = aux; | | 399 | struct i2cbus_attach_args *iba = aux; |
202 | prop_array_t child_devices; | | 400 | prop_array_t child_devices; |
203 | prop_dictionary_t props; | | 401 | prop_dictionary_t props; |
204 | char *buf; | | 402 | char *buf; |
205 | i2c_tag_t ic; | | 403 | i2c_tag_t ic; |
206 | int rv; | | 404 | int rv; |
207 | bool indirect_config; | | 405 | bool indirect_config; |
208 | | | 406 | |
209 | aprint_naive("\n"); | | 407 | aprint_naive("\n"); |
210 | aprint_normal(": I2C bus\n"); | | 408 | aprint_normal(": I2C bus\n"); |
211 | | | 409 | |
| | | 410 | sc->sc_dev = self; |
212 | sc->sc_tag = iba->iba_tag; | | 411 | sc->sc_tag = iba->iba_tag; |
213 | sc->sc_type = iba->iba_type; | | 412 | sc->sc_type = iba->iba_type; |
214 | ic = sc->sc_tag; | | 413 | ic = sc->sc_tag; |
215 | ic->ic_devname = device_xname(self); | | 414 | ic->ic_devname = device_xname(self); |
216 | | | 415 | |
217 | LIST_INIT(&(sc->sc_tag->ic_list)); | | 416 | LIST_INIT(&(sc->sc_tag->ic_list)); |
218 | LIST_INIT(&(sc->sc_tag->ic_proc_list)); | | 417 | LIST_INIT(&(sc->sc_tag->ic_proc_list)); |
219 | | | 418 | |
220 | rv = kthread_create(PRI_NONE, KTHREAD_MUSTJOIN, NULL, | | 419 | rv = kthread_create(PRI_NONE, KTHREAD_MUSTJOIN, NULL, |
221 | iic_smbus_intr_thread, ic, &ic->ic_intr_thread, | | 420 | iic_smbus_intr_thread, ic, &ic->ic_intr_thread, |
222 | "%s", ic->ic_devname); | | 421 | "%s", ic->ic_devname); |
223 | if (rv) | | 422 | if (rv) |
224 | aprint_error_dev(self, "unable to create intr thread\n"); | | 423 | aprint_error_dev(self, "unable to create intr thread\n"); |
225 | | | 424 | |
226 | if (!pmf_device_register(self, NULL, NULL)) | | 425 | if (!pmf_device_register(self, NULL, NULL)) |
227 | aprint_error_dev(self, "couldn't establish power handler\n"); | | 426 | aprint_error_dev(self, "couldn't establish power handler\n"); |
228 | | | 427 | |
229 | if (iba->iba_child_devices) { | | 428 | if (iba->iba_child_devices) { |
230 | child_devices = iba->iba_child_devices; | | 429 | child_devices = iba->iba_child_devices; |
231 | indirect_config = false; | | 430 | indirect_config = false; |
232 | } else { | | 431 | } else { |
233 | props = device_properties(parent); | | 432 | props = device_properties(parent); |
234 | if (!prop_dictionary_get_bool(props, "i2c-indirect-config", | | 433 | if (!prop_dictionary_get_bool(props, "i2c-indirect-config", |
235 | &indirect_config)) | | 434 | &indirect_config)) |
236 | indirect_config = true; | | 435 | indirect_config = true; |
237 | child_devices = prop_dictionary_get(props, "i2c-child-devices"); | | 436 | child_devices = prop_dictionary_get(props, "i2c-child-devices"); |
238 | } | | 437 | } |
239 | | | 438 | |
240 | if (child_devices) { | | 439 | if (child_devices) { |
241 | unsigned int i, count; | | 440 | unsigned int i, count; |
242 | prop_dictionary_t dev; | | 441 | prop_dictionary_t dev; |
243 | prop_data_t cdata; | | 442 | prop_data_t cdata; |
244 | uint32_t addr, size; | | 443 | uint32_t addr, size; |
245 | uint64_t cookie; | | 444 | uint64_t cookie; |
246 | const char *name; | | 445 | const char *name; |
247 | struct i2c_attach_args ia; | | 446 | struct i2c_attach_args ia; |
248 | int loc[IICCF_NLOCS]; | | 447 | int loc[IICCF_NLOCS]; |
249 | | | 448 | |
250 | memset(loc, 0, sizeof loc); | | 449 | memset(loc, 0, sizeof loc); |
251 | count = prop_array_count(child_devices); | | 450 | count = prop_array_count(child_devices); |
252 | for (i = 0; i < count; i++) { | | 451 | for (i = 0; i < count; i++) { |
253 | dev = prop_array_get(child_devices, i); | | 452 | dev = prop_array_get(child_devices, i); |
254 | if (!dev) continue; | | 453 | if (!dev) continue; |
255 | if (!prop_dictionary_get_cstring_nocopy( | | 454 | if (!prop_dictionary_get_cstring_nocopy( |
256 | dev, "name", &name)) | | 455 | dev, "name", &name)) |
257 | continue; | | 456 | continue; |
258 | if (!prop_dictionary_get_uint32(dev, "addr", &addr)) | | 457 | if (!prop_dictionary_get_uint32(dev, "addr", &addr)) |
259 | continue; | | 458 | continue; |
260 | if (!prop_dictionary_get_uint64(dev, "cookie", &cookie)) | | 459 | if (!prop_dictionary_get_uint64(dev, "cookie", &cookie)) |
261 | cookie = 0; | | 460 | cookie = 0; |
262 | loc[IICCF_ADDR] = addr; | | 461 | loc[IICCF_ADDR] = addr; |
263 | if (prop_dictionary_get_uint32(dev, "size", &size)) | | 462 | if (prop_dictionary_get_uint32(dev, "size", &size)) |
264 | loc[IICCF_SIZE] = size; | | 463 | loc[IICCF_SIZE] = size; |
265 | else | | 464 | else |
266 | size = loc[IICCF_SIZE] = IICCF_SIZE_DEFAULT; | | 465 | size = loc[IICCF_SIZE] = IICCF_SIZE_DEFAULT; |
267 | | | 466 | |
268 | memset(&ia, 0, sizeof ia); | | 467 | memset(&ia, 0, sizeof ia); |
269 | ia.ia_addr = addr; | | 468 | ia.ia_addr = addr; |
270 | ia.ia_type = sc->sc_type; | | 469 | ia.ia_type = sc->sc_type; |
271 | ia.ia_tag = ic; | | 470 | ia.ia_tag = ic; |
272 | ia.ia_name = name; | | 471 | ia.ia_name = name; |
273 | ia.ia_cookie = cookie; | | 472 | ia.ia_cookie = cookie; |
274 | ia.ia_size = size; | | 473 | ia.ia_size = size; |
275 | ia.ia_prop = dev; | | 474 | ia.ia_prop = dev; |
276 | | | 475 | |
277 | buf = NULL; | | 476 | buf = NULL; |
278 | cdata = prop_dictionary_get(dev, "compatible"); | | 477 | cdata = prop_dictionary_get(dev, "compatible"); |
279 | if (cdata) | | 478 | if (cdata) |
280 | iic_fill_compat(&ia, | | 479 | iic_fill_compat(&ia, |
281 | prop_data_data_nocopy(cdata), | | 480 | prop_data_data_nocopy(cdata), |
282 | prop_data_size(cdata), &buf); | | 481 | prop_data_size(cdata), &buf); |
283 | | | 482 | |
284 | if (addr > I2C_MAX_ADDR) { | | 483 | if (addr > I2C_MAX_ADDR) { |
285 | aprint_error_dev(self, | | 484 | aprint_error_dev(self, |
286 | "WARNING: ignoring bad device address " | | 485 | "WARNING: ignoring bad device address " |
287 | "@ 0x%02x\n", addr); | | 486 | "@ 0x%02x\n", addr); |
288 | } else if (sc->sc_devices[addr] == NULL) { | | 487 | } else if (sc->sc_devices[addr] == NULL) { |
289 | sc->sc_devices[addr] = | | 488 | sc->sc_devices[addr] = |
290 | config_found_sm_loc(self, "iic", loc, &ia, | | 489 | config_found_sm_loc(self, "iic", loc, &ia, |
291 | iic_print_direct, NULL); | | 490 | iic_print_direct, NULL); |
292 | } | | 491 | } |
293 | | | 492 | |
294 | if (ia.ia_compat) | | 493 | if (ia.ia_compat) |
295 | free(ia.ia_compat, M_TEMP); | | 494 | free(ia.ia_compat, M_TEMP); |
296 | if (buf) | | 495 | if (buf) |
297 | free(buf, M_TEMP); | | 496 | free(buf, M_TEMP); |
298 | } | | 497 | } |
299 | } else if (indirect_config) { | | 498 | } else if (indirect_config) { |
300 | /* | | 499 | /* |
301 | * Attach all i2c devices described in the kernel | | 500 | * Attach all i2c devices described in the kernel |
302 | * configuration file. | | 501 | * configuration file. |
303 | */ | | 502 | */ |
304 | iic_rescan(self, "iic", NULL); | | 503 | iic_rescan(self, "iic", NULL); |
305 | } | | 504 | } |
306 | } | | 505 | } |
307 | | | 506 | |
308 | static int | | 507 | static int |
309 | iic_detach(device_t self, int flags) | | 508 | iic_detach(device_t self, int flags) |
310 | { | | 509 | { |
311 | struct iic_softc *sc = device_private(self); | | 510 | struct iic_softc *sc = device_private(self); |
312 | i2c_tag_t ic = sc->sc_tag; | | 511 | i2c_tag_t ic = sc->sc_tag; |
313 | int i, error; | | 512 | int i, error; |
314 | void *hdl; | | 513 | void *hdl; |
315 | | | 514 | |
316 | for (i = 0; i <= I2C_MAX_ADDR; i++) { | | 515 | for (i = 0; i <= I2C_MAX_ADDR; i++) { |
317 | if (sc->sc_devices[i]) { | | 516 | if (sc->sc_devices[i]) { |
318 | error = config_detach(sc->sc_devices[i], flags); | | 517 | error = config_detach(sc->sc_devices[i], flags); |
319 | if (error) | | 518 | if (error) |
320 | return error; | | 519 | return error; |
321 | } | | 520 | } |
322 | } | | 521 | } |
323 | | | 522 | |
324 | if (ic->ic_running) { | | 523 | if (ic->ic_running) { |
325 | ic->ic_running = 0; | | 524 | ic->ic_running = 0; |
326 | wakeup(ic); | | 525 | wakeup(ic); |
327 | kthread_join(ic->ic_intr_thread); | | 526 | kthread_join(ic->ic_intr_thread); |
328 | } | | 527 | } |
329 | | | 528 | |
330 | if (!LIST_EMPTY(&ic->ic_list)) { | | 529 | if (!LIST_EMPTY(&ic->ic_list)) { |
331 | device_printf(self, "WARNING: intr handler list not empty\n"); | | 530 | device_printf(self, "WARNING: intr handler list not empty\n"); |
332 | while (!LIST_EMPTY(&ic->ic_list)) { | | 531 | while (!LIST_EMPTY(&ic->ic_list)) { |
333 | hdl = LIST_FIRST(&ic->ic_list); | | 532 | hdl = LIST_FIRST(&ic->ic_list); |
334 | iic_smbus_intr_disestablish(ic, hdl); | | 533 | iic_smbus_intr_disestablish(ic, hdl); |
335 | } | | 534 | } |
336 | } | | 535 | } |
337 | if (!LIST_EMPTY(&ic->ic_proc_list)) { | | 536 | if (!LIST_EMPTY(&ic->ic_proc_list)) { |
338 | device_printf(self, "WARNING: proc handler list not empty\n"); | | 537 | device_printf(self, "WARNING: proc handler list not empty\n"); |
339 | while (!LIST_EMPTY(&ic->ic_proc_list)) { | | 538 | while (!LIST_EMPTY(&ic->ic_proc_list)) { |
340 | hdl = LIST_FIRST(&ic->ic_proc_list); | | 539 | hdl = LIST_FIRST(&ic->ic_proc_list); |
341 | iic_smbus_intr_disestablish_proc(ic, hdl); | | 540 | iic_smbus_intr_disestablish_proc(ic, hdl); |
342 | } | | 541 | } |
343 | } | | 542 | } |
344 | | | 543 | |
345 | pmf_device_deregister(self); | | 544 | pmf_device_deregister(self); |
346 | | | 545 | |
347 | return 0; | | 546 | return 0; |
348 | } | | 547 | } |
349 | | | 548 | |
350 | static void | | 549 | static void |
351 | iic_smbus_intr_thread(void *aux) | | 550 | iic_smbus_intr_thread(void *aux) |
352 | { | | 551 | { |
353 | i2c_tag_t ic; | | 552 | i2c_tag_t ic; |
354 | struct ic_intr_list *il; | | 553 | struct ic_intr_list *il; |
355 | | | 554 | |
356 | ic = (i2c_tag_t)aux; | | 555 | ic = (i2c_tag_t)aux; |
357 | ic->ic_running = 1; | | 556 | ic->ic_running = 1; |
358 | ic->ic_pending = 0; | | 557 | ic->ic_pending = 0; |
359 | | | 558 | |
360 | while (ic->ic_running) { | | 559 | while (ic->ic_running) { |
361 | if (ic->ic_pending == 0) | | 560 | if (ic->ic_pending == 0) |
362 | tsleep(ic, PZERO, "iicintr", hz); | | 561 | tsleep(ic, PZERO, "iicintr", hz); |
363 | if (ic->ic_pending > 0) { | | 562 | if (ic->ic_pending > 0) { |
364 | LIST_FOREACH(il, &(ic->ic_proc_list), il_next) { | | 563 | LIST_FOREACH(il, &(ic->ic_proc_list), il_next) { |
365 | (*il->il_intr)(il->il_intrarg); | | 564 | (*il->il_intr)(il->il_intrarg); |
366 | } | | 565 | } |
367 | ic->ic_pending--; | | 566 | ic->ic_pending--; |
368 | } | | 567 | } |
369 | } | | 568 | } |
370 | | | 569 | |
371 | kthread_exit(0); | | 570 | kthread_exit(0); |
372 | } | | 571 | } |
373 | | | 572 | |
374 | void * | | 573 | void * |
375 | iic_smbus_intr_establish(i2c_tag_t ic, int (*intr)(void *), void *intrarg) | | 574 | iic_smbus_intr_establish(i2c_tag_t ic, int (*intr)(void *), void *intrarg) |
376 | { | | 575 | { |
377 | struct ic_intr_list *il; | | 576 | struct ic_intr_list *il; |
378 | | | 577 | |
379 | il = malloc(sizeof(struct ic_intr_list), M_DEVBUF, M_WAITOK); | | 578 | il = malloc(sizeof(struct ic_intr_list), M_DEVBUF, M_WAITOK); |
380 | if (il == NULL) | | 579 | if (il == NULL) |
381 | return NULL; | | 580 | return NULL; |
382 | | | 581 | |
383 | il->il_intr = intr; | | 582 | il->il_intr = intr; |
384 | il->il_intrarg = intrarg; | | 583 | il->il_intrarg = intrarg; |
385 | | | 584 | |
386 | LIST_INSERT_HEAD(&(ic->ic_list), il, il_next); | | 585 | LIST_INSERT_HEAD(&(ic->ic_list), il, il_next); |
387 | | | 586 | |
388 | return il; | | 587 | return il; |
389 | } | | 588 | } |
390 | | | 589 | |
391 | void | | 590 | void |
392 | iic_smbus_intr_disestablish(i2c_tag_t ic, void *hdl) | | 591 | iic_smbus_intr_disestablish(i2c_tag_t ic, void *hdl) |
393 | { | | 592 | { |
394 | struct ic_intr_list *il; | | 593 | struct ic_intr_list *il; |
395 | | | 594 | |
396 | il = (struct ic_intr_list *)hdl; | | 595 | il = (struct ic_intr_list *)hdl; |
397 | | | 596 | |
398 | LIST_REMOVE(il, il_next); | | 597 | LIST_REMOVE(il, il_next); |
399 | free(il, M_DEVBUF); | | 598 | free(il, M_DEVBUF); |
400 | | | 599 | |
401 | return; | | 600 | return; |
402 | } | | 601 | } |
403 | | | 602 | |
404 | void * | | 603 | void * |
405 | iic_smbus_intr_establish_proc(i2c_tag_t ic, int (*intr)(void *), void *intrarg) | | 604 | iic_smbus_intr_establish_proc(i2c_tag_t ic, int (*intr)(void *), void *intrarg) |
406 | { | | 605 | { |
407 | struct ic_intr_list *il; | | 606 | struct ic_intr_list *il; |
408 | | | 607 | |
409 | il = malloc(sizeof(struct ic_intr_list), M_DEVBUF, M_WAITOK); | | 608 | il = malloc(sizeof(struct ic_intr_list), M_DEVBUF, M_WAITOK); |
410 | if (il == NULL) | | 609 | if (il == NULL) |
411 | return NULL; | | 610 | return NULL; |
412 | | | 611 | |
413 | il->il_intr = intr; | | 612 | il->il_intr = intr; |
414 | il->il_intrarg = intrarg; | | 613 | il->il_intrarg = intrarg; |
415 | | | 614 | |
416 | LIST_INSERT_HEAD(&(ic->ic_proc_list), il, il_next); | | 615 | LIST_INSERT_HEAD(&(ic->ic_proc_list), il, il_next); |
417 | | | 616 | |
418 | return il; | | 617 | return il; |
419 | } | | 618 | } |
420 | | | 619 | |
421 | void | | 620 | void |
422 | iic_smbus_intr_disestablish_proc(i2c_tag_t ic, void *hdl) | | 621 | iic_smbus_intr_disestablish_proc(i2c_tag_t ic, void *hdl) |
423 | { | | 622 | { |
424 | struct ic_intr_list *il; | | 623 | struct ic_intr_list *il; |
425 | | | 624 | |
426 | il = (struct ic_intr_list *)hdl; | | 625 | il = (struct ic_intr_list *)hdl; |
427 | | | 626 | |
428 | LIST_REMOVE(il, il_next); | | 627 | LIST_REMOVE(il, il_next); |
429 | free(il, M_DEVBUF); | | 628 | free(il, M_DEVBUF); |
430 | | | 629 | |
431 | return; | | 630 | return; |
432 | } | | 631 | } |
433 | | | 632 | |
434 | int | | 633 | int |
435 | iic_smbus_intr(i2c_tag_t ic) | | 634 | iic_smbus_intr(i2c_tag_t ic) |
436 | { | | 635 | { |
437 | struct ic_intr_list *il; | | 636 | struct ic_intr_list *il; |
438 | | | 637 | |
439 | LIST_FOREACH(il, &(ic->ic_list), il_next) { | | 638 | LIST_FOREACH(il, &(ic->ic_list), il_next) { |
440 | (*il->il_intr)(il->il_intrarg); | | 639 | (*il->il_intr)(il->il_intrarg); |
441 | } | | 640 | } |
442 | | | 641 | |
443 | ic->ic_pending++; | | 642 | ic->ic_pending++; |
444 | wakeup(ic); | | 643 | wakeup(ic); |
445 | | | 644 | |
446 | return 1; | | 645 | return 1; |
447 | } | | 646 | } |
448 | | | 647 | |
449 | static void | | 648 | static void |
450 | iic_fill_compat(struct i2c_attach_args *ia, const char *compat, size_t len, | | 649 | iic_fill_compat(struct i2c_attach_args *ia, const char *compat, size_t len, |
451 | char **buffer) | | 650 | char **buffer) |
452 | { | | 651 | { |
453 | int count, i; | | 652 | int count, i; |
454 | const char *c, *start, **ptr; | | 653 | const char *c, *start, **ptr; |
455 | | | 654 | |
456 | *buffer = NULL; | | 655 | *buffer = NULL; |
457 | for (i = count = 0, c = compat; i < len; i++, c++) | | 656 | for (i = count = 0, c = compat; i < len; i++, c++) |
458 | if (*c == 0) | | 657 | if (*c == 0) |
459 | count++; | | 658 | count++; |
460 | count += 2; | | 659 | count += 2; |
461 | ptr = malloc(sizeof(char*)*count, M_TEMP, M_WAITOK); | | 660 | ptr = malloc(sizeof(char*)*count, M_TEMP, M_WAITOK); |
462 | if (!ptr) return; | | 661 | if (!ptr) return; |
463 | | | 662 | |
464 | for (i = count = 0, start = c = compat; i < len; i++, c++) { | | 663 | for (i = count = 0, start = c = compat; i < len; i++, c++) { |
465 | if (*c == 0) { | | 664 | if (*c == 0) { |
466 | ptr[count++] = start; | | 665 | ptr[count++] = start; |
467 | start = c+1; | | 666 | start = c+1; |
468 | } | | 667 | } |
469 | } | | 668 | } |
470 | if (start < compat+len) { | | 669 | if (start < compat+len) { |
471 | /* last string not 0 terminated */ | | 670 | /* last string not 0 terminated */ |
472 | size_t l = c-start; | | 671 | size_t l = c-start; |
473 | *buffer = malloc(l+1, M_TEMP, M_WAITOK); | | 672 | *buffer = malloc(l+1, M_TEMP, M_WAITOK); |
474 | memcpy(*buffer, start, l); | | 673 | memcpy(*buffer, start, l); |
475 | (*buffer)[l] = 0; | | 674 | (*buffer)[l] = 0; |
476 | ptr[count++] = *buffer; | | 675 | ptr[count++] = *buffer; |
477 | } | | 676 | } |
478 | ptr[count] = NULL; | | 677 | ptr[count] = NULL; |
479 | | | 678 | |
480 | ia->ia_compat = ptr; | | 679 | ia->ia_compat = ptr; |
481 | ia->ia_ncompat = count; | | 680 | ia->ia_ncompat = count; |
482 | } | | 681 | } |
483 | | | 682 | |
484 | int | | 683 | int |
485 | iic_compat_match(struct i2c_attach_args *ia, const char ** compats) | | 684 | iic_compat_match(struct i2c_attach_args *ia, const char ** compats) |
486 | { | | 685 | { |
487 | int i; | | 686 | int i; |
488 | | | 687 | |
489 | for (; compats && *compats; compats++) { | | 688 | for (; compats && *compats; compats++) { |
490 | for (i = 0; i < ia->ia_ncompat; i++) { | | 689 | for (i = 0; i < ia->ia_ncompat; i++) { |
491 | if (strcmp(*compats, ia->ia_compat[i]) == 0) | | 690 | if (strcmp(*compats, ia->ia_compat[i]) == 0) |
492 | return 1; | | 691 | return 1; |
493 | } | | 692 | } |
494 | } | | 693 | } |
495 | return 0; | | 694 | return 0; |
496 | } | | 695 | } |
497 | | | 696 | |
498 | static int | | 697 | static int |
499 | iic_open(dev_t dev, int flag, int fmt, lwp_t *l) | | 698 | iic_open(dev_t dev, int flag, int fmt, lwp_t *l) |
500 | { | | 699 | { |
501 | struct iic_softc *sc = device_lookup_private(&iic_cd, minor(dev)); | | 700 | struct iic_softc *sc = device_lookup_private(&iic_cd, minor(dev)); |
502 | | | 701 | |
503 | mutex_enter(&iic_mtx); | | 702 | mutex_enter(&iic_mtx); |
504 | if (sc == NULL) { | | 703 | if (sc == NULL) { |
505 | mutex_exit(&iic_mtx); | | 704 | mutex_exit(&iic_mtx); |
506 | return ENXIO; | | 705 | return ENXIO; |
507 | } | | 706 | } |
508 | iic_refcnt++; | | 707 | iic_refcnt++; |
509 | mutex_exit(&iic_mtx); | | 708 | mutex_exit(&iic_mtx); |
510 | | | 709 | |
511 | return 0; | | 710 | return 0; |
512 | } | | 711 | } |
513 | | | 712 | |
514 | static int | | 713 | static int |
515 | iic_close(dev_t dev, int flag, int fmt, lwp_t *l) | | 714 | iic_close(dev_t dev, int flag, int fmt, lwp_t *l) |
516 | { | | 715 | { |
517 | | | 716 | |
518 | mutex_enter(&iic_mtx); | | 717 | mutex_enter(&iic_mtx); |
519 | iic_refcnt--; | | 718 | iic_refcnt--; |
520 | mutex_exit(&iic_mtx); | | 719 | mutex_exit(&iic_mtx); |
521 | | | 720 | |
522 | return 0; | | 721 | return 0; |
523 | } | | 722 | } |
524 | | | 723 | |
525 | static int | | 724 | static int |
526 | iic_ioctl_exec(struct iic_softc *sc, i2c_ioctl_exec_t *iie, int flag) | | 725 | iic_ioctl_exec(struct iic_softc *sc, i2c_ioctl_exec_t *iie, int flag) |
527 | { | | 726 | { |
528 | i2c_tag_t ic = sc->sc_tag; | | 727 | i2c_tag_t ic = sc->sc_tag; |
529 | uint8_t buf[I2C_EXEC_MAX_BUFLEN]; | | 728 | uint8_t buf[I2C_EXEC_MAX_BUFLEN]; |
530 | void *cmd = NULL; | | 729 | void *cmd = NULL; |
531 | int error; | | 730 | int error; |
532 | | | 731 | |
533 | /* Validate parameters */ | | 732 | /* Validate parameters */ |
534 | if (iie->iie_addr > I2C_MAX_ADDR) | | 733 | if (iie->iie_addr > I2C_MAX_ADDR) |
535 | return EINVAL; | | 734 | return EINVAL; |
536 | if (iie->iie_cmdlen > I2C_EXEC_MAX_CMDLEN || | | 735 | if (iie->iie_cmdlen > I2C_EXEC_MAX_CMDLEN || |
537 | iie->iie_buflen > I2C_EXEC_MAX_BUFLEN) | | 736 | iie->iie_buflen > I2C_EXEC_MAX_BUFLEN) |
538 | return EINVAL; | | 737 | return EINVAL; |
539 | if (iie->iie_cmd != NULL && iie->iie_cmdlen == 0) | | 738 | if (iie->iie_cmd != NULL && iie->iie_cmdlen == 0) |
540 | return EINVAL; | | 739 | return EINVAL; |
541 | if (iie->iie_buf != NULL && iie->iie_buflen == 0) | | 740 | if (iie->iie_buf != NULL && iie->iie_buflen == 0) |
542 | return EINVAL; | | 741 | return EINVAL; |
543 | if (I2C_OP_WRITE_P(iie->iie_op) && (flag & FWRITE) == 0) | | 742 | if (I2C_OP_WRITE_P(iie->iie_op) && (flag & FWRITE) == 0) |
544 | return EBADF; | | 743 | return EBADF; |
545 | | | 744 | |
546 | #if 0 | | 745 | #if 0 |
547 | /* Disallow userspace access to devices that have drivers attached. */ | | 746 | /* Disallow userspace access to devices that have drivers attached. */ |
548 | if (sc->sc_devices[iie->iie_addr] != NULL) | | 747 | if (sc->sc_devices[iie->iie_addr] != NULL) |
549 | return EBUSY; | | 748 | return EBUSY; |
550 | #endif | | 749 | #endif |
551 | | | 750 | |
552 | if (iie->iie_cmd != NULL) { | | 751 | if (iie->iie_cmd != NULL) { |
553 | cmd = kmem_alloc(iie->iie_cmdlen, KM_SLEEP); | | 752 | cmd = kmem_alloc(iie->iie_cmdlen, KM_SLEEP); |
554 | error = copyin(iie->iie_cmd, cmd, iie->iie_cmdlen); | | 753 | error = copyin(iie->iie_cmd, cmd, iie->iie_cmdlen); |
555 | if (error) | | 754 | if (error) |
556 | goto out; | | 755 | goto out; |
557 | } | | 756 | } |
558 | | | 757 | |
559 | if (iie->iie_buf != NULL && I2C_OP_WRITE_P(iie->iie_op)) { | | 758 | if (iie->iie_buf != NULL && I2C_OP_WRITE_P(iie->iie_op)) { |
560 | error = copyin(iie->iie_buf, buf, iie->iie_buflen); | | 759 | error = copyin(iie->iie_buf, buf, iie->iie_buflen); |
561 | if (error) | | 760 | if (error) |
562 | goto out; | | 761 | goto out; |
563 | } | | 762 | } |
564 | | | 763 | |
565 | iic_acquire_bus(ic, 0); | | 764 | iic_acquire_bus(ic, 0); |
566 | error = iic_exec(ic, iie->iie_op, iie->iie_addr, cmd, iie->iie_cmdlen, | | 765 | error = iic_exec(ic, iie->iie_op, iie->iie_addr, cmd, iie->iie_cmdlen, |
567 | buf, iie->iie_buflen, 0); | | 766 | buf, iie->iie_buflen, 0); |
568 | iic_release_bus(ic, 0); | | 767 | iic_release_bus(ic, 0); |
569 | | | 768 | |
570 | /* | | 769 | /* |
571 | * Some drivers return error codes on failure, and others return -1. | | 770 | * Some drivers return error codes on failure, and others return -1. |
572 | */ | | 771 | */ |
573 | if (error < 0) | | 772 | if (error < 0) |
574 | error = EIO; | | 773 | error = EIO; |
575 | | | 774 | |
576 | out: | | 775 | out: |
577 | if (cmd) | | 776 | if (cmd) |
578 | kmem_free(cmd, iie->iie_cmdlen); | | 777 | kmem_free(cmd, iie->iie_cmdlen); |
579 | | | 778 | |
580 | if (error) | | 779 | if (error) |
581 | return error; | | 780 | return error; |
582 | | | 781 | |
583 | if (iie->iie_buf != NULL && I2C_OP_READ_P(iie->iie_op)) | | 782 | if (iie->iie_buf != NULL && I2C_OP_READ_P(iie->iie_op)) |
584 | error = copyout(buf, iie->iie_buf, iie->iie_buflen); | | 783 | error = copyout(buf, iie->iie_buf, iie->iie_buflen); |
585 | | | 784 | |
586 | return error; | | 785 | return error; |
587 | } | | 786 | } |
588 | | | 787 | |
589 | static int | | 788 | static int |
590 | iic_ioctl(dev_t dev, u_long cmd, void *data, int flag, lwp_t *l) | | 789 | iic_ioctl(dev_t dev, u_long cmd, void *data, int flag, lwp_t *l) |
591 | { | | 790 | { |
592 | struct iic_softc *sc = device_lookup_private(&iic_cd, minor(dev)); | | 791 | struct iic_softc *sc = device_lookup_private(&iic_cd, minor(dev)); |
593 | | | 792 | |
594 | if (sc == NULL) | | 793 | if (sc == NULL) |
595 | return ENXIO; | | 794 | return ENXIO; |
596 | | | 795 | |
597 | switch (cmd) { | | 796 | switch (cmd) { |
598 | case I2C_IOCTL_EXEC: | | 797 | case I2C_IOCTL_EXEC: |
599 | return iic_ioctl_exec(sc, (i2c_ioctl_exec_t *)data, flag); | | 798 | return iic_ioctl_exec(sc, (i2c_ioctl_exec_t *)data, flag); |
600 | default: | | 799 | default: |
601 | return ENODEV; | | 800 | return ENODEV; |
602 | } | | 801 | } |
603 | } | | 802 | } |
604 | | | 803 | |
605 | | | 804 | |
606 | CFATTACH_DECL2_NEW(iic, sizeof(struct iic_softc), | | 805 | CFATTACH_DECL2_NEW(iic, sizeof(struct iic_softc), |
607 | iic_match, iic_attach, iic_detach, NULL, iic_rescan, iic_child_detach); | | 806 | iic_match, iic_attach, iic_detach, NULL, iic_rescan, iic_child_detach); |
608 | | | 807 | |
609 | MODULE(MODULE_CLASS_DRIVER, iic, "i2cexec,i2c_bitbang"); | | 808 | MODULE(MODULE_CLASS_DRIVER, iic, "i2cexec,i2c_bitbang"); |
610 | | | 809 | |
611 | #ifdef _MODULE | | 810 | #ifdef _MODULE |
612 | #include "ioconf.c" | | 811 | #include "ioconf.c" |
613 | #endif | | 812 | #endif |
614 | | | 813 | |
615 | int | | 814 | int |
616 | iic_init(void) | | 815 | iic_init(void) |
617 | { | | 816 | { |
618 | | | 817 | |
619 | mutex_init(&iic_mtx, MUTEX_DEFAULT, IPL_NONE); | | 818 | mutex_init(&iic_mtx, MUTEX_DEFAULT, IPL_NONE); |
620 | iic_refcnt = 0; | | 819 | iic_refcnt = 0; |
621 | return 0; | | 820 | return 0; |
622 | } | | 821 | } |
623 | | | 822 | |
624 | static int | | 823 | static int |
625 | iic_modcmd(modcmd_t cmd, void *opaque) | | 824 | iic_modcmd(modcmd_t cmd, void *opaque) |
626 | { | | 825 | { |
627 | #ifdef _MODULE | | 826 | #ifdef _MODULE |
628 | int bmajor, cmajor; | | 827 | int bmajor, cmajor; |
629 | #endif | | 828 | #endif |
630 | int error; | | 829 | int error; |
631 | | | 830 | |
632 | error = 0; | | 831 | error = 0; |
633 | switch (cmd) { | | 832 | switch (cmd) { |
634 | case MODULE_CMD_INIT: | | 833 | case MODULE_CMD_INIT: |
635 | RUN_ONCE(&iic_once, iic_init); | | 834 | RUN_ONCE(&iic_once, iic_init); |
636 | | | 835 | |
637 | #ifdef _MODULE | | 836 | #ifdef _MODULE |
638 | mutex_enter(&iic_mtx); | | 837 | mutex_enter(&iic_mtx); |
639 | bmajor = cmajor = -1; | | 838 | bmajor = cmajor = -1; |
640 | error = devsw_attach("iic", NULL, &bmajor, | | 839 | error = devsw_attach("iic", NULL, &bmajor, |
641 | &iic_cdevsw, &cmajor); | | 840 | &iic_cdevsw, &cmajor); |
642 | if (error != 0) { | | 841 | if (error != 0) { |
643 | mutex_exit(&iic_mtx); | | 842 | mutex_exit(&iic_mtx); |
644 | break; | | 843 | break; |
645 | } | | 844 | } |
646 | error = config_init_component(cfdriver_ioconf_iic, | | 845 | error = config_init_component(cfdriver_ioconf_iic, |
647 | cfattach_ioconf_iic, cfdata_ioconf_iic); | | 846 | cfattach_ioconf_iic, cfdata_ioconf_iic); |
648 | if (error) { | | 847 | if (error) { |
649 | aprint_error("%s: unable to init component\n", | | 848 | aprint_error("%s: unable to init component\n", |
650 | iic_cd.cd_name); | | 849 | iic_cd.cd_name); |
651 | (void)devsw_detach(NULL, &iic_cdevsw); | | 850 | (void)devsw_detach(NULL, &iic_cdevsw); |
652 | } | | 851 | } |
653 | mutex_exit(&iic_mtx); | | 852 | mutex_exit(&iic_mtx); |
654 | #endif | | 853 | #endif |
655 | break; | | 854 | break; |
656 | case MODULE_CMD_FINI: | | 855 | case MODULE_CMD_FINI: |
657 | mutex_enter(&iic_mtx); | | 856 | mutex_enter(&iic_mtx); |
658 | if (iic_refcnt != 0) { | | 857 | if (iic_refcnt != 0) { |
659 | mutex_exit(&iic_mtx); | | 858 | mutex_exit(&iic_mtx); |
660 | return EBUSY; | | 859 | return EBUSY; |
661 | } | | 860 | } |
662 | #ifdef _MODULE | | 861 | #ifdef _MODULE |
663 | error = config_fini_component(cfdriver_ioconf_iic, | | 862 | error = config_fini_component(cfdriver_ioconf_iic, |
664 | cfattach_ioconf_iic, cfdata_ioconf_iic); | | 863 | cfattach_ioconf_iic, cfdata_ioconf_iic); |
665 | if (error != 0) { | | 864 | if (error != 0) { |
666 | mutex_exit(&iic_mtx); | | 865 | mutex_exit(&iic_mtx); |
667 | break; | | 866 | break; |
668 | } | | 867 | } |
669 | error = devsw_detach(NULL, &iic_cdevsw); | | 868 | error = devsw_detach(NULL, &iic_cdevsw); |
670 | if (error != 0) | | 869 | if (error != 0) |
671 | config_init_component(cfdriver_ioconf_iic, | | 870 | config_init_component(cfdriver_ioconf_iic, |
672 | cfattach_ioconf_iic, cfdata_ioconf_iic); | | 871 | cfattach_ioconf_iic, cfdata_ioconf_iic); |
673 | #endif | | 872 | #endif |
674 | mutex_exit(&iic_mtx); | | 873 | mutex_exit(&iic_mtx); |
675 | break; | | 874 | break; |
676 | default: | | 875 | default: |
677 | error = ENOTTY; | | 876 | error = ENOTTY; |
678 | } | | 877 | } |
679 | return error; | | 878 | return error; |
680 | } | | 879 | } |