New 1-Wire bus implementation. 1-Wire controller is abstracted, though

only gpiobus configured via FDT is supported. Bus enumeration is
supported. Devices are created for each device found. 1-Wire
temperature controllers are supported, but other drivers could be
written. Temperatures are polled and reported via a sysctl.  Errors
are reported via sysctl counters. Mis-wired bus detection is included
for more trouble shooting. See ow(4), owc(4) and ow_temp(4) for
details of what's supported and known issues.

This has been tested on Raspberry Pi-B, Pi2 and Beagle Bone Black
with up to 7 devices.

Differential Revision: https://reviews.freebsd.org/D2956
Relnotes: yes
MFC after: 2 weeks
Reviewed by: loos@ (with many insightful comments)
This commit is contained in:
Warner Losh 2015-08-27 23:33:38 +00:00
parent 01da73abdc
commit ae1f3df434
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=287225
22 changed files with 2519 additions and 0 deletions

View File

@ -379,6 +379,9 @@ MAN= aac.4 \
oce.4 \
ohci.4 \
orm.4 \
ow.4 \
ow_temp.4 \
owc.4 \
${_padlock.4} \
pass.4 \
patm.4 \
@ -667,6 +670,7 @@ MLINKS+=nge.4 if_nge.4
MLINKS+=${_ntb.4} ${_if_ntb.4} \
${_ntb.4} ${_ntb_hw.4}
MLINKS+=${_nxge.4} ${_if_nxge.4}
MLINKS+=ow.4 onewire.4
MLINKS+=patm.4 if_patm.4
MLINKS+=pccbb.4 cbb.4
MLINKS+=pcm.4 snd.4 \

60
share/man/man4/ow.4 Normal file
View File

@ -0,0 +1,60 @@
.\"
.\" Copyright (c) 2015 M. Warner Losh
.\" All rights reserved.
.\"
.\" Redistribution and use in source and binary forms, with or without
.\" modification, are permitted provided that the following conditions
.\" are met:
.\" 1. Redistributions of source code must retain the above copyright
.\" notice, this list of conditions and the following disclaimer.
.\" 2. The name of the author may not be used to endorse or promote products
.\" derived from this software without specific prior written permission.
.\"
.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
.\" $FreeBSD$
.\"
.Dd July 20, 2015
.Dt OW 4
.Os
.Sh NAME
.Nm ow
.Nd Dallas Semiconductor 1-Wire bus
.Sh SYNOPSIS
.Cd device ow
.Sh DESCRIPTION
The
.Nm
module implements the Dallas Semiconductor 1-Wire bus.
It attaches to the
.Xr owc 4
driver, which implements the low-level signaling of the
1-Wire bus.
.Sh SEE ALSO
.Xr ow_temp 4 ,
.Xr owc 4 ,
.Xr owll 9 ,
.Xr own 9
.Sh LEGAL
.Tn 1-Wire
is a registered trademark of Maxim Integrated Products, Inc.
.Sh HISTORY
The
.Nm
driver first appeared in
.Fx 11.0 .
.Sh AUTHORS
The
.Nm
device driver and this manual page were written by
.An Warner Losh .

155
share/man/man4/ow_temp.4 Normal file
View File

@ -0,0 +1,155 @@
.\"
.\" Copyright (c) 2015 M. Warner Losh
.\" All rights reserved.
.\"
.\" Redistribution and use in source and binary forms, with or without
.\" modification, are permitted provided that the following conditions
.\" are met:
.\" 1. Redistributions of source code must retain the above copyright
.\" notice, this list of conditions and the following disclaimer.
.\" 2. The name of the author may not be used to endorse or promote products
.\" derived from this software without specific prior written permission.
.\"
.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
.\" $FreeBSD$
.\"
.Dd July 20, 2015
.Dt OW_TEMP 4
.Os
.Sh NAME
.Nm ow_temp
.Nd Dallas Semiconductor 1-Wire Temperature sensor
.Sh SYNOPSIS
.Cd device ow_temp
.Sh DESCRIPTION
The
.Nm
module supports many of the 1-Wire temperature sensors.
.Pp
The sensor is read periodically and the results returned via a
.Xr sysctl 3
as described below.
.Sh HARDWARE
These temperature sensors are supported by the
.Nm
driver:
.Bl -tag -width MAX31820 -compact
.It DS1820
1-Wire Digital Thermometer
.It DS18S20
High-Precision 1-Wire Digital Thermometer
.It DS18B20
Programmable Resolution 1-Wire Digital Thermometer
.It DS1822
Econo 1-Wire Digital Thermometer
.It DS1825
Programmable Resolution 1-Wire Digital Thermometer with 4-bit ID
.It MAX31820
1-Wire, Parasite-Power, Ambient Temperature Sensor
.El
.Pp
The driver supports Family codes 0x10, 0x22, 0x28, and 0x3b.
.Sh SYSCTL
The
.Nm
driver reports data via
.Xr sysctl 8
entries in the device's node in the
.Xr sysctl 8
tree:
.Bl -tag -width xxxxxxxxxx
.It temperature
The last temperature read, in milli-Kelvin.
.It badcrc
The number of CRC errors in reading the temperature form the
device.
Some CRC errors are to be expected.
High rates of CRC errors, however, generally indicate a noisy
environment, cabling issues, or too many devices on the bus.
.It badread
The number of times a non-CRC error was encountered reading the temperature
from the card.
This type of error is very rare.
.It reading_interval
The time, in ticks, between successive reads of the sensor.
.It parasite
This item is non-zero when the device is connected using its parasitic
power mode.
It can also indicate a wiring error.
.El
.Pp
Temperatures are reported in milli-Kelvin, even though the absolute
accuracy is around 0.2 degrees for the good devices and around 1
degree for cheaper devices.
The devices report in steps of 0.0625 degrees.
The driver preserves the precision of the device's measurements
in its
.Xr sysctl 8
reports.
These devices often have a much higher relative accuracy and
repeatability than their absolute accuracy.
This makes them well suited for control loops that strive for
stability and become possible if the full precision is preserved.
.Sh SEE ALSO
.Xr ow 4 ,
.Xr owc 4 ,
.Xr sysctl 8 ,
.Xr owll 9 ,
.Xr own 9
.Sh LEGAL
.Tn 1-Wire
is a registered trademark of Maxim Integrated Products, Inc.
.Sh HISTORY
The
.Nm
driver first appeared in
.Fx 11.0 .
.Sh AUTHORS
The
.Nm
device driver and this manual page were written by
.An Warner Losh .
.Sh BUGS
The parasitic mode of the devices does not work.
It requires support from the
.Xr owc 4
driver that is unimplemented.
.Pp
The ID bits from the
.Em DS1825
are not recognized or reported.
.Pp
The type of the device is not reported via
.Xr sysctl 8 .
.Pp
Alarm mode is not supported.
It is not possible to set the low and high alarm temperatures.
.Pp
There is no way to write to the EEPROM.
.Pp
.Dq Convert Temperature
requests are sent directly to the device.
There is no way to use the broadcast ability of the 1-Wire bus to do
all the conversions in parallel.
.Pp
It is not possible to set the precision on those devices that support
it.
.Pp
The time to convert is fixed at 1 second, even though some devices are
faster.
.Pp
There is no character device to supply a stream of readings to a
program.
Programs interested in the temperature must poll the sysctl to get the
temperature.

95
share/man/man4/owc.4 Normal file
View File

@ -0,0 +1,95 @@
.\"
.\" Copyright (c) 2015 M. Warner Losh
.\" All rights reserved.
.\"
.\" Redistribution and use in source and binary forms, with or without
.\" modification, are permitted provided that the following conditions
.\" are met:
.\" 1. Redistributions of source code must retain the above copyright
.\" notice, this list of conditions and the following disclaimer.
.\" 2. The name of the author may not be used to endorse or promote products
.\" derived from this software without specific prior written permission.
.\"
.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
.\" $FreeBSD$
.\"
.Dd July 20, 2015
.Dt OWC 4
.Os
.Sh NAME
.Nm owc
.Nd Dallas Semiconductor 1-Wire Controller
.Sh SYNOPSIS
.Cd device owc
.Sh DESCRIPTION
The
.Nm
module implements Dallas Semiconductor 1-Wire signaling.
It attaches the
.Xr ow 4
driver 1-Wire bus protocol.
The
.Nm
device implements the Link Layer of the 1-Wire bus protocol stack.
.Pp
Bit banging a pin on a
.Xr gpiobus 4
is the only supported controller.
Both standard and overdrive transfer timings are implemented.
Strong pull-up functionality needed to support parasitic mode is not
implemented.
.Pp
To enable 1-Wire for FDT systems requires modifying the DTS for your
board to add something like:
.Bd -literal
/ {
...
onewire {
compatible = "w1-gpio";
gpios = <&gpio 4 1>;
};
...
};
.Ed
.Pp
The gpios property describes the GPIO pin the 1-Wire bus is connected
to.
For more details about the
.Va gpios
property, please consult
.Pa /usr/src/sys/boot/fdt/dts/bindings-gpio.txt .
.Sh SEE ALSO
.Xr gpiobus 4 ,
.Xr ow 4 ,
.Xr ow_temp 4 ,
.Xr owll 9 ,
.Xr own 9
.Sh LEGAL
.Tn 1-Wire
is a registered trademark of Maxim Integrated Products, Inc.
.Sh HISTORY
The
.Nm
driver first appeared in
.Fx 11.0 .
.Sh AUTHORS
The
.Nm
device driver and this manual page were written by
.An Warner Losh .
.Sh CAVEATS
The gpio driver implements timing by busy waiting, which can cause a
high load on slower systems.
.Sh BUGS
Overdrive mode has not actually been tested.

