LCOV - code coverage report
Current view: top level - dev/onewire - onewire.c (source / functions) Hit Total Coverage
Test: 6.4 Lines: 0 214 0.0 %
Date: 2018-10-19 03:25:38 Functions: 0 20 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*      $OpenBSD: onewire.c,v 1.17 2017/04/03 16:10:00 deraadt 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           0 : onewire_match(struct device *parent, void *match, void *aux)
      88             : {
      89           0 :         struct cfdata *cf = match;
      90             : 
      91           0 :         return (strcmp(cf->cf_driver->cd_name, "onewire") == 0);
      92             : }
      93             : 
      94             : void
      95           0 : onewire_attach(struct device *parent, struct device *self, void *aux)
      96             : {
      97           0 :         struct onewire_softc *sc = (struct onewire_softc *)self;
      98           0 :         struct onewirebus_attach_args *oba = aux;
      99             : 
     100           0 :         sc->sc_bus = oba->oba_bus;
     101           0 :         sc->sc_flags = oba->oba_flags;
     102           0 :         rw_init(&sc->sc_lock, sc->sc_dev.dv_xname);
     103           0 :         TAILQ_INIT(&sc->sc_devs);
     104             : 
     105           0 :         printf("\n");
     106             : 
     107           0 :         if (sc->sc_flags & ONEWIRE_SCAN_NOW) {
     108           0 :                 onewire_scan(sc);
     109           0 :                 if (sc->sc_flags & ONEWIRE_NO_PERIODIC_SCAN)
     110           0 :                         return;
     111             :         }
     112             : 
     113           0 :         kthread_create_deferred(onewire_createthread, sc);
     114           0 : }
     115             : 
     116             : int
     117           0 : onewire_detach(struct device *self, int flags)
     118             : {
     119           0 :         struct onewire_softc *sc = (struct onewire_softc *)self;
     120             : 
     121           0 :         sc->sc_dying = 1;
     122           0 :         if (sc->sc_thread != NULL) {
     123           0 :                 wakeup(sc->sc_thread);
     124           0 :                 tsleep(&sc->sc_dying, PWAIT, "owdt", 0);
     125           0 :         }
     126             : 
     127           0 :         return (config_detach_children(self, flags));
     128             : }
     129             : 
     130             : int
     131           0 : onewire_activate(struct device *self, int act)
     132             : {
     133           0 :         struct onewire_softc *sc = (struct onewire_softc *)self;
     134             : 
     135           0 :         switch (act) {
     136             :         case DVACT_DEACTIVATE:
     137           0 :                 sc->sc_dying = 1;
     138           0 :                 break;
     139             :         }
     140             : 
     141           0 :         return (config_activate_children(self, act));
     142             : }
     143             : 
     144             : int
     145           0 : onewire_print(void *aux, const char *pnp)
     146             : {
     147           0 :         struct onewire_attach_args *oa = aux;
     148             :         const char *famname;
     149             : 
     150           0 :         if (pnp == NULL)
     151           0 :                 printf(" ");
     152             : 
     153           0 :         famname = onewire_famname(ONEWIRE_ROM_FAMILY_TYPE(oa->oa_rom));
     154           0 :         if (famname == NULL)
     155           0 :                 printf("family 0x%02x", ONEWIRE_ROM_FAMILY_TYPE(oa->oa_rom));
     156             :         else
     157           0 :                 printf("\"%s\"", famname);
     158           0 :         printf(" sn %012llx", ONEWIRE_ROM_SN(oa->oa_rom));
     159             : 
     160           0 :         if (pnp != NULL)
     161           0 :                 printf(" at %s", pnp);
     162             : 
     163           0 :         return (UNCONF);
     164             : }
     165             : 
     166             : int
     167           0 : onewirebus_print(void *aux, const char *pnp)
     168             : {
     169           0 :         if (pnp != NULL)
     170           0 :                 printf("onewire at %s", pnp);
     171             : 
     172           0 :         return (UNCONF);
     173             : }
     174             : 
     175             : int
     176           0 : onewire_lock(void *arg, int flags)
     177             : {
     178           0 :         struct onewire_softc *sc = arg;
     179             :         int lflags = RW_WRITE;
     180             : 
     181           0 :         if (flags & ONEWIRE_NOWAIT)
     182           0 :                 lflags |= RW_NOSLEEP;
     183             : 
     184           0 :         return (rw_enter(&sc->sc_lock, lflags));
     185             : }
     186             : 
     187             : void
     188           0 : onewire_unlock(void *arg)
     189             : {
     190           0 :         struct onewire_softc *sc = arg;
     191             : 
     192           0 :         rw_exit(&sc->sc_lock);
     193           0 : }
     194             : 
     195             : int
     196           0 : onewire_reset(void *arg)
     197             : {
     198           0 :         struct onewire_softc *sc = arg;
     199           0 :         struct onewire_bus *bus = sc->sc_bus;
     200             : 
     201           0 :         return (bus->bus_reset(bus->bus_cookie));
     202             : }
     203             : 
     204             : int
     205           0 : onewire_bit(void *arg, int value)
     206             : {
     207           0 :         struct onewire_softc *sc = arg;
     208           0 :         struct onewire_bus *bus = sc->sc_bus;
     209             : 
     210           0 :         return (bus->bus_bit(bus->bus_cookie, value));
     211             : }
     212             : 
     213             : int
     214           0 : onewire_read_byte(void *arg)
     215             : {
     216           0 :         struct onewire_softc *sc = arg;
     217           0 :         struct onewire_bus *bus = sc->sc_bus;
     218             :         u_int8_t value = 0;
     219             :         int i;
     220             : 
     221           0 :         if (bus->bus_read_byte != NULL)
     222           0 :                 return (bus->bus_read_byte(bus->bus_cookie));
     223             : 
     224           0 :         for (i = 0; i < 8; i++)
     225           0 :                 value |= (bus->bus_bit(bus->bus_cookie, 1) << i);
     226             : 
     227           0 :         return (value);
     228           0 : }
     229             : 
     230             : void
     231           0 : onewire_write_byte(void *arg, int value)
     232             : {
     233           0 :         struct onewire_softc *sc = arg;
     234           0 :         struct onewire_bus *bus = sc->sc_bus;
     235             :         int i;
     236             : 
     237           0 :         if (bus->bus_write_byte != NULL)
     238           0 :                 return (bus->bus_write_byte(bus->bus_cookie, value));
     239             : 
     240           0 :         for (i = 0; i < 8; i++)
     241           0 :                 bus->bus_bit(bus->bus_cookie, (value >> i) & 0x1);
     242           0 : }
     243             : 
     244             : void
     245           0 : onewire_read_block(void *arg, void *buf, int len)
     246             : {
     247           0 :         struct onewire_softc *sc = arg;
     248           0 :         struct onewire_bus *bus = sc->sc_bus;
     249             :         u_int8_t *p = buf;
     250             : 
     251           0 :         if (bus->bus_read_block != NULL)
     252           0 :                 return (bus->bus_read_block(bus->bus_cookie, buf, len));
     253             : 
     254           0 :         while (len--)
     255           0 :                 *p++ = onewire_read_byte(arg);
     256           0 : }
     257             : 
     258             : void
     259           0 : onewire_write_block(void *arg, const void *buf, int len)
     260             : {
     261           0 :         struct onewire_softc *sc = arg;
     262           0 :         struct onewire_bus *bus = sc->sc_bus;
     263             :         const u_int8_t *p = buf;
     264             : 
     265           0 :         if (bus->bus_write_block != NULL)
     266           0 :                 return (bus->bus_write_block(bus->bus_cookie, buf, len));
     267             : 
     268           0 :         while (len--)
     269           0 :                 onewire_write_byte(arg, *p++);
     270           0 : }
     271             : 
     272             : int
     273           0 : onewire_triplet(void *arg, int dir)
     274             : {
     275           0 :         struct onewire_softc *sc = arg;
     276           0 :         struct onewire_bus *bus = sc->sc_bus;
     277             :         int rv;
     278             : 
     279           0 :         if (bus->bus_triplet != NULL)
     280           0 :                 return (bus->bus_triplet(bus->bus_cookie, dir));
     281             : 
     282           0 :         rv = bus->bus_bit(bus->bus_cookie, 1);
     283           0 :         rv <<= 1;
     284           0 :         rv |= bus->bus_bit(bus->bus_cookie, 1);
     285             : 
     286           0 :         switch (rv) {
     287             :         case 0x0:
     288           0 :                 bus->bus_bit(bus->bus_cookie, dir);
     289           0 :                 break;
     290             :         case 0x1:
     291           0 :                 bus->bus_bit(bus->bus_cookie, 0);
     292           0 :                 break;
     293             :         default:
     294           0 :                 bus->bus_bit(bus->bus_cookie, 1);
     295           0 :         }
     296             : 
     297           0 :         return (rv);
     298           0 : }
     299             : 
     300             : void
     301           0 : onewire_matchrom(void *arg, u_int64_t rom)
     302             : {
     303           0 :         struct onewire_softc *sc = arg;
     304           0 :         struct onewire_bus *bus = sc->sc_bus;
     305             :         int i;
     306             : 
     307           0 :         if (bus->bus_matchrom != NULL)
     308           0 :                 return (bus->bus_matchrom(bus->bus_cookie, rom));
     309             : 
     310           0 :         onewire_write_byte(arg, ONEWIRE_CMD_MATCH_ROM);
     311           0 :         for (i = 0; i < 8; i++)
     312           0 :                 onewire_write_byte(arg, (rom >> (i * 8)) & 0xff);
     313           0 : }
     314             : 
     315             : int
     316           0 : onewire_search(void *arg, u_int64_t *buf, int size, u_int64_t startrom)
     317             : {
     318           0 :         struct onewire_softc *sc = arg;
     319           0 :         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           0 :         u_int8_t data[8];
     323             : 
     324           0 :         if (bus->bus_search != NULL)
     325           0 :                 return (bus->bus_search(bus->bus_cookie, buf, size, rom));
     326             : 
     327           0 :         while (search && count < size) {
     328             :                 /* XXX: yield processor */
     329           0 :                 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           0 :                 onewire_lock(sc, 0);
     340           0 :                 onewire_reset(sc);
     341           0 :                 onewire_write_byte(sc, ONEWIRE_CMD_SEARCH_ROM);
     342           0 :                 for (i = 0, i0 = -1; i < 64; i++) {
     343           0 :                         dir = (lastrom >> i) & 0x1;
     344           0 :                         if (i == lastd)
     345           0 :                                 dir = 1;
     346           0 :                         else if (i > lastd)
     347           0 :                                 dir = 0;
     348           0 :                         rv = onewire_triplet(sc, dir);
     349           0 :                         switch (rv) {
     350             :                         case 0x0:
     351           0 :                                 if (i != lastd && dir == 0)
     352           0 :                                         i0 = i;
     353           0 :                                 mask = dir;
     354           0 :                                 break;
     355             :                         case 0x1:
     356             :                                 mask = 0;
     357           0 :                                 break;
     358             :                         case 0x2:
     359             :                                 mask = 1;
     360           0 :                                 break;
     361             :                         default:
     362             :                                 DPRINTF(("%s: search triplet error 0x%x, "
     363             :                                     "step %d\n",
     364             :                                     sc->sc_dev.dv_xname, rv, i));
     365           0 :                                 onewire_unlock(sc);
     366           0 :                                 return (-1);
     367             :                         }
     368           0 :                         rom |= (mask << i);
     369             :                 }
     370           0 :                 onewire_unlock(sc);
     371             : 
     372           0 :                 if ((lastd = i0) == -1)
     373           0 :                         search = 0;
     374             : 
     375           0 :                 if (rom == 0)
     376           0 :                         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           0 :                 for (i = 0; i < 8; i++)
     384           0 :                         data[i] = (rom >> (i * 8)) & 0xff;
     385           0 :                 if (onewire_crc(data, 7) != data[7])
     386           0 :                         continue;
     387             : 
     388           0 :                 buf[count++] = rom;
     389             :         }
     390             : 
     391           0 :         return (count);
     392           0 : }
     393             : 
     394             : void
     395           0 : onewire_thread(void *arg)
     396             : {
     397           0 :         struct onewire_softc *sc = arg;
     398             : 
     399           0 :         while (!sc->sc_dying) {
     400           0 :                 onewire_scan(sc);
     401           0 :                 if (sc->sc_flags & ONEWIRE_NO_PERIODIC_SCAN)
     402             :                         break;
     403           0 :                 tsleep(sc->sc_thread, PWAIT, "owidle", ONEWIRE_SCANTIME * hz);
     404             :         }
     405             : 
     406           0 :         sc->sc_thread = NULL;
     407           0 :         wakeup(&sc->sc_dying);
     408           0 :         kthread_exit(0);
     409             : }
     410             : 
     411             : void
     412           0 : onewire_createthread(void *arg)
     413             : {
     414           0 :         struct onewire_softc *sc = arg;
     415             : 
     416           0 :         if (kthread_create(onewire_thread, sc, &sc->sc_thread,
     417           0 :             sc->sc_dev.dv_xname) != 0)
     418           0 :                 printf("%s: can't create kernel thread\n",
     419             :                     sc->sc_dev.dv_xname);
     420           0 : }
     421             : 
     422             : void
     423           0 : onewire_scan(struct onewire_softc *sc)
     424             : {
     425             :         struct onewire_device *d, *next, *nd;
     426           0 :         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           0 :         TAILQ_FOREACH(d, &sc->sc_devs, d_list)
     438           0 :                 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           0 :         onewire_lock(sc, 0);
     445           0 :         rv = onewire_reset(sc);
     446           0 :         onewire_unlock(sc);
     447           0 :         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           0 :         if ((rv = onewire_search(sc, sc->sc_rombuf, ONEWIRE_MAXDEVS, 0)) == -1)
     454           0 :                 return;
     455             : 
     456           0 :         for (i = 0; i < rv; i++) {
     457           0 :                 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           0 :                 TAILQ_FOREACH(d, &sc->sc_devs, d_list) {
     465           0 :                         if (d->d_rom == rom) {
     466           0 :                                 d->d_present = 1;
     467             :                                 present = 1;
     468           0 :                                 break;
     469             :                         }
     470             :                 }
     471           0 :                 if (!present) {
     472           0 :                         nd = malloc(sizeof(struct onewire_device),
     473             :                             M_DEVBUF, M_NOWAIT);
     474           0 :                         if (nd == NULL)
     475             :                                 continue;
     476             : 
     477           0 :                         bzero(&oa, sizeof(oa));
     478           0 :                         oa.oa_onewire = sc;
     479           0 :                         oa.oa_rom = rom;
     480           0 :                         dev = config_found(&sc->sc_dev, &oa, onewire_print);
     481             : 
     482           0 :                         nd->d_dev = dev;
     483           0 :                         nd->d_rom = rom;
     484           0 :                         nd->d_present = 1;
     485           0 :                         TAILQ_INSERT_TAIL(&sc->sc_devs, nd, d_list);
     486           0 :                 }
     487             :         }
     488             : 
     489             : out:
     490             :         /* Detach disappeared devices */
     491           0 :         TAILQ_FOREACH_SAFE(d, &sc->sc_devs, d_list, next) {
     492           0 :                 if (!d->d_present) {
     493           0 :                         if (d->d_dev != NULL)
     494           0 :                                 config_detach(d->d_dev, DETACH_FORCE);
     495           0 :                         TAILQ_REMOVE(&sc->sc_devs, d, d_list);
     496           0 :                         free(d, M_DEVBUF, sizeof *d);
     497           0 :                 }
     498             :         }
     499           0 : }

Generated by: LCOV version 1.13