summaryrefslogtreecommitdiffstats
path: root/dependencies/pkg/mod/golang.org/x/exp@v0.0.0-20220613132600-b0d781184e0d/io/spi/devfs.go
diff options
context:
space:
mode:
Diffstat (limited to 'dependencies/pkg/mod/golang.org/x/exp@v0.0.0-20220613132600-b0d781184e0d/io/spi/devfs.go')
-rw-r--r--dependencies/pkg/mod/golang.org/x/exp@v0.0.0-20220613132600-b0d781184e0d/io/spi/devfs.go177
1 files changed, 177 insertions, 0 deletions
diff --git a/dependencies/pkg/mod/golang.org/x/exp@v0.0.0-20220613132600-b0d781184e0d/io/spi/devfs.go b/dependencies/pkg/mod/golang.org/x/exp@v0.0.0-20220613132600-b0d781184e0d/io/spi/devfs.go
new file mode 100644
index 0000000..a5f1bca
--- /dev/null
+++ b/dependencies/pkg/mod/golang.org/x/exp@v0.0.0-20220613132600-b0d781184e0d/io/spi/devfs.go
@@ -0,0 +1,177 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//go:build linux
+// +build linux
+
+package spi
+
+import (
+ "fmt"
+ "os"
+ "syscall"
+ "unsafe"
+
+ "golang.org/x/exp/io/spi/driver"
+)
+
+const (
+ devfs_MAGIC = 107
+
+ devfs_NRBITS = 8
+ devfs_TYPEBITS = 8
+ devfs_SIZEBITS = 13
+ devfs_DIRBITS = 3
+
+ devfs_NRSHIFT = 0
+ devfs_TYPESHIFT = devfs_NRSHIFT + devfs_NRBITS
+ devfs_SIZESHIFT = devfs_TYPESHIFT + devfs_TYPEBITS
+ devfs_DIRSHIFT = devfs_SIZESHIFT + devfs_SIZEBITS
+
+ devfs_READ = 2
+ devfs_WRITE = 4
+)
+
+type payload struct {
+ tx uint64
+ rx uint64
+ length uint32
+ speed uint32
+ delay uint16
+ bits uint8
+ csChange uint8
+ txNBits uint8
+ rxNBits uint8
+ pad uint16
+}
+
+// Devfs is an SPI driver that works against the devfs.
+// You need to have loaded the "spidev" Linux module to use this driver.
+type Devfs struct {
+ // Dev is the device to be opened.
+ // Device name is usually in the /dev/spidev<bus>.<chip> format.
+ // Required.
+ Dev string
+
+ // Mode is the SPI mode. SPI mode is a combination of polarity and phases.
+ // CPOL is the high order bit, CPHA is the low order. Pre-computed mode
+ // values are Mode0, Mode1, Mode2 and Mode3. The value of the mode argument
+ // can be overridden by the device's driver.
+ // Required.
+ Mode Mode
+
+ // MaxSpeed is the max clock speed (Hz) and can be overridden by the device's driver.
+ // Required.
+ MaxSpeed int64
+}
+
+// Open opens the provided device with the specified options
+// and returns a connection.
+func (d *Devfs) Open() (driver.Conn, error) {
+ f, err := os.OpenFile(d.Dev, os.O_RDWR, os.ModeDevice)
+ if err != nil {
+ return nil, err
+ }
+ conn := &devfsConn{f: f}
+ if err := conn.Configure(driver.Mode, int(d.Mode)); err != nil {
+ conn.Close()
+ return nil, err
+ }
+ if err := conn.Configure(driver.MaxSpeed, int(d.MaxSpeed)); err != nil {
+ conn.Close()
+ return nil, err
+ }
+ return conn, nil
+}
+
+type devfsConn struct {
+ f *os.File
+ mode uint8
+ speed uint32
+ bits uint8
+ delay uint16
+ csChange uint8
+}
+
+func (c *devfsConn) Configure(k, v int) error {
+ switch k {
+ case driver.Mode:
+ m := uint8(v)
+ if err := c.ioctl(requestCode(devfs_WRITE, devfs_MAGIC, 1, 1), uintptr(unsafe.Pointer(&m))); err != nil {
+ return fmt.Errorf("error setting mode to %v: %v", m, err)
+ }
+ c.mode = m
+ case driver.Bits:
+ b := uint8(v)
+ if err := c.ioctl(requestCode(devfs_WRITE, devfs_MAGIC, 3, 1), uintptr(unsafe.Pointer(&b))); err != nil {
+ return fmt.Errorf("error setting bits per word to %v: %v", b, err)
+ }
+ c.bits = b
+ case driver.MaxSpeed:
+ s := uint32(v)
+ if err := c.ioctl(requestCode(devfs_WRITE, devfs_MAGIC, 4, 4), uintptr(unsafe.Pointer(&s))); err != nil {
+ return fmt.Errorf("error setting speed to %v: %v", s, err)
+ }
+ c.speed = s
+ case driver.Order:
+ o := uint8(v)
+ if err := c.ioctl(requestCode(devfs_WRITE, devfs_MAGIC, 2, 1), uintptr(unsafe.Pointer(&o))); err != nil {
+ return fmt.Errorf("error setting bit order to %v: %v", o, err)
+ }
+ case driver.Delay:
+ c.delay = uint16(v)
+ case driver.CSChange:
+ c.csChange = uint8(v)
+ default:
+ return fmt.Errorf("unknown key: %v", k)
+ }
+ return nil
+}
+
+func (c *devfsConn) Tx(w, r []byte) error {
+ if r == nil {
+ r = make([]byte, len(w))
+ }
+ // TODO(jbd): len(w) == len(r)?
+ // TODO(jbd): Allow nil w.
+ p := payload{
+ tx: uint64(uintptr(unsafe.Pointer(&w[0]))),
+ rx: uint64(uintptr(unsafe.Pointer(&r[0]))),
+ length: uint32(len(w)),
+ speed: c.speed,
+ delay: c.delay,
+ bits: c.bits,
+ csChange: c.csChange,
+ }
+ // TODO(jbd): Read from the device and fill rx.
+ return c.ioctl(msgRequestCode(1), uintptr(unsafe.Pointer(&p)))
+}
+
+func (c *devfsConn) Close() error {
+ return c.f.Close()
+}
+
+// requestCode returns the device specific request code for the specified direction,
+// type, number and size to be used in the ioctl call.
+func requestCode(dir, typ, nr, size uintptr) uintptr {
+ return (dir << devfs_DIRSHIFT) | (typ << devfs_TYPESHIFT) | (nr << devfs_NRSHIFT) | (size << devfs_SIZESHIFT)
+}
+
+// msgRequestCode returns the device specific value for the SPI
+// message payload to be used in the ioctl call.
+// n represents the number of messages.
+func msgRequestCode(n uint32) uintptr {
+ return uintptr(0x40006B00 + (n * 0x200000))
+}
+
+// ioctl makes an IOCTL on the open device file descriptor.
+func (c *devfsConn) ioctl(a1, a2 uintptr) error {
+ _, _, errno := syscall.Syscall(
+ syscall.SYS_IOCTL, c.f.Fd(), a1, a2,
+ )
+ if errno != 0 {
+ return syscall.Errno(errno)
+ }
+ return nil
+}