View File

@ -190,6 +190,8 @@ MAN= accept_filter.9 \
netisr.9 \
nv.9 \
osd.9 \
owll.9 \
own.9 \
panic.9 \
pbuf.9 \
PCBGROUP.9 \

93
share/man/man9/owll.9 Normal file
View File

@ -0,0 +1,93 @@
.\"
.\" Copyright (c) 2015 M. Warner Losh
.\" All rights reserved.
.\"
.\" Redistribution and use in source and binary forms, with or without
.\" modification, are permitted provided that the following conditions
.\" are met:
.\" 1. Redistributions of source code must retain the above copyright
.\" notice, this list of conditions and the following disclaimer.
.\" 2. The name of the author may not be used to endorse or promote products
.\" derived from this software without specific prior written permission.
.\"
.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
.\" $FreeBSD$
.\"
.Dd July 20, 2015
.Dt OWLL 9
.Os
.Sh NAME
.Nm owll
.Nm OWLL_WRITE_ONE,
.Nm OWLL_WRITE_ZERO,
.Nm OWLL_READ_DATA,
.Nm OWLL_REASET_AND_PRESENCE
.Nd Dallas Semiconductor 1-Wire Link Layer Interface
.Sh SYNOPSIS
.Ft int
.Fn OWLL_WRITE_ONE "device_t lldev" "struct ow_timing *timing"
.Ft int
.Fn OWLL_WRITE_ZERO "device_t lldev" "struct ow_timing *timing"
.Ft int
.Fn OWLL_READ_DATA "device_t lldev" "struct ow_timing *timing" "int *bit"
.Ft int
.Fn OWLL_RESET_AND_PRESENCE "device_t lldev" "struct ow_timing *timing" "int *bit"
.Sh DESCRIPTION
The
.Nm
interface provides access to the link layer of the Dallas
Semiconductor 1-Wire from upper layers of the protocol.
.Pp
.Fn OWLL_WRITE_ONE
and
.Fn OWLL_WRITE_ZERO
writes a one bitor a zero bit respectively on the 1-Wire bus.
.Pp
.Fn OWLL_READ_DATA
reads one bit from the 1-Wire bus.
This is often referred to as a
.Dq Read Time Slot
in the 1-Wire device data sheets.
.Pp
The
.Fn OWLL_RESET_AND_PRESENCE
function starts a reset sequence and detects if any device(s) are
present on the bus.
This is the beginning of all 1-Wire transactions.
.Sh NOTES
This interface is intended to be used only by the
.Xr ow 4
device to talk to the low-level bus.
By convention, the device that implements this interface is called
.Xr owc 4 .
Only devices that implement
.Xr own 9
should call these interfaces.
.Sh SEE ALSO
.Xr ow 4 ,
.Xr owc 4 ,
.Xr own 9
.Sh LEGAL
.Tn 1-Wire
is a registered trademark of Maxim Integrated Products, Inc.
.Sh HISTORY
The
.Nm
driver first appeared in
.Fx 11.0 .
.Sh AUTHORS
The
.Nm
device driver and this manual page were written by
.An Warner Losh .

230
share/man/man9/own.9 Normal file
View File

@ -0,0 +1,230 @@
.\"
.\" Copyright (c) 2015 M. Warner Losh
.\" All rights reserved.
.\"
.\" Redistribution and use in source and binary forms, with or without
.\" modification, are permitted provided that the following conditions
.\" are met:
.\" 1. Redistributions of source code must retain the above copyright
.\" notice, this list of conditions and the following disclaimer.
.\" 2. The name of the author may not be used to endorse or promote products
.\" derived from this software without specific prior written permission.
.\"
.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
.\" $FreeBSD$
.\"
.Dd July 20, 2015
.Dt OWN 9
.Os
.Sh NAME
.Nm own ,
.Nm own_send_command ,
.Nm own_commmand_wait ,
.Nm own_self_command ,
.Nm own_acquire_bus ,
.Nm own crc ,
.Nm own_release_bus ,
.Nm OWN_ACQUIRE_BUS ,
.Nm OWN_CRC ,
.Nm OWN_RELEASE_BUS ,
.Nm OWN_SEND_COMMAND
.Nd Dallas Semiconductor 1-Wire Network and Transport Interface
.Sh SYNOPSIS
.In sys/bus.h
.In dev/ow/own.h
.Ft int
.Fn own_send_command "device_t pdev" "struct ow_cmd *cmd"
.Ft int
.Fn own_command_wait "device_t pdev" "struct ow_cmd *cmd"
.Ft int
.Fn own_self_command "device_t pdev" "struct ow_cmd *cmd" "uint8_t xpt_cmd"
.Ft int
.Fn own_acquire_bus "device_t pdev" "int how"
.Ft int
.Fn own_release_bus "device_t pdev"
.Ft int
.Fn own_crc "device_t pdev" "uint8_t *buffer" "size_t len"
.Ft int
.Fn OWN_SEND_COMMAND "device_t ndev" "device_t pdev" "struct ow_cmd *cmd"
.Ft int
.Fn OWN_ACQUIRE_BUS "device_t ndev" "device_t pdev" "int how"
.Ft void
.Fn OWN_RELEASE_BUS "device_t ndev" "device_t pdev"
.Ft uint8_t
.Fn OWN_CRC "device_t ndev" "device_t pdev" "uint8_t *buffer" "size_t len"
.Sh DESCRIPTION
The
.Nm
interface defines three sets of functions for interacting with 1-Wire
devices:
sending commands,
reserving the bus,
and
ensuring data integrity.
Wrappers are provided for the raw
.Nm OWN
.Xr kobj 9
interfaces and should be used for improved safety over the
.Xr kobj 9
ones.
.Ss Bus Commands
The 1-Wire bus defines different layers of access to the devices on
the bus.
The
.Nm
functions provide access to the network and transport layers.
The network layer designates the next command as being either for all
devices on the bus, or for a specific device.
The network layer also specifies the speed used by the link layer.
.Pp
.Vt "struct ow_cmd"
encapsulates network access, speed, and timing information.
It specifies the commands to send and whether or not to read data.
Its members are:
.Bl -tag -width ".Va xxxx"
.It Va flags
Flags controlling the interpretation of the structure.
These flags are defined in
.In dev/ow/ow.h :
.Bl -tag -width indent
.It OW_FLAG_OVERDRIVE
Send
.Va xpt_cmd
bytes and read
.Va xpt_read
bytes at overdrive speed.
.It OW_FLAG_READ_BIT
Interpret
.Va xpt_read_len
to be in bits to be read after
.Va xpt_cmd
rather than bytes.
.El
.It Va rom_cmd
ROM command bytes to send.
.It Va rom_len
Number of ROM command bytes to send.
.It Va rom_read_len
Number of bytes to read after sending the ROM command.
.It Va rom_read
Buffer for bytes read after the ROM command.
.It Va xpt_cmd
Transport command to send.
.It Va xpt_len
Length of the transport command bytes to send.
Specify 0 for no transport command.
.It Va xpt_read_len
Number of bytes to read after
.Va xpt_cmd
bytes are sent.
If the
.Dv OW_FLAG_READ_BIT
bit is set in
.Va flags ,
then it is the number of bits to read.
Bits read are packed into bytes.
.It Va xpt_read
Buffer for data read.
.El
.Pp
.Fn own_command_wait
acquires the 1-Wire bus, waiting if necessary,
sends the command,
and
then releases the bus.
.Fn own_send_command
sends the command without bus reservation.
.Fa pdev
is the client device (the presentation layer device) sending the command.
The
.Fa cmd
argument describes the transaction to send to the 1-Wire bus.
.Pp
.Fn own_self_command
fills in
.Fa cmd
with a MATCH_ROM ROM command, the ROM address of
.Fa pdev
and the
.Fa xpt_cmd
as a convenient way to create directed commands.
.Ss Bus Reservation
The 1-Wire system includes an advisory lock for the bus that
presentation layer devices can use to coordinate access.
Locking is purely advisory at this time.
.Pp
.Fn own_acquire_bus
reserves the bus.
It waits indefinitely if the
.Fa how
argument is
.Dv OWN_WAIT
and returns the error
.Dv EWOULDBLOCK
if passed
.Dv OWN_DONTWAIT
when the bus is owned by another client.
.Pp
.Fn own_release_bus
releases the bus.
.Ss Data Integrity
.Fn own_crc
computes the 1-Wire standard CRC function over the data
passed in
.Fa buffer
and
.Fa len
and returns the result.
.Ss Notes
The 1-Wire standard (Maxim AN937) defines layers that are akin to ISO
networking layers.
The lowest relevant layer, the link layer, defines the polling windows
and the timing of the signaling of different modes.
The network layer is built on top of the link layer
and is used to address devices in a unicast or multicast manner.
The transport layer defines commands and responses from the devices.
The presentation layer is composed of the device specific commands and
actions used to control the specific 1-Wire devices on bus.
.Pp
These interfaces are implemented by the
.Xr ow 4
device.
Presentation layer devices (children of the newbus
.Xr ow 4
device) should only call the functions described here.
The functionality provided by the
.Xr owc 4
device (specifically the
.Xr owll 9
interface) should only be called by the
.Xr ow 4
driver.
.Sh SEE ALSO
.Xr ow 4 ,
.Xr owc 4 ,
.Xr owll 9
.Pa http://pdfserv.maximintegrated.com/en/an/AN937.pdf
.Sh LEGAL
.Tn 1-Wire
is a registered trademark of Maxim Integrated Products, Inc.
.Sh HISTORY
The
.Nm
driver first appeared in
.Fx 11.0 .
.Sh AUTHORS
The
.Nm
device driver and this manual page were written by
.An Warner Losh .

