xref: /openbsd-src/sys/dev/onewire/owctr.c (revision 898184e3e61f9129feb5978fad5a8c6865f00b92)
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