<commit_before>// 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.

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.
type DevFS struct{}

// Open opens /dev/spidev<bus>.<chip> and returns a connection.
func (d *DevFS) Open(bus, chip int) (driver.Conn, error) {
	n := fmt.Sprintf("/dev/spidev%d.%d", bus, chip)
	f, err := os.OpenFile(n, os.O_RDWR, 0)
	if err != nil {
		return nil, err
	}
	return &devfsConn{f: f}, nil
}

type devfsConn struct {
	f     *os.File
	mode  uint8
	speed uint32
	bits  uint8
	delay uint16
}

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.Speed:
		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)
	default:
		return fmt.Errorf("unknown key: %v", k)
	}
	return nil
}

func (c *devfsConn) Transfer(tx, rx []byte) error {
	p := payload{
		tx:     uint64(uintptr(unsafe.Pointer(&tx[0]))),
		rx:     uint64(uintptr(unsafe.Pointer(&rx[0]))),
		length: uint32(len(tx)),
		speed:  c.speed,
		delay:  c.delay,
		bits:   c.bits,
	}
	// 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
}
<commit_msg>io/spi: note that spidev module is required to use devfs<commit_after>// 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.

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 load the "spidev" module to use this driver.
type DevFS struct{}

// Open opens /dev/spidev<bus>.<chip> and returns a connection.
func (d *DevFS) Open(bus, chip int) (driver.Conn, error) {
	n := fmt.Sprintf("/dev/spidev%d.%d", bus, chip)
	f, err := os.OpenFile(n, os.O_RDWR, 0)
	if err != nil {
		return nil, err
	}
	return &devfsConn{f: f}, nil
}

type devfsConn struct {
	f     *os.File
	mode  uint8
	speed uint32
	bits  uint8
	delay uint16
}

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.Speed:
		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)
	default:
		return fmt.Errorf("unknown key: %v", k)
	}
	return nil
}

func (c *devfsConn) Transfer(tx, rx []byte) error {
	p := payload{
		tx:     uint64(uintptr(unsafe.Pointer(&tx[0]))),
		rx:     uint64(uintptr(unsafe.Pointer(&rx[0]))),
		length: uint32(len(tx)),
		speed:  c.speed,
		delay:  c.delay,
		bits:   c.bits,
	}
	// 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
}

{'fraction_non_alphanumeric': 0.12985386221294362, 'fraction_numerical': 0.02338204592901879, 'mean_word_length': 3.530895334174023, 'pattern_counts': {'":': 0, '<': 23, '<?xml version=': 0, '>': 7, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '604003', 'n_tokens_mistral': 2946, 'n_tokens_neox': 2721, 'n_words': 824}