View File

@ -2088,6 +2088,13 @@ dev/ofw/ofw_iicbus.c optional fdt iicbus
dev/ofw/ofwbus.c optional fdt
dev/ofw/openfirm.c optional fdt
dev/ofw/openfirmio.c optional fdt
dev/ow/ow.c optional ow \
dependency "owll_if.h" \
dependency "own_if.h"
dev/ow/owll_if.m optional ow
dev/ow/own_if.m optional ow
dev/ow/ow_temp.c optional ow_temp
dev/ow/owc_gpiobus.c optional owc gpio
dev/patm/if_patm.c optional patm pci
dev/patm/if_patm_attach.c optional patm pci
dev/patm/if_patm_intr.c optional patm pci

19
sys/dev/ow/README.txt Normal file
View File

@ -0,0 +1,19 @@
Quick Design Document for 1-wire bus
In new bus terms, 1-wire devices are attached to 1-wire buses (ow)
which are attached to a one wire bridge (owc).
The implementation follows the terminology used in the Maxim AN927
Application note which defines the 1-wire bus as implemented for the
iButton product. This is considered to be the canonical definition of
the 1-wire bus. This means that the 1-wire bridge will implement the
owll(9) interface. ow is one wire. ll is for Link Level to mirror the ISO
stack terminology used by AN927. The 1-wire bus is implemented in the ow(4)
device, which implements the own(9) interface (n for network, the layer
described in the AN927). The presentation layer and above is the
responsibility of the client device drivers to implement.
Client drivers may only call the own(9) interface. The ow(4) driver
calls the owll(9) interface and implements the own(9).
$FreeBSD$

639
sys/dev/ow/ow.c Normal file
View File

