github.com/holoplot/go-evdev@v0.0.0-20220721205823-d31c64b9d636/ioctl.go (about)

     1  package evdev
     2  
     3  import (
     4  	"errors"
     5  	"fmt"
     6  	"strings"
     7  	"syscall"
     8  	"unsafe"
     9  )
    10  
    11  const (
    12  	ioctlDirNone  = 0x0
    13  	ioctlDirWrite = 0x1
    14  	ioctlDirRead  = 0x2
    15  )
    16  
    17  func trimNull(s string) string {
    18  	return strings.Trim(s, "\x00")
    19  }
    20  
    21  func ioctlMakeCode(dir, typ, nr int, size uintptr) uint32 {
    22  	var code uint32
    23  	if dir > ioctlDirWrite|ioctlDirRead {
    24  		panic(fmt.Errorf("invalid ioctl dir value: %d", dir))
    25  	}
    26  
    27  	if size > 1<<14 {
    28  		panic(fmt.Errorf("invalid ioctl size value: %d", size))
    29  	}
    30  
    31  	code |= uint32(dir) << 30
    32  	code |= uint32(size) << 16
    33  	code |= uint32(typ) << 8
    34  	code |= uint32(nr)
    35  
    36  	return code
    37  }
    38  
    39  func doIoctl(fd uintptr, code uint32, ptr unsafe.Pointer) error {
    40  	_, _, errno := syscall.Syscall(syscall.SYS_IOCTL, fd, uintptr(code), uintptr(ptr))
    41  	if errno != 0 {
    42  		return errors.New(errno.Error())
    43  	}
    44  
    45  	return nil
    46  }
    47  
    48  func ioctlEVIOCGVERSION(fd uintptr) (int32, error) {
    49  	version := int32(0)
    50  	code := ioctlMakeCode(ioctlDirRead, 'E', 0x01, unsafe.Sizeof(version))
    51  	err := doIoctl(fd, code, unsafe.Pointer(&version))
    52  	return version, err
    53  }
    54  
    55  func ioctlEVIOCGID(fd uintptr) (InputID, error) {
    56  	id := InputID{}
    57  	code := ioctlMakeCode(ioctlDirRead, 'E', 0x02, unsafe.Sizeof(id))
    58  	err := doIoctl(fd, code, unsafe.Pointer(&id))
    59  	return id, err
    60  }
    61  
    62  func ioctlEVIOCGREP(fd uintptr) ([2]uint32, error) {
    63  	rep := [2]uint32{}
    64  	code := ioctlMakeCode(ioctlDirRead, 'E', 0x03, unsafe.Sizeof(rep))
    65  	err := doIoctl(fd, code, unsafe.Pointer(&rep))
    66  	return rep, err
    67  }
    68  
    69  func ioctlEVIOCSREP(fd uintptr, rep [2]uint32) error {
    70  	code := ioctlMakeCode(ioctlDirWrite, 'E', 0x03, unsafe.Sizeof(rep))
    71  	return doIoctl(fd, code, unsafe.Pointer(&rep))
    72  }
    73  
    74  func ioctlEVIOCGKEYCODE(fd uintptr) (InputKeymapEntry, error) {
    75  	entry := InputKeymapEntry{}
    76  	code := ioctlMakeCode(ioctlDirRead, 'E', 0x04, unsafe.Sizeof(entry))
    77  	err := doIoctl(fd, code, unsafe.Pointer(&entry))
    78  	return entry, err
    79  }
    80  
    81  func ioctlEVIOCSKEYCODE(fd uintptr, entry InputKeymapEntry) error {
    82  	code := ioctlMakeCode(ioctlDirWrite, 'E', 0x04, unsafe.Sizeof(entry))
    83  	return doIoctl(fd, code, unsafe.Pointer(&entry))
    84  }
    85  
    86  func ioctlEVIOCGNAME(fd uintptr) (string, error) {
    87  	str := [256]byte{}
    88  	code := ioctlMakeCode(ioctlDirRead, 'E', 0x06, unsafe.Sizeof(str))
    89  	err := doIoctl(fd, code, unsafe.Pointer(&str))
    90  	return trimNull(string(str[:])), err
    91  }
    92  
    93  func ioctlEVIOCGPHYS(fd uintptr) (string, error) {
    94  	str := [256]byte{}
    95  	code := ioctlMakeCode(ioctlDirRead, 'E', 0x07, unsafe.Sizeof(str))
    96  	err := doIoctl(fd, code, unsafe.Pointer(&str))
    97  	return trimNull(string(str[:])), err
    98  }
    99  
   100  func ioctlEVIOCGUNIQ(fd uintptr) (string, error) {
   101  	str := [256]byte{}
   102  	code := ioctlMakeCode(ioctlDirRead, 'E', 0x08, unsafe.Sizeof(str))
   103  	err := doIoctl(fd, code, unsafe.Pointer(&str))
   104  	return trimNull(string(str[:])), err
   105  }
   106  
   107  func ioctlEVIOCGPROP(fd uintptr) ([]byte, error) {
   108  	bits := [256]byte{}
   109  	code := ioctlMakeCode(ioctlDirRead, 'E', 0x09, unsafe.Sizeof(bits))
   110  	err := doIoctl(fd, code, unsafe.Pointer(&bits))
   111  	return bits[:], err
   112  }
   113  
   114  func ioctlEVIOCGKEY(fd uintptr) ([]byte, error) {
   115  	bits := [KEY_MAX]byte{}
   116  	code := ioctlMakeCode(ioctlDirRead, 'E', 0x18, unsafe.Sizeof(bits))
   117  	err := doIoctl(fd, code, unsafe.Pointer(&bits))
   118  	return bits[:], err
   119  }
   120  
   121  func ioctlEVIOCGLED(fd uintptr) ([]byte, error) {
   122  	bits := [LED_MAX]byte{}
   123  	code := ioctlMakeCode(ioctlDirRead, 'E', 0x19, unsafe.Sizeof(bits))
   124  	err := doIoctl(fd, code, unsafe.Pointer(&bits))
   125  	return bits[:], err
   126  }
   127  
   128  func ioctlEVIOCGSND(fd uintptr) ([]byte, error) {
   129  	bits := [SND_MAX]byte{}
   130  	code := ioctlMakeCode(ioctlDirRead, 'E', 0x1a, unsafe.Sizeof(bits))
   131  	err := doIoctl(fd, code, unsafe.Pointer(&bits))
   132  	return bits[:], err
   133  }
   134  
   135  func ioctlEVIOCGSW(fd uintptr) ([]byte, error) {
   136  	bits := [SW_MAX]byte{}
   137  	code := ioctlMakeCode(ioctlDirRead, 'E', 0x1b, unsafe.Sizeof(bits))
   138  	err := doIoctl(fd, code, unsafe.Pointer(&bits))
   139  	return bits[:], err
   140  }
   141  
   142  func ioctlEVIOCGBIT(fd uintptr, evtype int) ([]byte, error) {
   143  	var cnt int
   144  
   145  	switch evtype {
   146  	case 0:
   147  		// special case, indicating the list of all feature types supported should be returned,
   148  		// rather than the list of particular features for that type
   149  		cnt = EV_CNT
   150  	case EV_KEY:
   151  		cnt = KEY_CNT
   152  	case EV_REL:
   153  		cnt = REL_CNT
   154  	case EV_ABS:
   155  		cnt = ABS_CNT
   156  	case EV_MSC:
   157  		cnt = MSC_CNT
   158  	case EV_SW:
   159  		cnt = SW_CNT
   160  	case EV_LED:
   161  		cnt = LED_CNT
   162  	case EV_SND:
   163  		cnt = SND_CNT
   164  	case EV_REP:
   165  		cnt = REP_CNT
   166  	case EV_FF:
   167  		cnt = FF_CNT
   168  	default: // EV_PWR, EV_FF_STATUS ??
   169  		cnt = KEY_MAX
   170  	}
   171  
   172  	bytesNumber := (cnt + 7) / 8
   173  
   174  	bits := [KEY_MAX]byte{}
   175  	code := ioctlMakeCode(ioctlDirRead, 'E', 0x20+evtype, unsafe.Sizeof(bits))
   176  	err := doIoctl(fd, code, unsafe.Pointer(&bits))
   177  	return bits[:bytesNumber], err
   178  }
   179  
   180  func ioctlEVIOCGABS(fd uintptr, abs int) (AbsInfo, error) {
   181  	info := AbsInfo{}
   182  	code := ioctlMakeCode(ioctlDirRead, 'E', 0x40+abs, unsafe.Sizeof(info))
   183  	err := doIoctl(fd, code, unsafe.Pointer(&info))
   184  	return info, err
   185  }
   186  
   187  func ioctlEVIOCSABS(fd uintptr, abs int, info AbsInfo) error {
   188  	code := ioctlMakeCode(ioctlDirWrite, 'E', 0xc0+abs, unsafe.Sizeof(info))
   189  	return doIoctl(fd, code, unsafe.Pointer(&info))
   190  }
   191  
   192  func ioctlEVIOCGRAB(fd uintptr, p int32) error {
   193  	code := ioctlMakeCode(ioctlDirWrite, 'E', 0x90, unsafe.Sizeof(p))
   194  	if p != 0 {
   195  		return doIoctl(fd, code, unsafe.Pointer(&p))
   196  	}
   197  	return doIoctl(fd, code, nil)
   198  }
   199  
   200  func ioctlEVIOCREVOKE(fd uintptr) error {
   201  	var p int32
   202  	code := ioctlMakeCode(ioctlDirWrite, 'E', 0x91, unsafe.Sizeof(p))
   203  	return doIoctl(fd, code, nil)
   204  }
   205  
   206  func ioctlUISETEVBIT(fd uintptr, ev uintptr) error {
   207  	var p int32
   208  	code := ioctlMakeCode(ioctlDirWrite, 'U', 100, unsafe.Sizeof(p))
   209  	return doIoctl(fd, code, unsafe.Pointer(ev))
   210  }
   211  
   212  func ioctlUISETKEYBIT(fd uintptr, key uintptr) error {
   213  	var p int32
   214  	code := ioctlMakeCode(ioctlDirWrite, 'U', 101, unsafe.Sizeof(p))
   215  	return doIoctl(fd, code, unsafe.Pointer(key))
   216  }
   217  
   218  func ioctlUISETRELBIT(fd uintptr, rel uintptr) error {
   219  	var p int32
   220  	code := ioctlMakeCode(ioctlDirWrite, 'U', 102, unsafe.Sizeof(p))
   221  	return doIoctl(fd, code, unsafe.Pointer(rel))
   222  }
   223  
   224  func ioctlUISETABSBIT(fd uintptr, abs uintptr) error {
   225  	var p int32
   226  	code := ioctlMakeCode(ioctlDirWrite, 'U', 103, unsafe.Sizeof(p))
   227  	return doIoctl(fd, code, unsafe.Pointer(abs))
   228  }
   229  
   230  func ioctlUISETMSCBIT(fd uintptr, msc uintptr) error {
   231  	var p int32
   232  	code := ioctlMakeCode(ioctlDirWrite, 'U', 104, unsafe.Sizeof(p))
   233  	return doIoctl(fd, code, unsafe.Pointer(msc))
   234  }
   235  
   236  func ioctlUISETLEDBIT(fd uintptr, led uintptr) error {
   237  	var p int32
   238  	code := ioctlMakeCode(ioctlDirWrite, 'U', 105, unsafe.Sizeof(p))
   239  	return doIoctl(fd, code, unsafe.Pointer(led))
   240  }
   241  
   242  func ioctlUISETSNDBIT(fd uintptr, snd uintptr) error {
   243  	var p int32
   244  	code := ioctlMakeCode(ioctlDirWrite, 'U', 106, unsafe.Sizeof(p))
   245  	return doIoctl(fd, code, unsafe.Pointer(snd))
   246  }
   247  
   248  func ioctlUISETFFBIT(fd uintptr, fe uintptr) error {
   249  	var p int32
   250  	code := ioctlMakeCode(ioctlDirWrite, 'U', 107, unsafe.Sizeof(p))
   251  	return doIoctl(fd, code, unsafe.Pointer(fe))
   252  }
   253  
   254  func ioctlUISETSWBIT(fd uintptr, sw uintptr) error {
   255  	var p int32
   256  	code := ioctlMakeCode(ioctlDirWrite, 'U', 109, unsafe.Sizeof(p))
   257  	return doIoctl(fd, code, unsafe.Pointer(sw))
   258  }
   259  
   260  func ioctlUISETPROPBIT(fd uintptr, prop uintptr) error {
   261  	var p int32
   262  	code := ioctlMakeCode(ioctlDirWrite, 'U', 110, unsafe.Sizeof(p))
   263  	return doIoctl(fd, code, unsafe.Pointer(prop))
   264  }
   265  
   266  func ioctlUIDEVCREATE(fd uintptr) error {
   267  	code := ioctlMakeCode(ioctlDirNone, 'U', 1, 0)
   268  	return doIoctl(fd, code, nil)
   269  }
   270  
   271  func ioctlUIDEVDESTROY(fd uintptr) error {
   272  	code := ioctlMakeCode(ioctlDirNone, 'U', 2, 0)
   273  	return doIoctl(fd, code, nil)
   274  }