go语言调用linux 硬件设备驱动--ioctl、syscall

       在go语言里调用Linux设备驱动不像在C语言那样简单方便,C语言中直接像普通文件那样open就好了,而且可以直接使用ioctl去控制配置设备,在go中要实现驱动调用又另外封装了一层且与打开普通文件也不一样。

1、ioctl

go其实没有ioctl,最终调用的都是:

func Syscall(trap, a1, a2, a3 uintptr) (r1, r2 uintptr, err Errno)

需要使用的话得自己封装一下,这里是封装好的:

package go_ioctl

import (
    "syscall"
)

// Generic ioctl constants
const (
    IOC_NONE  = 0x0
    IOC_WRITE = 0x1
    IOC_READ  = 0x2

    IOC_NRBITS   = 8
    IOC_TYPEBITS = 8

    IOC_SIZEBITS = 14
    IOC_DIRBITS  = 2

    IOC_NRSHIFT   = 0
    IOC_TYPESHIFT = IOC_NRSHIFT + IOC_NRBITS
    IOC_SIZESHIFT = IOC_TYPESHIFT + IOC_TYPEBITS
    IOC_DIRSHIFT  = IOC_SIZESHIFT + IOC_SIZEBITS

    IOC_NRMASK   = ((1 << IOC_NRBITS) - 1)
    IOC_TYPEMASK = ((1 << IOC_TYPEBITS) - 1)
    IOC_SIZEMASK = ((1 << IOC_SIZEBITS) - 1)
    IOC_DIRMASK  = ((1 << IOC_DIRBITS) - 1)
)

// Some useful additional ioctl constanst
const (
    IOC_IN        = IOC_WRITE << IOC_DIRSHIFT
    IOC_OUT       = IOC_READ << IOC_DIRSHIFT
    IOC_INOUT     = (IOC_WRITE | IOC_READ) << IOC_DIRSHIFT
    IOCSIZE_MASK  = IOC_SIZEMASK << IOC_SIZESHIFT
    IOCSIZE_SHIFT = IOC_SIZESHIFT
)

// IOC generate IOC
func IOC(dir, t, nr, size uintptr) uintptr {
    return (dir << IOC_DIRSHIFT) | (t << IOC_TYPESHIFT) |
        (nr << IOC_NRSHIFT) | (size << IOC_SIZESHIFT)
}

// IOR generate IOR
func IOR(t, nr, size uintptr) uintptr {
    return IOC(IOC_READ, t, nr, size)
}

// IOW generate IOW
func IOW(t, nr, size uintptr) uintptr {
    return IOC(IOC_WRITE, t, nr, size)
}

// IOWR generate IOWR
func IOWR(t, nr, size uintptr) uintptr {
    return IOC(IOC_READ|IOC_WRITE, t, nr, size)
}

// IO generate IO
func IO(t, nr uintptr) uintptr {
    return IOC(IOC_NONE, t, nr, 0)
}

// IOCTL send ioctl
func IOCTL(fd, name, data uintptr) error {
    _, _, err := syscall.Syscall(syscall.SYS_IOCTL, fd, name, data)
    if err != 0 {
        return syscall.Errno(err)
    }
    return nil
}

现在这个 func IOCTL(fd, name, data uintptr) 就很像C的写法了,不过与具体设备的驱动交互还得增加命令,下面是封装好的SPI驱动的部分ioctl命令,方便调用


const spiIoctlMAGIC = 'k'

// Read of SPI mode (SPI_MODE_0..SPI_MODE_3)
func SPI_IOC_RD_MODE() uintptr {
    return IOR(spiIoctlMAGIC, 1, 1)
}

// Write of SPI mode (SPI_MODE_0..SPI_MODE_3)
func SPI_IOC_WR_MODE() uintptr {
    return IOW(spiIoctlMAGIC, 1, 1)
}

// Read SPI bit justification
func SPI_IOC_RD_LSB_FIRST() uintptr {
    return IOR(spiIoctlMAGIC, 2, 1)
}

// Write SPI bit justification
func SPI_IOC_WR_LSB_FIRST() uintptr {
    return IOW(spiIoctlMAGIC, 2, 1)
}

// Read SPI device word length (1..N)
func SPI_IOC_RD_BITS_PER_WORD() uintptr {
    return IOR(spiIoctlMAGIC, 3, 1)
}

// Write SPI device word length (1..N)
func SPI_IOC_WR_BITS_PER_WORD() uintptr {
    return IOW(spiIoctlMAGIC, 3, 1)
}

// Read SPI device default max speed hz
func SPI_IOC_RD_MAX_SPEED_HZ() uintptr {
    return IOR(spiIoctlMAGIC, 4, 4)
}

// Write SPI device default max speed hz
func SPI_IOC_WR_MAX_SPEED_HZ() uintptr {
    return IOW(spiIoctlMAGIC, 4, 4)
}

2、syscall

这是go一个与操作系统进行低级交互的一个包,驱动操作位于内核态,其地址空间与用户态隔离,在用户态得使用系统调用函数才能访问内核态数据,是内核与用户的桥梁。

当然,用syscall也是可以访问普通文件的。

syscall打开文件获得文件描述符之后就能使用上面封装好的IOCTL来配置设备了

package main

import (
    "fmt"
    "go_ioctl"
    "syscall"
    "unsafe"
)

const DEVICE string = "/dev/spidev0.0" /* 设备文件*/

var fd int 
var err error

func main() {
    //参数:文件路径,打开方式,打开模式(权限)
    fd, err = syscall.Open(DEVICE, syscall.O_RDWR, 0777) 
    if err != nil {
        fmt.Printf("device open failed\r\n")
        syscall.Close(fd)
        fmt.Println(fd, err)
    }else{
            speed := 8192000
            //参数:文件描述符,命令,数据
            err = go_ioctl.IOCTL(uintptr(fd), go_ioctl.SPI_IOC_WR_MAX_SPEED_HZ(), uintptr(unsafe.Pointer(&speed))) /*设置SPI时钟频率*/
            if err != nil {
                   fmt.Printf("can't set spi speed\r\n")
                    syscall.Close(fd)
             }else{
                    var filedata = make([]byte, 64)
                    len, _ := syscall.Read(fd, filedata)
                    if len > 0 {
                       fmt.Printf("filedata: %v\n", filedata)
                    }              
             }
    }
 }

你可能感兴趣的:(go,linux,golang,驱动开发)