@ -0,0 +1,639 @@
/*-
* Copyright (c) 2015 M. Warner Losh <imp@freebsd.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice unmodified, this list of conditions, and the following
* disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/kernel.h>
#include <sys/bus.h>
#include <sys/errno.h>
#include <sys/libkern.h>
#include <sys/malloc.h>
#include <sys/module.h>
#include <dev/ow/ow.h>
#include <dev/ow/owll.h>
#include <dev/ow/own.h>
/*
* lldev - link level device
* ndev - network / transport device (this module)
* pdev - presentation device (children of this module)
*/
typedef int ow_enum_fn(device_t, device_t);
typedef int ow_found_fn(device_t, romid_t);
struct ow_softc
{
device_t dev; /* Newbus driver back pointer */
struct mtx mtx; /* bus mutex */
device_t owner; /* bus owner, if != NULL */
};
struct ow_devinfo
{
romid_t romid;
};
static int ow_acquire_bus(device_t ndev, device_t pdev, int how);
static void ow_release_bus(device_t ndev, device_t pdev);
#define OW_LOCK(_sc) mtx_lock(&(_sc)->mtx)
#define OW_UNLOCK(_sc) mtx_unlock(&(_sc)->mtx)
#define OW_LOCK_DESTROY(_sc) mtx_destroy(&_sc->mtx)
#define OW_ASSERT_LOCKED(_sc) mtx_assert(&_sc->mtx, MA_OWNED)
#define OW_ASSERT_UNLOCKED(_sc) mtx_assert(&_sc->mtx, MA_NOTOWNED)
static MALLOC_DEFINE(M_OW, "ow", "House keeping data for 1wire bus");
static struct ow_timing timing_regular = {
.t_slot = 60, /* 60 to 120 */
.t_low0 = 60, /* really 60 to 120 */
.t_low1 = 1, /* really 1 to 15 */
.t_release = 45, /* <= 45us */
.t_rec = 1, /* at least 1us */
.t_rdv = 15, /* 15us */
.t_rstl = 480, /* 480us or more */
.t_rsth = 480, /* 480us or more */
.t_pdl = 60, /* 60us to 240us */
.t_pdh = 60, /* 15us to 60us */
.t_lowr = 1, /* 1us */
};
/* NB: Untested */
static struct ow_timing timing_overdrive = {
.t_slot = 11, /* 6us to 16us */
.t_low0 = 6, /* really 6 to 16 */
.t_low1 = 1, /* really 1 to 2 */
.t_release = 4, /* <= 4us */
.t_rec = 1, /* at least 1us */
.t_rdv = 2, /* 2us */
.t_rstl = 48, /* 48us to 80us */
.t_rsth = 48, /* 48us or more */
.t_pdl = 8, /* 8us to 24us */
.t_pdh = 2, /* 2us to 6us */
.t_lowr = 1, /* 1us */
};
static void
ow_send_byte(device_t lldev, struct ow_timing *t, uint8_t byte)
{
int i;
for (i = 0; i < 8; i++)
if (byte & (1 << i))
OWLL_WRITE_ONE(lldev, t);
else
OWLL_WRITE_ZERO(lldev, t);
}
static void
ow_read_byte(device_t lldev, struct ow_timing *t, uint8_t *bytep)
{
int i;
uint8_t byte = 0;
int bit;
for (i = 0; i < 8; i++) {
OWLL_READ_DATA(lldev, t, &bit);
byte |= bit << i;
}
*bytep = byte;
}
static int
ow_send_command(device_t ndev, device_t pdev, struct ow_cmd *cmd)
{
int present, i, bit, tries;
device_t lldev;
struct ow_timing *t;
lldev = device_get_parent(ndev);
/*
* Retry the reset a couple of times before giving up.
*/
tries = 4;
do {
OWLL_RESET_AND_PRESENCE(lldev, &timing_regular, &present);
if (present == 1)
device_printf(ndev, "Reset said no device on bus?.\n");
} while (present == 1 && tries-- > 0);
if (present == 1) {
device_printf(ndev, "Reset said the device wasn't there.\n");
return ENOENT; /* No devices acked the RESET */
}
if (present == -1) {
device_printf(ndev, "Reset discovered bus wired wrong.\n");
return ENOENT;
}
for (i = 0; i < cmd->rom_len; i++)
ow_send_byte(lldev, &timing_regular, cmd->rom_cmd[i]);
for (i = 0; i < cmd->rom_read_len; i++)
ow_read_byte(lldev, &timing_regular, cmd->rom_read + i);
if (cmd->xpt_len) {
/*
* Per AN937, the reset pulse and ROM level are always
* done with the regular timings. Certain ROM commands
* put the device into overdrive mode for the remainder
* of the data transfer, which is why we have to pass the
* timings here. Commands that need to be handled like this
* are expected to be flagged by the client.
*/
t = (cmd->flags & OW_FLAG_OVERDRIVE) ?
&timing_overdrive : &timing_regular;
for (i = 0; i < cmd->xpt_len; i++)
ow_send_byte(lldev, t, cmd->xpt_cmd[i]);
if (cmd->flags & OW_FLAG_READ_BIT) {
memset(cmd->xpt_read, 0, (cmd->xpt_read_len + 7) / 8);
for (i = 0; i < cmd->xpt_read_len; i++) {
OWLL_READ_DATA(lldev, t, &bit);
cmd->xpt_read[i / 8] |= bit << (i % 8);
}
} else {
for (i = 0; i < cmd->xpt_read_len; i++)
ow_read_byte(lldev, t, cmd->xpt_read + i);
}
}
return 0;
}
static int
ow_search_rom(device_t lldev, device_t dev)
{
struct ow_cmd cmd;
memset(&cmd, 0, sizeof(cmd));
cmd.rom_cmd[0] = SEARCH_ROM;
cmd.rom_len = 1;
return ow_send_command(lldev, dev, &cmd);
}
#if 0
static int
ow_alarm_search(device_t lldev, device_t dev)
{
struct ow_cmd cmd;
memset(&cmd, 0, sizeof(cmd));
cmd.rom_cmd[0] = ALARM_SEARCH;
cmd.rom_len = 1;
return ow_send_command(lldev, dev, &cmd);
}
#endif
static int
ow_add_child(device_t dev, romid_t romid)
{
struct ow_devinfo *di;
device_t child;
di = malloc(sizeof(*di), M_OW, M_WAITOK);
di->romid = romid;
child = device_add_child(dev, NULL, -1);
if (child == NULL) {
free(di, M_OW);
return ENOMEM;
}
device_set_ivars(child, di);
return (0);
}
static device_t
ow_child_by_romid(device_t dev, romid_t romid)
{
device_t *children, retval, child;
int nkid, i;
struct ow_devinfo *di;
if (device_get_children(dev, &children, &nkid) != 0)
return (NULL);
retval = NULL;
for (i = 0; i < nkid; i++) {
child = children[i];
di = device_get_ivars(child);
if (di->romid == romid) {
retval = child;
break;
}
}
free(children, M_TEMP);
return (retval);
}
/*
* CRC generator table -- taken from AN937 DOW CRC LOOKUP FUNCTION Table 2
*/
const uint8_t ow_crc_table[] = {
0, 94, 188, 226, 97, 63, 221, 131, 194, 156, 126, 32, 163, 253, 31, 65,
157, 195, 33, 127, 252, 162, 64, 30, 95, 1, 227, 189, 62, 96, 130, 220,
35, 125, 159, 193, 66, 28, 254, 160, 225, 191, 93, 3, 128, 222, 60, 98,
190, 224, 2, 92, 223, 129, 99, 61, 124, 34, 192, 158, 29, 67, 161, 255,
70, 24, 250, 164, 39, 121, 155, 197, 132, 218, 56, 102, 229, 187, 89, 7,
219, 133,103, 57, 186, 228, 6, 88, 25, 71, 165, 251, 120, 38, 196, 154,
101, 59, 217, 135, 4, 90, 184, 230, 167, 249, 27, 69, 198, 152, 122, 36,
248, 166, 68, 26, 153, 199, 37, 123, 58, 100, 134, 216, 91, 5, 231, 185,
140,210, 48, 110, 237, 179, 81, 15, 78, 16, 242, 172, 47, 113,147, 205,
17, 79, 173, 243, 112, 46, 204, 146, 211,141, 111, 49, 178, 236, 14, 80,
175, 241, 19, 77, 206, 144, 114, 44, 109, 51, 209, 143, 12, 82,176, 238,
50, 108, 142, 208, 83, 13, 239, 177, 240, 174, 76, 18, 145, 207, 45, 115,
202, 148, 118, 40, 171, 245, 23, 73, 8, 86, 180, 234, 105, 55, 213, 139,
87, 9, 235, 181, 54, 104, 138, 212, 149, 203, 41, 119, 244, 170, 72, 22,
233, 183, 85, 11, 136, 214, 52, 106, 43, 117, 151, 201, 74, 20, 246, 168,
116, 42, 200, 150, 21, 75, 169, 247, 182, 232, 10, 84, 215, 137, 107, 53
};
/*
* Converted from DO_CRC page 131 ANN937
*/
static uint8_t
ow_crc(device_t ndev, device_t pdev, uint8_t *buffer, size_t len)
{
uint8_t crc = 0;
int i;
for (i = 0; i < len; i++)
crc = ow_crc_table[crc ^ buffer[i]];
return crc;
}
static int
ow_check_crc(romid_t romid)
{
return ow_crc(NULL, NULL, (uint8_t *)&romid, sizeof(romid)) == 0;
}
static int
ow_device_found(device_t dev, romid_t romid)
{
/* XXX Move this up into enumerate? */
/*
* All valid ROM IDs have a valid CRC. Check that first.
*/
if (!ow_check_crc(romid)) {
device_printf(dev, "Device romid %8D failed CRC.\n",
&romid, ":");
return EINVAL;
}
/*
* If we've seen this child before, don't add a new one for it.
*/
if (ow_child_by_romid(dev, romid) != NULL)
return 0;
return ow_add_child(dev, romid);
}
static int
ow_enumerate(device_t dev, ow_enum_fn *enumfp, ow_found_fn *foundfp)
{
device_t lldev = device_get_parent(dev);
int first, second, i, dir, prior, last, err, retries;
uint64_t probed, last_mask;
int sanity = 10;
prior = -1;
last_mask = 0;
retries = 0;
last = -2;
err = ow_acquire_bus(dev, dev, OWN_DONTWAIT);
if (err != 0)
return err;
while (last != -1) {
if (sanity-- < 0) {
printf("Reached the sanity limit\n");
return EIO;
}
again:
probed = 0;
last = -1;
/*
* See AN397 section 5.II.C.3 for the algorithm (though a bit
* poorly stated). The search command forces each device to
* send ROM ID bits one at a time (first the bit, then the
* complement) the the master (us) sends back a bit. If the
* device's bit doesn't match what we send back, that device
* stops sending bits back. So each time through we remember
* where we made the last decision (always 0). If there's a
* conflict there this time (and there will be in the absence
* of a hardware failure) we go with 1. This way, we prune the
* devices on the bus and wind up with a unique ROM. We know
* we're done when we detect no new conflicts. The same
* algorithm is used for devices in alarm state as well.
*
* In addition, experience has shown that sometimes devices
* stop responding in the middle of enumeration, so try this
* step again a few times when that happens. It is unclear if
* this is due to a nosiy electrical environment or some odd
* timing issue.
*/
/*
* The enumeration command should be successfully sent, if not,
* we have big issues on the bus so punt. Lower layers report
* any unusual errors, so we don't need to here.
*/
err = enumfp(dev, dev);
if (err != 0)
return (err);
for (i = 0; i < 64; i++) {
OWLL_READ_DATA(lldev, &timing_regular, &first);
OWLL_READ_DATA(lldev, &timing_regular, &second);
switch (first | second << 1) {
case 0: /* Conflict */
if (i < prior)
dir = (last_mask >> i) & 1;
else
dir = i == prior;
if (dir == 0)
last = i;
break;
case 1: /* 1 then 0 -> 1 for all */
dir = 1;
break;
case 2: /* 0 then 1 -> 0 for all */
dir = 0;
break;
case 3:
/*
* No device responded. This is unexpected, but
* experience has shown that on some platforms
* we miss a timing window, or otherwise have
* an issue. Start this step over. Since we've
* not updated prior yet, we can just jump to
* the top of the loop for a re-do of this step.
*/
printf("oops, starting over\n");
if (++retries > 5)
return (EIO);
goto again;
}
if (dir) {
OWLL_WRITE_ONE(lldev, &timing_regular);
probed |= 1ull << i;
} else {
OWLL_WRITE_ZERO(lldev, &timing_regular);
}
}
retries = 0;
foundfp(dev, probed);
last_mask = probed;
prior = last;
};
ow_release_bus(dev, dev);
return (0);
}
static int
ow_probe(device_t dev)
{
device_set_desc(dev, "1 Wire Bus");
return (BUS_PROBE_GENERIC);
}
static int
ow_attach(device_t ndev)
{
struct ow_softc *sc;
/*
* Find all the devices on the bus. We don't probe / attach them in the
* enumeration phase. We do this because we want to allow the probe /
* attach routines of the child drivers to have as full an access to the
* bus as possible. While we reset things before the next step of the
* search (so it would likely be OK to allow access by the clients to
* the bus), it is more conservative to find them all, then to do the
* attach of the devices. This also allows the child devices to have
* more knowledge of the bus. We also ignore errors from the enumeration
* because they might happen after we've found a few devices.
*/
sc = device_get_softc(ndev);
sc->dev = ndev;
mtx_init(&sc->mtx, device_get_nameunit(sc->dev), "ow", MTX_DEF);
ow_enumerate(ndev, ow_search_rom, ow_device_found);
return bus_generic_attach(ndev);
}
static int
ow_detach(device_t ndev)
{
device_t *children, child;
int nkid, i;
struct ow_devinfo *di;
struct ow_softc *sc;
sc = device_get_softc(ndev);
/*
* detach all the children first. This is blocking until any threads
* have stopped, etc.
*/
bus_generic_detach(ndev);
/*
* We delete all the children, and free up the ivars
*/
if (device_get_children(ndev, &children, &nkid) != 0)
return ENOMEM;
for (i = 0; i < nkid; i++) {
child = children[i];
di = device_get_ivars(child);
free(di, M_OW);
device_delete_child(ndev, child);
}
free(children, M_TEMP);
OW_LOCK_DESTROY(sc);
return 0;
}
/*
* Not sure this is really needed. I'm having trouble figuring out what
* location means in the context of the one wire bus.
*/
static int
ow_child_location_str(device_t dev, device_t child, char *buf,
size_t buflen)
{
snprintf(buf, buflen, "");
return (0);
}
static int
ow_child_pnpinfo_str(device_t dev, device_t child, char *buf,
size_t buflen)
{
struct ow_devinfo *di;
di = device_get_ivars(child);
snprintf(buf, buflen, "romid=%8D", &di->romid, ":");
return (0);
}
static int
ow_read_ivar(device_t dev, device_t child, int which, uintptr_t *result)
{
struct ow_devinfo *di;
romid_t **ptr;
di = device_get_ivars(child);
switch (which) {
case OW_IVAR_FAMILY:
*result = di->romid & 0xff;
break;
case OW_IVAR_ROMID:
ptr = (romid_t **)result;
*ptr = &di->romid;
break;
default:
return EINVAL;
}
return 0;
}
static int
ow_write_ivar(device_t dev, device_t child, int which, uintptr_t value)
{
return EINVAL;
}
static int
ow_print_child(device_t ndev, device_t pdev)
{
int retval = 0;
struct ow_devinfo *di;
di = device_get_ivars(pdev);
retval += bus_print_child_header(ndev, pdev);
retval += printf(" romid %8D", &di->romid, ":");
retval += bus_print_child_footer(ndev, pdev);
return retval;
}
static void
ow_probe_nomatch(device_t ndev, device_t pdev)
{
struct ow_devinfo *di;
di = device_get_ivars(pdev);
device_printf(ndev, "romid %8D: no driver\n", &di->romid, ":");
}
static int
ow_acquire_bus(device_t ndev, device_t pdev, int how)
{
struct ow_softc *sc;
sc = device_get_softc(ndev);
OW_ASSERT_UNLOCKED(sc);
OW_LOCK(sc);
if (sc->owner != NULL) {
if (sc->owner == pdev)
panic("%s: %s recursively acquiring the bus.\n",
device_get_nameunit(ndev),
device_get_nameunit(pdev));
if (how == OWN_DONTWAIT) {
OW_UNLOCK(sc);
return EWOULDBLOCK;
}
while (sc->owner != NULL)
mtx_sleep(sc, &sc->mtx, 0, "owbuswait", 0);
}
sc->owner = pdev;
OW_UNLOCK(sc);
return 0;
}
static void
ow_release_bus(device_t ndev, device_t pdev)
{
struct ow_softc *sc;
sc = device_get_softc(ndev);
OW_ASSERT_UNLOCKED(sc);
OW_LOCK(sc);
if (sc->owner == NULL)
panic("%s: %s releasing unowned bus.", device_get_nameunit(ndev),
device_get_nameunit(pdev));
if (sc->owner != pdev)
panic("%s: %s don't own the bus. %s does. game over.",
device_get_nameunit(ndev), device_get_nameunit(pdev),
device_get_nameunit(sc->owner));
sc->owner = NULL;
wakeup(sc);
OW_UNLOCK(sc);
}
devclass_t ow_devclass;
static device_method_t ow_methods[] = {
/* Device interface */
DEVMETHOD(device_probe, ow_probe),
DEVMETHOD(device_attach, ow_attach),
DEVMETHOD(device_detach, ow_detach),
/* Bus interface */
DEVMETHOD(bus_child_pnpinfo_str, ow_child_pnpinfo_str),
DEVMETHOD(bus_child_location_str, ow_child_location_str),
DEVMETHOD(bus_read_ivar, ow_read_ivar),
DEVMETHOD(bus_write_ivar, ow_write_ivar),
DEVMETHOD(bus_print_child, ow_print_child),
DEVMETHOD(bus_probe_nomatch, ow_probe_nomatch),
/* One Wire Network/Transport layer interface */
DEVMETHOD(own_send_command, ow_send_command),
DEVMETHOD(own_acquire_bus, ow_acquire_bus),
DEVMETHOD(own_release_bus, ow_release_bus),
DEVMETHOD(own_crc, ow_crc),
{ 0, 0 }
};
static driver_t ow_driver = {
"ow",
ow_methods,
sizeof(struct ow_softc),
};
DRIVER_MODULE(ow, owc, ow_driver, ow_devclass, 0, 0);
MODULE_VERSION(ow, 1);

