Skip to content

Instantly share code, notes, and snippets.

@ToadKing
Last active July 13, 2020 20:50
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save ToadKing/d26f8f046a3b707e9e4b9821be5c9efc to your computer and use it in GitHub Desktop.
Save ToadKing/d26f8f046a3b707e9e4b9821be5c9efc to your computer and use it in GitHub Desktop.
steelseries udev rules+script
ACTION=="add", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="1038" RUN+="/etc/udev/rules.d/steelseries-perms.py '%E{DEVNAME}'"
#!/usr/bin/env python3
import ctypes
import fcntl
import os
import struct
import sys
# from linux headers hidraw.h, hid.h, and ioctl.h
_IOC_NRBITS = 8
_IOC_TYPEBITS = 8
_IOC_SIZEBITS = 14
_IOC_NRSHIFT = 0
_IOC_TYPESHIFT = _IOC_NRSHIFT + _IOC_NRBITS
_IOC_SIZESHIFT = _IOC_TYPESHIFT + _IOC_TYPEBITS
_IOC_DIRSHIFT = _IOC_SIZESHIFT + _IOC_SIZEBITS
_IOC_READ = 2
def _IOC(dir, type, nr, size):
return (dir << _IOC_DIRSHIFT) | \
(ord(type) << _IOC_TYPESHIFT) | \
(nr << _IOC_NRSHIFT) | \
(size << _IOC_SIZESHIFT)
def _IOR(type, nr, size):
return _IOC(_IOC_READ, type, nr, size)
HID_MAX_DESCRIPTOR_SIZE = 4096
class hidraw_report_descriptor(ctypes.Structure):
_fields_ = [
('size', ctypes.c_uint),
('value', ctypes.c_uint8 * HID_MAX_DESCRIPTOR_SIZE),
]
HIDIOCGRDESCSIZE = _IOR('H', 0x01, ctypes.sizeof(ctypes.c_int))
HIDIOCGRDESC = _IOR('H', 0x02, ctypes.sizeof(hidraw_report_descriptor))
hidraw = sys.argv[1]
with open(hidraw, 'wb') as fd:
size = ctypes.c_uint()
fcntl.ioctl(fd, HIDIOCGRDESCSIZE, size, True)
descriptor = hidraw_report_descriptor()
descriptor.size = size
fcntl.ioctl(fd, HIDIOCGRDESC, descriptor, True)
descriptor = bytes(descriptor.value)[0:int.from_bytes(size, byteorder=sys.byteorder)]
# walk through the descriptor until we find the usage page
usagePage = 0
i = 0
while i < len(descriptor):
b = descriptor[i]
bTag = (b >> 4) & 0x0F
bType = (b >> 2) & 0x03
bSize = b & 0x03
if bSize != 0:
bSize = 2 ** (bSize - 1)
if b == 0b11111110:
# long types shouldn't be the usage page, skip them
i += 3 + descriptor[i+1]
continue
if bType == 1 and bTag == 0:
# usage page, grab it
format = ''
if bSize == 1:
format = 'B'
elif bSize == 2:
format = 'H'
elif bSize == 4:
format = 'I'
else:
raise Exception('usage page is length {}???'.format(bSize))
usagePage = struct.unpack_from(format, descriptor, i + 1)[0]
break
i += 1 + bSize
# set read/write permissions for vendor and consumer usage pages
# some devices don't use the vendor page, allow the interfaces they do use
if usagePage == 0x000C or usagePage >= 0xFF00:
os.chmod(hidraw, 0o666)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment