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