1 /* $NetBSD: onewire.c,v 1.7 2007/09/05 15:24:07 xtraeme 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.7 2007/09/05 15:24:07 xtraeme 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 struct device 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 struct device * d_dev; 65 u_int64_t d_rom; 66 int d_present; 67 }; 68 69 int onewire_match(struct device *, struct cfdata *, void *); 70 void onewire_attach(struct device *, struct device *, void *); 71 int onewire_detach(struct device *, int); 72 int onewire_activate(struct device *, enum devact); 73 int onewire_print(void *, const char *); 74 75 void onewire_thread(void *); 76 void onewire_scan(struct onewire_softc *); 77 78 CFATTACH_DECL(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 int 89 onewire_match(struct device *parent, struct cfdata *cf, void *aux) 90 { 91 return 1; 92 } 93 94 void 95 onewire_attach(struct device *parent, struct device *self, void *aux) 96 { 97 struct onewire_softc *sc = device_private(self); 98 struct onewirebus_attach_args *oba = aux; 99 100 sc->sc_bus = oba->oba_bus; 101 rw_init(&sc->sc_rwlock); 102 TAILQ_INIT(&sc->sc_devs); 103 104 aprint_naive("\n"); 105 aprint_normal("\n"); 106 107 if (kthread_create(PRI_NONE, 0, NULL, onewire_thread, sc, 108 &sc->sc_thread, "%s", sc->sc_dev.dv_xname) != 0) 109 aprint_error("%s: can't create kernel thread\n", 110 sc->sc_dev.dv_xname); 111 } 112 113 int 114 onewire_detach(struct device *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 int 135 onewire_activate(struct device *self, enum devact act) 136 { 137 struct onewire_softc *sc = device_private(self); 138 int rv = 0; 139 140 switch (act) { 141 case DVACT_ACTIVATE: 142 rv = EOPNOTSUPP; 143 break; 144 case DVACT_DEACTIVATE: 145 sc->sc_dying = 1; 146 break; 147 } 148 149 //return (config_activate_children(self, act)); 150 return rv; 151 } 152 153 int 154 onewire_print(void *aux, const char *pnp) 155 { 156 struct onewire_attach_args *oa = aux; 157 const char *famname; 158 159 if (pnp == NULL) 160 aprint_normal(" "); 161 162 famname = onewire_famname(ONEWIRE_ROM_FAMILY_TYPE(oa->oa_rom)); 163 if (famname == NULL) 164 aprint_normal("family 0x%02x", 165 (uint)ONEWIRE_ROM_FAMILY_TYPE(oa->oa_rom)); 166 else 167 aprint_normal("\"%s\"", famname); 168 aprint_normal(" sn %012llx", ONEWIRE_ROM_SN(oa->oa_rom)); 169 170 if (pnp != NULL) 171 aprint_normal(" at %s", pnp); 172 173 return UNCONF; 174 } 175 176 int 177 onewirebus_print(void *aux, const char *pnp) 178 { 179 if (pnp != NULL) 180 aprint_normal("onewire at %s", pnp); 181 182 return UNCONF; 183 } 184 185 void 186 onewire_lock(void *arg) 187 { 188 struct onewire_softc *sc = arg; 189 190 rw_enter(&sc->sc_rwlock, RW_WRITER); 191 } 192 193 void 194 onewire_unlock(void *arg) 195 { 196 struct onewire_softc *sc = arg; 197 198 rw_exit(&sc->sc_rwlock); 199 } 200 201 int 202 onewire_reset(void *arg) 203 { 204 struct onewire_softc *sc = arg; 205 struct onewire_bus *bus = sc->sc_bus; 206 207 return bus->bus_reset(bus->bus_cookie); 208 } 209 210 int 211 onewire_bit(void *arg, int value) 212 { 213 struct onewire_softc *sc = arg; 214 struct onewire_bus *bus = sc->sc_bus; 215 216 return bus->bus_bit(bus->bus_cookie, value); 217 } 218 219 int 220 onewire_read_byte(void *arg) 221 { 222 struct onewire_softc *sc = arg; 223 struct onewire_bus *bus = sc->sc_bus; 224 uint8_t value = 0; 225 int i; 226 227 if (bus->bus_read_byte != NULL) 228 return bus->bus_read_byte(bus->bus_cookie); 229 230 for (i = 0; i < 8; i++) 231 value |= (bus->bus_bit(bus->bus_cookie, 1) << i); 232 233 return value; 234 } 235 236 void 237 onewire_write_byte(void *arg, int value) 238 { 239 struct onewire_softc *sc = arg; 240 struct onewire_bus *bus = sc->sc_bus; 241 int i; 242 243 if (bus->bus_write_byte != NULL) 244 return bus->bus_write_byte(bus->bus_cookie, value); 245 246 for (i = 0; i < 8; i++) 247 bus->bus_bit(bus->bus_cookie, (value >> i) & 0x1); 248 } 249 250 int 251 onewire_triplet(void *arg, int dir) 252 { 253 struct onewire_softc *sc = arg; 254 struct onewire_bus *bus = sc->sc_bus; 255 int rv; 256 257 if (bus->bus_triplet != NULL) 258 return bus->bus_triplet(bus->bus_cookie, dir); 259 260 rv = bus->bus_bit(bus->bus_cookie, 1); 261 rv <<= 1; 262 rv |= bus->bus_bit(bus->bus_cookie, 1); 263 264 switch (rv) { 265 case 0x0: 266 bus->bus_bit(bus->bus_cookie, dir); 267 break; 268 case 0x1: 269 bus->bus_bit(bus->bus_cookie, 0); 270 break; 271 default: 272 bus->bus_bit(bus->bus_cookie, 1); 273 } 274 275 return rv; 276 } 277 278 void 279 onewire_read_block(void *arg, void *buf, int len) 280 { 281 uint8_t *p = buf; 282 283 while (len--) 284 *p++ = onewire_read_byte(arg); 285 } 286 287 void 288 onewire_write_block(void *arg, const void *buf, int len) 289 { 290 const uint8_t *p = buf; 291 292 while (len--) 293 onewire_write_byte(arg, *p++); 294 } 295 296 void 297 onewire_matchrom(void *arg, u_int64_t rom) 298 { 299 int i; 300 301 onewire_write_byte(arg, ONEWIRE_CMD_MATCH_ROM); 302 for (i = 0; i < 8; i++) 303 onewire_write_byte(arg, (rom >> (i * 8)) & 0xff); 304 } 305 306 void 307 onewire_thread(void *arg) 308 { 309 struct onewire_softc *sc = arg; 310 311 while (!sc->sc_dying) { 312 onewire_scan(sc); 313 tsleep(sc->sc_thread, PWAIT, "owidle", ONEWIRE_SCANTIME * hz); 314 } 315 316 sc->sc_thread = NULL; 317 wakeup(&sc->sc_dying); 318 kthread_exit(0); 319 } 320 void 321 onewire_scan(struct onewire_softc *sc) 322 { 323 struct onewire_device *d, *next, *nd; 324 struct onewire_attach_args oa; 325 struct device *dev; 326 int search = 1, count = 0, present; 327 int dir, rv; 328 uint64_t mask, rom = 0, lastrom; 329 uint8_t data[8]; 330 int i, i0 = -1, lastd = -1; 331 332 TAILQ_FOREACH(d, &sc->sc_devs, d_list) 333 d->d_present = 0; 334 335 while (search && count++ < ONEWIRE_MAXDEVS) { 336 /* XXX: yield processor */ 337 tsleep(sc, PWAIT, "owscan", hz / 10); 338 339 /* 340 * Reset the bus. If there's no presence pulse 341 * don't search for any devices. 342 */ 343 onewire_lock(sc); 344 if (onewire_reset(sc) != 0) { 345 DPRINTF(("%s: scan: no presence pulse\n", 346 sc->sc_dev.dv_xname)); 347 onewire_unlock(sc); 348 break; 349 } 350 351 /* 352 * Start new search. Go through the previous path to 353 * the point we made a decision last time and make an 354 * opposite decision. If we didn't make any decision 355 * stop searching. 356 */ 357 search = 0; 358 lastrom = rom; 359 rom = 0; 360 onewire_write_byte(sc, ONEWIRE_CMD_SEARCH_ROM); 361 for (i = 0,i0 = -1; i < 64; i++) { 362 dir = (lastrom >> i) & 0x1; 363 if (i == lastd) 364 dir = 1; 365 else if (i > lastd) 366 dir = 0; 367 rv = onewire_triplet(sc, dir); 368 switch (rv) { 369 case 0x0: 370 if (i != lastd) { 371 if (dir == 0) 372 i0 = i; 373 search = 1; 374 } 375 mask = dir; 376 break; 377 case 0x1: 378 mask = 0; 379 break; 380 case 0x2: 381 mask = 1; 382 break; 383 default: 384 DPRINTF(("%s: scan: triplet error 0x%x, " 385 "step %d\n", 386 sc->sc_dev.dv_xname, rv, i)); 387 onewire_unlock(sc); 388 return; 389 } 390 rom |= (mask << i); 391 } 392 lastd = i0; 393 onewire_unlock(sc); 394 395 if (rom == 0) 396 continue; 397 398 /* 399 * The last byte of the ROM code contains a CRC calculated 400 * from the first 7 bytes. Re-calculate it to make sure 401 * we found a valid device. 402 */ 403 for (i = 0; i < 8; i++) 404 data[i] = (rom >> (i * 8)) & 0xff; 405 if (onewire_crc(data, 7) != data[7]) 406 continue; 407 408 /* 409 * Go through the list of attached devices to see if we 410 * found a new one. 411 */ 412 present = 0; 413 TAILQ_FOREACH(d, &sc->sc_devs, d_list) { 414 if (d->d_rom == rom) { 415 d->d_present = 1; 416 present = 1; 417 break; 418 } 419 } 420 if (!present) { 421 bzero(&oa, sizeof(oa)); 422 oa.oa_onewire = sc; 423 oa.oa_rom = rom; 424 if ((dev = config_found(&sc->sc_dev, &oa, 425 onewire_print)) == NULL) 426 continue; 427 428 MALLOC(nd, struct onewire_device *, 429 sizeof(struct onewire_device), M_DEVBUF, M_NOWAIT); 430 if (nd == NULL) 431 continue; 432 nd->d_dev = dev; 433 nd->d_rom = rom; 434 nd->d_present = 1; 435 TAILQ_INSERT_TAIL(&sc->sc_devs, nd, d_list); 436 } 437 } 438 439 /* Detach disappeared devices */ 440 onewire_lock(sc); 441 for (d = TAILQ_FIRST(&sc->sc_devs); 442 d != NULL; d = next) { 443 next = TAILQ_NEXT(d, d_list); 444 if (!d->d_present) { 445 config_detach(d->d_dev, DETACH_FORCE); 446 TAILQ_REMOVE(&sc->sc_devs, d, d_list); 447 FREE(d, M_DEVBUF); 448 } 449 } 450 onewire_unlock(sc); 451 } 452