xref: /freebsd/sys/dev/ow/ow.c (revision 1bce6aaf96ec117615a459d3a562a80e601b8ca1)
1ae1f3df4SWarner Losh /*-
2ae1f3df4SWarner Losh  * Copyright (c) 2015 M. Warner Losh <imp@freebsd.org>
3ae1f3df4SWarner Losh  * All rights reserved.
4ae1f3df4SWarner Losh  *
5ae1f3df4SWarner Losh  * Redistribution and use in source and binary forms, with or without
6ae1f3df4SWarner Losh  * modification, are permitted provided that the following conditions
7ae1f3df4SWarner Losh  * are met:
8ae1f3df4SWarner Losh  * 1. Redistributions of source code must retain the above copyright
9ae1f3df4SWarner Losh  *    notice unmodified, this list of conditions, and the following
10ae1f3df4SWarner Losh  *    disclaimer.
11ae1f3df4SWarner Losh  * 2. Redistributions in binary form must reproduce the above copyright
12ae1f3df4SWarner Losh  *    notice, this list of conditions and the following disclaimer in the
13ae1f3df4SWarner Losh  *    documentation and/or other materials provided with the distribution.
14ae1f3df4SWarner Losh  *
15ae1f3df4SWarner Losh  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16ae1f3df4SWarner Losh  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17ae1f3df4SWarner Losh  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18ae1f3df4SWarner Losh  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19ae1f3df4SWarner Losh  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20ae1f3df4SWarner Losh  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21ae1f3df4SWarner Losh  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22ae1f3df4SWarner Losh  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23ae1f3df4SWarner Losh  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24ae1f3df4SWarner Losh  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25ae1f3df4SWarner Losh  */
26ae1f3df4SWarner Losh 
27ae1f3df4SWarner Losh #include <sys/cdefs.h>
28ae1f3df4SWarner Losh __FBSDID("$FreeBSD$");
29ae1f3df4SWarner Losh 
30ae1f3df4SWarner Losh #include <sys/param.h>
31ae1f3df4SWarner Losh #include <sys/systm.h>
32ae1f3df4SWarner Losh #include <sys/kernel.h>
33ae1f3df4SWarner Losh 
34ae1f3df4SWarner Losh #include <sys/bus.h>
35ae1f3df4SWarner Losh #include <sys/errno.h>
36ae1f3df4SWarner Losh #include <sys/libkern.h>
37e2e050c8SConrad Meyer #include <sys/lock.h>
38ae1f3df4SWarner Losh #include <sys/malloc.h>
39ae1f3df4SWarner Losh #include <sys/module.h>
40e2e050c8SConrad Meyer #include <sys/mutex.h>
41*1bce6aafSAndriy Gapon #include <sys/sysctl.h>
42ae1f3df4SWarner Losh 
43ae1f3df4SWarner Losh #include <dev/ow/ow.h>
44ae1f3df4SWarner Losh #include <dev/ow/owll.h>
45ae1f3df4SWarner Losh #include <dev/ow/own.h>
46ae1f3df4SWarner Losh 
47ae1f3df4SWarner Losh /*
48ae1f3df4SWarner Losh  * lldev - link level device
49ae1f3df4SWarner Losh  * ndev - network / transport device (this module)
50ae1f3df4SWarner Losh  * pdev - presentation device (children of this module)
51ae1f3df4SWarner Losh  */
52ae1f3df4SWarner Losh 
53ae1f3df4SWarner Losh typedef int ow_enum_fn(device_t, device_t);
54ae1f3df4SWarner Losh typedef int ow_found_fn(device_t, romid_t);
55ae1f3df4SWarner Losh 
56ae1f3df4SWarner Losh struct ow_softc
57ae1f3df4SWarner Losh {
58ae1f3df4SWarner Losh 	device_t	dev;		/* Newbus driver back pointer */
59ae1f3df4SWarner Losh 	struct mtx	mtx;		/* bus mutex */
60ae1f3df4SWarner Losh 	device_t	owner;		/* bus owner, if != NULL */
61ae1f3df4SWarner Losh };
62ae1f3df4SWarner Losh 
63ae1f3df4SWarner Losh struct ow_devinfo
64ae1f3df4SWarner Losh {
65ae1f3df4SWarner Losh 	romid_t	romid;
66ae1f3df4SWarner Losh };
67ae1f3df4SWarner Losh 
68ae1f3df4SWarner Losh static int ow_acquire_bus(device_t ndev, device_t pdev, int how);
69ae1f3df4SWarner Losh static void ow_release_bus(device_t ndev, device_t pdev);
70ae1f3df4SWarner Losh 
71ae1f3df4SWarner Losh #define	OW_LOCK(_sc) mtx_lock(&(_sc)->mtx)
72ae1f3df4SWarner Losh #define	OW_UNLOCK(_sc) mtx_unlock(&(_sc)->mtx)
73ae1f3df4SWarner Losh #define	OW_LOCK_DESTROY(_sc) mtx_destroy(&_sc->mtx)
74ae1f3df4SWarner Losh #define	OW_ASSERT_LOCKED(_sc) mtx_assert(&_sc->mtx, MA_OWNED)
75ae1f3df4SWarner Losh #define	OW_ASSERT_UNLOCKED(_sc) mtx_assert(&_sc->mtx, MA_NOTOWNED)
76ae1f3df4SWarner Losh 
77ae1f3df4SWarner Losh static MALLOC_DEFINE(M_OW, "ow", "House keeping data for 1wire bus");
78ae1f3df4SWarner Losh 
79*1bce6aafSAndriy Gapon static const struct ow_timing timing_regular_min = {
80*1bce6aafSAndriy Gapon 	.t_slot = 60,
81*1bce6aafSAndriy Gapon 	.t_low0 = 60,
82*1bce6aafSAndriy Gapon 	.t_low1 = 1,
83*1bce6aafSAndriy Gapon 	.t_release = 0,
84*1bce6aafSAndriy Gapon 	.t_rec = 1,
85*1bce6aafSAndriy Gapon 	.t_rdv = 15,		/* fixed */
86*1bce6aafSAndriy Gapon 	.t_rstl = 480,
87*1bce6aafSAndriy Gapon 	.t_rsth = 480,
88*1bce6aafSAndriy Gapon 	.t_pdl = 60,
89*1bce6aafSAndriy Gapon 	.t_pdh = 15,
90*1bce6aafSAndriy Gapon 	.t_lowr = 1,
91*1bce6aafSAndriy Gapon };
92*1bce6aafSAndriy Gapon 
93*1bce6aafSAndriy Gapon static const struct ow_timing timing_regular_max = {
94*1bce6aafSAndriy Gapon 	.t_slot = 120,
95*1bce6aafSAndriy Gapon 	.t_low0 = 120,
96*1bce6aafSAndriy Gapon 	.t_low1 = 15,
97*1bce6aafSAndriy Gapon 	.t_release = 45,
98*1bce6aafSAndriy Gapon 	.t_rec = 960,		/* infinity */
99*1bce6aafSAndriy Gapon 	.t_rdv = 15,		/* fixed */
100*1bce6aafSAndriy Gapon 	.t_rstl = 960,		/* infinity */
101*1bce6aafSAndriy Gapon 	.t_rsth = 960,		/* infinity */
102*1bce6aafSAndriy Gapon 	.t_pdl = 240,		/* 60us to 240us */
103ae1f3df4SWarner Losh 	.t_pdh = 60,		/* 15us to 60us */
104*1bce6aafSAndriy Gapon 	.t_lowr = 15,		/* 1us */
105*1bce6aafSAndriy Gapon };
106*1bce6aafSAndriy Gapon 
107*1bce6aafSAndriy Gapon static struct ow_timing timing_regular = {
108*1bce6aafSAndriy Gapon 	.t_slot = 60,		/*  60 <= t < 120 */
109*1bce6aafSAndriy Gapon 	.t_low0 = 60,		/*  60 <= t < t_slot < 120 */
110*1bce6aafSAndriy Gapon 	.t_low1 = 1,		/*   1 <= t < 15 */
111*1bce6aafSAndriy Gapon 	.t_release = 45,	/*   0 <= t < 45 */
112*1bce6aafSAndriy Gapon 	.t_rec = 15,		/*   1 <= t < inf */
113*1bce6aafSAndriy Gapon 	.t_rdv = 15,		/* t == 15 */
114*1bce6aafSAndriy Gapon 	.t_rstl = 480,		/* 480 <= t < inf */
115*1bce6aafSAndriy Gapon 	.t_rsth = 480,		/* 480 <= t < inf */
116*1bce6aafSAndriy Gapon 	.t_pdl = 60,		/*  60 <= t < 240 */
117*1bce6aafSAndriy Gapon 	.t_pdh = 60,		/*  15 <= t < 60 */
118*1bce6aafSAndriy Gapon 	.t_lowr = 1,		/*   1 <= t < 15 */
119ae1f3df4SWarner Losh };
120ae1f3df4SWarner Losh 
121ae1f3df4SWarner Losh /* NB: Untested */
122*1bce6aafSAndriy Gapon static const struct ow_timing timing_overdrive_min = {
123*1bce6aafSAndriy Gapon 	.t_slot = 6,
124*1bce6aafSAndriy Gapon 	.t_low0 = 6,
125*1bce6aafSAndriy Gapon 	.t_low1 = 1,
126*1bce6aafSAndriy Gapon 	.t_release = 0,
127*1bce6aafSAndriy Gapon 	.t_rec = 1,
128*1bce6aafSAndriy Gapon 	.t_rdv = 2,		/* fixed */
129*1bce6aafSAndriy Gapon 	.t_rstl = 48,
130*1bce6aafSAndriy Gapon 	.t_rsth = 48,
131*1bce6aafSAndriy Gapon 	.t_pdl = 8,
132*1bce6aafSAndriy Gapon 	.t_pdh = 2,
133*1bce6aafSAndriy Gapon 	.t_lowr = 1,
134ae1f3df4SWarner Losh };
135ae1f3df4SWarner Losh 
136*1bce6aafSAndriy Gapon static const struct ow_timing timing_overdrive_max = {
137*1bce6aafSAndriy Gapon 	.t_slot = 16,
138*1bce6aafSAndriy Gapon 	.t_low0 = 16,
139*1bce6aafSAndriy Gapon 	.t_low1 = 2,
140*1bce6aafSAndriy Gapon 	.t_release = 4,
141*1bce6aafSAndriy Gapon 	.t_rec = 960,		/* infinity */
142*1bce6aafSAndriy Gapon 	.t_rdv = 2,		/* fixed */
143*1bce6aafSAndriy Gapon 	.t_rstl = 80,
144*1bce6aafSAndriy Gapon 	.t_rsth = 960,		/* infinity */
145*1bce6aafSAndriy Gapon 	.t_pdl = 24,
146*1bce6aafSAndriy Gapon 	.t_pdh = 6,
147*1bce6aafSAndriy Gapon 	.t_lowr = 2,
148*1bce6aafSAndriy Gapon };
149*1bce6aafSAndriy Gapon 
150*1bce6aafSAndriy Gapon static struct ow_timing timing_overdrive = {
151*1bce6aafSAndriy Gapon 	.t_slot = 11,		/* 6 <= t < 16 */
152*1bce6aafSAndriy Gapon 	.t_low0 = 6,		/* 6 <= t < t_slot < 16 */
153*1bce6aafSAndriy Gapon 	.t_low1 = 1,		/* 1 <= t < 2 */
154*1bce6aafSAndriy Gapon 	.t_release = 4,		/* 0 <= t < 4 */
155*1bce6aafSAndriy Gapon 	.t_rec = 1,		/* 1 <= t < inf */
156*1bce6aafSAndriy Gapon 	.t_rdv = 2,		/* t == 2 */
157*1bce6aafSAndriy Gapon 	.t_rstl = 48,		/* 48 <= t < 80 */
158*1bce6aafSAndriy Gapon 	.t_rsth = 48,		/* 48 <= t < inf */
159*1bce6aafSAndriy Gapon 	.t_pdl = 8,		/* 8 <= t < 24 */
160*1bce6aafSAndriy Gapon 	.t_pdh = 2,		/* 2 <= t < 6 */
161*1bce6aafSAndriy Gapon 	.t_lowr = 1,		/* 1 <= t < 2 */
162*1bce6aafSAndriy Gapon };
163*1bce6aafSAndriy Gapon 
164*1bce6aafSAndriy Gapon SYSCTL_DECL(_hw);
165*1bce6aafSAndriy Gapon SYSCTL_NODE(_hw, OID_AUTO, ow, CTLFLAG_RD, 0, "1-Wire protocol");
166*1bce6aafSAndriy Gapon SYSCTL_NODE(_hw_ow, OID_AUTO, regular, CTLFLAG_RD, 0,
167*1bce6aafSAndriy Gapon     "Regular mode timings");
168*1bce6aafSAndriy Gapon SYSCTL_NODE(_hw_ow, OID_AUTO, overdrive, CTLFLAG_RD, 0,
169*1bce6aafSAndriy Gapon     "Overdrive mode timings");
170*1bce6aafSAndriy Gapon 
171*1bce6aafSAndriy Gapon #define	_OW_TIMING_SYSCTL(mode, param)		\
172*1bce6aafSAndriy Gapon     static int \
173*1bce6aafSAndriy Gapon     sysctl_ow_timing_ ## mode ## _ ## param(SYSCTL_HANDLER_ARGS) \
174*1bce6aafSAndriy Gapon     { \
175*1bce6aafSAndriy Gapon 	    int val = timing_ ## mode.param; \
176*1bce6aafSAndriy Gapon 	    int err; \
177*1bce6aafSAndriy Gapon 	    err = sysctl_handle_int(oidp, &val, 0, req); \
178*1bce6aafSAndriy Gapon 	    if (err != 0 || req->newptr == NULL) \
179*1bce6aafSAndriy Gapon 		return (err); \
180*1bce6aafSAndriy Gapon 	    if (val < timing_ ## mode ## _min.param) \
181*1bce6aafSAndriy Gapon 		return (EINVAL); \
182*1bce6aafSAndriy Gapon 	    else if (val >= timing_ ## mode ## _max.param) \
183*1bce6aafSAndriy Gapon 		return (EINVAL); \
184*1bce6aafSAndriy Gapon 	    timing_ ## mode.param = val; \
185*1bce6aafSAndriy Gapon 	    return (0); \
186*1bce6aafSAndriy Gapon     } \
187*1bce6aafSAndriy Gapon SYSCTL_PROC(_hw_ow_ ## mode, OID_AUTO, param, \
188*1bce6aafSAndriy Gapon     CTLTYPE_INT | CTLFLAG_RWTUN, 0, sizeof(int), \
189*1bce6aafSAndriy Gapon     sysctl_ow_timing_ ## mode ## _ ## param, "I", \
190*1bce6aafSAndriy Gapon     "1-Wire timing parameter in microseconds (-1 resets to default)")
191*1bce6aafSAndriy Gapon 
192*1bce6aafSAndriy Gapon #define	OW_TIMING_SYSCTL(param)	\
193*1bce6aafSAndriy Gapon     _OW_TIMING_SYSCTL(regular, param); \
194*1bce6aafSAndriy Gapon     _OW_TIMING_SYSCTL(overdrive, param)
195*1bce6aafSAndriy Gapon 
196*1bce6aafSAndriy Gapon OW_TIMING_SYSCTL(t_slot);
197*1bce6aafSAndriy Gapon OW_TIMING_SYSCTL(t_low0);
198*1bce6aafSAndriy Gapon OW_TIMING_SYSCTL(t_low1);
199*1bce6aafSAndriy Gapon OW_TIMING_SYSCTL(t_release);
200*1bce6aafSAndriy Gapon OW_TIMING_SYSCTL(t_rec);
201*1bce6aafSAndriy Gapon OW_TIMING_SYSCTL(t_rdv);
202*1bce6aafSAndriy Gapon OW_TIMING_SYSCTL(t_rstl);
203*1bce6aafSAndriy Gapon OW_TIMING_SYSCTL(t_rsth);
204*1bce6aafSAndriy Gapon OW_TIMING_SYSCTL(t_pdl);
205*1bce6aafSAndriy Gapon OW_TIMING_SYSCTL(t_pdh);
206*1bce6aafSAndriy Gapon OW_TIMING_SYSCTL(t_lowr);
207*1bce6aafSAndriy Gapon 
208*1bce6aafSAndriy Gapon #undef _OW_TIMING_SYSCTL
209*1bce6aafSAndriy Gapon #undef OW_TIMING_SYSCTL
210*1bce6aafSAndriy Gapon 
211ae1f3df4SWarner Losh static void
212ae1f3df4SWarner Losh ow_send_byte(device_t lldev, struct ow_timing *t, uint8_t byte)
213ae1f3df4SWarner Losh {
214ae1f3df4SWarner Losh 	int i;
215ae1f3df4SWarner Losh 
216ae1f3df4SWarner Losh 	for (i = 0; i < 8; i++)
217ae1f3df4SWarner Losh 		if (byte & (1 << i))
218ae1f3df4SWarner Losh 			OWLL_WRITE_ONE(lldev, t);
219ae1f3df4SWarner Losh 		else
220ae1f3df4SWarner Losh 			OWLL_WRITE_ZERO(lldev, t);
221ae1f3df4SWarner Losh }
222ae1f3df4SWarner Losh 
223ae1f3df4SWarner Losh static void
224ae1f3df4SWarner Losh ow_read_byte(device_t lldev, struct ow_timing *t, uint8_t *bytep)
225ae1f3df4SWarner Losh {
226ae1f3df4SWarner Losh 	int i;
227ae1f3df4SWarner Losh 	uint8_t byte = 0;
228ae1f3df4SWarner Losh 	int bit;
229ae1f3df4SWarner Losh 
230ae1f3df4SWarner Losh 	for (i = 0; i < 8; i++) {
231ae1f3df4SWarner Losh 		OWLL_READ_DATA(lldev, t, &bit);
232ae1f3df4SWarner Losh 		byte |= bit << i;
233ae1f3df4SWarner Losh 	}
234ae1f3df4SWarner Losh 	*bytep = byte;
235ae1f3df4SWarner Losh }
236ae1f3df4SWarner Losh 
237ae1f3df4SWarner Losh static int
238ae1f3df4SWarner Losh ow_send_command(device_t ndev, device_t pdev, struct ow_cmd *cmd)
239ae1f3df4SWarner Losh {
240ae1f3df4SWarner Losh 	int present, i, bit, tries;
241ae1f3df4SWarner Losh 	device_t lldev;
242ae1f3df4SWarner Losh 	struct ow_timing *t;
243ae1f3df4SWarner Losh 
244ae1f3df4SWarner Losh 	lldev = device_get_parent(ndev);
245ae1f3df4SWarner Losh 
246ae1f3df4SWarner Losh 	/*
247ae1f3df4SWarner Losh 	 * Retry the reset a couple of times before giving up.
248ae1f3df4SWarner Losh 	 */
249ae1f3df4SWarner Losh 	tries = 4;
250ae1f3df4SWarner Losh 	do {
251ae1f3df4SWarner Losh 		OWLL_RESET_AND_PRESENCE(lldev, &timing_regular, &present);
252ae1f3df4SWarner Losh 		if (present == 1)
253ae1f3df4SWarner Losh 			device_printf(ndev, "Reset said no device on bus?.\n");
254ae1f3df4SWarner Losh 	} while (present == 1 && tries-- > 0);
255ae1f3df4SWarner Losh 	if (present == 1) {
256ae1f3df4SWarner Losh 		device_printf(ndev, "Reset said the device wasn't there.\n");
257ae1f3df4SWarner Losh 		return ENOENT;		/* No devices acked the RESET */
258ae1f3df4SWarner Losh 	}
259ae1f3df4SWarner Losh 	if (present == -1) {
260ae1f3df4SWarner Losh 		device_printf(ndev, "Reset discovered bus wired wrong.\n");
261ae1f3df4SWarner Losh 		return ENOENT;
262ae1f3df4SWarner Losh 	}
263ae1f3df4SWarner Losh 
264ae1f3df4SWarner Losh 	for (i = 0; i < cmd->rom_len; i++)
265ae1f3df4SWarner Losh 		ow_send_byte(lldev, &timing_regular, cmd->rom_cmd[i]);
266ae1f3df4SWarner Losh 	for (i = 0; i < cmd->rom_read_len; i++)
267ae1f3df4SWarner Losh 		ow_read_byte(lldev, &timing_regular, cmd->rom_read + i);
268ae1f3df4SWarner Losh 	if (cmd->xpt_len) {
269ae1f3df4SWarner Losh 		/*
270ae1f3df4SWarner Losh 		 * Per AN937, the reset pulse and ROM level are always
271ae1f3df4SWarner Losh 		 * done with the regular timings. Certain ROM commands
272ae1f3df4SWarner Losh 		 * put the device into overdrive mode for the remainder
273ae1f3df4SWarner Losh 		 * of the data transfer, which is why we have to pass the
274ae1f3df4SWarner Losh 		 * timings here. Commands that need to be handled like this
275ae1f3df4SWarner Losh 		 * are expected to be flagged by the client.
276ae1f3df4SWarner Losh 		 */
277ae1f3df4SWarner Losh 		t = (cmd->flags & OW_FLAG_OVERDRIVE) ?
278ae1f3df4SWarner Losh 		    &timing_overdrive : &timing_regular;
279ae1f3df4SWarner Losh 		for (i = 0; i < cmd->xpt_len; i++)
280ae1f3df4SWarner Losh 			ow_send_byte(lldev, t, cmd->xpt_cmd[i]);
281ae1f3df4SWarner Losh 		if (cmd->flags & OW_FLAG_READ_BIT) {
282ae1f3df4SWarner Losh 			memset(cmd->xpt_read, 0, (cmd->xpt_read_len + 7) / 8);
283ae1f3df4SWarner Losh 			for (i = 0; i < cmd->xpt_read_len; i++) {
284ae1f3df4SWarner Losh 				OWLL_READ_DATA(lldev, t, &bit);
285ae1f3df4SWarner Losh 				cmd->xpt_read[i / 8] |= bit << (i % 8);
286ae1f3df4SWarner Losh 			}
287ae1f3df4SWarner Losh 		} else {
288ae1f3df4SWarner Losh 			for (i = 0; i < cmd->xpt_read_len; i++)
289ae1f3df4SWarner Losh 				ow_read_byte(lldev, t, cmd->xpt_read + i);
290ae1f3df4SWarner Losh 		}
291ae1f3df4SWarner Losh 	}
292ae1f3df4SWarner Losh 	return 0;
293ae1f3df4SWarner Losh }
294ae1f3df4SWarner Losh 
295ae1f3df4SWarner Losh static int
296ae1f3df4SWarner Losh ow_search_rom(device_t lldev, device_t dev)
297ae1f3df4SWarner Losh {
298ae1f3df4SWarner Losh 	struct ow_cmd cmd;
299ae1f3df4SWarner Losh 
300ae1f3df4SWarner Losh 	memset(&cmd, 0, sizeof(cmd));
301ae1f3df4SWarner Losh 	cmd.rom_cmd[0] = SEARCH_ROM;
302ae1f3df4SWarner Losh 	cmd.rom_len = 1;
303ae1f3df4SWarner Losh 	return ow_send_command(lldev, dev, &cmd);
304ae1f3df4SWarner Losh }
305ae1f3df4SWarner Losh 
306ae1f3df4SWarner Losh #if 0
307ae1f3df4SWarner Losh static int
308ae1f3df4SWarner Losh ow_alarm_search(device_t lldev, device_t dev)
309ae1f3df4SWarner Losh {
310ae1f3df4SWarner Losh 	struct ow_cmd cmd;
311ae1f3df4SWarner Losh 
312ae1f3df4SWarner Losh 	memset(&cmd, 0, sizeof(cmd));
313ae1f3df4SWarner Losh 	cmd.rom_cmd[0] = ALARM_SEARCH;
314ae1f3df4SWarner Losh 	cmd.rom_len = 1;
315ae1f3df4SWarner Losh 	return ow_send_command(lldev, dev, &cmd);
316ae1f3df4SWarner Losh }
317ae1f3df4SWarner Losh #endif
318ae1f3df4SWarner Losh 
319ae1f3df4SWarner Losh static int
320ae1f3df4SWarner Losh ow_add_child(device_t dev, romid_t romid)
321ae1f3df4SWarner Losh {
322ae1f3df4SWarner Losh 	struct ow_devinfo *di;
323ae1f3df4SWarner Losh 	device_t child;
324ae1f3df4SWarner Losh 
325ae1f3df4SWarner Losh 	di = malloc(sizeof(*di), M_OW, M_WAITOK);
326ae1f3df4SWarner Losh 	di->romid = romid;
327ae1f3df4SWarner Losh 	child = device_add_child(dev, NULL, -1);
328ae1f3df4SWarner Losh 	if (child == NULL) {
329ae1f3df4SWarner Losh 		free(di, M_OW);
330ae1f3df4SWarner Losh 		return ENOMEM;
331ae1f3df4SWarner Losh 	}
332ae1f3df4SWarner Losh 	device_set_ivars(child, di);
333ae1f3df4SWarner Losh 	return (0);
334ae1f3df4SWarner Losh }
335ae1f3df4SWarner Losh 
336ae1f3df4SWarner Losh static device_t
337ae1f3df4SWarner Losh ow_child_by_romid(device_t dev, romid_t romid)
338ae1f3df4SWarner Losh {
339ae1f3df4SWarner Losh 	device_t *children, retval, child;
340ae1f3df4SWarner Losh 	int nkid, i;
341ae1f3df4SWarner Losh 	struct ow_devinfo *di;
342ae1f3df4SWarner Losh 
343ae1f3df4SWarner Losh 	if (device_get_children(dev, &children, &nkid) != 0)
344ae1f3df4SWarner Losh 		return (NULL);
345ae1f3df4SWarner Losh 	retval = NULL;
346ae1f3df4SWarner Losh 	for (i = 0; i < nkid; i++) {
347ae1f3df4SWarner Losh 		child = children[i];
348ae1f3df4SWarner Losh 		di = device_get_ivars(child);
349ae1f3df4SWarner Losh 		if (di->romid == romid) {
350ae1f3df4SWarner Losh 			retval = child;
351ae1f3df4SWarner Losh 			break;
352ae1f3df4SWarner Losh 		}
353ae1f3df4SWarner Losh 	}
354ae1f3df4SWarner Losh 	free(children, M_TEMP);
355ae1f3df4SWarner Losh 
356ae1f3df4SWarner Losh 	return (retval);
357ae1f3df4SWarner Losh }
358ae1f3df4SWarner Losh 
359ae1f3df4SWarner Losh /*
360ae1f3df4SWarner Losh  * CRC generator table -- taken from AN937 DOW CRC LOOKUP FUNCTION Table 2
361ae1f3df4SWarner Losh  */
362ae1f3df4SWarner Losh const uint8_t ow_crc_table[] = {
363ae1f3df4SWarner Losh 	0, 94, 188, 226, 97, 63, 221, 131, 194, 156, 126, 32, 163, 253, 31, 65,
364ae1f3df4SWarner Losh 	157, 195, 33, 127, 252, 162, 64, 30, 95, 1, 227, 189, 62, 96, 130, 220,
365ae1f3df4SWarner Losh 	35, 125, 159, 193, 66, 28, 254, 160, 225, 191, 93, 3, 128, 222, 60, 98,
366ae1f3df4SWarner Losh 	190, 224, 2, 92, 223, 129, 99, 61, 124, 34, 192, 158, 29, 67, 161, 255,
367ae1f3df4SWarner Losh 	70, 24, 250, 164, 39, 121, 155, 197, 132, 218, 56, 102, 229, 187, 89, 7,
368ae1f3df4SWarner Losh 	219, 133,103, 57, 186, 228, 6, 88, 25, 71, 165, 251, 120, 38, 196, 154,
369ae1f3df4SWarner Losh 	101, 59, 217, 135, 4, 90, 184, 230, 167, 249, 27, 69, 198, 152, 122, 36,
370ae1f3df4SWarner Losh 	248, 166, 68, 26, 153, 199, 37, 123, 58, 100, 134, 216, 91, 5, 231, 185,
371ae1f3df4SWarner Losh 	140,210, 48, 110, 237, 179, 81, 15, 78, 16, 242,  172, 47, 113,147, 205,
372ae1f3df4SWarner Losh 	17, 79, 173, 243, 112, 46, 204, 146, 211,141, 111, 49, 178, 236, 14, 80,
373ae1f3df4SWarner Losh 	175, 241, 19, 77, 206, 144, 114, 44, 109, 51, 209, 143, 12, 82,176, 238,
374ae1f3df4SWarner Losh 	50, 108, 142, 208, 83, 13, 239, 177, 240, 174, 76, 18, 145, 207, 45, 115,
375ae1f3df4SWarner Losh 	202, 148, 118, 40, 171, 245, 23, 73, 8, 86, 180, 234, 105, 55, 213, 139,
376ae1f3df4SWarner Losh 	87, 9, 235, 181, 54, 104, 138, 212, 149, 203, 41, 119, 244, 170, 72, 22,
377ae1f3df4SWarner Losh 	233, 183, 85, 11, 136, 214, 52, 106, 43, 117, 151, 201, 74, 20, 246, 168,
378ae1f3df4SWarner Losh 	116, 42, 200, 150, 21, 75, 169, 247, 182, 232, 10, 84, 215, 137, 107, 53
379ae1f3df4SWarner Losh };
380ae1f3df4SWarner Losh 
381ae1f3df4SWarner Losh /*
382ae1f3df4SWarner Losh  * Converted from DO_CRC page 131 ANN937
383ae1f3df4SWarner Losh  */
384ae1f3df4SWarner Losh static uint8_t
385ae1f3df4SWarner Losh ow_crc(device_t ndev, device_t pdev, uint8_t *buffer, size_t len)
386ae1f3df4SWarner Losh {
387ae1f3df4SWarner Losh 	uint8_t crc = 0;
388ae1f3df4SWarner Losh 	int i;
389ae1f3df4SWarner Losh 
390ae1f3df4SWarner Losh 	for (i = 0; i < len; i++)
391ae1f3df4SWarner Losh 		crc = ow_crc_table[crc ^ buffer[i]];
392ae1f3df4SWarner Losh 	return crc;
393ae1f3df4SWarner Losh }
394ae1f3df4SWarner Losh 
395ae1f3df4SWarner Losh static int
396ae1f3df4SWarner Losh ow_check_crc(romid_t romid)
397ae1f3df4SWarner Losh {
398ae1f3df4SWarner Losh 	return ow_crc(NULL, NULL, (uint8_t *)&romid, sizeof(romid)) == 0;
399ae1f3df4SWarner Losh }
400ae1f3df4SWarner Losh 
401ae1f3df4SWarner Losh static int
402ae1f3df4SWarner Losh ow_device_found(device_t dev, romid_t romid)
403ae1f3df4SWarner Losh {
404ae1f3df4SWarner Losh 
405ae1f3df4SWarner Losh 	/* XXX Move this up into enumerate? */
406ae1f3df4SWarner Losh 	/*
407ae1f3df4SWarner Losh 	 * All valid ROM IDs have a valid CRC. Check that first.
408ae1f3df4SWarner Losh 	 */
409ae1f3df4SWarner Losh 	if (!ow_check_crc(romid)) {
410ae1f3df4SWarner Losh 		device_printf(dev, "Device romid %8D failed CRC.\n",
411ae1f3df4SWarner Losh 		    &romid, ":");
412ae1f3df4SWarner Losh 		return EINVAL;
413ae1f3df4SWarner Losh 	}
414ae1f3df4SWarner Losh 
415ae1f3df4SWarner Losh 	/*
416ae1f3df4SWarner Losh 	 * If we've seen this child before, don't add a new one for it.
417ae1f3df4SWarner Losh 	 */
418ae1f3df4SWarner Losh 	if (ow_child_by_romid(dev, romid) != NULL)
419ae1f3df4SWarner Losh 		return 0;
420ae1f3df4SWarner Losh 
421ae1f3df4SWarner Losh 	return ow_add_child(dev, romid);
422ae1f3df4SWarner Losh }
423ae1f3df4SWarner Losh 
424ae1f3df4SWarner Losh static int
425ae1f3df4SWarner Losh ow_enumerate(device_t dev, ow_enum_fn *enumfp, ow_found_fn *foundfp)
426ae1f3df4SWarner Losh {
427ae1f3df4SWarner Losh 	device_t lldev = device_get_parent(dev);
428ae1f3df4SWarner Losh 	int first, second, i, dir, prior, last, err, retries;
429ae1f3df4SWarner Losh 	uint64_t probed, last_mask;
430ae1f3df4SWarner Losh 	int sanity = 10;
431ae1f3df4SWarner Losh 
432ae1f3df4SWarner Losh 	prior = -1;
433ae1f3df4SWarner Losh 	last_mask = 0;
434ae1f3df4SWarner Losh 	retries = 0;
435ae1f3df4SWarner Losh 	last = -2;
436ae1f3df4SWarner Losh 	err = ow_acquire_bus(dev, dev, OWN_DONTWAIT);
437ae1f3df4SWarner Losh 	if (err != 0)
438ae1f3df4SWarner Losh 		return err;
439ae1f3df4SWarner Losh 	while (last != -1) {
440ae1f3df4SWarner Losh 		if (sanity-- < 0) {
441ae1f3df4SWarner Losh 			printf("Reached the sanity limit\n");
442ae1f3df4SWarner Losh 			return EIO;
443ae1f3df4SWarner Losh 		}
444ae1f3df4SWarner Losh again:
445ae1f3df4SWarner Losh 		probed = 0;
446ae1f3df4SWarner Losh 		last = -1;
447ae1f3df4SWarner Losh 
448ae1f3df4SWarner Losh 		/*
449ae1f3df4SWarner Losh 		 * See AN397 section 5.II.C.3 for the algorithm (though a bit
450ae1f3df4SWarner Losh 		 * poorly stated). The search command forces each device to
451ae1f3df4SWarner Losh 		 * send ROM ID bits one at a time (first the bit, then the
452cef367e6SEitan Adler 		 * complement) the master (us) sends back a bit. If the
453ae1f3df4SWarner Losh 		 * device's bit doesn't match what we send back, that device
454ae1f3df4SWarner Losh 		 * stops sending bits back. So each time through we remember
455ae1f3df4SWarner Losh 		 * where we made the last decision (always 0). If there's a
456ae1f3df4SWarner Losh 		 * conflict there this time (and there will be in the absence
457ae1f3df4SWarner Losh 		 * of a hardware failure) we go with 1. This way, we prune the
458ae1f3df4SWarner Losh 		 * devices on the bus and wind up with a unique ROM. We know
459ae1f3df4SWarner Losh 		 * we're done when we detect no new conflicts. The same
460ae1f3df4SWarner Losh 		 * algorithm is used for devices in alarm state as well.
461ae1f3df4SWarner Losh 		 *
462ae1f3df4SWarner Losh 		 * In addition, experience has shown that sometimes devices
463ae1f3df4SWarner Losh 		 * stop responding in the middle of enumeration, so try this
464ae1f3df4SWarner Losh 		 * step again a few times when that happens. It is unclear if
465ae1f3df4SWarner Losh 		 * this is due to a nosiy electrical environment or some odd
466ae1f3df4SWarner Losh 		 * timing issue.
467ae1f3df4SWarner Losh 		 */
468ae1f3df4SWarner Losh 
469ae1f3df4SWarner Losh 		/*
470ae1f3df4SWarner Losh 		 * The enumeration command should be successfully sent, if not,
471ae1f3df4SWarner Losh 		 * we have big issues on the bus so punt. Lower layers report
472ae1f3df4SWarner Losh 		 * any unusual errors, so we don't need to here.
473ae1f3df4SWarner Losh 		 */
474ae1f3df4SWarner Losh 		err = enumfp(dev, dev);
475ae1f3df4SWarner Losh 		if (err != 0)
476ae1f3df4SWarner Losh 			return (err);
477ae1f3df4SWarner Losh 
478ae1f3df4SWarner Losh 		for (i = 0; i < 64; i++) {
479ae1f3df4SWarner Losh 			OWLL_READ_DATA(lldev, &timing_regular, &first);
480ae1f3df4SWarner Losh 			OWLL_READ_DATA(lldev, &timing_regular, &second);
481ae1f3df4SWarner Losh 			switch (first | second << 1) {
482ae1f3df4SWarner Losh 			case 0: /* Conflict */
483ae1f3df4SWarner Losh 				if (i < prior)
484ae1f3df4SWarner Losh 					dir = (last_mask >> i) & 1;
485ae1f3df4SWarner Losh 				else
486ae1f3df4SWarner Losh 					dir = i == prior;
487ae1f3df4SWarner Losh 
488ae1f3df4SWarner Losh 				if (dir == 0)
489ae1f3df4SWarner Losh 					last = i;
490ae1f3df4SWarner Losh 				break;
491ae1f3df4SWarner Losh 			case 1: /* 1 then 0 -> 1 for all */
492ae1f3df4SWarner Losh 				dir = 1;
493ae1f3df4SWarner Losh 				break;
494ae1f3df4SWarner Losh 			case 2: /* 0 then 1 -> 0 for all */
495ae1f3df4SWarner Losh 				dir = 0;
496ae1f3df4SWarner Losh 				break;
497ae1f3df4SWarner Losh 			case 3:
498ae1f3df4SWarner Losh 				/*
499ae1f3df4SWarner Losh 				 * No device responded. This is unexpected, but
500ae1f3df4SWarner Losh 				 * experience has shown that on some platforms
501ae1f3df4SWarner Losh 				 * we miss a timing window, or otherwise have
502ae1f3df4SWarner Losh 				 * an issue. Start this step over. Since we've
503ae1f3df4SWarner Losh 				 * not updated prior yet, we can just jump to
504ae1f3df4SWarner Losh 				 * the top of the loop for a re-do of this step.
505ae1f3df4SWarner Losh 				 */
506ae1f3df4SWarner Losh 				printf("oops, starting over\n");
507ae1f3df4SWarner Losh 				if (++retries > 5)
508ae1f3df4SWarner Losh 					return (EIO);
509ae1f3df4SWarner Losh 				goto again;
51063aa6c0cSPedro F. Giffuni 			default: /* NOTREACHED */
51163aa6c0cSPedro F. Giffuni 				__unreachable();
512ae1f3df4SWarner Losh 			}
513ae1f3df4SWarner Losh 			if (dir) {
514ae1f3df4SWarner Losh 				OWLL_WRITE_ONE(lldev, &timing_regular);
515ae1f3df4SWarner Losh 				probed |= 1ull << i;
516ae1f3df4SWarner Losh 			} else {
517ae1f3df4SWarner Losh 				OWLL_WRITE_ZERO(lldev, &timing_regular);
518ae1f3df4SWarner Losh 			}
519ae1f3df4SWarner Losh 		}
520ae1f3df4SWarner Losh 		retries = 0;
521ae1f3df4SWarner Losh 		foundfp(dev, probed);
522ae1f3df4SWarner Losh 		last_mask = probed;
523ae1f3df4SWarner Losh 		prior = last;
52474b8d63dSPedro F. Giffuni 	}
525ae1f3df4SWarner Losh 	ow_release_bus(dev, dev);
526ae1f3df4SWarner Losh 
527ae1f3df4SWarner Losh 	return (0);
528ae1f3df4SWarner Losh }
529ae1f3df4SWarner Losh 
530ae1f3df4SWarner Losh static int
531ae1f3df4SWarner Losh ow_probe(device_t dev)
532ae1f3df4SWarner Losh {
533ae1f3df4SWarner Losh 
534ae1f3df4SWarner Losh 	device_set_desc(dev, "1 Wire Bus");
535ae1f3df4SWarner Losh 	return (BUS_PROBE_GENERIC);
536ae1f3df4SWarner Losh }
537ae1f3df4SWarner Losh 
538ae1f3df4SWarner Losh static int
539ae1f3df4SWarner Losh ow_attach(device_t ndev)
540ae1f3df4SWarner Losh {
541ae1f3df4SWarner Losh 	struct ow_softc *sc;
542ae1f3df4SWarner Losh 
543ae1f3df4SWarner Losh 	/*
544ae1f3df4SWarner Losh 	 * Find all the devices on the bus. We don't probe / attach them in the
545ae1f3df4SWarner Losh 	 * enumeration phase. We do this because we want to allow the probe /
546ae1f3df4SWarner Losh 	 * attach routines of the child drivers to have as full an access to the
547ae1f3df4SWarner Losh 	 * bus as possible. While we reset things before the next step of the
548ae1f3df4SWarner Losh 	 * search (so it would likely be OK to allow access by the clients to
549ae1f3df4SWarner Losh 	 * the bus), it is more conservative to find them all, then to do the
550ae1f3df4SWarner Losh 	 * attach of the devices. This also allows the child devices to have
551ae1f3df4SWarner Losh 	 * more knowledge of the bus. We also ignore errors from the enumeration
552ae1f3df4SWarner Losh 	 * because they might happen after we've found a few devices.
553ae1f3df4SWarner Losh 	 */
554ae1f3df4SWarner Losh 	sc = device_get_softc(ndev);
555ae1f3df4SWarner Losh 	sc->dev = ndev;
556ae1f3df4SWarner Losh 	mtx_init(&sc->mtx, device_get_nameunit(sc->dev), "ow", MTX_DEF);
557ae1f3df4SWarner Losh 	ow_enumerate(ndev, ow_search_rom, ow_device_found);
558ae1f3df4SWarner Losh 	return bus_generic_attach(ndev);
559ae1f3df4SWarner Losh }
560ae1f3df4SWarner Losh 
561ae1f3df4SWarner Losh static int
562ae1f3df4SWarner Losh ow_detach(device_t ndev)
563ae1f3df4SWarner Losh {
564ae1f3df4SWarner Losh 	device_t *children, child;
565ae1f3df4SWarner Losh 	int nkid, i;
566ae1f3df4SWarner Losh 	struct ow_devinfo *di;
567ae1f3df4SWarner Losh 	struct ow_softc *sc;
568ae1f3df4SWarner Losh 
569ae1f3df4SWarner Losh 	sc = device_get_softc(ndev);
570ae1f3df4SWarner Losh 	/*
571ae1f3df4SWarner Losh 	 * detach all the children first. This is blocking until any threads
572ae1f3df4SWarner Losh 	 * have stopped, etc.
573ae1f3df4SWarner Losh 	 */
574ae1f3df4SWarner Losh 	bus_generic_detach(ndev);
575ae1f3df4SWarner Losh 
576ae1f3df4SWarner Losh 	/*
577ae1f3df4SWarner Losh 	 * We delete all the children, and free up the ivars
578ae1f3df4SWarner Losh 	 */
579ae1f3df4SWarner Losh 	if (device_get_children(ndev, &children, &nkid) != 0)
580ae1f3df4SWarner Losh 		return ENOMEM;
581ae1f3df4SWarner Losh 	for (i = 0; i < nkid; i++) {
582ae1f3df4SWarner Losh 		child = children[i];
583ae1f3df4SWarner Losh 		di = device_get_ivars(child);
584ae1f3df4SWarner Losh 		free(di, M_OW);
585ae1f3df4SWarner Losh 		device_delete_child(ndev, child);
586ae1f3df4SWarner Losh 	}
587ae1f3df4SWarner Losh 	free(children, M_TEMP);
588ae1f3df4SWarner Losh 
589ae1f3df4SWarner Losh 	OW_LOCK_DESTROY(sc);
590ae1f3df4SWarner Losh 	return 0;
591ae1f3df4SWarner Losh }
592ae1f3df4SWarner Losh 
593ae1f3df4SWarner Losh /*
594ae1f3df4SWarner Losh  * Not sure this is really needed. I'm having trouble figuring out what
595ae1f3df4SWarner Losh  * location means in the context of the one wire bus.
596ae1f3df4SWarner Losh  */
597ae1f3df4SWarner Losh static int
598ae1f3df4SWarner Losh ow_child_location_str(device_t dev, device_t child, char *buf,
599ae1f3df4SWarner Losh     size_t buflen)
600ae1f3df4SWarner Losh {
601ae1f3df4SWarner Losh 
602d63180f2SWarner Losh 	*buf = '\0';
603ae1f3df4SWarner Losh 	return (0);
604ae1f3df4SWarner Losh }
605ae1f3df4SWarner Losh 
606ae1f3df4SWarner Losh static int
607ae1f3df4SWarner Losh ow_child_pnpinfo_str(device_t dev, device_t child, char *buf,
608ae1f3df4SWarner Losh     size_t buflen)
609ae1f3df4SWarner Losh {
610ae1f3df4SWarner Losh 	struct ow_devinfo *di;
611ae1f3df4SWarner Losh 
612ae1f3df4SWarner Losh 	di = device_get_ivars(child);
613ae1f3df4SWarner Losh 	snprintf(buf, buflen, "romid=%8D", &di->romid, ":");
614ae1f3df4SWarner Losh 	return (0);
615ae1f3df4SWarner Losh }
616ae1f3df4SWarner Losh 
617ae1f3df4SWarner Losh static int
618ae1f3df4SWarner Losh ow_read_ivar(device_t dev, device_t child, int which, uintptr_t *result)
619ae1f3df4SWarner Losh {
620ae1f3df4SWarner Losh 	struct ow_devinfo *di;
621ae1f3df4SWarner Losh 	romid_t **ptr;
622ae1f3df4SWarner Losh 
623ae1f3df4SWarner Losh 	di = device_get_ivars(child);
624ae1f3df4SWarner Losh 	switch (which) {
625ae1f3df4SWarner Losh 	case OW_IVAR_FAMILY:
626ae1f3df4SWarner Losh 		*result = di->romid & 0xff;
627ae1f3df4SWarner Losh 		break;
628ae1f3df4SWarner Losh 	case OW_IVAR_ROMID:
629ae1f3df4SWarner Losh 		ptr = (romid_t **)result;
630ae1f3df4SWarner Losh 		*ptr = &di->romid;
631ae1f3df4SWarner Losh 		break;
632ae1f3df4SWarner Losh 	default:
633ae1f3df4SWarner Losh 		return EINVAL;
634ae1f3df4SWarner Losh 	}
635ae1f3df4SWarner Losh 
636ae1f3df4SWarner Losh 	return 0;
637ae1f3df4SWarner Losh }
638ae1f3df4SWarner Losh 
639ae1f3df4SWarner Losh static int
640ae1f3df4SWarner Losh ow_write_ivar(device_t dev, device_t child, int which, uintptr_t value)
641ae1f3df4SWarner Losh {
642ae1f3df4SWarner Losh 
643ae1f3df4SWarner Losh 	return EINVAL;
644ae1f3df4SWarner Losh }
645ae1f3df4SWarner Losh 
646ae1f3df4SWarner Losh static int
647ae1f3df4SWarner Losh ow_print_child(device_t ndev, device_t pdev)
648ae1f3df4SWarner Losh {
649ae1f3df4SWarner Losh 	int retval = 0;
650ae1f3df4SWarner Losh 	struct ow_devinfo *di;
651ae1f3df4SWarner Losh 
652ae1f3df4SWarner Losh 	di = device_get_ivars(pdev);
653ae1f3df4SWarner Losh 
654ae1f3df4SWarner Losh 	retval += bus_print_child_header(ndev, pdev);
655ae1f3df4SWarner Losh 	retval += printf(" romid %8D", &di->romid, ":");
656ae1f3df4SWarner Losh 	retval += bus_print_child_footer(ndev, pdev);
657ae1f3df4SWarner Losh 
658ae1f3df4SWarner Losh 	return retval;
659ae1f3df4SWarner Losh }
660ae1f3df4SWarner Losh 
661ae1f3df4SWarner Losh static void
662ae1f3df4SWarner Losh ow_probe_nomatch(device_t ndev, device_t pdev)
663ae1f3df4SWarner Losh {
664ae1f3df4SWarner Losh 	struct ow_devinfo *di;
665ae1f3df4SWarner Losh 
666ae1f3df4SWarner Losh 	di = device_get_ivars(pdev);
667ae1f3df4SWarner Losh 	device_printf(ndev, "romid %8D: no driver\n", &di->romid, ":");
668ae1f3df4SWarner Losh }
669ae1f3df4SWarner Losh 
670ae1f3df4SWarner Losh static int
671ae1f3df4SWarner Losh ow_acquire_bus(device_t ndev, device_t pdev, int how)
672ae1f3df4SWarner Losh {
673ae1f3df4SWarner Losh 	struct ow_softc *sc;
674ae1f3df4SWarner Losh 
675ae1f3df4SWarner Losh 	sc = device_get_softc(ndev);
676ae1f3df4SWarner Losh 	OW_ASSERT_UNLOCKED(sc);
677ae1f3df4SWarner Losh 	OW_LOCK(sc);
678ae1f3df4SWarner Losh 	if (sc->owner != NULL) {
679ae1f3df4SWarner Losh 		if (sc->owner == pdev)
680ae1f3df4SWarner Losh 			panic("%s: %s recursively acquiring the bus.\n",
681ae1f3df4SWarner Losh 			    device_get_nameunit(ndev),
682ae1f3df4SWarner Losh 			    device_get_nameunit(pdev));
683ae1f3df4SWarner Losh 		if (how == OWN_DONTWAIT) {
684ae1f3df4SWarner Losh 			OW_UNLOCK(sc);
685ae1f3df4SWarner Losh 			return EWOULDBLOCK;
686ae1f3df4SWarner Losh 		}
687ae1f3df4SWarner Losh 		while (sc->owner != NULL)
688ae1f3df4SWarner Losh 			mtx_sleep(sc, &sc->mtx, 0, "owbuswait", 0);
689ae1f3df4SWarner Losh 	}
690ae1f3df4SWarner Losh 	sc->owner = pdev;
691ae1f3df4SWarner Losh 	OW_UNLOCK(sc);
692ae1f3df4SWarner Losh 
693ae1f3df4SWarner Losh 	return 0;
694ae1f3df4SWarner Losh }
695ae1f3df4SWarner Losh 
696ae1f3df4SWarner Losh static void
697ae1f3df4SWarner Losh ow_release_bus(device_t ndev, device_t pdev)
698ae1f3df4SWarner Losh {
699ae1f3df4SWarner Losh 	struct ow_softc *sc;
700ae1f3df4SWarner Losh 
701ae1f3df4SWarner Losh 	sc = device_get_softc(ndev);
702ae1f3df4SWarner Losh 	OW_ASSERT_UNLOCKED(sc);
703ae1f3df4SWarner Losh 	OW_LOCK(sc);
704ae1f3df4SWarner Losh 	if (sc->owner == NULL)
705ae1f3df4SWarner Losh 		panic("%s: %s releasing unowned bus.", device_get_nameunit(ndev),
706ae1f3df4SWarner Losh 		    device_get_nameunit(pdev));
707ae1f3df4SWarner Losh 	if (sc->owner != pdev)
708ae1f3df4SWarner Losh 		panic("%s: %s don't own the bus. %s does. game over.",
709ae1f3df4SWarner Losh 		    device_get_nameunit(ndev), device_get_nameunit(pdev),
710ae1f3df4SWarner Losh 		    device_get_nameunit(sc->owner));
711ae1f3df4SWarner Losh 	sc->owner = NULL;
712ae1f3df4SWarner Losh 	wakeup(sc);
713ae1f3df4SWarner Losh 	OW_UNLOCK(sc);
714ae1f3df4SWarner Losh }
715ae1f3df4SWarner Losh 
716ae1f3df4SWarner Losh devclass_t ow_devclass;
717ae1f3df4SWarner Losh 
718ae1f3df4SWarner Losh static device_method_t ow_methods[] = {
719ae1f3df4SWarner Losh 	/* Device interface */
720ae1f3df4SWarner Losh 	DEVMETHOD(device_probe,		ow_probe),
721ae1f3df4SWarner Losh 	DEVMETHOD(device_attach,	ow_attach),
722ae1f3df4SWarner Losh 	DEVMETHOD(device_detach,	ow_detach),
723ae1f3df4SWarner Losh 
724ae1f3df4SWarner Losh 	/* Bus interface */
725ae1f3df4SWarner Losh 	DEVMETHOD(bus_child_pnpinfo_str, ow_child_pnpinfo_str),
726ae1f3df4SWarner Losh 	DEVMETHOD(bus_child_location_str, ow_child_location_str),
727ae1f3df4SWarner Losh 	DEVMETHOD(bus_read_ivar,	ow_read_ivar),
728ae1f3df4SWarner Losh 	DEVMETHOD(bus_write_ivar,	ow_write_ivar),
729ae1f3df4SWarner Losh 	DEVMETHOD(bus_print_child,	ow_print_child),
730ae1f3df4SWarner Losh 	DEVMETHOD(bus_probe_nomatch,	ow_probe_nomatch),
731ae1f3df4SWarner Losh 
732ae1f3df4SWarner Losh 	/* One Wire Network/Transport layer interface */
733ae1f3df4SWarner Losh 	DEVMETHOD(own_send_command,	ow_send_command),
734ae1f3df4SWarner Losh 	DEVMETHOD(own_acquire_bus,	ow_acquire_bus),
735ae1f3df4SWarner Losh 	DEVMETHOD(own_release_bus,	ow_release_bus),
736ae1f3df4SWarner Losh 	DEVMETHOD(own_crc,		ow_crc),
737ae1f3df4SWarner Losh 	{ 0, 0 }
738ae1f3df4SWarner Losh };
739ae1f3df4SWarner Losh 
740ae1f3df4SWarner Losh static driver_t ow_driver = {
741ae1f3df4SWarner Losh 	"ow",
742ae1f3df4SWarner Losh 	ow_methods,
743ae1f3df4SWarner Losh 	sizeof(struct ow_softc),
744ae1f3df4SWarner Losh };
745ae1f3df4SWarner Losh 
746ae1f3df4SWarner Losh DRIVER_MODULE(ow, owc, ow_driver, ow_devclass, 0, 0);
747ae1f3df4SWarner Losh MODULE_VERSION(ow, 1);
748