1 /* $OpenBSD: owctr.c,v 1.4 2010/07/19 23:44:09 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/kernel.h> 29 #include <sys/malloc.h> 30 #include <sys/proc.h> 31 #include <sys/rwlock.h> 32 #include <sys/sensors.h> 33 34 #include <dev/onewire/onewiredevs.h> 35 #include <dev/onewire/onewirereg.h> 36 #include <dev/onewire/onewirevar.h> 37 38 /* Commands */ 39 #define DSCTR_CMD_READ_MEMCOUNTER 0xa5 40 41 /* External counter banks */ 42 #define DS2423_COUNTER_BANK_A 0x1c0 43 #define DS2423_COUNTER_BANK_B 0x1e0 44 45 /* Buffer offsets */ 46 #define DS2423_COUNTER_BUF_COUNTER 35 47 #define DS2423_COUNTER_BUF_CRC 43 48 49 #define DS2423_COUNTER_BUFSZ 45 50 51 struct owctr_softc { 52 struct device sc_dev; 53 54 void * sc_onewire; 55 u_int64_t sc_rom; 56 57 struct ksensordev sc_sensordev; 58 59 struct ksensor sc_counterA; 60 struct ksensor sc_counterB; 61 62 struct sensor_task *sc_sensortask; 63 64 struct rwlock sc_lock; 65 }; 66 67 int owctr_match(struct device *, void *, void *); 68 void owctr_attach(struct device *, struct device *, void *); 69 int owctr_detach(struct device *, int); 70 int owctr_activate(struct device *, int); 71 72 void owctr_update(void *); 73 void owctr_update_counter(void *, int); 74 75 struct cfattach owctr_ca = { 76 sizeof(struct owctr_softc), 77 owctr_match, 78 owctr_attach, 79 owctr_detach, 80 owctr_activate 81 }; 82 83 struct cfdriver owctr_cd = { 84 NULL, "owctr", DV_DULL 85 }; 86 87 static const struct onewire_matchfam owctr_fams[] = { 88 { ONEWIRE_FAMILY_DS2423 } 89 }; 90 91 int 92 owctr_match(struct device *parent, void *match, void *aux) 93 { 94 return (onewire_matchbyfam(aux, owctr_fams, nitems(owctr_fams))); 95 } 96 97 void 98 owctr_attach(struct device *parent, struct device *self, void *aux) 99 { 100 struct owctr_softc *sc = (struct owctr_softc *)self; 101 struct onewire_attach_args *oa = aux; 102 103 sc->sc_onewire = oa->oa_onewire; 104 sc->sc_rom = oa->oa_rom; 105 106 /* Initialize counter sensors */ 107 strlcpy(sc->sc_sensordev.xname, sc->sc_dev.dv_xname, 108 sizeof(sc->sc_sensordev.xname)); 109 sc->sc_counterA.type = SENSOR_INTEGER; 110 snprintf(sc->sc_counterA.desc, sizeof(sc->sc_counterA.desc), 111 "Counter A sn %012llx", ONEWIRE_ROM_SN(oa->oa_rom)); 112 sensor_attach(&sc->sc_sensordev, &sc->sc_counterA); 113 sc->sc_counterB.type = SENSOR_INTEGER; 114 snprintf(sc->sc_counterB.desc, sizeof(sc->sc_counterB.desc), 115 "Counter B sn %012llx", ONEWIRE_ROM_SN(oa->oa_rom)); 116 sensor_attach(&sc->sc_sensordev, &sc->sc_counterB); 117 118 sc->sc_sensortask = sensor_task_register(sc, owctr_update, 10); 119 if (sc->sc_sensortask == NULL) { 120 printf(": unable to register update task\n"); 121 return; 122 } 123 124 sensordev_install(&sc->sc_sensordev); 125 126 rw_init(&sc->sc_lock, sc->sc_dev.dv_xname); 127 printf("\n"); 128 } 129 130 int 131 owctr_detach(struct device *self, int flags) 132 { 133 struct owctr_softc *sc = (struct owctr_softc *)self; 134 135 rw_enter_write(&sc->sc_lock); 136 sensordev_deinstall(&sc->sc_sensordev); 137 if (sc->sc_sensortask != NULL) 138 sensor_task_unregister(sc->sc_sensortask); 139 rw_exit_write(&sc->sc_lock); 140 141 return (0); 142 } 143 144 int 145 owctr_activate(struct device *self, int act) 146 { 147 return (0); 148 } 149 150 void 151 owctr_update(void *arg) 152 { 153 owctr_update_counter(arg, DS2423_COUNTER_BANK_A); 154 owctr_update_counter(arg, DS2423_COUNTER_BANK_B); 155 } 156 157 void 158 owctr_update_counter(void *arg, int bank) 159 { 160 struct owctr_softc *sc = arg; 161 u_int32_t counter; 162 u_int16_t crc; 163 u_int8_t *buf; 164 165 rw_enter_write(&sc->sc_lock); 166 onewire_lock(sc->sc_onewire, 0); 167 if (onewire_reset(sc->sc_onewire) != 0) 168 goto done; 169 170 buf = malloc(DS2423_COUNTER_BUFSZ, M_DEVBUF, M_NOWAIT); 171 if (buf == NULL) { 172 printf("%s: malloc() failed\n", sc->sc_dev.dv_xname); 173 goto done; 174 } 175 176 onewire_matchrom(sc->sc_onewire, sc->sc_rom); 177 buf[0] = DSCTR_CMD_READ_MEMCOUNTER; 178 buf[1] = bank; 179 buf[2] = bank >> 8; 180 onewire_write_byte(sc->sc_onewire, buf[0]); 181 onewire_write_byte(sc->sc_onewire, buf[1]); 182 onewire_write_byte(sc->sc_onewire, buf[2]); 183 onewire_read_block(sc->sc_onewire, &buf[3], DS2423_COUNTER_BUFSZ-3); 184 185 crc = onewire_crc16(buf, DS2423_COUNTER_BUFSZ-2); 186 crc ^= buf[DS2423_COUNTER_BUF_CRC] 187 | (buf[DS2423_COUNTER_BUF_CRC+1] << 8); 188 if ( crc != 0xffff) { 189 printf("%s: invalid CRC\n", sc->sc_dev.dv_xname); 190 if (bank == DS2423_COUNTER_BANK_A) { 191 sc->sc_counterA.value = 0; 192 sc->sc_counterA.status = SENSOR_S_UNKNOWN; 193 sc->sc_counterA.flags |= SENSOR_FUNKNOWN; 194 } else { 195 sc->sc_counterB.value = 0; 196 sc->sc_counterB.status = SENSOR_S_UNKNOWN; 197 sc->sc_counterB.flags |= SENSOR_FUNKNOWN; 198 } 199 } else { 200 counter = buf[DS2423_COUNTER_BUF_COUNTER] 201 | (buf[DS2423_COUNTER_BUF_COUNTER+1] << 8) 202 | (buf[DS2423_COUNTER_BUF_COUNTER+2] << 16) 203 | (buf[DS2423_COUNTER_BUF_COUNTER+3] << 24); 204 if (bank == DS2423_COUNTER_BANK_A) { 205 sc->sc_counterA.value = counter; 206 sc->sc_counterA.status = SENSOR_S_UNSPEC; 207 sc->sc_counterA.flags &= ~SENSOR_FUNKNOWN; 208 } else { 209 sc->sc_counterB.value = counter; 210 sc->sc_counterB.status = SENSOR_S_UNSPEC; 211 sc->sc_counterB.flags &= ~SENSOR_FUNKNOWN; 212 } 213 } 214 215 onewire_reset(sc->sc_onewire); 216 free(buf, M_DEVBUF); 217 218 done: 219 onewire_unlock(sc->sc_onewire); 220 rw_exit_write(&sc->sc_lock); 221 } 222