tech-userlevel archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

Reading I2C HID descriptor from userland



Hello

I have a ihidev device that fails to find its HID descriptor. In order to
debug that, I try to retreive it from userspace.

At kernel boot, I have:
ihidev1 at iic2 addr 0x5d

I try the code at the end of this message, inspired from sys/dec/i2c/ihidev.c.
I am supposed to find the HID descriptor at address sc_hid_desc_addr, which 
should come frome ACPI.

The HID over I2C specification is at https://docs.microsoft.com/en-us/previous-versions/windows/hardware/design/dn642101%28v=vs.85%29?redirectedfrom=MSDN
Section 10 deals with ACPI bindings. It says the HID descriptor
address is to be find in a _DSM object that "defines a structure
that contains the HID Descriptor address (2 bytes)"

acpdump -dt gives me this:
            Method (_DSM, 4, Serialized)  // _DSM: Device-Specific Method
            {
                If ((Arg0 == HIDG))
                {
                    Return (HIDD (Arg0, Arg1, Arg2, Arg3, HID2))
                }

                Return (Buffer (One)
                {
                     0x00                                             // .
                })
            }

How should this be readen? I found the HIDG definition earlier in the 
ACPI dump, and my device has Name (HID2, One).
        Name (HIDG, ToUUID ("3cdff6f7-4267-4555-ad05-b30a3d8938de") /* HID I2C Device */)
(...)
        Method (HIDD, 5, Serialized)
        {
            If ((Arg0 == HIDG))
            {
                If ((Arg2 == Zero))
                {
                    If ((Arg1 == One))
                    {
                        Return (Buffer (One)
                        {
                             0x03                                             // .
                        })
                    }
                }

                If ((Arg2 == One))
                {
                    Return (Arg4)
                }
            }

Hence 1 or 3? Both return garbage. In fact I tried to brute-force the thing, 
I never get anything relevant.

Here is the code:
	
#include <sys/ioctl.h>

#include <err.h>
#include <errno.h>
#include <fcntl.h>
#include <paths.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

#include <dev/i2c/i2c_io.h>

struct i2c_hid_desc {
        uint16_t wHIDDescLength;
        uint16_t bcdVersion;
        uint16_t wReportDescLength;
        uint16_t wReportDescRegister;
        uint16_t wInputRegister;
        uint16_t wMaxInputLength;
        uint16_t wOutputRegister;
        uint16_t wMaxOutputLength;
        uint16_t wCommandRegister;
        uint16_t wDataRegister;
        uint16_t wVendorID; 
        uint16_t wProductID;
        uint16_t wVersionID;
        uint32_t reserved;
} __packed;


int
main(void)
{
        i2c_ioctl_exec_t iie;
        u_int   sc_hid_desc_addr = 0;
        uint8_t get_desc_cmd[] = {
                htole16(sc_hid_desc_addr) & 0xff,
                htole16(sc_hid_desc_addr) >> 8,
        };
        struct i2c_hid_desc desc;
        int fd;

        if ((fd = open("/dev/iic2", O_RDWR)) == -1)
                err(1, "open /dev/iic1 failed");


        iie.iie_op = I2C_OP_READ_WITH_STOP;
        iie.iie_addr = 0x5d;
        iie.iie_cmd = get_desc_cmd;
        iie.iie_cmdlen = sizeof(get_desc_cmd);
        iie.iie_buf = (char *)&desc;
        iie.iie_buflen = sizeof(desc);

        if (ioctl(fd, I2C_IOCTL_EXEC, &iie) == -1)
                return errno;

        printf("bcdVersion = %04x\n", desc.bcdVersion);

	return 0;
}


-- 
Emmanuel Dreyfus
manu%netbsd.org@localhost


Home | Main Index | Thread Index | Old Index