Line data Source code
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 0 : owctr_match(struct device *parent, void *match, void *aux)
91 : {
92 0 : return (onewire_matchbyfam(aux, owctr_fams, nitems(owctr_fams)));
93 : }
94 :
95 : void
96 0 : owctr_attach(struct device *parent, struct device *self, void *aux)
97 : {
98 0 : struct owctr_softc *sc = (struct owctr_softc *)self;
99 0 : struct onewire_attach_args *oa = aux;
100 :
101 0 : sc->sc_onewire = oa->oa_onewire;
102 0 : sc->sc_rom = oa->oa_rom;
103 :
104 : /* Initialize counter sensors */
105 0 : strlcpy(sc->sc_sensordev.xname, sc->sc_dev.dv_xname,
106 : sizeof(sc->sc_sensordev.xname));
107 0 : sc->sc_counterA.type = SENSOR_INTEGER;
108 0 : snprintf(sc->sc_counterA.desc, sizeof(sc->sc_counterA.desc),
109 0 : "Counter A sn %012llx", ONEWIRE_ROM_SN(oa->oa_rom));
110 0 : sensor_attach(&sc->sc_sensordev, &sc->sc_counterA);
111 0 : sc->sc_counterB.type = SENSOR_INTEGER;
112 0 : snprintf(sc->sc_counterB.desc, sizeof(sc->sc_counterB.desc),
113 0 : "Counter B sn %012llx", ONEWIRE_ROM_SN(oa->oa_rom));
114 0 : sensor_attach(&sc->sc_sensordev, &sc->sc_counterB);
115 :
116 0 : sc->sc_sensortask = sensor_task_register(sc, owctr_update, 10);
117 0 : if (sc->sc_sensortask == NULL) {
118 0 : printf(": unable to register update task\n");
119 0 : return;
120 : }
121 :
122 0 : sensordev_install(&sc->sc_sensordev);
123 :
124 0 : rw_init(&sc->sc_lock, sc->sc_dev.dv_xname);
125 0 : printf("\n");
126 0 : }
127 :
128 : int
129 0 : owctr_detach(struct device *self, int flags)
130 : {
131 0 : struct owctr_softc *sc = (struct owctr_softc *)self;
132 :
133 0 : rw_enter_write(&sc->sc_lock);
134 0 : sensordev_deinstall(&sc->sc_sensordev);
135 0 : if (sc->sc_sensortask != NULL)
136 0 : sensor_task_unregister(sc->sc_sensortask);
137 0 : rw_exit_write(&sc->sc_lock);
138 :
139 0 : return (0);
140 : }
141 :
142 : int
143 0 : owctr_activate(struct device *self, int act)
144 : {
145 0 : return (0);
146 : }
147 :
148 : void
149 0 : owctr_update(void *arg)
150 : {
151 0 : owctr_update_counter(arg, DS2423_COUNTER_BANK_A);
152 0 : owctr_update_counter(arg, DS2423_COUNTER_BANK_B);
153 0 : }
154 :
155 : void
156 0 : owctr_update_counter(void *arg, int bank)
157 : {
158 0 : struct owctr_softc *sc = arg;
159 : u_int32_t counter;
160 : u_int16_t crc;
161 : u_int8_t *buf;
162 :
163 0 : rw_enter_write(&sc->sc_lock);
164 0 : onewire_lock(sc->sc_onewire, 0);
165 0 : if (onewire_reset(sc->sc_onewire) != 0)
166 : goto done;
167 :
168 0 : buf = malloc(DS2423_COUNTER_BUFSZ, M_DEVBUF, M_NOWAIT);
169 0 : if (buf == NULL) {
170 0 : printf("%s: malloc() failed\n", sc->sc_dev.dv_xname);
171 0 : goto done;
172 : }
173 :
174 0 : onewire_matchrom(sc->sc_onewire, sc->sc_rom);
175 0 : buf[0] = DSCTR_CMD_READ_MEMCOUNTER;
176 0 : buf[1] = bank;
177 0 : buf[2] = bank >> 8;
178 0 : onewire_write_byte(sc->sc_onewire, buf[0]);
179 0 : onewire_write_byte(sc->sc_onewire, buf[1]);
180 0 : onewire_write_byte(sc->sc_onewire, buf[2]);
181 0 : onewire_read_block(sc->sc_onewire, &buf[3], DS2423_COUNTER_BUFSZ-3);
182 :
183 0 : crc = onewire_crc16(buf, DS2423_COUNTER_BUFSZ-2);
184 0 : crc ^= buf[DS2423_COUNTER_BUF_CRC]
185 0 : | (buf[DS2423_COUNTER_BUF_CRC+1] << 8);
186 0 : if ( crc != 0xffff) {
187 0 : printf("%s: invalid CRC\n", sc->sc_dev.dv_xname);
188 0 : if (bank == DS2423_COUNTER_BANK_A) {
189 0 : sc->sc_counterA.value = 0;
190 0 : sc->sc_counterA.status = SENSOR_S_UNKNOWN;
191 0 : sc->sc_counterA.flags |= SENSOR_FUNKNOWN;
192 0 : } else {
193 0 : sc->sc_counterB.value = 0;
194 0 : sc->sc_counterB.status = SENSOR_S_UNKNOWN;
195 0 : sc->sc_counterB.flags |= SENSOR_FUNKNOWN;
196 : }
197 : } else {
198 0 : counter = buf[DS2423_COUNTER_BUF_COUNTER]
199 0 : | (buf[DS2423_COUNTER_BUF_COUNTER+1] << 8)
200 0 : | (buf[DS2423_COUNTER_BUF_COUNTER+2] << 16)
201 0 : | (buf[DS2423_COUNTER_BUF_COUNTER+3] << 24);
202 0 : if (bank == DS2423_COUNTER_BANK_A) {
203 0 : sc->sc_counterA.value = counter;
204 0 : sc->sc_counterA.status = SENSOR_S_UNSPEC;
205 0 : sc->sc_counterA.flags &= ~SENSOR_FUNKNOWN;
206 0 : } else {
207 0 : sc->sc_counterB.value = counter;
208 0 : sc->sc_counterB.status = SENSOR_S_UNSPEC;
209 0 : sc->sc_counterB.flags &= ~SENSOR_FUNKNOWN;
210 : }
211 : }
212 :
213 0 : onewire_reset(sc->sc_onewire);
214 0 : free(buf, M_DEVBUF, DS2423_COUNTER_BUFSZ);
215 :
216 : done:
217 0 : onewire_unlock(sc->sc_onewire);
218 0 : rw_exit_write(&sc->sc_lock);
219 0 : }
|