jcs's openbsd hax
openbsd
at jcs 219 lines 6.0 kB view raw
1/* $OpenBSD: owctr.c,v 1.9 2022/04/06 18:59:29 naddy Exp $ */ 2/* 3 * Copyright (c) 2010 John L. Scarfone <john@scarfone.net> 4 * 5 * Permission to use, copy, modify, and distribute this software for any 6 * purpose with or without fee is hereby granted, provided that the above 7 * copyright notice and this permission notice appear in all copies. 8 * 9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 */ 17 18/* 19 * DS2423 1-Wire 4kbit SRAM with Counter family type device driver. 20 * Provides 4096 bits of SRAM and four 32-bit, read-only counters. 21 * This driver provides access to the two externally triggered 22 * counters. 23 */ 24 25#include <sys/param.h> 26#include <sys/systm.h> 27#include <sys/device.h> 28#include <sys/malloc.h> 29#include <sys/rwlock.h> 30#include <sys/sensors.h> 31 32#include <dev/onewire/onewiredevs.h> 33#include <dev/onewire/onewirereg.h> 34#include <dev/onewire/onewirevar.h> 35 36/* Commands */ 37#define DSCTR_CMD_READ_MEMCOUNTER 0xa5 38 39/* External counter banks */ 40#define DS2423_COUNTER_BANK_A 0x1c0 41#define DS2423_COUNTER_BANK_B 0x1e0 42 43/* Buffer offsets */ 44#define DS2423_COUNTER_BUF_COUNTER 35 45#define DS2423_COUNTER_BUF_CRC 43 46 47#define DS2423_COUNTER_BUFSZ 45 48 49struct owctr_softc { 50 struct device sc_dev; 51 52 void * sc_onewire; 53 u_int64_t sc_rom; 54 55 struct ksensordev sc_sensordev; 56 57 struct ksensor sc_counterA; 58 struct ksensor sc_counterB; 59 60 struct sensor_task *sc_sensortask; 61 62 struct rwlock sc_lock; 63}; 64 65int owctr_match(struct device *, void *, void *); 66void owctr_attach(struct device *, struct device *, void *); 67int owctr_detach(struct device *, int); 68int owctr_activate(struct device *, int); 69 70void owctr_update(void *); 71void owctr_update_counter(void *, int); 72 73const struct cfattach owctr_ca = { 74 sizeof(struct owctr_softc), 75 owctr_match, 76 owctr_attach, 77 owctr_detach, 78 owctr_activate 79}; 80 81struct cfdriver owctr_cd = { 82 NULL, "owctr", DV_DULL 83}; 84 85static const struct onewire_matchfam owctr_fams[] = { 86 { ONEWIRE_FAMILY_DS2423 } 87}; 88 89int 90owctr_match(struct device *parent, void *match, void *aux) 91{ 92 return (onewire_matchbyfam(aux, owctr_fams, nitems(owctr_fams))); 93} 94 95void 96owctr_attach(struct device *parent, struct device *self, void *aux) 97{ 98 struct owctr_softc *sc = (struct owctr_softc *)self; 99 struct onewire_attach_args *oa = aux; 100 101 sc->sc_onewire = oa->oa_onewire; 102 sc->sc_rom = oa->oa_rom; 103 104 /* Initialize counter sensors */ 105 strlcpy(sc->sc_sensordev.xname, sc->sc_dev.dv_xname, 106 sizeof(sc->sc_sensordev.xname)); 107 sc->sc_counterA.type = SENSOR_INTEGER; 108 snprintf(sc->sc_counterA.desc, sizeof(sc->sc_counterA.desc), 109 "Counter A sn %012llx", ONEWIRE_ROM_SN(oa->oa_rom)); 110 sensor_attach(&sc->sc_sensordev, &sc->sc_counterA); 111 sc->sc_counterB.type = SENSOR_INTEGER; 112 snprintf(sc->sc_counterB.desc, sizeof(sc->sc_counterB.desc), 113 "Counter B sn %012llx", ONEWIRE_ROM_SN(oa->oa_rom)); 114 sensor_attach(&sc->sc_sensordev, &sc->sc_counterB); 115 116 sc->sc_sensortask = sensor_task_register(sc, owctr_update, 10); 117 if (sc->sc_sensortask == NULL) { 118 printf(": unable to register update task\n"); 119 return; 120 } 121 122 sensordev_install(&sc->sc_sensordev); 123 124 rw_init(&sc->sc_lock, sc->sc_dev.dv_xname); 125 printf("\n"); 126} 127 128int 129owctr_detach(struct device *self, int flags) 130{ 131 struct owctr_softc *sc = (struct owctr_softc *)self; 132 133 rw_enter_write(&sc->sc_lock); 134 sensordev_deinstall(&sc->sc_sensordev); 135 if (sc->sc_sensortask != NULL) 136 sensor_task_unregister(sc->sc_sensortask); 137 rw_exit_write(&sc->sc_lock); 138 139 return (0); 140} 141 142int 143owctr_activate(struct device *self, int act) 144{ 145 return (0); 146} 147 148void 149owctr_update(void *arg) 150{ 151 owctr_update_counter(arg, DS2423_COUNTER_BANK_A); 152 owctr_update_counter(arg, DS2423_COUNTER_BANK_B); 153} 154 155void 156owctr_update_counter(void *arg, int bank) 157{ 158 struct owctr_softc *sc = arg; 159 u_int32_t counter; 160 u_int16_t crc; 161 u_int8_t *buf; 162 163 rw_enter_write(&sc->sc_lock); 164 onewire_lock(sc->sc_onewire, 0); 165 if (onewire_reset(sc->sc_onewire) != 0) 166 goto done; 167 168 buf = malloc(DS2423_COUNTER_BUFSZ, M_DEVBUF, M_NOWAIT); 169 if (buf == NULL) { 170 printf("%s: malloc() failed\n", sc->sc_dev.dv_xname); 171 goto done; 172 } 173 174 onewire_matchrom(sc->sc_onewire, sc->sc_rom); 175 buf[0] = DSCTR_CMD_READ_MEMCOUNTER; 176 buf[1] = bank; 177 buf[2] = bank >> 8; 178 onewire_write_byte(sc->sc_onewire, buf[0]); 179 onewire_write_byte(sc->sc_onewire, buf[1]); 180 onewire_write_byte(sc->sc_onewire, buf[2]); 181 onewire_read_block(sc->sc_onewire, &buf[3], DS2423_COUNTER_BUFSZ-3); 182 183 crc = onewire_crc16(buf, DS2423_COUNTER_BUFSZ-2); 184 crc ^= buf[DS2423_COUNTER_BUF_CRC] 185 | (buf[DS2423_COUNTER_BUF_CRC+1] << 8); 186 if ( crc != 0xffff) { 187 printf("%s: invalid CRC\n", sc->sc_dev.dv_xname); 188 if (bank == DS2423_COUNTER_BANK_A) { 189 sc->sc_counterA.value = 0; 190 sc->sc_counterA.status = SENSOR_S_UNKNOWN; 191 sc->sc_counterA.flags |= SENSOR_FUNKNOWN; 192 } else { 193 sc->sc_counterB.value = 0; 194 sc->sc_counterB.status = SENSOR_S_UNKNOWN; 195 sc->sc_counterB.flags |= SENSOR_FUNKNOWN; 196 } 197 } else { 198 counter = buf[DS2423_COUNTER_BUF_COUNTER] 199 | (buf[DS2423_COUNTER_BUF_COUNTER+1] << 8) 200 | (buf[DS2423_COUNTER_BUF_COUNTER+2] << 16) 201 | (buf[DS2423_COUNTER_BUF_COUNTER+3] << 24); 202 if (bank == DS2423_COUNTER_BANK_A) { 203 sc->sc_counterA.value = counter; 204 sc->sc_counterA.status = SENSOR_S_UNSPEC; 205 sc->sc_counterA.flags &= ~SENSOR_FUNKNOWN; 206 } else { 207 sc->sc_counterB.value = counter; 208 sc->sc_counterB.status = SENSOR_S_UNSPEC; 209 sc->sc_counterB.flags &= ~SENSOR_FUNKNOWN; 210 } 211 } 212 213 onewire_reset(sc->sc_onewire); 214 free(buf, M_DEVBUF, DS2423_COUNTER_BUFSZ); 215 216done: 217 onewire_unlock(sc->sc_onewire); 218 rw_exit_write(&sc->sc_lock); 219}