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