| @@ -1,452 +1,452 @@ | | | @@ -1,452 +1,452 @@ |
1 | /* $NetBSD: onewire.c,v 1.11 2009/03/18 16:00:19 cegger Exp $ */ | | 1 | /* $NetBSD: onewire.c,v 1.12 2009/05/12 14:39:51 cegger Exp $ */ |
2 | /* $OpenBSD: onewire.c,v 1.1 2006/03/04 16:27:03 grange Exp $ */ | | 2 | /* $OpenBSD: onewire.c,v 1.1 2006/03/04 16:27:03 grange Exp $ */ |
3 | | | 3 | |
4 | /* | | 4 | /* |
5 | * Copyright (c) 2006 Alexander Yurchenko <grange@openbsd.org> | | 5 | * Copyright (c) 2006 Alexander Yurchenko <grange@openbsd.org> |
6 | * | | 6 | * |
7 | * Permission to use, copy, modify, and distribute this software for any | | 7 | * Permission to use, copy, modify, and distribute this software for any |
8 | * purpose with or without fee is hereby granted, provided that the above | | 8 | * purpose with or without fee is hereby granted, provided that the above |
9 | * copyright notice and this permission notice appear in all copies. | | 9 | * copyright notice and this permission notice appear in all copies. |
10 | * | | 10 | * |
11 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | | 11 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
12 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | | 12 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
13 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | | 13 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR |
14 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | | 14 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
15 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | | 15 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN |
16 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | | 16 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF |
17 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | | 17 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
18 | */ | | 18 | */ |
19 | | | 19 | |
20 | #include <sys/cdefs.h> | | 20 | #include <sys/cdefs.h> |
21 | __KERNEL_RCSID(0, "$NetBSD: onewire.c,v 1.11 2009/03/18 16:00:19 cegger Exp $"); | | 21 | __KERNEL_RCSID(0, "$NetBSD: onewire.c,v 1.12 2009/05/12 14:39:51 cegger Exp $"); |
22 | | | 22 | |
23 | /* | | 23 | /* |
24 | * 1-Wire bus driver. | | 24 | * 1-Wire bus driver. |
25 | */ | | 25 | */ |
26 | | | 26 | |
27 | #include <sys/param.h> | | 27 | #include <sys/param.h> |
28 | #include <sys/systm.h> | | 28 | #include <sys/systm.h> |
29 | #include <sys/conf.h> | | 29 | #include <sys/conf.h> |
30 | #include <sys/device.h> | | 30 | #include <sys/device.h> |
31 | #include <sys/kernel.h> | | 31 | #include <sys/kernel.h> |
32 | #include <sys/kthread.h> | | 32 | #include <sys/kthread.h> |
33 | #include <sys/rwlock.h> | | 33 | #include <sys/rwlock.h> |
34 | #include <sys/malloc.h> | | 34 | #include <sys/malloc.h> |
35 | #include <sys/proc.h> | | 35 | #include <sys/proc.h> |
36 | #include <sys/queue.h> | | 36 | #include <sys/queue.h> |
37 | | | 37 | |
38 | #include <dev/onewire/onewirereg.h> | | 38 | #include <dev/onewire/onewirereg.h> |
39 | #include <dev/onewire/onewirevar.h> | | 39 | #include <dev/onewire/onewirevar.h> |
40 | | | 40 | |
41 | #ifdef ONEWIRE_DEBUG | | 41 | #ifdef ONEWIRE_DEBUG |
42 | #define DPRINTF(x) printf x | | 42 | #define DPRINTF(x) printf x |
43 | #else | | 43 | #else |
44 | #define DPRINTF(x) | | 44 | #define DPRINTF(x) |
45 | #endif | | 45 | #endif |
46 | | | 46 | |
47 | //#define ONEWIRE_MAXDEVS 256 | | 47 | //#define ONEWIRE_MAXDEVS 256 |
48 | #define ONEWIRE_MAXDEVS 8 | | 48 | #define ONEWIRE_MAXDEVS 8 |
49 | #define ONEWIRE_SCANTIME 3 | | 49 | #define ONEWIRE_SCANTIME 3 |
50 | | | 50 | |
51 | struct onewire_softc { | | 51 | struct onewire_softc { |
52 | device_t sc_dev; | | 52 | device_t sc_dev; |
53 | | | 53 | |
54 | struct onewire_bus * sc_bus; | | 54 | struct onewire_bus * sc_bus; |
55 | krwlock_t sc_rwlock; | | 55 | krwlock_t sc_rwlock; |
56 | struct lwp * sc_thread; | | 56 | struct lwp * sc_thread; |
57 | TAILQ_HEAD(, onewire_device) sc_devs; | | 57 | TAILQ_HEAD(, onewire_device) sc_devs; |
58 | | | 58 | |
59 | int sc_dying; | | 59 | int sc_dying; |
60 | }; | | 60 | }; |
61 | | | 61 | |
62 | struct onewire_device { | | 62 | struct onewire_device { |
63 | TAILQ_ENTRY(onewire_device) d_list; | | 63 | TAILQ_ENTRY(onewire_device) d_list; |
64 | device_t d_dev; | | 64 | device_t d_dev; |
65 | u_int64_t d_rom; | | 65 | u_int64_t d_rom; |
66 | int d_present; | | 66 | int d_present; |
67 | }; | | 67 | }; |
68 | | | 68 | |
69 | static int onewire_match(device_t, cfdata_t, void *); | | 69 | static int onewire_match(device_t, cfdata_t, void *); |
70 | static void onewire_attach(device_t, device_t, void *); | | 70 | static void onewire_attach(device_t, device_t, void *); |
71 | static int onewire_detach(device_t, int); | | 71 | static int onewire_detach(device_t, int); |
72 | static int onewire_activate(device_t, enum devact); | | 72 | static int onewire_activate(device_t, enum devact); |
73 | int onewire_print(void *, const char *); | | 73 | int onewire_print(void *, const char *); |
74 | | | 74 | |
75 | static void onewire_thread(void *); | | 75 | static void onewire_thread(void *); |
76 | static void onewire_scan(struct onewire_softc *); | | 76 | static void onewire_scan(struct onewire_softc *); |
77 | | | 77 | |
78 | CFATTACH_DECL_NEW(onewire, sizeof(struct onewire_softc), | | 78 | CFATTACH_DECL_NEW(onewire, sizeof(struct onewire_softc), |
79 | onewire_match, onewire_attach, onewire_detach, onewire_activate); | | 79 | onewire_match, onewire_attach, onewire_detach, onewire_activate); |
80 | | | 80 | |
81 | const struct cdevsw onewire_cdevsw = { | | 81 | const struct cdevsw onewire_cdevsw = { |
82 | noopen, noclose, noread, nowrite, noioctl, nostop, notty, | | 82 | noopen, noclose, noread, nowrite, noioctl, nostop, notty, |
83 | nopoll, nommap, nokqfilter, D_OTHER, | | 83 | nopoll, nommap, nokqfilter, D_OTHER, |
84 | }; | | 84 | }; |
85 | | | 85 | |
86 | extern struct cfdriver onewire_cd; | | 86 | extern struct cfdriver onewire_cd; |
87 | | | 87 | |
88 | static int | | 88 | static int |
89 | onewire_match(device_t parent, cfdata_t cf, void *aux) | | 89 | onewire_match(device_t parent, cfdata_t cf, void *aux) |
90 | { | | 90 | { |
91 | return 1; | | 91 | return 1; |
92 | } | | 92 | } |
93 | | | 93 | |
94 | static void | | 94 | static void |
95 | onewire_attach(device_t parent, device_t self, void *aux) | | 95 | onewire_attach(device_t parent, device_t self, void *aux) |
96 | { | | 96 | { |
97 | struct onewire_softc *sc = device_private(self); | | 97 | struct onewire_softc *sc = device_private(self); |
98 | struct onewirebus_attach_args *oba = aux; | | 98 | struct onewirebus_attach_args *oba = aux; |
99 | | | 99 | |
100 | sc->sc_dev = self; | | 100 | sc->sc_dev = self; |
101 | sc->sc_bus = oba->oba_bus; | | 101 | sc->sc_bus = oba->oba_bus; |
102 | rw_init(&sc->sc_rwlock); | | 102 | rw_init(&sc->sc_rwlock); |
103 | TAILQ_INIT(&sc->sc_devs); | | 103 | TAILQ_INIT(&sc->sc_devs); |
104 | | | 104 | |
105 | aprint_naive("\n"); | | 105 | aprint_naive("\n"); |
106 | aprint_normal("\n"); | | 106 | aprint_normal("\n"); |
107 | | | 107 | |
108 | if (kthread_create(PRI_NONE, 0, NULL, onewire_thread, sc, | | 108 | if (kthread_create(PRI_NONE, 0, NULL, onewire_thread, sc, |
109 | &sc->sc_thread, "%s", device_xname(self)) != 0) | | 109 | &sc->sc_thread, "%s", device_xname(self)) != 0) |
110 | aprint_error_dev(self, "can't create kernel thread\n"); | | 110 | aprint_error_dev(self, "can't create kernel thread\n"); |
111 | } | | 111 | } |
112 | | | 112 | |
113 | static int | | 113 | static int |
114 | onewire_detach(device_t self, int flags) | | 114 | onewire_detach(device_t self, int flags) |
115 | { | | 115 | { |
116 | struct onewire_softc *sc = device_private(self); | | 116 | struct onewire_softc *sc = device_private(self); |
117 | int rv; | | 117 | int rv; |
118 | | | 118 | |
119 | sc->sc_dying = 1; | | 119 | sc->sc_dying = 1; |
120 | if (sc->sc_thread != NULL) { | | 120 | if (sc->sc_thread != NULL) { |
121 | wakeup(sc->sc_thread); | | 121 | wakeup(sc->sc_thread); |
122 | tsleep(&sc->sc_dying, PWAIT, "owdt", 0); | | 122 | tsleep(&sc->sc_dying, PWAIT, "owdt", 0); |
123 | } | | 123 | } |
124 | | | 124 | |
125 | onewire_lock(sc); | | 125 | onewire_lock(sc); |
126 | //rv = config_detach_children(self, flags); | | 126 | //rv = config_detach_children(self, flags); |
127 | rv = 0; /* XXX riz */ | | 127 | rv = 0; /* XXX riz */ |
128 | onewire_unlock(sc); | | 128 | onewire_unlock(sc); |
129 | rw_destroy(&sc->sc_rwlock); | | 129 | rw_destroy(&sc->sc_rwlock); |
130 | | | 130 | |
131 | return rv; | | 131 | return rv; |
132 | } | | 132 | } |
133 | | | 133 | |
134 | static int | | 134 | static int |
135 | onewire_activate(device_t self, enum devact act) | | 135 | onewire_activate(device_t self, enum devact act) |
136 | { | | 136 | { |
137 | struct onewire_softc *sc = device_private(self); | | 137 | struct onewire_softc *sc = device_private(self); |
138 | int rv = 0; | | 138 | int rv = 0; |
139 | | | 139 | |
140 | switch (act) { | | 140 | switch (act) { |
141 | case DVACT_ACTIVATE: | | 141 | case DVACT_ACTIVATE: |
142 | rv = EOPNOTSUPP; | | 142 | rv = EOPNOTSUPP; |
143 | break; | | 143 | break; |
144 | case DVACT_DEACTIVATE: | | 144 | case DVACT_DEACTIVATE: |
145 | sc->sc_dying = 1; | | 145 | sc->sc_dying = 1; |
146 | break; | | 146 | break; |
147 | } | | 147 | } |
148 | | | 148 | |
149 | //return (config_activate_children(self, act)); | | 149 | //return (config_activate_children(self, act)); |
150 | return rv; | | 150 | return rv; |
151 | } | | 151 | } |
152 | | | 152 | |
153 | int | | 153 | int |
154 | onewire_print(void *aux, const char *pnp) | | 154 | onewire_print(void *aux, const char *pnp) |
155 | { | | 155 | { |
156 | struct onewire_attach_args *oa = aux; | | 156 | struct onewire_attach_args *oa = aux; |
157 | const char *famname; | | 157 | const char *famname; |
158 | | | 158 | |
159 | if (pnp == NULL) | | 159 | if (pnp == NULL) |
160 | aprint_normal(" "); | | 160 | aprint_normal(" "); |
161 | | | 161 | |
162 | famname = onewire_famname(ONEWIRE_ROM_FAMILY_TYPE(oa->oa_rom)); | | 162 | famname = onewire_famname(ONEWIRE_ROM_FAMILY_TYPE(oa->oa_rom)); |
163 | if (famname == NULL) | | 163 | if (famname == NULL) |
164 | aprint_normal("family 0x%02x", | | 164 | aprint_normal("family 0x%02x", |
165 | (uint)ONEWIRE_ROM_FAMILY_TYPE(oa->oa_rom)); | | 165 | (uint)ONEWIRE_ROM_FAMILY_TYPE(oa->oa_rom)); |
166 | else | | 166 | else |
167 | aprint_normal("\"%s\"", famname); | | 167 | aprint_normal("\"%s\"", famname); |
168 | aprint_normal(" sn %012llx", ONEWIRE_ROM_SN(oa->oa_rom)); | | 168 | aprint_normal(" sn %012llx", ONEWIRE_ROM_SN(oa->oa_rom)); |
169 | | | 169 | |
170 | if (pnp != NULL) | | 170 | if (pnp != NULL) |
171 | aprint_normal(" at %s", pnp); | | 171 | aprint_normal(" at %s", pnp); |
172 | | | 172 | |
173 | return UNCONF; | | 173 | return UNCONF; |
174 | } | | 174 | } |
175 | | | 175 | |
176 | int | | 176 | int |
177 | onewirebus_print(void *aux, const char *pnp) | | 177 | onewirebus_print(void *aux, const char *pnp) |
178 | { | | 178 | { |
179 | if (pnp != NULL) | | 179 | if (pnp != NULL) |
180 | aprint_normal("onewire at %s", pnp); | | 180 | aprint_normal("onewire at %s", pnp); |
181 | | | 181 | |
182 | return UNCONF; | | 182 | return UNCONF; |
183 | } | | 183 | } |
184 | | | 184 | |
185 | void | | 185 | void |
186 | onewire_lock(void *arg) | | 186 | onewire_lock(void *arg) |
187 | { | | 187 | { |
188 | struct onewire_softc *sc = arg; | | 188 | struct onewire_softc *sc = arg; |
189 | | | 189 | |
190 | rw_enter(&sc->sc_rwlock, RW_WRITER); | | 190 | rw_enter(&sc->sc_rwlock, RW_WRITER); |
191 | } | | 191 | } |
192 | | | 192 | |
193 | void | | 193 | void |
194 | onewire_unlock(void *arg) | | 194 | onewire_unlock(void *arg) |
195 | { | | 195 | { |
196 | struct onewire_softc *sc = arg; | | 196 | struct onewire_softc *sc = arg; |
197 | | | 197 | |
198 | rw_exit(&sc->sc_rwlock); | | 198 | rw_exit(&sc->sc_rwlock); |
199 | } | | 199 | } |
200 | | | 200 | |
201 | int | | 201 | int |
202 | onewire_reset(void *arg) | | 202 | onewire_reset(void *arg) |
203 | { | | 203 | { |
204 | struct onewire_softc *sc = arg; | | 204 | struct onewire_softc *sc = arg; |
205 | struct onewire_bus *bus = sc->sc_bus; | | 205 | struct onewire_bus *bus = sc->sc_bus; |
206 | | | 206 | |
207 | return bus->bus_reset(bus->bus_cookie); | | 207 | return bus->bus_reset(bus->bus_cookie); |
208 | } | | 208 | } |
209 | | | 209 | |
210 | int | | 210 | int |
211 | onewire_bit(void *arg, int value) | | 211 | onewire_bit(void *arg, int value) |
212 | { | | 212 | { |
213 | struct onewire_softc *sc = arg; | | 213 | struct onewire_softc *sc = arg; |
214 | struct onewire_bus *bus = sc->sc_bus; | | 214 | struct onewire_bus *bus = sc->sc_bus; |
215 | | | 215 | |
216 | return bus->bus_bit(bus->bus_cookie, value); | | 216 | return bus->bus_bit(bus->bus_cookie, value); |
217 | } | | 217 | } |
218 | | | 218 | |
219 | int | | 219 | int |
220 | onewire_read_byte(void *arg) | | 220 | onewire_read_byte(void *arg) |
221 | { | | 221 | { |
222 | struct onewire_softc *sc = arg; | | 222 | struct onewire_softc *sc = arg; |
223 | struct onewire_bus *bus = sc->sc_bus; | | 223 | struct onewire_bus *bus = sc->sc_bus; |
224 | uint8_t value = 0; | | 224 | uint8_t value = 0; |
225 | int i; | | 225 | int i; |
226 | | | 226 | |
227 | if (bus->bus_read_byte != NULL) | | 227 | if (bus->bus_read_byte != NULL) |
228 | return bus->bus_read_byte(bus->bus_cookie); | | 228 | return bus->bus_read_byte(bus->bus_cookie); |
229 | | | 229 | |
230 | for (i = 0; i < 8; i++) | | 230 | for (i = 0; i < 8; i++) |
231 | value |= (bus->bus_bit(bus->bus_cookie, 1) << i); | | 231 | value |= (bus->bus_bit(bus->bus_cookie, 1) << i); |
232 | | | 232 | |
233 | return value; | | 233 | return value; |
234 | } | | 234 | } |
235 | | | 235 | |
236 | void | | 236 | void |
237 | onewire_write_byte(void *arg, int value) | | 237 | onewire_write_byte(void *arg, int value) |
238 | { | | 238 | { |
239 | struct onewire_softc *sc = arg; | | 239 | struct onewire_softc *sc = arg; |
240 | struct onewire_bus *bus = sc->sc_bus; | | 240 | struct onewire_bus *bus = sc->sc_bus; |
241 | int i; | | 241 | int i; |
242 | | | 242 | |
243 | if (bus->bus_write_byte != NULL) | | 243 | if (bus->bus_write_byte != NULL) |
244 | return bus->bus_write_byte(bus->bus_cookie, value); | | 244 | return bus->bus_write_byte(bus->bus_cookie, value); |
245 | | | 245 | |
246 | for (i = 0; i < 8; i++) | | 246 | for (i = 0; i < 8; i++) |
247 | bus->bus_bit(bus->bus_cookie, (value >> i) & 0x1); | | 247 | bus->bus_bit(bus->bus_cookie, (value >> i) & 0x1); |
248 | } | | 248 | } |
249 | | | 249 | |
250 | int | | 250 | int |
251 | onewire_triplet(void *arg, int dir) | | 251 | onewire_triplet(void *arg, int dir) |
252 | { | | 252 | { |
253 | struct onewire_softc *sc = arg; | | 253 | struct onewire_softc *sc = arg; |
254 | struct onewire_bus *bus = sc->sc_bus; | | 254 | struct onewire_bus *bus = sc->sc_bus; |
255 | int rv; | | 255 | int rv; |
256 | | | 256 | |
257 | if (bus->bus_triplet != NULL) | | 257 | if (bus->bus_triplet != NULL) |
258 | return bus->bus_triplet(bus->bus_cookie, dir); | | 258 | return bus->bus_triplet(bus->bus_cookie, dir); |
259 | | | 259 | |
260 | rv = bus->bus_bit(bus->bus_cookie, 1); | | 260 | rv = bus->bus_bit(bus->bus_cookie, 1); |
261 | rv <<= 1; | | 261 | rv <<= 1; |
262 | rv |= bus->bus_bit(bus->bus_cookie, 1); | | 262 | rv |= bus->bus_bit(bus->bus_cookie, 1); |
263 | | | 263 | |
264 | switch (rv) { | | 264 | switch (rv) { |
265 | case 0x0: | | 265 | case 0x0: |
266 | bus->bus_bit(bus->bus_cookie, dir); | | 266 | bus->bus_bit(bus->bus_cookie, dir); |
267 | break; | | 267 | break; |
268 | case 0x1: | | 268 | case 0x1: |
269 | bus->bus_bit(bus->bus_cookie, 0); | | 269 | bus->bus_bit(bus->bus_cookie, 0); |
270 | break; | | 270 | break; |
271 | default: | | 271 | default: |
272 | bus->bus_bit(bus->bus_cookie, 1); | | 272 | bus->bus_bit(bus->bus_cookie, 1); |
273 | } | | 273 | } |
274 | | | 274 | |
275 | return rv; | | 275 | return rv; |
276 | } | | 276 | } |
277 | | | 277 | |
278 | void | | 278 | void |
279 | onewire_read_block(void *arg, void *buf, int len) | | 279 | onewire_read_block(void *arg, void *buf, int len) |
280 | { | | 280 | { |
281 | uint8_t *p = buf; | | 281 | uint8_t *p = buf; |
282 | | | 282 | |
283 | while (len--) | | 283 | while (len--) |
284 | *p++ = onewire_read_byte(arg); | | 284 | *p++ = onewire_read_byte(arg); |
285 | } | | 285 | } |
286 | | | 286 | |
287 | void | | 287 | void |
288 | onewire_write_block(void *arg, const void *buf, int len) | | 288 | onewire_write_block(void *arg, const void *buf, int len) |
289 | { | | 289 | { |
290 | const uint8_t *p = buf; | | 290 | const uint8_t *p = buf; |
291 | | | 291 | |
292 | while (len--) | | 292 | while (len--) |
293 | onewire_write_byte(arg, *p++); | | 293 | onewire_write_byte(arg, *p++); |
294 | } | | 294 | } |
295 | | | 295 | |
296 | void | | 296 | void |
297 | onewire_matchrom(void *arg, u_int64_t rom) | | 297 | onewire_matchrom(void *arg, u_int64_t rom) |
298 | { | | 298 | { |
299 | int i; | | 299 | int i; |
300 | | | 300 | |
301 | onewire_write_byte(arg, ONEWIRE_CMD_MATCH_ROM); | | 301 | onewire_write_byte(arg, ONEWIRE_CMD_MATCH_ROM); |
302 | for (i = 0; i < 8; i++) | | 302 | for (i = 0; i < 8; i++) |
303 | onewire_write_byte(arg, (rom >> (i * 8)) & 0xff); | | 303 | onewire_write_byte(arg, (rom >> (i * 8)) & 0xff); |
304 | } | | 304 | } |
305 | | | 305 | |
306 | static void | | 306 | static void |
307 | onewire_thread(void *arg) | | 307 | onewire_thread(void *arg) |
308 | { | | 308 | { |
309 | struct onewire_softc *sc = arg; | | 309 | struct onewire_softc *sc = arg; |
310 | | | 310 | |
311 | while (!sc->sc_dying) { | | 311 | while (!sc->sc_dying) { |
312 | onewire_scan(sc); | | 312 | onewire_scan(sc); |
313 | tsleep(sc->sc_thread, PWAIT, "owidle", ONEWIRE_SCANTIME * hz); | | 313 | tsleep(sc->sc_thread, PWAIT, "owidle", ONEWIRE_SCANTIME * hz); |
314 | } | | 314 | } |
315 | | | 315 | |
316 | sc->sc_thread = NULL; | | 316 | sc->sc_thread = NULL; |
317 | wakeup(&sc->sc_dying); | | 317 | wakeup(&sc->sc_dying); |
318 | kthread_exit(0); | | 318 | kthread_exit(0); |
319 | } | | 319 | } |
320 | | | 320 | |
321 | static void | | 321 | static void |
322 | onewire_scan(struct onewire_softc *sc) | | 322 | onewire_scan(struct onewire_softc *sc) |
323 | { | | 323 | { |
324 | struct onewire_device *d, *next, *nd; | | 324 | struct onewire_device *d, *next, *nd; |
325 | struct onewire_attach_args oa; | | 325 | struct onewire_attach_args oa; |
326 | struct device *dev; | | 326 | device_t dev; |
327 | int search = 1, count = 0, present; | | 327 | int search = 1, count = 0, present; |
328 | int dir, rv; | | 328 | int dir, rv; |
329 | uint64_t mask, rom = 0, lastrom; | | 329 | uint64_t mask, rom = 0, lastrom; |
330 | uint8_t data[8]; | | 330 | uint8_t data[8]; |
331 | int i, i0 = -1, lastd = -1; | | 331 | int i, i0 = -1, lastd = -1; |
332 | | | 332 | |
333 | TAILQ_FOREACH(d, &sc->sc_devs, d_list) | | 333 | TAILQ_FOREACH(d, &sc->sc_devs, d_list) |
334 | d->d_present = 0; | | 334 | d->d_present = 0; |
335 | | | 335 | |
336 | while (search && count++ < ONEWIRE_MAXDEVS) { | | 336 | while (search && count++ < ONEWIRE_MAXDEVS) { |
337 | /* XXX: yield processor */ | | 337 | /* XXX: yield processor */ |
338 | tsleep(sc, PWAIT, "owscan", hz / 10); | | 338 | tsleep(sc, PWAIT, "owscan", hz / 10); |
339 | | | 339 | |
340 | /* | | 340 | /* |
341 | * Reset the bus. If there's no presence pulse | | 341 | * Reset the bus. If there's no presence pulse |
342 | * don't search for any devices. | | 342 | * don't search for any devices. |
343 | */ | | 343 | */ |
344 | onewire_lock(sc); | | 344 | onewire_lock(sc); |
345 | if (onewire_reset(sc) != 0) { | | 345 | if (onewire_reset(sc) != 0) { |
346 | DPRINTF(("%s: scan: no presence pulse\n", | | 346 | DPRINTF(("%s: scan: no presence pulse\n", |
347 | device_xname(sc->sc_dev))); | | 347 | device_xname(sc->sc_dev))); |
348 | onewire_unlock(sc); | | 348 | onewire_unlock(sc); |
349 | break; | | 349 | break; |
350 | } | | 350 | } |
351 | | | 351 | |
352 | /* | | 352 | /* |
353 | * Start new search. Go through the previous path to | | 353 | * Start new search. Go through the previous path to |
354 | * the point we made a decision last time and make an | | 354 | * the point we made a decision last time and make an |
355 | * opposite decision. If we didn't make any decision | | 355 | * opposite decision. If we didn't make any decision |
356 | * stop searching. | | 356 | * stop searching. |
357 | */ | | 357 | */ |
358 | search = 0; | | 358 | search = 0; |
359 | lastrom = rom; | | 359 | lastrom = rom; |
360 | rom = 0; | | 360 | rom = 0; |
361 | onewire_write_byte(sc, ONEWIRE_CMD_SEARCH_ROM); | | 361 | onewire_write_byte(sc, ONEWIRE_CMD_SEARCH_ROM); |
362 | for (i = 0,i0 = -1; i < 64; i++) { | | 362 | for (i = 0,i0 = -1; i < 64; i++) { |
363 | dir = (lastrom >> i) & 0x1; | | 363 | dir = (lastrom >> i) & 0x1; |
364 | if (i == lastd) | | 364 | if (i == lastd) |
365 | dir = 1; | | 365 | dir = 1; |
366 | else if (i > lastd) | | 366 | else if (i > lastd) |
367 | dir = 0; | | 367 | dir = 0; |
368 | rv = onewire_triplet(sc, dir); | | 368 | rv = onewire_triplet(sc, dir); |
369 | switch (rv) { | | 369 | switch (rv) { |
370 | case 0x0: | | 370 | case 0x0: |
371 | if (i != lastd) { | | 371 | if (i != lastd) { |
372 | if (dir == 0) | | 372 | if (dir == 0) |
373 | i0 = i; | | 373 | i0 = i; |
374 | search = 1; | | 374 | search = 1; |
375 | } | | 375 | } |
376 | mask = dir; | | 376 | mask = dir; |
377 | break; | | 377 | break; |
378 | case 0x1: | | 378 | case 0x1: |
379 | mask = 0; | | 379 | mask = 0; |
380 | break; | | 380 | break; |
381 | case 0x2: | | 381 | case 0x2: |
382 | mask = 1; | | 382 | mask = 1; |
383 | break; | | 383 | break; |
384 | default: | | 384 | default: |
385 | DPRINTF(("%s: scan: triplet error 0x%x, " | | 385 | DPRINTF(("%s: scan: triplet error 0x%x, " |
386 | "step %d\n", | | 386 | "step %d\n", |
387 | device_xname(sc->sc_dev), rv, i)); | | 387 | device_xname(sc->sc_dev), rv, i)); |
388 | onewire_unlock(sc); | | 388 | onewire_unlock(sc); |
389 | return; | | 389 | return; |
390 | } | | 390 | } |
391 | rom |= (mask << i); | | 391 | rom |= (mask << i); |
392 | } | | 392 | } |
393 | lastd = i0; | | 393 | lastd = i0; |
394 | onewire_unlock(sc); | | 394 | onewire_unlock(sc); |
395 | | | 395 | |
396 | if (rom == 0) | | 396 | if (rom == 0) |
397 | continue; | | 397 | continue; |
398 | | | 398 | |
399 | /* | | 399 | /* |
400 | * The last byte of the ROM code contains a CRC calculated | | 400 | * The last byte of the ROM code contains a CRC calculated |
401 | * from the first 7 bytes. Re-calculate it to make sure | | 401 | * from the first 7 bytes. Re-calculate it to make sure |
402 | * we found a valid device. | | 402 | * we found a valid device. |
403 | */ | | 403 | */ |
404 | for (i = 0; i < 8; i++) | | 404 | for (i = 0; i < 8; i++) |
405 | data[i] = (rom >> (i * 8)) & 0xff; | | 405 | data[i] = (rom >> (i * 8)) & 0xff; |
406 | if (onewire_crc(data, 7) != data[7]) | | 406 | if (onewire_crc(data, 7) != data[7]) |
407 | continue; | | 407 | continue; |
408 | | | 408 | |
409 | /* | | 409 | /* |
410 | * Go through the list of attached devices to see if we | | 410 | * Go through the list of attached devices to see if we |
411 | * found a new one. | | 411 | * found a new one. |
412 | */ | | 412 | */ |
413 | present = 0; | | 413 | present = 0; |
414 | TAILQ_FOREACH(d, &sc->sc_devs, d_list) { | | 414 | TAILQ_FOREACH(d, &sc->sc_devs, d_list) { |
415 | if (d->d_rom == rom) { | | 415 | if (d->d_rom == rom) { |
416 | d->d_present = 1; | | 416 | d->d_present = 1; |
417 | present = 1; | | 417 | present = 1; |
418 | break; | | 418 | break; |
419 | } | | 419 | } |
420 | } | | 420 | } |
421 | if (!present) { | | 421 | if (!present) { |
422 | memset(&oa, 0, sizeof(oa)); | | 422 | memset(&oa, 0, sizeof(oa)); |
423 | oa.oa_onewire = sc; | | 423 | oa.oa_onewire = sc; |
424 | oa.oa_rom = rom; | | 424 | oa.oa_rom = rom; |
425 | if ((dev = config_found(sc->sc_dev, &oa, | | 425 | if ((dev = config_found(sc->sc_dev, &oa, |
426 | onewire_print)) == NULL) | | 426 | onewire_print)) == NULL) |
427 | continue; | | 427 | continue; |
428 | | | 428 | |
429 | nd = malloc(sizeof(struct onewire_device), | | 429 | nd = malloc(sizeof(struct onewire_device), |
430 | M_DEVBUF, M_NOWAIT); | | 430 | M_DEVBUF, M_NOWAIT); |
431 | if (nd == NULL) | | 431 | if (nd == NULL) |
432 | continue; | | 432 | continue; |
433 | nd->d_dev = dev; | | 433 | nd->d_dev = dev; |
434 | nd->d_rom = rom; | | 434 | nd->d_rom = rom; |
435 | nd->d_present = 1; | | 435 | nd->d_present = 1; |
436 | TAILQ_INSERT_TAIL(&sc->sc_devs, nd, d_list); | | 436 | TAILQ_INSERT_TAIL(&sc->sc_devs, nd, d_list); |
437 | } | | 437 | } |
438 | } | | 438 | } |
439 | | | 439 | |
440 | /* Detach disappeared devices */ | | 440 | /* Detach disappeared devices */ |
441 | onewire_lock(sc); | | 441 | onewire_lock(sc); |
442 | for (d = TAILQ_FIRST(&sc->sc_devs); | | 442 | for (d = TAILQ_FIRST(&sc->sc_devs); |
443 | d != NULL; d = next) { | | 443 | d != NULL; d = next) { |
444 | next = TAILQ_NEXT(d, d_list); | | 444 | next = TAILQ_NEXT(d, d_list); |
445 | if (!d->d_present) { | | 445 | if (!d->d_present) { |
446 | config_detach(d->d_dev, DETACH_FORCE); | | 446 | config_detach(d->d_dev, DETACH_FORCE); |
447 | TAILQ_REMOVE(&sc->sc_devs, d, d_list); | | 447 | TAILQ_REMOVE(&sc->sc_devs, d, d_list); |
448 | free(d, M_DEVBUF); | | 448 | free(d, M_DEVBUF); |
449 | } | | 449 | } |
450 | } | | 450 | } |
451 | onewire_unlock(sc); | | 451 | onewire_unlock(sc); |
452 | } | | 452 | } |