|
@@ -6,18 +6,20 @@ import "gitlab.com/beoran/galago/os/linux"
|
|
|
import "strings"
|
|
|
import "os"
|
|
|
import "unsafe"
|
|
|
-import syscall "golang.org/x/sys/unix"
|
|
|
+import "golang.org/x/sys/unix"
|
|
|
import "fmt"
|
|
|
import "path/filepath"
|
|
|
import "time"
|
|
|
import "sync"
|
|
|
import "runtime"
|
|
|
+import "syscall"
|
|
|
|
|
|
|
|
|
|
|
|
type Device struct {
|
|
|
FileName string
|
|
|
*os.File
|
|
|
+ syscall.RawConn
|
|
|
|
|
|
Info struct {
|
|
|
Events []SupportedEvent
|
|
@@ -30,6 +32,16 @@ type Device struct {
|
|
|
}
|
|
|
|
|
|
const Directory = "/dev/input"
|
|
|
+var DoLogDebug = false
|
|
|
+
|
|
|
+func LogDebug(format string, args...interface{}) {
|
|
|
+ if !DoLogDebug {
|
|
|
+ return
|
|
|
+ }
|
|
|
+ LogDebug(format, args...)
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
|
|
|
func (d * Device) KeepAlive() {
|
|
|
runtime.KeepAlive(d.File)
|
|
@@ -44,19 +56,25 @@ func (d * Device) String() string {
|
|
|
|
|
|
func Open(name string) (*Device, error) {
|
|
|
f, err := os.OpenFile(filepath.Join(Directory, name),
|
|
|
- syscall.O_ASYNC|syscall.O_NONBLOCK|os.O_RDWR, 0666)
|
|
|
+ unix.O_ASYNC|unix.O_NONBLOCK|os.O_RDWR, 0666)
|
|
|
if err != nil {
|
|
|
return nil, err
|
|
|
}
|
|
|
- if err = syscall.SetNonblock(int(f.Fd()), true); err != nil {
|
|
|
+ if err = unix.SetNonblock(int(f.Fd()), true); err != nil {
|
|
|
+ return nil, err
|
|
|
+ }
|
|
|
+ flags, err := unix.FcntlInt(f.Fd(), unix.F_GETFL, 0);
|
|
|
+ if flags, err = unix.FcntlInt(f.Fd(), unix.F_SETFL, flags | unix.O_NONBLOCK); err != nil {
|
|
|
return nil, err
|
|
|
}
|
|
|
- flags, err := syscall.FcntlInt(f.Fd(), syscall.F_GETFL, 0);
|
|
|
- if flags, err = syscall.FcntlInt(f.Fd(), syscall.F_SETFL, flags | syscall.O_NONBLOCK); err != nil {
|
|
|
+
|
|
|
+ rawConn, err := f.SyscallConn()
|
|
|
+
|
|
|
+ if err != nil {
|
|
|
return nil, err
|
|
|
}
|
|
|
|
|
|
- return &Device{FileName: name, File: f}, nil
|
|
|
+ return &Device{FileName: name, File: f, RawConn: rawConn}, nil
|
|
|
}
|
|
|
|
|
|
func (d *Device) GatherInfo() error {
|
|
@@ -115,20 +133,100 @@ func List() ([]string, error) {
|
|
|
|
|
|
|
|
|
func (d * Device) Ioctl(code uint32, pointer unsafe.Pointer) error {
|
|
|
- fmt.Printf("ioctl: %d %d %d\n", uintptr(d.Fd()), uintptr(code), uintptr(pointer))
|
|
|
- _, _, errno := syscall.Syscall(
|
|
|
- syscall.SYS_IOCTL,
|
|
|
- uintptr(d.Fd()),
|
|
|
- uintptr(code),
|
|
|
- uintptr(pointer))
|
|
|
- if (errno != 0) {
|
|
|
- return errno
|
|
|
- }
|
|
|
- d.KeepAlive()
|
|
|
- return nil
|
|
|
+ var errno syscall.Errno = 0
|
|
|
+ ioctler := func (fd uintptr) {
|
|
|
+ LogDebug("ioctl: %d %d %d\n", uintptr(fd), uintptr(code), uintptr(pointer))
|
|
|
+ _, _, errno = unix.Syscall(
|
|
|
+ unix.SYS_IOCTL,
|
|
|
+ uintptr(fd),
|
|
|
+ uintptr(code),
|
|
|
+ uintptr(pointer))
|
|
|
+ }
|
|
|
+ err2 := d.Control(ioctler)
|
|
|
+ if err2 != nil {
|
|
|
+ return err2
|
|
|
+ }
|
|
|
+ if errno == 0 {
|
|
|
+ return nil
|
|
|
+ }
|
|
|
+ return errno
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+func (d * Device) Read(pointer unsafe.Pointer, size uintptr) (uintptr, error) {
|
|
|
+ var errno syscall.Errno = 0
|
|
|
+ var read uintptr = 0
|
|
|
+ reader := func (fd uintptr) bool {
|
|
|
+ LogDebug("read: %d %d %d\n", uintptr(fd), uintptr(pointer), uintptr(size))
|
|
|
+ read, _, errno = unix.Syscall(
|
|
|
+ unix.SYS_READ,
|
|
|
+ uintptr(fd),
|
|
|
+ uintptr(pointer),
|
|
|
+ uintptr(size))
|
|
|
+ return true
|
|
|
+ }
|
|
|
+ err2 := d.RawConn.Read(reader)
|
|
|
+ if err2 != nil {
|
|
|
+ return read, err2
|
|
|
+ }
|
|
|
+ if errno == 0 {
|
|
|
+ return read, nil
|
|
|
+ }
|
|
|
+ if errno == syscall.EAGAIN {
|
|
|
+ return 0, nil
|
|
|
+ }
|
|
|
+ return read, errno
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+func (d * Device) ReadBlock(pointer unsafe.Pointer, size uintptr) (uintptr, error) {
|
|
|
+ var errno syscall.Errno = 0
|
|
|
+ var read uintptr = 0
|
|
|
+ reader := func (fd uintptr) bool {
|
|
|
+ LogDebug("read: %d %d %d\n", uintptr(fd), uintptr(pointer), uintptr(size))
|
|
|
+ read, _, errno = unix.Syscall(
|
|
|
+ unix.SYS_READ,
|
|
|
+ uintptr(fd),
|
|
|
+ uintptr(pointer),
|
|
|
+ uintptr(size))
|
|
|
+ return errno != syscall.EAGAIN
|
|
|
+ }
|
|
|
+ err2 := d.RawConn.Read(reader)
|
|
|
+ if err2 != nil {
|
|
|
+ return read, err2
|
|
|
+ }
|
|
|
+ if errno == 0 {
|
|
|
+ return read, nil
|
|
|
+ }
|
|
|
+ return read, errno
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+func (d * Device) Write(pointer unsafe.Pointer, size uintptr) (uintptr, error) {
|
|
|
+ var errno syscall.Errno = 0
|
|
|
+ var wrote uintptr = 0
|
|
|
+ writer := func(fd uintptr) bool {
|
|
|
+ LogDebug("write: %d %d %d\n", uintptr(d.Fd()), uintptr(pointer), uintptr(size))
|
|
|
+ wrote, _, errno = unix.Syscall(
|
|
|
+ unix.SYS_WRITE,
|
|
|
+ uintptr(d.Fd()),
|
|
|
+ uintptr(pointer),
|
|
|
+ uintptr(size))
|
|
|
+ return errno != syscall.EAGAIN
|
|
|
+ }
|
|
|
+ err2 := d.RawConn.Write(writer)
|
|
|
+ if err2 != nil {
|
|
|
+ return wrote, err2
|
|
|
+ }
|
|
|
+ if errno == 0 {
|
|
|
+ return wrote, nil
|
|
|
+ }
|
|
|
+ return wrote, errno
|
|
|
}
|
|
|
|
|
|
|
|
|
+
|
|
|
func (d * Device) DriverVersion() (int32, error) {
|
|
|
res := int32(0)
|
|
|
data := unsafe.Pointer(&res)
|
|
@@ -158,6 +256,7 @@ func (d * Device) Id() (linux.INPUT_id, error) {
|
|
|
|
|
|
|
|
|
|
|
|
+
|
|
|
const SIZEOF_LONG = uint(unsafe.Sizeof(*((*linux.UnsignedLong)(nil))))
|
|
|
const BITS_PER_LONG = SIZEOF_LONG * 8
|
|
|
|
|
@@ -196,7 +295,7 @@ func (d * Device) SupportedEvents() ([]SupportedEvent, error) {
|
|
|
if err != nil {
|
|
|
return nil, err
|
|
|
}
|
|
|
- fmt.Printf("size %d, bits: %v\n", size, bits)
|
|
|
+ LogDebug("size %d, bits: %v\n", size, bits)
|
|
|
result := []SupportedEvent{}
|
|
|
for i := uint(0); i < uint(linux.EV_MAX); i++ {
|
|
|
if (TestBit(bits[0:len(bits)],i)) {
|
|
@@ -209,7 +308,6 @@ func (d * Device) SupportedEvents() ([]SupportedEvent, error) {
|
|
|
|
|
|
|
|
|
|
|
|
-
|
|
|
type InputAbsinfo linux.INPUT_absinfo
|
|
|
type InputEvent linux.INPUT_event
|
|
|
|
|
@@ -247,37 +345,6 @@ func (ev InputEvent) String() string {
|
|
|
}
|
|
|
|
|
|
|
|
|
-
|
|
|
-func (d * Device) Read(pointer unsafe.Pointer, size uintptr) (uintptr, error) {
|
|
|
- fmt.Printf("read: %d %d %d\n", uintptr(d.Fd()), uintptr(pointer), uintptr(size))
|
|
|
- read, _, errno := syscall.Syscall(
|
|
|
- syscall.SYS_READ,
|
|
|
- uintptr(d.Fd()),
|
|
|
- uintptr(pointer),
|
|
|
- uintptr(size))
|
|
|
- d.KeepAlive()
|
|
|
-
|
|
|
- if (errno != 0) {
|
|
|
- return read, errno
|
|
|
- }
|
|
|
- return read, nil
|
|
|
-}
|
|
|
-
|
|
|
-
|
|
|
-func (d * Device) Write(pointer unsafe.Pointer, size uintptr) (uintptr, error) {
|
|
|
- fmt.Printf("write: %d %d %d\n", uintptr(d.Fd()), uintptr(pointer), uintptr(size))
|
|
|
- wrote, _, errno := syscall.Syscall(
|
|
|
- syscall.SYS_WRITE,
|
|
|
- uintptr(d.Fd()),
|
|
|
- uintptr(pointer),
|
|
|
- uintptr(size))
|
|
|
- d.KeepAlive()
|
|
|
-
|
|
|
- if (errno != 0) {
|
|
|
- return wrote, errno
|
|
|
- }
|
|
|
- return wrote, nil
|
|
|
-}
|
|
|
|
|
|
|
|
|
const READ_EVENTS_MAX = 64
|
|
@@ -288,11 +355,23 @@ func (d * Device) ReadEvents() ([]InputEvent, error) {
|
|
|
read, err := d.Read(unsafe.Pointer(&events), size)
|
|
|
if err != nil {
|
|
|
return nil, err
|
|
|
- }
|
|
|
+ }
|
|
|
len := read / unsafe.Sizeof(events[0])
|
|
|
return events[0:len], nil
|
|
|
}
|
|
|
|
|
|
+func (d * Device) ReadEventsBlock() ([]InputEvent, error) {
|
|
|
+ var events [READ_EVENTS_MAX]InputEvent
|
|
|
+ size := unsafe.Sizeof(events)
|
|
|
+ read, err := d.ReadBlock(unsafe.Pointer(&events), size)
|
|
|
+ if err != nil {
|
|
|
+ return nil, err
|
|
|
+ }
|
|
|
+ len := read / unsafe.Sizeof(events[0])
|
|
|
+ return events[0:len], nil
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
const WRITE_EVENTS_MAX = 64
|
|
|
|
|
|
func (d * Device) WriteEvents(events []InputEvent) (uint, error) {
|
|
@@ -312,10 +391,10 @@ func (d * Device) SupportedAxes() ([]AbsoluteAxis, error) {
|
|
|
return nil, err
|
|
|
}
|
|
|
result := []AbsoluteAxis{}
|
|
|
- fmt.Printf("Supported Absolute axes:\n");
|
|
|
+ LogDebug("Supported Absolute axes:\n");
|
|
|
for yalv := uint(0); yalv < linux.ABS_MAX; yalv++ {
|
|
|
if TestBit(abs_b[0:len(abs_b)], uint(yalv)) {
|
|
|
- fmt.Printf(" Absolute axis 0x%02x %s", yalv, linux.AbsToString(yalv))
|
|
|
+ LogDebug(" Absolute axis 0x%02x %s", yalv, linux.AbsToString(yalv))
|
|
|
err = d.Ioctl(linux.EVIOCGABS(uint32(yalv)), unsafe.Pointer(&abs_feat))
|
|
|
if err != nil {
|
|
|
return result, err
|
|
@@ -345,7 +424,7 @@ func (d * Device) SupportedKeys() ([]SupportedKey, error) {
|
|
|
if err != nil {
|
|
|
return nil, err
|
|
|
}
|
|
|
- fmt.Printf("size %d, bits: %v\n", size, bits)
|
|
|
+ LogDebug("size %d, bits: %v\n", size, bits)
|
|
|
result := []SupportedKey{}
|
|
|
for i := uint(0); i < uint(linux.KEY_MAX); i++ {
|
|
|
if (TestBit(bits[0:len(bits)],i)) {
|
|
@@ -372,7 +451,7 @@ func (d * Device) SupportedRelatives() ([]RelativeAxis, error) {
|
|
|
if err != nil {
|
|
|
return nil, err
|
|
|
}
|
|
|
- fmt.Printf("size %d, bits: %v\n", size, bits)
|
|
|
+ LogDebug("size %d, bits: %v\n", size, bits)
|
|
|
result := []RelativeAxis{}
|
|
|
for i := uint(0); i < uint(linux.REL_MAX); i++ {
|
|
|
if (TestBit(bits[0:len(bits)],i)) {
|
|
@@ -385,10 +464,10 @@ func (d * Device) SupportedRelatives() ([]RelativeAxis, error) {
|
|
|
|
|
|
|
|
|
|
|
|
-
|
|
|
+
|
|
|
const MANAGER_DEVICE_SCAN_DELAY = 3 * time.Second
|
|
|
|
|
|
-type Manager struct {
|
|
|
+type Driver struct {
|
|
|
sync.Mutex
|
|
|
Connect chan(*Device)
|
|
|
Disconnect chan(*Device)
|
|
@@ -399,100 +478,105 @@ type Manager struct {
|
|
|
DevicesByName map[string] *Device
|
|
|
DevicesByFd map[int] *Device
|
|
|
Verbose bool
|
|
|
- fds []syscall.PollFd
|
|
|
-}
|
|
|
-
|
|
|
-
|
|
|
-func NewManager(connect chan(*Device), disconnect chan(*Device), event chan(InputEvent), errors chan(error), done chan (struct{})) * Manager {
|
|
|
- manager := &Manager{Connect: connect, Disconnect: disconnect, Errors: errors, Done: false}
|
|
|
- manager.Events = event
|
|
|
- manager.Devices = []*Device{}
|
|
|
- manager.DevicesByName = make(map[string] *Device)
|
|
|
- manager.DevicesByFd = make(map[int] *Device)
|
|
|
- manager.fds = []syscall.PollFd{}
|
|
|
- return manager
|
|
|
+ fds []unix.PollFd
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+func NewDriver() * Driver {
|
|
|
+ eveChan := make(chan InputEvent)
|
|
|
+ conChan := make(chan *Device)
|
|
|
+ disChan := make(chan *Device)
|
|
|
+ errChan := make(chan error)
|
|
|
+ driver := &Driver{Connect: conChan, Disconnect: disChan, Errors: errChan,
|
|
|
+ Events: eveChan,
|
|
|
+ Done: false}
|
|
|
+ driver.Devices = []*Device{}
|
|
|
+ driver.DevicesByName = make(map[string] *Device)
|
|
|
+ driver.DevicesByFd = make(map[int] *Device)
|
|
|
+ driver.fds = []unix.PollFd{}
|
|
|
+ return driver
|
|
|
}
|
|
|
|
|
|
-func (manager *Manager) connectDevice(device * Device) {
|
|
|
- manager.Lock()
|
|
|
- defer manager.Unlock()
|
|
|
- manager.DevicesByName[device.FileName] = device
|
|
|
- manager.DevicesByFd[int(device.Fd())] = device
|
|
|
- manager.Devices = append(manager.Devices, device)
|
|
|
- pollfd := syscall.PollFd{Fd: int32(device.Fd()), Events : syscall.POLLIN}
|
|
|
- manager.fds = append(manager.fds, pollfd)
|
|
|
- manager.Connect <- device
|
|
|
-}
|
|
|
-
|
|
|
-func (manager *Manager) disconnectDevice(device * Device) {
|
|
|
- manager.Lock()
|
|
|
- defer manager.Unlock()
|
|
|
- delete(manager.DevicesByName, device.FileName)
|
|
|
- delete(manager.DevicesByFd, int(device.Fd()))
|
|
|
+func (driver *Driver) connectDevice(device * Device) {
|
|
|
+ driver.Lock()
|
|
|
+ defer driver.Unlock()
|
|
|
+ driver.DevicesByName[device.FileName] = device
|
|
|
+ driver.DevicesByFd[int(device.Fd())] = device
|
|
|
+ driver.Devices = append(driver.Devices, device)
|
|
|
+ pollfd := unix.PollFd{Fd: int32(device.Fd()), Events : unix.POLLIN}
|
|
|
+ driver.fds = append(driver.fds, pollfd)
|
|
|
+ driver.Connect <- device
|
|
|
+}
|
|
|
+
|
|
|
+func (driver *Driver) disconnectDevice(device * Device) {
|
|
|
+ driver.Lock()
|
|
|
+ defer driver.Unlock()
|
|
|
+ delete(driver.DevicesByName, device.FileName)
|
|
|
+ delete(driver.DevicesByFd, int(device.Fd()))
|
|
|
found := false
|
|
|
var i int
|
|
|
- var pollfd syscall.PollFd
|
|
|
- for i, pollfd = range manager.fds {
|
|
|
+ var pollfd unix.PollFd
|
|
|
+ for i, pollfd = range driver.fds {
|
|
|
if pollfd.Fd == int32(device.Fd()) {
|
|
|
found = true
|
|
|
break
|
|
|
}
|
|
|
}
|
|
|
if found {
|
|
|
- manager.fds = append(manager.fds[:i], manager.fds[(i+1):]...)
|
|
|
- manager.Devices = append(manager.Devices[:i], manager.Devices[(i+1):]...)
|
|
|
- manager.Disconnect <- device
|
|
|
+ driver.fds = append(driver.fds[:i], driver.fds[(i+1):]...)
|
|
|
+ driver.Devices = append(driver.Devices[:i], driver.Devices[(i+1):]...)
|
|
|
+ driver.Disconnect <- device
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-func (manager * Manager) ManageNewDevicesOnce() {
|
|
|
+func (driver * Driver) ManageNewDevicesOnce() {
|
|
|
fmt.Println("ManageNewDevicesOnce")
|
|
|
names, err := List()
|
|
|
if err != nil {
|
|
|
- manager.Errors <- err
|
|
|
+ driver.Errors <- err
|
|
|
} else {
|
|
|
for _, name := range names {
|
|
|
- if _, found := manager.DevicesByName[name] ; !found {
|
|
|
+ if _, found := driver.DevicesByName[name] ; !found {
|
|
|
device, err := OpenAndGatherInfo(name)
|
|
|
if err == nil {
|
|
|
- manager.connectDevice(device)
|
|
|
- } else if manager.Verbose {
|
|
|
- manager.Errors <- err
|
|
|
+ driver.connectDevice(device)
|
|
|
+ } else if driver.Verbose {
|
|
|
+ driver.Errors <- err
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-func (manager *Manager) ReadEventsOnce(device * Device) {
|
|
|
+func (driver *Driver) ReadEventsOnce(device * Device) {
|
|
|
events, err := device.ReadEvents()
|
|
|
if err != nil {
|
|
|
- manager.Errors <- err
|
|
|
- manager.disconnectDevice(device)
|
|
|
+ driver.Errors <- err
|
|
|
+ driver.disconnectDevice(device)
|
|
|
} else {
|
|
|
for _, event := range events {
|
|
|
- manager.Events <- event
|
|
|
+ driver.Events <- event
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-func (manager *Manager) ManageInputOnce() {
|
|
|
- res, err := syscall.Poll(manager.fds, 0)
|
|
|
+func (driver *Driver) ManageInputOnce() {
|
|
|
+ res, err := unix.Poll(driver.fds, 0)
|
|
|
if err != nil {
|
|
|
- manager.Errors <- err
|
|
|
+ driver.Errors <- err
|
|
|
}
|
|
|
if res > 0 {
|
|
|
- for _, fd := range manager.fds {
|
|
|
- if (fd.Revents & syscall.POLLIN) != 0 {
|
|
|
- device, ok := manager.DevicesByFd[int(fd.Fd)]
|
|
|
+ for _, fd := range driver.fds {
|
|
|
+ if (fd.Revents & unix.POLLIN) != 0 {
|
|
|
+ device, ok := driver.DevicesByFd[int(fd.Fd)]
|
|
|
if ok && device != nil {
|
|
|
- manager.ReadEventsOnce(device)
|
|
|
+ driver.ReadEventsOnce(device)
|
|
|
}
|
|
|
}
|
|
|
- if (fd.Revents & syscall.POLLHUP) != 0 {
|
|
|
- device, ok := manager.DevicesByFd[int(fd.Fd)]
|
|
|
+ if (fd.Revents & unix.POLLHUP) != 0 {
|
|
|
+ device, ok := driver.DevicesByFd[int(fd.Fd)]
|
|
|
if ok && device != nil {
|
|
|
- manager.disconnectDevice(device)
|
|
|
+ driver.disconnectDevice(device)
|
|
|
}
|
|
|
}
|
|
|
|
|
@@ -500,27 +584,27 @@ func (manager *Manager) ManageInputOnce() {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-func (manager *Manager) ManageDevices() {
|
|
|
- for !manager.Done {
|
|
|
- manager.ManageNewDevicesOnce()
|
|
|
+func (driver *Driver) ManageDevices() {
|
|
|
+ for !driver.Done {
|
|
|
+ driver.ManageNewDevicesOnce()
|
|
|
time.Sleep(MANAGER_DEVICE_SCAN_DELAY)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-func (manager *Manager) ManageInput() {
|
|
|
- for !manager.Done {
|
|
|
- manager.ManageInputOnce()
|
|
|
+func (driver *Driver) ManageInput() {
|
|
|
+ for !driver.Done {
|
|
|
+ driver.ManageInputOnce()
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-func (manager *Manager) Start() {
|
|
|
- go manager.ManageDevices()
|
|
|
- go manager.ManageInput()
|
|
|
+func (driver *Driver) Start() {
|
|
|
+ go driver.ManageDevices()
|
|
|
+ go driver.ManageInput()
|
|
|
}
|
|
|
|
|
|
-func (manager *Manager) Stop() {
|
|
|
- manager.Lock() ; defer manager.Unlock()
|
|
|
- manager.Done = true
|
|
|
+func (driver *Driver) Stop() {
|
|
|
+ driver.Lock() ; defer driver.Unlock()
|
|
|
+ driver.Done = true
|
|
|
}
|
|
|
|
|
|
|