77
sys/dev/ow/ow.h Normal file
View File

@ -0,0 +1,77 @@
/*-
* Copyright (c) 2015 M. Warner Losh <imp@freebsd.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice unmodified, this list of conditions, and the following
* disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* $FreeBSD$
*/
#ifndef DEV_OW_OW_H
#define DEV_OW_OW_H 1
enum ow_device_ivars {
OW_IVAR_FAMILY,
OW_IVAR_ROMID
};
#define OW_ACCESSOR(var, ivar, type) \
__BUS_ACCESSOR(ow, var, OW, ivar, type);
OW_ACCESSOR(family, FAMILY, uint8_t)
OW_ACCESSOR(romid, ROMID, uint8_t *)
#undef OW_ACCSSOR
/*
* The following likely should be in the own.h file, but needs to be here to
* avoid recursive issues when defining the own_if.m interface.
*/
/*
* Generalized command structure for a 1wire bus transaction. Not all possible
* transactions on the 1wire bus can be represented here (a notable exception
* being both the search ROM commands), but most of them can be, allowing for
* general transactions from userland. A lower-level interface to the link
* layer is also provided.
*/
#define MAX_ROM 10
#define MAX_XPT 32
#define MAX_READ 32
struct ow_cmd
{
uint32_t flags; /* Various flags */
#define OW_FLAG_OVERDRIVE 1 /* Send xpt stuff overdrive speed */
#define OW_FLAG_READ_BIT 2 /* Read a single bit after xpt_cmd */
uint8_t rom_len; /* Number of ROM bytes to send */
uint8_t rom_cmd[MAX_ROM]; /* Rom command to send */
uint8_t rom_read_len; /* Number of bytes to read */
uint8_t rom_read[MAX_ROM]; /* Extra bytes read */
uint8_t xpt_len; /* Total transport bytes to send */
uint8_t xpt_cmd[MAX_XPT]; /* Device specific command to send, if flagged */
uint8_t xpt_read_len; /* Number of bytes to read after */
uint8_t xpt_read[MAX_READ]; /* Buffer for read bytes */
};
typedef uint64_t romid_t;
#endif /* DEV_OW_OW_H */

285
sys/dev/ow/ow_temp.c Normal file
View File

