The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/dev/ow/ow_temp.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*-
    2  * Copyright (c) 2015 M. Warner Losh <imp@freebsd.org>
    3  * All rights reserved.
    4  *
    5  * Redistribution and use in source and binary forms, with or without
    6  * modification, are permitted provided that the following conditions
    7  * are met:
    8  * 1. Redistributions of source code must retain the above copyright
    9  *    notice unmodified, this list of conditions, and the following
   10  *    disclaimer.
   11  * 2. Redistributions in binary form must reproduce the above copyright
   12  *    notice, this list of conditions and the following disclaimer in the
   13  *    documentation and/or other materials provided with the distribution.
   14  *
   15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
   16  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   17  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
   18  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
   19  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
   20  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
   21  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
   22  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
   23  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
   24  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   25  */
   26 
   27 #include <sys/cdefs.h>
   28 __FBSDID("$FreeBSD$");
   29 
   30 #include <sys/param.h>
   31 #include <sys/systm.h>
   32 #include <sys/kernel.h>
   33 
   34 #include <sys/bus.h>
   35 #include <sys/errno.h>
   36 #include <sys/libkern.h>
   37 #include <sys/kthread.h>
   38 #include <sys/malloc.h>
   39 #include <sys/module.h>
   40 #include <sys/mutex.h>
   41 #include <sys/proc.h>
   42 #include <sys/sysctl.h>
   43 
   44 #include <dev/ow/ow.h>
   45 #include <dev/ow/own.h>
   46 
   47 #define OWT_DS1820      0x10            /* Also 18S20 */
   48 #define OWT_DS1822      0x22            /* Very close to 18B20 */
   49 #define OWT_DS18B20     0x28            /* Also MAX31820 */
   50 #define OWT_DS1825      0x3B            /* Just like 18B20 with address bits */
   51 
   52 #define CONVERT_T               0x44
   53 #define COPY_SCRATCHPAD         0x48
   54 #define WRITE_SCRATCHPAD        0x4e
   55 #define READ_POWER_SUPPLY       0xb4
   56 #define RECALL_EE               0xb8
   57 #define READ_SCRATCHPAD         0xbe
   58 
   59 
   60 #define OW_TEMP_DONE            0x01
   61 #define OW_TEMP_RUNNING         0x02
   62 
   63 struct ow_temp_softc
   64 {
   65         device_t        dev;
   66         int             type;
   67         int             temp;
   68         int             flags;
   69         int             bad_crc;
   70         int             bad_reads;
   71         int             reading_interval;
   72         int             parasite;
   73         struct mtx      temp_lock;
   74         struct proc     *event_thread;
   75 };
   76 
   77 static int
   78 ow_temp_probe(device_t dev)
   79 {
   80 
   81         switch (ow_get_family(dev)) {
   82         case OWT_DS1820:
   83                 device_set_desc(dev, "One Wire Temperature");
   84                 return BUS_PROBE_DEFAULT;
   85         case OWT_DS1822:
   86         case OWT_DS1825:
   87         case OWT_DS18B20:
   88                 device_set_desc(dev, "Advanced One Wire Temperature");
   89                 return BUS_PROBE_DEFAULT;
   90         default:
   91                 return ENXIO;
   92         }
   93 }
   94 
   95 static int
   96 ow_temp_read_scratchpad(device_t dev, uint8_t *scratch, int len)
   97 {
   98         struct ow_cmd cmd;
   99         
  100         own_self_command(dev, &cmd, READ_SCRATCHPAD);
  101         cmd.xpt_read_len = len;
  102         own_command_wait(dev, &cmd);
  103         memcpy(scratch, cmd.xpt_read, len);
  104 
  105         return 0;
  106 }
  107 
  108 static int
  109 ow_temp_convert_t(device_t dev)
  110 {
  111         struct ow_cmd cmd;
  112 
  113         own_self_command(dev, &cmd, CONVERT_T);
  114         own_command_wait(dev, &cmd);
  115 
  116         return 0;
  117 }
  118 
  119 
  120 static int
  121 ow_temp_read_power_supply(device_t dev, int *parasite)
  122 {
  123         struct ow_cmd cmd;
  124 
  125         own_self_command(dev, &cmd, READ_POWER_SUPPLY);
  126         cmd.flags |= OW_FLAG_READ_BIT;
  127         cmd.xpt_read_len = 1;
  128         own_command_wait(dev, &cmd);
  129         *parasite = !cmd.xpt_read[0];   /* parasites pull bus low */
  130 
  131         return 0;
  132 }
  133 
  134 static void
  135 ow_temp_event_thread(void *arg)
  136 {
  137         struct ow_temp_softc *sc;
  138         uint8_t scratch[8 + 1];
  139         uint8_t crc;
  140         int retries, rv, tmp;
  141 
  142         sc = arg;
  143         pause("owtstart", device_get_unit(sc->dev) * hz / 100); // 10ms stagger
  144         mtx_lock(&sc->temp_lock);
  145         sc->flags |= OW_TEMP_RUNNING;
  146         mtx_unlock(&sc->temp_lock);
  147         ow_temp_read_power_supply(sc->dev, &sc->parasite);
  148         if (sc->parasite)
  149                 device_printf(sc->dev, "Running in parasitic mode unsupported\n");
  150         mtx_lock(&sc->temp_lock);
  151         while ((sc->flags & OW_TEMP_DONE) == 0) {
  152                 mtx_unlock(&sc->temp_lock);
  153                 ow_temp_convert_t(sc->dev);
  154                 mtx_lock(&sc->temp_lock);
  155                 msleep(sc, &sc->temp_lock, 0, "owtcvt", hz);
  156                 if (sc->flags & OW_TEMP_DONE)
  157                         break;
  158                 mtx_unlock(&sc->temp_lock);
  159                 for (retries = 5; retries > 0; retries--) {
  160                         rv = ow_temp_read_scratchpad(sc->dev, scratch, sizeof(scratch));
  161                         if (rv == 0) {
  162                                 crc = own_crc(sc->dev, scratch, sizeof(scratch) - 1);
  163                                 if (crc == scratch[8]) {
  164                                         if (sc->type == OWT_DS1820) {
  165                                                 if (scratch[7]) {
  166                                                         /*
  167                                                          * Formula from DS18S20 datasheet, page 6
  168                                                          * DS18S20 datasheet says count_per_c is 16, DS1820 does not
  169                                                          */
  170                                                         tmp = (int16_t)((scratch[0] & 0xfe) |
  171                                                             (scratch[1] << 8)) << 3;
  172                                                         tmp += 16 - scratch[6] - 4; /* count_per_c == 16 */
  173                                                 } else
  174                                                         tmp = (int16_t)(scratch[0] | (scratch[1] << 8)) << 3;
  175                                         } else
  176                                                 tmp = (int16_t)(scratch[0] | (scratch[1] << 8));
  177                                         sc->temp = tmp * 1000 / 16 + 273150;
  178                                         break;
  179                                 }
  180                                 sc->bad_crc++;
  181                         } else
  182                                 sc->bad_reads++;
  183                 }
  184                 mtx_lock(&sc->temp_lock);
  185                 msleep(sc, &sc->temp_lock, 0, "owtcvt", sc->reading_interval);
  186         }
  187         sc->flags &= ~OW_TEMP_RUNNING;
  188         mtx_unlock(&sc->temp_lock);
  189         kproc_exit(0);
  190 }
  191 
  192 static int
  193 ow_temp_attach(device_t dev)
  194 {
  195         struct ow_temp_softc *sc;
  196 
  197         sc = device_get_softc(dev);
  198         sc->dev = dev;
  199         sc->type = ow_get_family(dev);
  200         SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
  201             SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
  202             OID_AUTO, "temperature", CTLFLAG_RD | CTLTYPE_INT,
  203             &sc->temp, 0, sysctl_handle_int,
  204             "IK3", "Current Temperature");
  205         SYSCTL_ADD_INT(device_get_sysctl_ctx(dev),
  206             SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
  207             OID_AUTO, "badcrc", CTLFLAG_RD,
  208             &sc->bad_crc, 0,
  209             "Number of Bad CRC on reading scratchpad");
  210         SYSCTL_ADD_INT(device_get_sysctl_ctx(dev),
  211             SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
  212             OID_AUTO, "badread", CTLFLAG_RD,
  213             &sc->bad_reads, 0,
  214             "Number of errors on reading scratchpad");
  215         SYSCTL_ADD_INT(device_get_sysctl_ctx(dev),
  216             SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
  217             OID_AUTO, "reading_interval", CTLFLAG_RW,
  218             &sc->reading_interval, 0,
  219             "ticks between reads");
  220         SYSCTL_ADD_INT(device_get_sysctl_ctx(dev),
  221             SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
  222             OID_AUTO, "parasite", CTLFLAG_RW,
  223             &sc->parasite, 0,
  224             "In Parasite mode");
  225         /*
  226          * Just do this for unit 0 to avoid locking
  227          * the ow bus until that code can be put
  228          * into place.
  229          */
  230         sc->temp = -1;
  231         sc->reading_interval = 10 * hz;
  232         mtx_init(&sc->temp_lock, "lock for doing temperature", NULL, MTX_DEF);
  233         /* Start the thread */
  234         if (kproc_create(ow_temp_event_thread, sc, &sc->event_thread, 0, 0,
  235             "%s event thread", device_get_nameunit(dev))) {
  236                 device_printf(dev, "unable to create event thread.\n");
  237                 panic("cbb_create_event_thread");
  238         }
  239 
  240         return 0;
  241 }
  242 
  243 static int
  244 ow_temp_detach(device_t dev)
  245 {
  246         struct ow_temp_softc *sc;
  247 
  248         sc = device_get_softc(dev);
  249 
  250         /*
  251          * Wait for the thread to die.  kproc_exit will do a wakeup
  252          * on the event thread's struct thread * so that we know it is
  253          * safe to proceed.  IF the thread is running, set the please
  254          * die flag and wait for it to comply.  Since the wakeup on
  255          * the event thread happens only in kproc_exit, we don't
  256          * need to loop here.
  257          */
  258         mtx_lock(&sc->temp_lock);
  259         sc->flags |= OW_TEMP_DONE;
  260         while (sc->flags & OW_TEMP_RUNNING) {
  261                 wakeup(sc);
  262                 msleep(sc->event_thread, &sc->temp_lock, PWAIT, "owtun", 0);
  263         }
  264         mtx_destroy(&sc->temp_lock);
  265         
  266         return 0;
  267 }
  268 
  269 devclass_t ow_temp_devclass;
  270 
  271 static device_method_t ow_temp_methods[] = {
  272         /* Device interface */
  273         DEVMETHOD(device_probe,         ow_temp_probe),
  274         DEVMETHOD(device_attach,        ow_temp_attach),
  275         DEVMETHOD(device_detach,        ow_temp_detach),
  276 
  277         { 0, 0 }
  278 };
  279 
  280 static driver_t ow_temp_driver = {
  281         "ow_temp",
  282         ow_temp_methods,
  283         sizeof(struct ow_temp_softc),
  284 };
  285 
  286 DRIVER_MODULE(ow_temp, ow, ow_temp_driver, ow_temp_devclass, 0, 0);
  287 MODULE_DEPEND(ow_temp, ow, 1, 1, 1);

Cache object: ee91ce3bb77f7350fcd2d17b95aeb09f


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.