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