@ -0,0 +1,285 @@
/*-
* Copyright (c) 2015 M. Warner Losh <imp@freebsd.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice unmodified, this list of conditions, and the following
* disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/kernel.h>
#include <sys/bus.h>
#include <sys/errno.h>
#include <sys/libkern.h>
#include <sys/kthread.h>
#include <sys/malloc.h>
#include <sys/module.h>
#include <sys/mutex.h>
#include <sys/proc.h>
#include <sys/sysctl.h>
#include <dev/ow/ow.h>
#include <dev/ow/own.h>
#define OWT_DS1820 0x10 /* Also 18S20 */
#define OWT_DS1822 0x22 /* Very close to 18B20 */
#define OWT_DS18B20 0x28 /* Also MAX31820 */
#define OWT_DS1825 0x3B /* Just like 18B20 with address bits */
#define CONVERT_T 0x44
#define COPY_SCRATCHPAD 0x48
#define WRITE_SCRATCHPAD 0x4e
#define READ_POWER_SUPPLY 0xb4
#define RECALL_EE 0xb8
#define READ_SCRATCHPAD 0xbe
#define OW_TEMP_DONE 0x01
#define OW_TEMP_RUNNING 0x02
struct ow_temp_softc
{
device_t dev;
int type;
int temp;
int flags;
int bad_crc;
int bad_reads;
int reading_interval;
int parasite;
struct mtx temp_lock;
struct proc *event_thread;
};
static int
ow_temp_probe(device_t dev)
{
switch (ow_get_family(dev)) {
case OWT_DS1820:
device_set_desc(dev, "One Wire Temperature");
return BUS_PROBE_DEFAULT;
case OWT_DS1822:
case OWT_DS1825:
case OWT_DS18B20:
device_set_desc(dev, "Advanced One Wire Temperature");
return BUS_PROBE_DEFAULT;
default:
return ENXIO;
}
}
static int
ow_temp_read_scratchpad(device_t dev, uint8_t *scratch, int len)
{
struct ow_cmd cmd;
own_self_command(dev, &cmd, READ_SCRATCHPAD);
cmd.xpt_read_len = len;
own_command_wait(dev, &cmd);
memcpy(scratch, cmd.xpt_read, len);
return 0;
}
static int
ow_temp_convert_t(device_t dev)
{
struct ow_cmd cmd;
own_self_command(dev, &cmd, CONVERT_T);
own_command_wait(dev, &cmd);
return 0;
}
static int
ow_temp_read_power_supply(device_t dev, int *parasite)
{
struct ow_cmd cmd;
own_self_command(dev, &cmd, READ_POWER_SUPPLY);
cmd.flags |= OW_FLAG_READ_BIT;
cmd.xpt_read_len = 1;
own_command_wait(dev, &cmd);
*parasite = !cmd.xpt_read[0]; /* parasites pull bus low */
return 0;
}
static void
ow_temp_event_thread(void *arg)
{
struct ow_temp_softc *sc;
uint8_t scratch[8 + 1];
uint8_t crc;
int retries, rv;
sc = arg;
pause("owtstart", device_get_unit(sc->dev) * hz / 100); // 10ms stagger
mtx_lock(&sc->temp_lock);
sc->flags |= OW_TEMP_RUNNING;
ow_temp_read_power_supply(sc->dev, &sc->parasite);
if (sc->parasite)
device_printf(sc->dev, "Running in parasitic mode unsupported\n");
while ((sc->flags & OW_TEMP_DONE) == 0) {
mtx_unlock(&sc->temp_lock);
ow_temp_convert_t(sc->dev);
mtx_lock(&sc->temp_lock);
msleep(sc, &sc->temp_lock, 0, "owtcvt", hz);
if (sc->flags & OW_TEMP_DONE)
break;
for (retries = 5; retries > 0; retries--) {
mtx_unlock(&sc->temp_lock);
rv = ow_temp_read_scratchpad(sc->dev, scratch, sizeof(scratch));
mtx_lock(&sc->temp_lock);
if (rv == 0) {
crc = own_crc(sc->dev, scratch, sizeof(scratch) - 1);
if (crc == scratch[8]) {
if (sc->type == OWT_DS1820) {
if (scratch[7]) {
/*
* Formula from DS18S20 datasheet, page 6
* DS18S20 datahseet says count_per_c is 16, DS1820 does not
*/
sc->temp = (int16_t)((scratch[0] & 0xfe) |
(scratch[1] << 8)) << 3;
sc->temp += 16 - scratch[6] - 4; /* count_per_c == 16 */
} else
sc->temp = (int16_t)(scratch[0] | (scratch[1] << 8)) << 3;
} else
sc->temp = (int16_t)(scratch[0] | (scratch[1] << 8));
sc->temp = sc->temp * 1000 / 16 + 273150;
break;
}
sc->bad_crc++;
} else
sc->bad_reads++;
}
msleep(sc, &sc->temp_lock, 0, "owtcvt", sc->reading_interval);
}
sc->flags &= ~OW_TEMP_RUNNING;
mtx_unlock(&sc->temp_lock);
kproc_exit(0);
}
static int
ow_temp_attach(device_t dev)
{
struct ow_temp_softc *sc;
sc = device_get_softc(dev);
sc->dev = dev;
sc->type = ow_get_family(dev);
SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
OID_AUTO, "temperature", CTLFLAG_RD | CTLTYPE_INT,
&sc->temp, 0, sysctl_handle_int,
"IK3", "Current Temperature");
SYSCTL_ADD_INT(device_get_sysctl_ctx(dev),
SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
OID_AUTO, "badcrc", CTLFLAG_RD,
&sc->bad_crc, 0,
"Number of Bad CRC on reading scratchpad");
SYSCTL_ADD_INT(device_get_sysctl_ctx(dev),
SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
OID_AUTO, "badread", CTLFLAG_RD,
&sc->bad_reads, 0,
"Number of errors on reading scratchpad");
SYSCTL_ADD_INT(device_get_sysctl_ctx(dev),
SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
OID_AUTO, "reading_interval", CTLFLAG_RW,
&sc->reading_interval, 0,
"ticks between reads");
SYSCTL_ADD_INT(device_get_sysctl_ctx(dev),
SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
OID_AUTO, "parasite", CTLFLAG_RW,
&sc->parasite, 0,
"In Parasite mode");
/*
* Just do this for unit 0 to avoid locking
* the ow bus until that code can be put
* into place.
*/
sc->temp = -1;
sc->reading_interval = 10 * hz;
mtx_init(&sc->temp_lock, "lock for doing temperature", NULL, MTX_DEF);
/* Start the thread */
if (kproc_create(ow_temp_event_thread, sc, &sc->event_thread, 0, 0,
"%s event thread", device_get_nameunit(dev))) {
device_printf(dev, "unable to create event thread.\n");
panic("cbb_create_event_thread");
}
return 0;
}
static int
ow_temp_detach(device_t dev)
{
struct ow_temp_softc *sc;
sc = device_get_softc(dev);
/*
* Wait for the thread to die. kproc_exit will do a wakeup
* on the event thread's struct thread * so that we know it is
* safe to proceed. IF the thread is running, set the please
* die flag and wait for it to comply. Since the wakeup on
* the event thread happens only in kproc_exit, we don't
* need to loop here.
*/
mtx_lock(&sc->temp_lock);
sc->flags |= OW_TEMP_DONE;
while (sc->flags & OW_TEMP_RUNNING) {
wakeup(sc);
msleep(sc->event_thread, &sc->temp_lock, PWAIT, "owtun", 0);
}
mtx_destroy(&sc->temp_lock);
return 0;
}
devclass_t ow_temp_devclass;
static device_method_t ow_temp_methods[] = {
/* Device interface */
DEVMETHOD(device_probe, ow_temp_probe),
DEVMETHOD(device_attach, ow_temp_attach),
DEVMETHOD(device_detach, ow_temp_detach),
{ 0, 0 }
};
static driver_t ow_temp_driver = {
"ow_temp",
ow_temp_methods,
sizeof(struct ow_temp_softc),
};
DRIVER_MODULE(ow_temp, ow, ow_temp_driver, ow_temp_devclass, 0, 0);
MODULE_DEPEND(ow_temp, ow, 1, 1, 1);

420
sys/dev/ow/owc_gpiobus.c Normal file
View File

