root/dev/onewire/onewire.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. onewire_match
  2. onewire_attach
  3. onewire_detach
  4. onewire_activate
  5. onewire_print
  6. onewirebus_print
  7. onewire_lock
  8. onewire_unlock
  9. onewire_reset
  10. onewire_bit
  11. onewire_read_byte
  12. onewire_write_byte
  13. onewire_read_block
  14. onewire_write_block
  15. onewire_triplet
  16. onewire_matchrom
  17. onewire_search
  18. onewire_thread
  19. onewire_createthread
  20. onewire_scan

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

/* [<][>][^][v][top][bottom][index][help] */