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