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