1 /* $OpenBSD: owctr.c,v 1.8 2015/08/27 05:49:23 deraadt 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 49 struct 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 65 int owctr_match(struct device *, void *, void *); 66 void owctr_attach(struct device *, struct device *, void *); 67 int owctr_detach(struct device *, int); 68 int owctr_activate(struct device *, int); 69 70 void owctr_update(void *); 71 void owctr_update_counter(void *, int); 72 73 struct cfattach owctr_ca = { 74 sizeof(struct owctr_softc), 75 owctr_match, 76 owctr_attach, 77 owctr_detach, 78 owctr_activate 79 }; 80 81 struct cfdriver owctr_cd = { 82 NULL, "owctr", DV_DULL 83 }; 84 85 static const struct onewire_matchfam owctr_fams[] = { 86 { ONEWIRE_FAMILY_DS2423 } 87 }; 88 89 int 90 owctr_match(struct device *parent, void *match, void *aux) 91 { 92 return (onewire_matchbyfam(aux, owctr_fams, nitems(owctr_fams))); 93 } 94 95 void 96 owctr_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 128 int 129 owctr_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 142 int 143 owctr_activate(struct device *self, int act) 144 { 145 return (0); 146 } 147 148 void 149 owctr_update(void *arg) 150 { 151 owctr_update_counter(arg, DS2423_COUNTER_BANK_A); 152 owctr_update_counter(arg, DS2423_COUNTER_BANK_B); 153 } 154 155 void 156 owctr_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 216 done: 217 onewire_unlock(sc->sc_onewire); 218 rw_exit_write(&sc->sc_lock); 219 } 220