-
Notifications
You must be signed in to change notification settings - Fork 3
/
ffi.go
195 lines (155 loc) · 5.88 KB
/
ffi.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
package gpio
import (
"fmt"
"os"
"syscall"
"unsafe"
)
// struct gpiochip_info - Information about a certain GPIO chip
type ChipInfo struct {
// the Linux kernel name of this GPIO chip
Name [32]byte
// a functional name for this GPIO chip, such as a product number, may be NULL
Label [32]byte
// number of GPIO lines on this chip
Lines uint32
}
type LineFlag uint32
const (
GPIOLINE_FLAG_KERNEL LineFlag = 1 << 0 /* Line used by the kernel */
GPIOLINE_FLAG_IS_OUT LineFlag = 1 << 1
GPIOLINE_FLAG_ACTIVE_LOW LineFlag = 1 << 2
GPIOLINE_FLAG_OPEN_DRAIN LineFlag = 1 << 3
GPIOLINE_FLAG_OPEN_SOURCE LineFlag = 1 << 4
)
// struct gpioline_info - Information about a certain GPIO line
type LineInfo struct {
// the local offset on this GPIO device, fill this in when
// requesting the line information from the kernel
LineOffset uint32
Flags LineFlag
// the name of this GPIO line, such as the output pin of the line on the
// chip, a rail or a pin header name on a board, as specified by the gpio
// chip, may be NULL
Name [32]byte
// a functional name for the consumer of this GPIO line as set by
// whatever is using it, will be NULL if there is no current user but may
// also be NULL if the consumer doesn't set this up
Consumer [32]byte
}
const GPIOHANDLES_MAX = 64
type RequestFlag uint32
const (
GPIOHANDLE_REQUEST_INPUT RequestFlag = 1 << 0
GPIOHANDLE_REQUEST_OUTPUT RequestFlag = 1 << 1
GPIOHANDLE_REQUEST_ACTIVE_LOW RequestFlag = 1 << 2
GPIOHANDLE_REQUEST_OPEN_DRAIN RequestFlag = 1 << 3
GPIOHANDLE_REQUEST_OPEN_SOURCE RequestFlag = 1 << 4
)
// struct gpiohandle_request - Information about a GPIO handle request
type HandleRequest struct {
// an array of desired lines, specified by offset index for the associated GPIO device
LineOffsets [GPIOHANDLES_MAX]uint32
// desired flags for the desired GPIO lines, such as
// GPIOHANDLE_REQUEST_OUTPUT, GPIOHANDLE_REQUEST_ACTIVE_LOW etc, OR:ed
// together. Note that even if multiple lines are requested, the same flags
// must be applicable to all of them, if you want lines with individual
// flags set, request them one by one. It is possible to select
// a batch of input or output lines, but they must all have the same
// characteristics, i.e. all inputs or all outputs, all active low etc
Flags RequestFlag
// if the GPIOHANDLE_REQUEST_OUTPUT is set for a requested
// line, this specifies the default output value, should be 0 (low) or
// 1 (high), anything else than 0 or 1 will be interpreted as 1 (high)
// @consumer_label: a desired consumer label for the selected GPIO line(s)
// such as "my-bitbanged-relay"
DefaultValues [GPIOHANDLES_MAX]byte
// a desired consumer label for the selected GPIO line(s)
// such as "my-bitbanged-relay"
ConsumerLabel [32]byte
// number of lines requested in this request, i.e. the number of
// valid fields in the above arrays, set to 1 to request a single line
Lines uint32
// if successful this field will contain a valid anonymous file handle
// after a GPIO_GET_LINEHANDLE_IOCTL operation, zero or negative value
// means error
Fd int32
}
// struct gpiohandle_data - Information of values on a GPIO handle
type HandleData struct {
// GET: contains the current state of a line,
// SET: the desired target state
Values [GPIOHANDLES_MAX]byte
}
type EventFlag uint32
const (
GPIOEVENT_REQUEST_RISING_EDGE EventFlag = 1 << 0
GPIOEVENT_REQUEST_FALLING_EDGE EventFlag = 1 << 1
GPIOEVENT_REQUEST_BOTH_EDGES EventFlag = (1 << 0) | (1 << 1)
)
// struct gpioevent_request - Information about a GPIO event request
type EventRequest struct {
// the desired line to subscribe to events from, specified by
// offset index for the associated GPIO device
LineOffset uint32
// desired handle flags for the desired GPIO line, such as
// GPIOHANDLE_REQUEST_ACTIVE_LOW or GPIOHANDLE_REQUEST_OPEN_DRAIN
RequestFlags RequestFlag
// desired flags for the desired GPIO event line, such as
// GPIOEVENT_REQUEST_RISING_EDGE or GPIOEVENT_REQUEST_FALLING_EDGE
EventFlags EventFlag
// a desired consumer label for the selected GPIO line(s)
// such as "my-listener"
ConsumerLabel [32]byte
// if successful this field will contain a valid anonymous file handle
// after a GPIO_GET_LINEEVENT_IOCTL operation, zero or negative value means error
Fd int32
}
type EventID uint32
const (
GPIOEVENT_EVENT_RISING_EDGE = 0x01
GPIOEVENT_EVENT_FALLING_EDGE = 0x02
)
// struct gpioevent_data - The actual event being pushed to userspace
type EventData struct {
// best estimate of time of event occurrence, in nanoseconds
Timestamp uint64
// event identifier (e.g. rising/falling edge)
ID EventID
_pad uint32 //lint:ignore U1000 .
}
func RawGetChipInfo(fd int, arg *ChipInfo) error {
return ioctl(fd, GPIO_GET_CHIPINFO_IOCTL, uintptr(unsafe.Pointer(arg)))
}
func RawGetLineInfo(fd int, arg *LineInfo) error {
return ioctl(fd, GPIO_GET_LINEINFO_IOCTL, uintptr(unsafe.Pointer(arg)))
}
func RawGetLineHandle(fd int, arg *HandleRequest) error {
return ioctl(fd, GPIO_GET_LINEHANDLE_IOCTL, uintptr(unsafe.Pointer(arg)))
}
func RawGetLineEvent(fd int, arg *EventRequest) error {
return ioctl(fd, GPIO_GET_LINEEVENT_IOCTL, uintptr(unsafe.Pointer(arg)))
}
func RawGetLineValues(fd int, arg *HandleData) error {
return ioctl(fd, GPIOHANDLE_GET_LINE_VALUES_IOCTL, uintptr(unsafe.Pointer(arg)))
}
func RawSetLineValues(fd int, arg *HandleData) error {
return ioctl(fd, uintptr(GPIOHANDLE_SET_LINE_VALUES_IOCTL), uintptr(unsafe.Pointer(arg)))
}
func ioctl(fd int, op, arg uintptr) error {
retry:
r, _, errno := syscall.Syscall(syscall.SYS_IOCTL, uintptr(fd), op, arg)
if errno == syscall.EINTR {
goto retry
}
if errno != 0 {
err := os.NewSyscallError("SYS_IOCTL", errno)
// log.Printf("ioctl fd=%d op=%x arg=%x err=%v", fd, op, arg, err)
return err
} else if r != 0 {
err := fmt.Errorf("SYS_IOCTL r=%d", r)
// log.Printf("ioctl fd=%d op=%x arg=%x err=%v", fd, op, arg, err)
return err
}
return nil
}