@ -0,0 +1,420 @@
/*-
* Copyright (c) 2015 M. Warner Losh <imp@freebsd.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include "opt_platform.h"
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/bus.h>
#include <sys/gpio.h>
#include <sys/kernel.h>
#include <sys/lock.h>
#include <sys/malloc.h>
#include <sys/module.h>
#include <sys/mutex.h>
#ifdef FDT
#include <dev/fdt/fdt_common.h>
#include <dev/ofw/ofw_bus.h>
#include <dev/ofw/ofw_bus_subr.h>
#endif
#include <dev/gpio/gpiobusvar.h>
#include "gpiobus_if.h"
#include <dev/ow/owll.h>
#define OW_PIN 0
#define OWC_GPIOBUS_LOCK(_sc) mtx_lock(&(_sc)->sc_mtx)
#define OWC_GPIOBUS_UNLOCK(_sc) mtx_unlock(&(_sc)->sc_mtx)
#define OWC_GPIOBUS_LOCK_INIT(_sc) \
mtx_init(&_sc->sc_mtx, device_get_nameunit(_sc->sc_dev), \
"owc_gpiobus", MTX_DEF)
#define OWC_GPIOBUS_LOCK_DESTROY(_sc) mtx_destroy(&_sc->sc_mtx);
struct owc_gpiobus_softc
{
device_t sc_dev;
device_t sc_busdev;
struct mtx sc_mtx;
};
static int owc_gpiobus_probe(device_t);
static int owc_gpiobus_attach(device_t);
static int owc_gpiobus_detach(device_t);
#ifdef FDT
static void
owc_gpiobus_identify(driver_t *driver, device_t bus)
{
phandle_t w1, root;
/*
* Find all the 1-wire bus pseudo-nodes that are
* at the top level of the FDT. Would be nice to
* somehow preserve the node name of these busses,
* but there's no good place to put it. The driver's
* name is used for the device name, and the 1-wire
* bus overwrites the description.
*/
root = OF_finddevice("/");
if (root == 0)
return;
for (w1 = OF_child(root); w1 != 0; w1 = OF_peer(w1)) {
if (!fdt_is_compatible_strict(w1, "w1-gpio"))
continue;
if (!OF_hasprop(w1, "gpios"))
continue;
ofw_gpiobus_add_fdt_child(bus, driver->name, w1);
}
}
#endif
static int
owc_gpiobus_probe(device_t dev)
{
#ifdef FDT
if (!ofw_bus_status_okay(dev))
return (ENXIO);
if (ofw_bus_is_compatible(dev, "w1-gpio")) {
device_set_desc(dev, "FDT GPIO attached one-wire bus");
return (BUS_PROBE_DEFAULT);
}
return (ENXIO);
#else
device_set_desc(dev, "GPIO attached one-wire bus");
return 0;
#endif
}
static int
owc_gpiobus_attach(device_t dev)
{
struct owc_gpiobus_softc *sc;
device_t *kids;
int nkid;
sc = device_get_softc(dev);
sc->sc_dev = dev;
sc->sc_busdev = device_get_parent(dev);
OWC_GPIOBUS_LOCK_INIT(sc);
nkid = 0;
if (device_get_children(dev, &kids, &nkid) == 0)
free(kids, M_TEMP);
if (nkid == 0)
device_add_child(dev, "ow", -1);
bus_generic_attach(dev);
return (0);
}
static int
owc_gpiobus_detach(device_t dev)
{
struct owc_gpiobus_softc *sc;
sc = device_get_softc(dev);
OWC_GPIOBUS_LOCK_DESTROY(sc);
bus_generic_detach(dev);
return (0);
}
/*
* In the diagrams below, R is driven by the resistor pullup, M is driven by the
* master, and S is driven by the slave / target.
*/
/*
* These macros let what why we're doing stuff shine in the code
* below, and let the how be confined to here.
*/
#define GETBUS(sc) GPIOBUS_ACQUIRE_BUS((sc)->sc_busdev, \
(sc)->sc_dev, GPIOBUS_WAIT)
#define RELBUS(sc) GPIOBUS_RELEASE_BUS((sc)->sc_busdev, \
(sc)->sc_dev)
#define OUTPIN(sc) GPIOBUS_PIN_SETFLAGS((sc)->sc_busdev, \
(sc)->sc_dev, OW_PIN, GPIO_PIN_OUTPUT)
#define INPIN(sc) GPIOBUS_PIN_SETFLAGS((sc)->sc_busdev, \
(sc)->sc_dev, OW_PIN, GPIO_PIN_INPUT)
#define GETPIN(sc, bit) GPIOBUS_PIN_GET((sc)->sc_busdev, \
(sc)->sc_dev, OW_PIN, bit)
#define LOW(sc) GPIOBUS_PIN_SET((sc)->sc_busdev, \
(sc)->sc_dev, OW_PIN, GPIO_PIN_LOW)
/*
* WRITE-ONE (see owll_if.m for timings) From Figure 4-1 AN-937
*
* |<---------tSLOT---->|<-tREC->|
* High RRRRM | RRRRRRRRRRRR|RRRRRRRRM
* M | R | | | M
* M| R | | | M
* Low MMMMMMM | | | MMMMMM...
* |<-tLOW1->| | |
* |<------15us--->| |
* |<--------60us---->|
*/
static int
owc_gpiobus_write_one(device_t dev, struct ow_timing *t)
{
struct owc_gpiobus_softc *sc;
int error;
sc = device_get_softc(dev);
error = GETBUS(sc);
if (error != 0)
return error;
critical_enter();
/* Force low */
OUTPIN(sc);
LOW(sc);
DELAY(t->t_low1);
/* Allow resistor to float line high */
INPIN(sc);
DELAY(t->t_slot - t->t_low1 + t->t_rec);
critical_exit();
RELBUS(sc);
return 0;
}
/*
* WRITE-ZERO (see owll_if.m for timings) From Figure 4-2 AN-937
*
* |<---------tSLOT------>|<-tREC->|
* High RRRRM | | |RRRRRRRM
* M | | R M
* M| | | |R M
* Low MMMMMMMMMMMMMMMMMMMMMR MMMMMM...
* |<--15us->| | |
* |<------60us--->| |
* |<-------tLOW0------>|
*/
static int
owc_gpiobus_write_zero(device_t dev, struct ow_timing *t)
{
struct owc_gpiobus_softc *sc;
int error;
sc = device_get_softc(dev);
error = GETBUS(sc);
if (error != 0)
return error;
critical_enter();
/* Force low */
OUTPIN(sc);
LOW(sc);
DELAY(t->t_low0);
/* Allow resistor to float line high */
INPIN(sc);
DELAY(t->t_slot - t->t_low0 + t->t_rec);
critical_exit();
RELBUS(sc);
return 0;
}
/*
* READ-DATA (see owll_if.m for timings) From Figure 4-3 AN-937
*
* |<---------tSLOT------>|<-tREC->|
* High RRRRM | rrrrrrrrrrrrrrrRRRRRRRM
* M | r | R M
* M| r | |R M
* Low MMMMMMMSSSSSSSSSSSSSSR MMMMMM...
* |<tLOWR>< sample > |
* |<------tRDV---->| |
* ->| |<-tRELEASE
*
* r -- allowed to pull high via the resitor when slave writes a 1-bit
*
*/
static int
owc_gpiobus_read_data(device_t dev, struct ow_timing *t, int *bit)
{
struct owc_gpiobus_softc *sc;
int error, sample;
sbintime_t then, now;
sc = device_get_softc(dev);
error = GETBUS(sc);
if (error != 0)
return error;
/* Force low for t_lowr microseconds */
then = sbinuptime();
OUTPIN(sc);
LOW(sc);
DELAY(t->t_lowr);
/*
* Slave is supposed to hold the line low for t_rdv microseconds for 0
* and immediately float it high for a 1. This is measured from the
* master's pushing the line low.
*/
INPIN(sc);
critical_enter();
do {
now = sbinuptime();
GETPIN(sc, &sample);
} while ((now - then) / SBT_1US < t->t_rdv + 2 && sample == 0);
critical_exit();
if ((now - then) / SBT_1NS < t->t_rdv * 1000)
*bit = 1;
else
*bit = 0;
/* Wait out the rest of t_slot */
do {
now = sbinuptime();
} while ((now - then) / SBT_1US < t->t_slot);
RELBUS(sc);
return 0;
}
/*
* RESET AND PRESENCE PULSE (see owll_if.m for timings) From Figure 4-4 AN-937
*
* |<---------tRSTH------------>|
* High RRRM | | RRRRRRRS | RRRR RRM
* M | |R| |S | R M
* M| R | | S |R M
* Low MMMMMMMM MMMMMM| | | SSSSSSSSSS MMMMMM
* |<----tRSTL--->| | |<-tPDL---->|
* | ->| |<-tR | |
* |<tPDH>|
*
* Note: for Regular Speed operations, tRSTL + tR should be less than 960us to
* avoid interferring with other devices on the bus
*/
static int
owc_gpiobus_reset_and_presence(device_t dev, struct ow_timing *t, int *bit)
{
struct owc_gpiobus_softc *sc;
int error;
int buf = -1;
sc = device_get_softc(dev);
error = GETBUS(sc);
if (error != 0)
return error;
/*
* Read the current state of the bus. The steady state of an idle bus is
* high. Badly wired buses that are missing the required pull up, or
* that have a short circuit to ground cause all kinds of mischief when
* we try to read them later. Return EIO and release the bus if the bus
* is currently low.
*/
INPIN(sc);
GETPIN(sc, &buf);
if (buf == 0) {
*bit = -1;
RELBUS(sc);
return EIO;
}
critical_enter();
/* Force low */
OUTPIN(sc);
LOW(sc);
DELAY(t->t_rstl);
/* Allow resistor to float line high and then wait for reset pulse */
INPIN(sc);
DELAY(t->t_pdh + t->t_pdl / 2);
/* Read presence pulse */
GETPIN(sc, &buf);
*bit = !!buf;
critical_exit();
DELAY(t->t_rsth - (t->t_pdh + t->t_pdl / 2)); /* Timing not critical for this one */
/*
* Read the state of the bus after we've waited past the end of the rest
* window. It should return to high. If it is low, then we have some
* problem and should abort the reset.
*/
GETPIN(sc, &buf);
if (buf == 0) {
*bit = -1;
RELBUS(sc);
return EIO;
}
RELBUS(sc);
return 0;
}
static devclass_t owc_gpiobus_devclass;
static device_method_t owc_gpiobus_methods[] = {
/* Device interface */
#ifdef FDT
DEVMETHOD(device_identify, owc_gpiobus_identify),
#endif
DEVMETHOD(device_probe, owc_gpiobus_probe),
DEVMETHOD(device_attach, owc_gpiobus_attach),
DEVMETHOD(device_detach, owc_gpiobus_detach),
DEVMETHOD(owll_write_one, owc_gpiobus_write_one),
DEVMETHOD(owll_write_zero, owc_gpiobus_write_zero),
DEVMETHOD(owll_read_data, owc_gpiobus_read_data),
DEVMETHOD(owll_reset_and_presence, owc_gpiobus_reset_and_presence),
{ 0, 0 }
};
static driver_t owc_gpiobus_driver = {
"owc",
owc_gpiobus_methods,
sizeof(struct owc_gpiobus_softc),
};
DRIVER_MODULE(owc_gpiobus_fdt, gpiobus, owc_gpiobus_driver, owc_gpiobus_devclass, 0, 0);
MODULE_DEPEND(owc_gpiobus_fdt, ow, 1, 1, 1);

54
sys/dev/ow/owll.h Normal file
View File

@ -0,0 +1,54 @@
/*-
* Copyright (c) 2015 M. Warner Losh <imp@freebsd.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice unmodified, this list of conditions, and the following
* disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* $FreeBSD$
*/
#ifndef DEV_OW_OWLL_H
#define DEV_OW_OWLL_H 1
/*
* Generalized parameters for the mode of operation in the bus. All units
* are in nanoseconds, and assume that all timings are < 4s.
* See owll_if.m for timings, and refer to AN937 for details.
*/
struct ow_timing
{
uint32_t t_slot; /* Slot time */
uint32_t t_low0; /* Time low for a 0 bit. */
uint32_t t_low1; /* Time low for a 1 bit. */
uint32_t t_lowr; /* Time slave holds line down per bit */
uint32_t t_release; /* Time after t_rdv to float high */
uint32_t t_rec; /* After sample before M low */
uint32_t t_rdv; /* Time to poll the bit after M low */
uint32_t t_rstl; /* Time M low on reset */
uint32_t t_rsth; /* Time M high on reset */
uint32_t t_pdl; /* Time S low on reset */
uint32_t t_pdh; /* Time R high after M low on reset */
};
#include "owll_if.h"
#endif /* DEV_OW_OWLL_H */

158
sys/dev/ow/owll_if.m Normal file
View File

@ -0,0 +1,158 @@
#-
# Copyright (c) 2015 M. Warner Losh <imp@freebsd.org>
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
# 1. Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
# SUCH DAMAGE.
#
# $FreeBSD$
#
#include <sys/bus.h>
#include <dev/ow/owll.h>
INTERFACE owll;
#
# Dallas Semiconductor 1-Wire bus Link Layer (owll)
#
# See Maxim Application Note AN937: Book of iButton Standards for the
# 1-Wire protocol specification.
# http://pdfserv.maximintegrated.com/en/an/AN937.pdf
#
# Note: 1-Wire is a registered trademark of Maxim Integrated Products, Inc.
#
# This file provides an interface to the logical layer of the protocol.
# Although the first implementation is done with GPIO bit banging, some
# SoCs have a 1-Wire controller with more smarts or hardware offload.
# Maxim datasheets also describe how to use UARTs to generate timing,
# as well as both usb and i2c 1-Wire controllers.
#
# Chapter 4 has all the electrical timing diagrams that make up the link
# layer of this protocol.
#
# Two speed classes are defined: Regular speed and Overdrive speed.
# It is the responsibility of a device implementing the owll(9) interface
# to ensure that the timings are met:
#
# Regular Overdrive
#
# 60us <= tSLOT < 120us 6us <= tSLOT <= 16us
# 60us <= tLOW0 < tSLOT < 120us 6us <= tLOW0 < tSLOT < 16us
# 1us <= tLOW1 < 15us 1us <= tLOW < 2us
# 1us < tLOWR < 15us 1us <= tLOWR < 2us
# 0 <= tRELEASE < 45us 0 <= tRELEASE < 4us
# 1us <= tREC < inf 1us <= tREC < inf
# tRDV = 15us tRDV = 2us
# 480us <= tRSTL < inf 48us <= tRSTL < 80us
# 480us <= tRSTH < inf 48us <= tRSTH < inf
# 15us < tPDH < 60us 2us <= tPDH < 6us
# 60us < tPDL < 240us 8us <= tPDL < 24us
#
# In the diagrams below, R is driven by the resistor pullup, M is driven by
# the master, and S is driven by the slave / target.
#
# All of these methods are expected to be called from the "network"/bus layer
# for doing its operations. See 1wn_if.m for those.
#
# Note: This is the polling / busy-wait interface. An interrupt-based interface
# may be different. But an interrupt-based, non-blocking interface can be tricky.
#
# Only the owbus should talk to this interface.
#
# WRITE-ONE (see above for timings) From Figure 4-1 AN-937
#
# |<---------tSLOT---->|<-tREC->|
# High RRRRM | RRRRRRRRRRRR|RRRRRRRRM
# M | R | | | M
# M| R | | | M
# Low MMMMMMM | | | MMMMMM...
# |<-tLOW1->| | |
# |<------15us--->| |
# |<--------60us---->|
#
#
METHOD int write_one {
device_t lldev; /* Link Level device (eg bridge) */
struct ow_timing *timing; /* timing values */
};
# WRITE-ZERO (see above for timings) From Figure 4-2 AN-937
#
# |<---------tSLOT------>|<-tREC->|
# High RRRRM | | |RRRRRRRM
# M | | R M
# M| | | |R M
# Low MMMMMMMMMMMMMMMMMMMMMR MMMMMM...
# |<--15us->| | |
# |<------60us--->| |
# |<-------tLOW0------>|
#
#
METHOD int write_zero {
device_t lldev; /* Link Level device (eg bridge) */
struct ow_timing *timing; /* timing values */
};
# READ-DATA (see above for timings) From Figure 4-3 AN-937
#
# |<---------tSLOT------>|<-tREC->|
# High RRRRM | rrrrrrrrrrrrrrrRRRRRRRM
# M | r | R M
# M| r | |R M
# Low MMMMMMMSSSSSSSSSSSSSSR MMMMMM...
# |<tLOWR>< sample > |
# |<------tRDV---->| |
# ->| |<-tRELEASE
#
# r -- allowed to pull high via the resistor when slave writes a 1-bit
#
METHOD int read_data {
device_t lldev; /* Link Level device (eg bridge) */
struct ow_timing *timing; /* timing values */
int *bit; /* Bit we sampled */
};
# RESET AND PRESENCE PULSE (see above for timings) From Figure 4-4 AN-937
#
# |<---------tRSTH------------>|
# High RRRM | | RRRRRRRS | RRRR RRM
# M | |R| |S | R M
# M| R | | S |R M
# Low MMMMMMMM MMMMMM| | | SSSSSSSSSS MMMMMM
# |<----tRSTL--->| | |<-tPDL---->|
# | ->| |<-tR | |
# |<tPDH>|
#
# Note: for Regular Speed operations, tRSTL + tR should be less than 960us to
# avoid interfering with other devives on the bus.
#
# Returns errors associating with acquiring the bus, or EIO to indicate
# that the bus was low during the RRRR time where it should have been
# pulled high. The present field is always updated, even on error.
#
METHOD int reset_and_presence {
device_t lldev; /* Link level device (eg bridge) */
struct ow_timing *timing; /* timing values */
int *present; /* 0 = slave 1 = no slave -1 = bus error */
};

106
sys/dev/ow/own.h Normal file
View File

@ -0,0 +1,106 @@
/*-
* Copyright (c) 2015 M. Warner Losh <imp@freebsd.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice unmodified, this list of conditions, and the following
* disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* $FreeBSD$
*/
#ifndef DEV_OW_OWN_H
#define DEV_OW_OWN_H 1
#include "own_if.h"
#define READ_ROM 0x33
#define MATCH_ROM 0x55
#define SKIP_ROM 0xcc
#define ALARM_SEARCH 0xec
#define SEARCH_ROM 0xf0
static inline int
own_send_command(device_t pdev, struct ow_cmd *cmd)
{
device_t ndev = device_get_parent(pdev);
return OWN_SEND_COMMAND(ndev, pdev, cmd);
}
/*
* How args for own_acquire_bus
*/
#define OWN_WAIT 1
#define OWN_DONTWAIT 2
static inline int
own_acquire_bus(device_t pdev, int how)
{
device_t ndev = device_get_parent(pdev);
return OWN_ACQUIRE_BUS(ndev, pdev, how);
}
static inline void
own_release_bus(device_t pdev)
{
device_t ndev = device_get_parent(pdev);
OWN_RELEASE_BUS(ndev, pdev);
}
static inline uint8_t
own_crc(device_t pdev, uint8_t *buffer, size_t len)
{
device_t ndev = device_get_parent(pdev);
return OWN_CRC(ndev, pdev, buffer, len);
}
static inline void
own_self_command(device_t pdev, struct ow_cmd *cmd, uint8_t xpt_cmd)
{
uint8_t *mep;
memset(cmd, 0, sizeof(*cmd));
mep = ow_get_romid(pdev);
cmd->rom_cmd[0] = MATCH_ROM;
memcpy(&cmd->rom_cmd[1], mep, sizeof(romid_t));
cmd->rom_len = 1 + sizeof(romid_t);
cmd->xpt_cmd[0] = xpt_cmd;
cmd->xpt_len = 1;
}
static inline int
own_command_wait(device_t pdev, struct ow_cmd *cmd)
{
int rv;
rv = own_acquire_bus(pdev, OWN_WAIT);
if (rv != 0)
return rv;
rv = own_send_command(pdev, cmd);
own_release_bus(pdev);
return rv;
}
#endif /* DEV_OW_OWLL_H */

78
sys/dev/ow/own_if.m Normal file
View File

@ -0,0 +1,78 @@
#-
# Copyright (c) 2015 M. Warner Losh <imp@freebsd.org>
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
# 1. Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
# SUCH DAMAGE.
#
# $FreeBSD$
#
#include <sys/bus.h>
#include <dev/ow/ow.h>
INTERFACE own;
#
# Dallas Semiconductor 1-Wire bus network and transport layer (own)
#
# See Maxim Application Note AN937: Book of iButton Standards for the
# 1-Wire protocol specification.
# http://pdfserv.maximintegrated.com/en/an/AN937.pdf
#
# Note: 1-Wire is a registered trademark of Maxim Integrated Products, Inc.
#
#
# Send a command up the stack.
#
METHOD int send_command {
device_t ndev; /* Network (bus) level device */
device_t pdev; /* Device to send command for */
struct ow_cmd *cmd; /* Pointer to filled in command */
};
#
# Grab exclusive use of the bus (advisory)
#
METHOD int acquire_bus {
device_t ndev;
device_t pdev;
int how;
};
#
# Release exclusive use of the bus (advisory)
#
METHOD void release_bus {
device_t ndev;
device_t pdev;
};
#
# Compute a CRC for a given range of bytes
#
METHOD uint8_t crc {
device_t ndev;
device_t pdev;
uint8_t *buffer;
size_t len;
};

View File

@ -270,6 +270,7 @@ SUBDIR= \
${_nxge} \
${_opensolaris} \
oce \
ow \
${_padlock} \
${_padlock_rng} \
patm \

8
sys/modules/ow/Makefile Normal file
View File

@ -0,0 +1,8 @@
# $FreeBSD$
SYSDIR?=${.CURDIR}/../..
.include "${SYSDIR}/conf/kern.opts.mk"
SUBDIR = ow owc ow_temp
.include <bsd.subdir.mk>

View File

@ -0,0 +1,9 @@
# $FreeBSD$
.PATH: ${.CURDIR}/../../../dev/ow
KMOD= ow
SRCS= ow.c
SRCS+= own_if.c own_if.h owll_if.c owll_if.h bus_if.h device_if.h
.include <bsd.kmod.mk>

View File

@ -0,0 +1,9 @@
# $FreeBSD$
.PATH: ${.CURDIR}/../../../dev/ow
KMOD= ow_temp
SRCS= ow_temp.c
SRCS+= own_if.h bus_if.h device_if.h
.include <bsd.kmod.mk>

View File

@ -0,0 +1,10 @@
# $FreeBSD$
.PATH: ${.CURDIR}/../../../dev/ow
KMOD= owc
SRCS= owc_gpiobus.c
SRCS+= gpio_if.h gpiobus_if.h owll_if.h ofw_bus_if.h bus_if.h device_if.h
SRCS+= opt_platform.h
.include <bsd.kmod.mk>