fermentord/vendor/github.com/warthog618/go-gpiocdev/uapi/uapi_v2.go

625 lines
16 KiB
Go

// SPDX-FileCopyrightText: 2020 Kent Gibson <warthog618@gmail.com>
//
// SPDX-License-Identifier: MIT
//go:build linux
// +build linux
package uapi
import (
"encoding/binary"
"time"
"unsafe"
"golang.org/x/sys/unix"
)
// GetLineInfoV2 returns the LineInfoV2 for one line from the GPIO character device.
//
// The fd is an open GPIO character device.
// The offset is zero based.
func GetLineInfoV2(fd uintptr, offset int) (LineInfoV2, error) {
li := LineInfoV2{Offset: uint32(offset)}
_, _, errno := unix.Syscall(unix.SYS_IOCTL,
fd,
uintptr(getLineInfoV2Ioctl),
uintptr(unsafe.Pointer(&li)))
if errno != 0 {
return LineInfoV2{}, errno
}
return li, nil
}
// GetLine requests a line from the GPIO character device.
//
// The fd is an open GPIO character device.
// The lines must not already be requested.
// The flags in the request will be applied to all lines in the request.
// If successful, the fd for the line is returned in the request.fd.
func GetLine(fd uintptr, request *LineRequest) error {
_, _, errno := unix.Syscall(unix.SYS_IOCTL,
fd,
uintptr(getLineIoctl),
uintptr(unsafe.Pointer(request)))
if errno != 0 {
return errno
}
return nil
}
// GetLineValuesV2 returns the values of a set of requested lines.
//
// The fd is a requested line, as returned by GetLine.
//
// The values returned are the logical values, with inactive being 0.
func GetLineValuesV2(fd uintptr, values *LineValues) error {
_, _, errno := unix.Syscall(unix.SYS_IOCTL,
fd,
uintptr(getLineValuesV2Ioctl),
uintptr(unsafe.Pointer(values)))
if errno != 0 {
return errno
}
return nil
}
// SetLineValuesV2 sets the values of a set of requested lines.
//
// The fd is a requested line, as returned by GetLine.
func SetLineValuesV2(fd uintptr, values LineValues) error {
_, _, errno := unix.Syscall(unix.SYS_IOCTL,
fd,
uintptr(setLineValuesV2Ioctl),
uintptr(unsafe.Pointer(&values)))
if errno != 0 {
return errno
}
return nil
}
// SetLineConfigV2 sets the config of an existing handle request.
//
// The config flags in the request will be applied to all lines in the request.
func SetLineConfigV2(fd uintptr, config *LineConfig) error {
_, _, errno := unix.Syscall(unix.SYS_IOCTL,
fd,
uintptr(setLineConfigV2Ioctl),
uintptr(unsafe.Pointer(config)))
if errno != 0 {
return errno
}
return nil
}
// WatchLineInfoV2 sets a watch on info of a line.
//
// A watch is set on the line indicated by info.Offset. If successful the
// current line info is returned, else an error is returned.
func WatchLineInfoV2(fd uintptr, info *LineInfoV2) error {
_, _, errno := unix.Syscall(unix.SYS_IOCTL,
fd,
uintptr(watchLineInfoV2Ioctl),
uintptr(unsafe.Pointer(info)))
if errno != 0 {
return errno
}
return nil
}
// ReadLineEvent reads a single event from a requested line.
//
// The fd is a requested line, as returned by GetLine.
//
// This function is blocking and should only be called when the fd is known to
// be ready to read.
func ReadLineEvent(fd uintptr) (LineEvent, error) {
var le LineEvent
err := binary.Read(fdReader(fd), nativeEndian, &le)
return le, err
}
// ReadLineInfoChangedV2 reads a line info changed event from a chip.
//
// The fd is an open GPIO character device.
//
// This function is blocking and should only be called when the fd is known to
// be ready to read.
func ReadLineInfoChangedV2(fd uintptr) (LineInfoChangedV2, error) {
var lic LineInfoChangedV2
err := binary.Read(fdReader(fd), nativeEndian, &lic)
return lic, err
}
var (
getLineInfoV2Ioctl ioctl
getLineIoctl ioctl
getLineValuesV2Ioctl ioctl
setLineValuesV2Ioctl ioctl
setLineConfigV2Ioctl ioctl
watchLineInfoV2Ioctl ioctl
)
func init() {
// ioctls require struct sizes which are only available at runtime.
var liv2 LineInfoV2
getLineInfoV2Ioctl = iorw(0xB4, 0x05, unsafe.Sizeof(liv2))
watchLineInfoV2Ioctl = iorw(0xB4, 0x06, unsafe.Sizeof(liv2))
var lr LineRequest
getLineIoctl = iorw(0xB4, 0x07, unsafe.Sizeof(lr))
var lc LineConfig
setLineConfigV2Ioctl = iorw(0xB4, 0x0D, unsafe.Sizeof(lc))
var lv LineValues
getLineValuesV2Ioctl = iorw(0xB4, 0x0E, unsafe.Sizeof(lv))
setLineValuesV2Ioctl = iorw(0xB4, 0x0F, unsafe.Sizeof(lv))
}
// LineInfoV2 contains the details of a single line of a GPIO chip.
type LineInfoV2 struct {
// The system name for this line.
Name [nameSize]byte
// If requested, a string added by the requester to identify the
// owner of the request.
Consumer [nameSize]byte
// The offset of the line within the chip.
Offset uint32
NumAttrs uint32
Flags LineFlagV2
Attrs [10]LineAttribute
// reserved for future use.
Padding [lineInfoV2PadSize]uint32
}
// LineInfoChangedV2 contains the details of a change to line info.
//
// This is returned via the chip fd in response to changes to watched lines.
type LineInfoChangedV2 struct {
// The updated info.
Info LineInfoV2
// The time the change occurred.
Timestamp uint64
// The type of change.
Type ChangeType
// reserved for future use.
Padding [lineInfoChangedV2PadSize]uint32
}
// LineFlagV2 are the flags for a line.
type LineFlagV2 uint64
const (
// LineFlagV2Used indicates that the line is already in use.
// It may have been requested by this process or another process,
// or may be reserved by the kernel.
//
// The line cannot be requested until this flag is clear.
LineFlagV2Used LineFlagV2 = 1 << iota
// LineFlagV2ActiveLow indicates that the line is active low.
LineFlagV2ActiveLow
// LineFlagV2Input indicates that the line direction is an input.
LineFlagV2Input
// LineFlagV2Output indicates that the line direction is an output.
LineFlagV2Output
// LineFlagV2EdgeRising indicates that edge detection is enabled for rising
// edges.
LineFlagV2EdgeRising
// LineFlagV2EdgeFalling indicates that edge detection is enabled for
// falling edges.
LineFlagV2EdgeFalling
// LineFlagV2OpenDrain indicates that the line drive is open drain.
LineFlagV2OpenDrain
// LineFlagV2OpenSource indicates that the line drive is open source.
LineFlagV2OpenSource
// LineFlagV2BiasPullUp indicates that the line bias is pull-up.
LineFlagV2BiasPullUp
// LineFlagV2BiasPullDown indicates that the line bias is set pull-down.
LineFlagV2BiasPullDown
// LineFlagV2BiasDisabled indicates that the line bias is disabled.
LineFlagV2BiasDisabled
// LineFlagV2EventClockRealtime indicates that the CLOCK_REALTIME will be
// the source for event timestamps.
LineFlagV2EventClockRealtime
// LineFlagV2DirectionMask is a mask for all direction flags.
LineFlagV2DirectionMask = LineFlagV2Input | LineFlagV2Output
// LineFlagV2EdgeMask is a mask for all edge flags.
LineFlagV2EdgeMask = LineFlagV2EdgeRising | LineFlagV2EdgeFalling
// LineFlagV2EdgeBoth is a helper value for selecting edge detection on
// both edges.
LineFlagV2EdgeBoth = LineFlagV2EdgeMask
// LineFlagV2DriveMask is a mask for all drive flags.
LineFlagV2DriveMask = LineFlagV2OpenDrain | LineFlagV2OpenSource
// LineFlagV2BiasMask is a mask for all bias flags.
LineFlagV2BiasMask = LineFlagV2BiasDisabled | LineFlagV2BiasPullUp | LineFlagV2BiasPullDown
)
// IsAvailable returns true if the line is available to be requested.
func (f LineFlagV2) IsAvailable() bool {
return f&LineFlagV2Used == 0
}
// IsUsed returns true if the line is not available to be requested.
func (f LineFlagV2) IsUsed() bool {
return f&LineFlagV2Used != 0
}
// IsActiveLow returns true if the line is active low.
func (f LineFlagV2) IsActiveLow() bool {
return f&LineFlagV2ActiveLow != 0
}
// IsInput returns true if the line is an input.
func (f LineFlagV2) IsInput() bool {
return f&LineFlagV2Input != 0
}
// IsOutput returns true if the line is an output.
func (f LineFlagV2) IsOutput() bool {
return f&LineFlagV2Output != 0
}
// IsOpenDrain returns true if the line is an open drain.
func (f LineFlagV2) IsOpenDrain() bool {
return f&LineFlagV2OpenDrain != 0
}
// IsOpenSource returns true if the line is an open source.
func (f LineFlagV2) IsOpenSource() bool {
return f&LineFlagV2OpenSource != 0
}
// IsRisingEdge returns true if the line has edge detection on the rising edge.
func (f LineFlagV2) IsRisingEdge() bool {
return f&LineFlagV2EdgeRising != 0
}
// IsFallingEdge returns true if the line has edge detection on the falling edge.
func (f LineFlagV2) IsFallingEdge() bool {
return f&LineFlagV2EdgeFalling != 0
}
// IsBothEdges returns true if the line has edge detection on both edges.
func (f LineFlagV2) IsBothEdges() bool {
return f&LineFlagV2EdgeBoth == LineFlagV2EdgeBoth
}
// IsBiasDisabled returns true if the line has bias disabled.
func (f LineFlagV2) IsBiasDisabled() bool {
return f&LineFlagV2BiasDisabled != 0
}
// IsBiasPullUp returns true if the line has pull-up bias enabled.
func (f LineFlagV2) IsBiasPullUp() bool {
return f&LineFlagV2BiasPullUp != 0
}
// IsBiasPullDown returns true if the line has pull-down bias enabled.
func (f LineFlagV2) IsBiasPullDown() bool {
return f&LineFlagV2BiasPullDown != 0
}
// HasRealtimeEventClock returns true if the line events will contain real-time
// timestamps.
func (f LineFlagV2) HasRealtimeEventClock() bool {
return f&LineFlagV2EventClockRealtime != 0
}
// Encode creates a LineAttribute with the value from the LineFlagV2.
func (f LineFlagV2) Encode() (la LineAttribute) {
la.Encode64(LineAttributeIDFlags, uint64(f))
return
}
// Decode populates the LineFlagV2 with value from the LineAttribute.
func (f *LineFlagV2) Decode(la LineAttribute) {
*f = LineFlagV2(la.Value64())
}
const (
// LinesMax is the maximum number of lines that can be requested in a single
// request.
LinesMax int = 64
// the pad sizes of each struct
lineConfigPadSize int = 5
lineRequestPadSize int = 5
lineEventPadSize int = 6
lineInfoV2PadSize int = 4
lineInfoChangedV2PadSize int = 5
)
// LineAttribute defines a configuration attribute for a line.
type LineAttribute struct {
ID LineAttributeID
Padding [1]uint32
Value [8]byte
}
// Encode32 populates the LineAttribute using the id and 32-bit value.
func (la *LineAttribute) Encode32(id LineAttributeID, value uint32) {
la.ID = id
nativeEndian.PutUint32(la.Value[:], value)
}
// Encode64 populates the LineAttribute using the id and 64-bit value.
func (la *LineAttribute) Encode64(id LineAttributeID, value uint64) {
la.ID = id
nativeEndian.PutUint64(la.Value[:], value)
}
// Value32 returns the 32-bit value from the LineAttribute.
func (la LineAttribute) Value32() uint32 {
return nativeEndian.Uint32(la.Value[:])
}
// Value64 returns the 64-bit value from the LineAttribute.
func (la LineAttribute) Value64() uint64 {
return nativeEndian.Uint64(la.Value[:])
}
// LineAttributeID identfies the type of a configuration attribute.
type LineAttributeID uint32
const (
// LineAttributeIDFlags indicates the attribute contains LineFlagV2 flags.
LineAttributeIDFlags LineAttributeID = iota + 1
// LineAttributeIDOutputValues indicates the attribute contains line output values.
LineAttributeIDOutputValues
// LineAttributeIDDebounce indicates the attribute contains a debounce period.
LineAttributeIDDebounce
)
// DebouncePeriod specifies the time the line must be stable before a level
// transition is recognized.
type DebouncePeriod time.Duration
// Encode creates a LineAttribute with the value from the DebouncePeriod.
func (d DebouncePeriod) Encode() (la LineAttribute) {
la.Encode32(LineAttributeIDDebounce, uint32(d/1000))
return
}
// Decode populates the DebouncePeriod with value from the LineAttribute.
func (d *DebouncePeriod) Decode(la LineAttribute) {
*d = DebouncePeriod(la.Value32() * 1000)
}
// OutputValues specify the active level of output lines.
type OutputValues LineBitmap
// Encode creates a LineAttribute with the values from the OutputValues.
func (ov OutputValues) Encode() (la LineAttribute) {
la.Encode64(LineAttributeIDOutputValues, uint64(ov))
return
}
// Decode populates the OutputValues with values from the LineAttribute.
func (ov *OutputValues) Decode(la LineAttribute) {
*ov = OutputValues(la.Value64())
}
// LineConfigAttribute associates a configuration attribute with one or more
// requested lines.
type LineConfigAttribute struct {
// Attr contains the configuration attribute.
Attr LineAttribute
// Mask identifies the lines to which this attribute applies.
//
// This is a bitmap of lines in LineRequest.Offsets.
Mask LineBitmap
}
// LineConfig contains the configuration of a line.
type LineConfig struct {
// The flags to be applied to the lines.
Flags LineFlagV2
NumAttrs uint32
// reserved for future use.
Padding [lineConfigPadSize]uint32
Attrs [10]LineConfigAttribute
}
// AddAttribute adds an attribute to the configuration.
//
// This is an unconditional add - it performs no filtering or consistency
// checking other than limiting the number of attributes.
func (lc *LineConfig) AddAttribute(lca LineConfigAttribute) {
if lc.NumAttrs < 10 {
lc.Attrs[lc.NumAttrs] = lca
lc.NumAttrs++
}
}
// RemoveAttribute removes an attribute from the configuration.
func (lc *LineConfig) RemoveAttribute(lca LineConfigAttribute) {
d := 0
for s := 0; s < int(lc.NumAttrs); s++ {
if lc.Attrs[s] != lca {
if d != s {
lc.Attrs[d] = lc.Attrs[s]
}
d++
}
}
lc.NumAttrs = uint32(d)
}
// RemoveAttributeID removes all attributes with a given ID from the configuration.
func (lc *LineConfig) RemoveAttributeID(id LineAttributeID) {
d := 0
for s := 0; s < int(lc.NumAttrs); s++ {
if lc.Attrs[s].Attr.ID != id {
if d != s {
lc.Attrs[d] = lc.Attrs[s]
}
d++
}
}
lc.NumAttrs = uint32(d)
}
// LineRequest is a request for control of a set of lines.
// The lines must all be on the same GPIO chip.
type LineRequest struct {
// The lines to be requested.
Offsets [LinesMax]uint32
// The string identifying the requester to be applied to the lines.
Consumer [nameSize]byte
// The configuration for the requested lines
Config LineConfig
// The number of lines being requested.
Lines uint32
// Minimum size of the event buffer.
EventBufferSize uint32
// reserved for future use.
Padding [lineRequestPadSize]uint32
// The file handle for the requested lines.
// Set if the request is successful.
Fd int32
}
// LineBitmap is a bitmap containing a bit for each line.
type LineBitmap uint64
// NewLineBits creates a new LineBitmap from an array of bit numbers.
func NewLineBits(vv ...int) LineBitmap {
var lb LineBitmap
for _, bit := range vv {
lb = lb.Set(bit, 1)
}
return lb
}
// NewLineBitmap creates a bitmap from an array of bit values.
func NewLineBitmap(vv ...int) LineBitmap {
var lb LineBitmap
for i, v := range vv {
lb = lb.Set(i, v)
}
return lb
}
// NewLineBitMask returns a mask of n bits.
func NewLineBitMask(n int) LineBitmap {
if n >= LinesMax {
n = LinesMax
}
if n == LinesMax {
return 0xffffffffffffffff
}
return (LineBitmap(1) << uint(n)) - 1
}
// Get returns the value of the nth bit.
func (lb LineBitmap) Get(n int) int {
mask := LineBitmap(1) << uint(n)
if lb&mask != 0 {
return 1
}
return 0
}
// Set sets the value of the nth bit.
func (lb LineBitmap) Set(n, v int) LineBitmap {
mask := LineBitmap(1) << uint(n)
if v == 0 {
return lb &^ mask
}
return lb | mask
}
// LineValues contains the output values for a set of lines.
type LineValues struct {
// Bits contains the logical value of the the lines.
//
// Zero is a logical low (inactive) and 1 is a logical high (active).
//
// This is a bitmap of lines in LineRequest.Offsets.
Bits LineBitmap
// Mask identifies the lines to which this attribute applies.
//
// This is a bitmap of lines in LineRequest.Offsets.
Mask LineBitmap
}
// Get returns the value of the nth bit.
func (lv LineValues) Get(n int) int {
mask := LineBitmap(1) << uint(n)
if lv.Bits&mask != 0 {
return 1
}
return 0
}
// LineEventID indicates the type of event detected.
type LineEventID uint32
const (
// LineEventRisingEdge indicates the event is a rising edge.
LineEventRisingEdge LineEventID = iota + 1
// LineEventFallingEdge indicates the event is a falling edge.
LineEventFallingEdge
)
// LineEvent contains the details of a particular line event.
//
// This is returned via the event request fd in response to events.
type LineEvent struct {
// The time the event was detected.
Timestamp uint64
// The type of event detected.
ID LineEventID
// The line that triggered the event.
Offset uint32
// The seqno for this event in all events on all lines in this line request.
Seqno uint32
// The seqno for this event in all events in this line.
LineSeqno uint32
// reserved for future use
Padding [lineEventPadSize]uint32
}