Beispiel #1
0
    def __init__(self, path):
        # Resolve the path to device handle
        device_entry = iokit.IORegistryEntryFromPath(K_IO_MASTER_PORT_DEFAULT,
                                                     path)
        if not device_entry:
            raise errors.OsHidError(
                'Device path does not match any HID device on '
                'the system')

        self.device_handle = iokit.IOHIDDeviceCreate(K_CF_ALLOCATOR_DEFAULT,
                                                     device_entry)
        if not self.device_handle:
            raise errors.OsHidError(
                'Failed to obtain device handle from registry '
                'entry')
        iokit.IOObjectRelease(device_entry)

        self.device_path = path

        # Open device
        result = iokit.IOHIDDeviceOpen(self.device_handle, 0)
        if result != K_IO_RETURN_SUCCESS:
            raise errors.OsHidError(
                'Failed to open device for communication: {}'.format(result))

        # Create read queue
        self.read_queue = queue.Queue()

        # Create and start read thread
        self.run_loop_ref = None
        self.read_thread = threading.Thread(target=DeviceReadThread,
                                            args=(self, ))
        self.read_thread.daemon = True
        self.read_thread.start()

        # Read max report sizes for in/out
        self.internal_max_in_report_len = GetDeviceIntProperty(
            self.device_handle, HID_DEVICE_PROPERTY_MAX_INPUT_REPORT_SIZE)
        if not self.internal_max_in_report_len:
            raise errors.OsHidError('Unable to obtain max in report size')

        self.internal_max_out_report_len = GetDeviceIntProperty(
            self.device_handle, HID_DEVICE_PROPERTY_MAX_OUTPUT_REPORT_SIZE)
        if not self.internal_max_out_report_len:
            raise errors.OsHidError('Unable to obtain max out report size')

        # Register read callback
        self.in_report_buffer = (ctypes.c_uint8 *
                                 self.internal_max_in_report_len)()
        iokit.IOHIDDeviceRegisterInputReportCallback(
            self.device_handle, self.in_report_buffer,
            self.internal_max_in_report_len, REGISTERED_READ_CALLBACK,
            ctypes.py_object(self.read_queue))
Beispiel #2
0
    def Enumerate():
        """See base class."""
        # Init a HID manager
        hid_mgr = iokit.IOHIDManagerCreate(None, None)
        if not hid_mgr:
            raise errors.OsHidError('Unable to obtain HID manager reference')
        iokit.IOHIDManagerSetDeviceMatching(hid_mgr, None)

        # Get devices from HID manager
        device_set_ref = iokit.IOHIDManagerCopyDevices(hid_mgr)
        if not device_set_ref:
            raise errors.OsHidError(
                'Failed to obtain devices from HID manager')

        num = iokit.CFSetGetCount(device_set_ref)
        devices = (IO_HID_DEVICE_REF * num)()
        iokit.CFSetGetValues(device_set_ref, devices)

        # Retrieve and build descriptor dictionaries for each device
        descriptors = []
        for dev in devices:
            d = base.DeviceDescriptor()
            d.vendor_id = GetDeviceIntProperty(dev,
                                               HID_DEVICE_PROPERTY_VENDOR_ID)
            d.product_id = GetDeviceIntProperty(
                dev, HID_DEVICE_PROPERTY_PRODUCT_ID)
            d.product_string = GetDeviceStringProperty(
                dev, HID_DEVICE_PROPERTY_PRODUCT)
            d.usage = GetDeviceIntProperty(dev,
                                           HID_DEVICE_PROPERTY_PRIMARY_USAGE)
            d.usage_page = GetDeviceIntProperty(
                dev, HID_DEVICE_PROPERTY_PRIMARY_USAGE_PAGE)
            d.report_id = GetDeviceIntProperty(dev,
                                               HID_DEVICE_PROPERTY_REPORT_ID)
            d.path = GetDevicePath(dev)
            descriptors.append(d.ToPublicDict())

        # Clean up CF objects
        cf.CFRelease(device_set_ref)
        cf.CFRelease(hid_mgr)

        return descriptors
Beispiel #3
0
    def Write(self, packet):
        """See base class."""
        report_id = 0
        out_report_buffer = (ctypes.c_uint8 *
                             self.internal_max_out_report_len)()
        out_report_buffer[:] = packet[:]

        result = iokit.IOHIDDeviceSetReport(self.device_handle,
                                            K_IO_HID_REPORT_TYPE_OUTPUT,
                                            report_id, out_report_buffer,
                                            self.internal_max_out_report_len)

        # Non-zero status indicates failure
        if result != K_IO_RETURN_SUCCESS:
            raise errors.OsHidError('Failed to write report to device')
Beispiel #4
0
def GetDeviceIntProperty(dev_ref, key):
    """Reads int property from the HID device."""
    cf_key = CFStr(key)
    type_ref = iokit.IOHIDDeviceGetProperty(dev_ref, cf_key)
    cf.CFRelease(cf_key)
    if not type_ref:
        return None

    if cf.CFGetTypeID(type_ref) != cf.CFNumberGetTypeID():
        raise errors.OsHidError('Expected number type, got {}'.format(
            cf.CFGetTypeID(type_ref)))

    out = ctypes.c_int32()
    ret = cf.CFNumberGetValue(type_ref, K_CF_NUMBER_SINT32_TYPE,
                              ctypes.byref(out))
    if not ret:
        return None

    return out.value
Beispiel #5
0
def GetDeviceStringProperty(dev_ref, key):
  """Reads string property from the HID device."""
  cf_key = CFStr(key)
  type_ref = iokit.IOHIDDeviceGetProperty(dev_ref, cf_key)
  cf.CFRelease(cf_key)
  if not type_ref:
    return None

  if cf.CFGetTypeID(type_ref) != cf.CFStringGetTypeID():
    raise errors.OsHidError('Expected string type, got {}'.format(
        cf.CFGetTypeID(type_ref)))

  type_ref = ctypes.cast(type_ref, CF_STRING_REF)
  out = ctypes.create_string_buffer(DEVICE_STRING_PROPERTY_BUFFER_SIZE)
  ret = cf.CFStringGetCString(type_ref, out, DEVICE_STRING_PROPERTY_BUFFER_SIZE,
                              K_CF_STRING_ENCODING_UTF8)
  if not ret:
    return None

  return out.value.decode('utf8')
Beispiel #6
0
    def Enumerate():
        hidraw_devices = []
        try:
            hidraw_devices = os.listdir('/sys/class/hidraw')
        except FileNotFoundError:
            raise errors.OsHidError('No hidraw device is available')

        for dev in hidraw_devices:
            rd_path = (os.path.join('/sys/class/hidraw', dev,
                                    'device/report_descriptor'))
            uevent_path = os.path.join('/sys/class/hidraw', dev,
                                       'device/uevent')
            rd_file = open(rd_path, 'rb')
            uevent_file = open(uevent_path, 'rb')
            desc = base.DeviceDescriptor()
            desc.path = os.path.join('/dev/', dev)
            ParseReportDescriptor(rd_file.read(), desc)
            ParseUevent(uevent_file.read(), desc)

            rd_file.close()
            uevent_file.close()
            yield desc.ToPublicDict()