ID Innovations

From Bashlinux
Jump to: navigation, search

HID Map

The following map is a brief description about the elements of interest in the development of an application that communicates with the device.

The device has two IN Endpoints, the first is the keyboard wedge which has a built-in driver. The reports on data interface must be processed in order to get the desired data from.

EP 1 (0x081) IN -----> Keyboard wedge interface
                      Application  : 0x00010006
                      Report ID    : 0x01
                      Report Types : Input   = 8 bytes (?)
                                     Output  = 5 bytes (?)
                                     Output  = 1 byte  (?)
                                     Input   = 6 bytes (?)

EP 2 (0x082) IN --+--> Data interface (Serial Report)
                 |    Application : 0xffa00001
                 |    Report ID   : 0x02
                 |    Report Type : Input   = 6 bytes (0xffa00001)
                 |                  Output  = 7 bytes (0xffa00002)
                 |                  Feature = 6 bytes (0xffa00003)
                 |
                 |
                 +--> Data interface (Formmated Report)
                      Application : 0xff000004
                      Report ID   : 0x03
                      Report Type : Input   = 7 bytes   (0xff000020, 0xff000021, 0xff000022, 0xff000028,
                                                         0xff000029, 0xff00002a, 0xff000038)
                                    Input   = 110 bytes (0xff000030)
                                    Input   = 110 bytes (0xff000031)
                                    Input   = 110 bytes (0xff000032)
                                    Feature = 6 bytes   (0xff000003)

To be solved

  1. Does exist Report ID 0x00 ?
  2. Where to send USB Feature Report?
  3. Is possible to send a sequence of bytes instead memcpy struct-usb-feature \\-> arrary ?
    1. If possible, what are the possible sequences?

USB Feature

The original USB Feature is defined as follow:

typedef struct _USB_FEATURE {
    unsigned bReportID;
    // Bit Defintions:
    //     Bit 0-1  = Interface settings (KBD, SERIAL, FORMATTED)
    unsigned btInterface : 2;
    unsigned btReserved1 : 6;
    unsigned bReserved1[3];
    unsigned btReservedBits  : 4;
    unsigned btSoundGoodRead : 1; // VALUE Only : tell unit to sound good beep
    unsigned btSoundErrorBeep: 1; // VALUE Only : tell unit to sound error beep
    unsigned btMSRDisabled   : 1; // VALUE Only : tell msr to disable & msr enable state
    unsigned btOPOSEnabled   : 1; // VALUE Only : tell MSR to enter OPOS mode & current OPOS status
    unsigned bReserved2;
} USB_FEATURE, *PUSB_FEATURE;

NOTE

  • The hid_get_feature function retrieves 7 bytes
  • The hid_set_feature function only send 6 bytes

So, to be clear, not all the variables are a complete byte, must of them are only a couple of bits. The following diagram shows how each one of the 6 bytes in the feature are displayed.

 -----------------------------------------------------------------------------------------------------------
|        1        |        2        |        3        |        4        |        5        |        6        |BYTES
 -----------------------------------------------------------------------------------------------------------
| 1 2 3 4 5 6 7 8 | 1 2 3 4 5 6 7 8 | 1 2 3 4 5 6 7 8 | 1 2 3 4 5 6 7 8 | 1 2 3 4 5 6 7 8 | 1 2 3 4 5 6 7 8 |BITS
 -----------------------------------------------------------------------------------------------------------
|        A        | B  |      C     |      D[1]       |      D[2]       |      D[3]       |    E   |F|G|H|I |VARS
 -----------------------------------------------------------------------------------------------------------

Where:

  • A bReportID
  • B btInterface
  • C btReserved1
  • D[1] bReserved[1]
  • D[2] bReserved[2]
  • D[3] bReserved[3]
  • E btReservedBits
  • F btSoundGoodRead
  • G btSoundErrorBeep
  • H btMSRDisabled
  • I btOPOSEnabled

Development History

Important notes about the process to get working the MSR on CentOS Linux. There are 2 kernels and 3 implementations in order to try to get done the communications with the HID MSR device.

The kernels used are the default on CentOS 5.1 distribution as original and customized for our needs.

The implementations are: hiddev, libhid, and pyusb.

Default Kernel on CentOS 5.1: 2.6.18-53.el5

The default kernel claims the ID Innovations device, that allows to work direct with it by hiddev. To develop a user space application is necessary to remove the device from the kernel space.

  • HIDDEV

Hiddev libraries on kernel uses defined ioctl definitions to operate the device.

ACCOMPLISHED: The application can read and write to the feature, but later the feature return to its original values
  • LIBHID

libhid libraries need to unbind the device in order to get access to, the methods tried by now are:

  • libhid-detach-device command
Process : Execute the command "libhid-detach-device 154a:0004"
Results : The command runs fine, but the device is attached immediately.
  • hid_force_open function
Process : The fuction is implemented like comes in the example source
Results : The debug messages said that the device is dettached successfully but the application is unable to use the device, the message returned is "Device or resource busy"
       bmAttributes            3
         Transfer Type            Interrupt
         Synch Type               None
         Usage Type               Data
       wMaxPacketSize     0x0008  1x 8 bytes
       bInterval              10
   Interface Descriptor:
     bLength                 9
     bDescriptorType         4
     bInterfaceNumber        1
     bAlternateSetting       0
     bNumEndpoints           1
     bInterfaceClass         3 Human Interface Devices
     bInterfaceSubClass      0 No Subclass
     bInterfaceProtocol      0 None
     iInterface              6 Serial Interface
       HID Device Descriptor:
         bLength                 9
         bDescriptorType        33
         bcdHID               1.00
         bCountryCode            0 Not supported
         bNumDescriptors         1
         bDescriptorType        34 Report
         wDescriptorLength      97
         Report Descriptor: (length is 97)
           Item(Global): Usage Page, data= [ 0xa0 0xff ] 65440
                           (null)
           Item(Local ): Usage, data= [ 0x01 ] 1
                           (null)
           Item(Main  ): Collection, data= [ 0x01 ] 1
                           Application
           Item(Global): Report ID, data= [ 0x02 ] 2
           Item(Local ): Usage, data= [ 0x01 ] 1
                           (null)
           Item(Global): Logical Minimum, data= [ 0x00 ] 0
           Item(Global): Logical Maximum, data= [ 0xff 0x00 ] 255
           Item(Global): Report Size, data= [ 0x08 ] 8
           Item(Global): Report Count, data= [ 0x06 ] 6
           Item(Main  ): Input, data= [ 0x02 ] 2
                           Data Variable Absolute No_Wrap Linear
                           Preferred_State No_Null_Position Non_Volatile Bitfield
           Item(Local ): Usage, data= [ 0x02 ] 2
                           (null)
           Item(Global): Report Count, data= [ 0x07 ] 7
           Item(Main  ): Output, data= [ 0x02 ] 2
                           Data Variable Absolute No_Wrap Linear
                           Preferred_State No_Null_Position Non_Volatile Bitfield
           Item(Local ): Usage, data= [ 0x03 ] 3
                           (null)
           Item(Global): Report Count, data= [ 0x06 ] 6
           Item(Main  ): Feature, data= [ 0x02 ] 2
                           Data Variable Absolute No_Wrap Linear
                           Preferred_State No_Null_Position Non_Volatile Bitfield
           Item(Main  ): End Collection, data=none
           Item(Global): Usage Page, data= [ 0x00 0xff ] 65280
                           (null)
           Item(Local ): Usage, data= [ 0x04 ] 4
                           (null)
           Item(Main  ): Collection, data= [ 0x01 ] 1
                           Application
           Item(Global): Report ID, data= [ 0x03 ] 3
           Item(Global): Logical Minimum, data= [ 0x00 ] 0
           Item(Global): Logical Maximum, data= [ 0xff 0x00 ] 255
           Item(Global): Report Size, data= [ 0x08 ] 8
           Item(Local ): Usage, data= [ 0x20 ] 32
                           (null)
           Item(Local ): Usage, data= [ 0x21 ] 33
                           (null)
           Item(Local ): Usage, data= [ 0x22 ] 34
                           (null)
           Item(Local ): Usage, data= [ 0x28 ] 40
                           (null)
           Item(Local ): Usage, data= [ 0x29 ] 41
                           (null)
           Item(Local ): Usage, data= [ 0x2a ] 42
                           (null)
           Item(Local ): Usage, data= [ 0x38 ] 56
                           (null)
           Item(Global): Report Count, data= [ 0x07 ] 7
           Item(Main  ): Input, data= [ 0x02 ] 2
                           Data Variable Absolute No_Wrap Linear
                           Preferred_State No_Null_Position Non_Volatile Bitfield
           Item(Local ): Usage, data= [ 0x30 ] 48
                           (null)
           Item(Global): Report Count, data= [ 0x6e ] 110
           Item(Main  ): Input, data= [ 0x02 0x01 ] 258
                           Data Variable Absolute No_Wrap Linear
                           Preferred_State No_Null_Position Non_Volatile Buffered Bytes
           Item(Local ): Usage, data= [ 0x31 ] 49
                           (null)
           Item(Global): Report Count, data= [ 0x6e ] 110
           Item(Main  ): Input, data= [ 0x02 0x01 ] 258
                           Data Variable Absolute No_Wrap Linear
                           Preferred_State No_Null_Position Non_Volatile Buffered Bytes
           Item(Local ): Usage, data= [ 0x32 ] 50
                           (null)
           Item(Global): Report Count, data= [ 0x6e ] 110
           Item(Main  ): Input, data= [ 0x02 0x01 ] 258
                           Data Variable Absolute No_Wrap Linear
                           Preferred_State No_Null_Position Non_Volatile Buffered Bytes
           Item(Local ): Usage, data= [ 0x03 ] 3
                           (null)
           Item(Global): Report Count, data= [ 0x06 ] 6
           Item(Main  ): Feature, data= [ 0x02 ] 2
                           Data Variable Absolute No_Wrap Linear
                           Preferred_State No_Null_Position Non_Volatile Bitfield
           Item(Main  ): End Collection, data=none
     Endpoint Descriptor:
       bLength                 7
       bDescriptorType         5
       bEndpointAddress     0x82  EP 2 IN
       bmAttributes            3
         Transfer Type            Interrupt
         Synch Type               None
         Usage Type               Data
       wMaxPacketSize     0x0008  1x 8 bytes
       bInterval              10

Process :

  • Go the the folder /sys/bus/usb/drivers/usbhid
  • Execute "lsusb | grep 154a"
          Bus 001 Device 005: ID 154a:0004
  • Giving Bus=1 and Device=5, execute the command "echo -n 1-5:1.0 > unbind"
  • Do the same for the second interface "echo -n 1-5:1.1 > unbind"
Result : The device can be accessed, and lsusb -d 0x154a:0x0004 -vvv shows the report descriptor for the second interface (EP 2 0x82), but not for the first.
libhid can read the reports, but not write. and then after use the device it returns the device to the kernel space, that means, is necessary to unbind again before run the libhid application.
  • modprobe
Process : Add any or all of the following lines to /etc/modprobe.conf
options none vendor=0x154a product=0x0004
options hiddev off
options usbhid off
alias hiddev off
alias usbhid off
Results : Rules were ignored by the system, the device is loaded by the kernel.
  • modprobe blacklist

Process : Add the following lines to /etc/modprobe.d/blacklist

blacklist hiddev
blacklist usbhid
Results : The kernel is not blacklisting the devices

Custom Kernel on Centos 5.1: 2.6.18-53.1.el5

The kernel has been customized to load usbhid as module instead embedded, and the ID Innovations MSR has been blacklisted on /usr/src/linux/drivers/usb/input/hid-core.c

  • HIDDEV

Hiddev is unable to bind the device. No hiddev device is created under /dev/hiddev

  • LIBHID

By this time, libusb is able to list both Endpoints, and libhid show no errors when send/get data from MSR. The issue by now, is that the data remains unchanged on both features in each report, 2 and 3, even when the debug messages says "sucessfully retrieved report from USB device ..." and "successfully sent report to USB device" and the hid_find_object says "found requested item".

Full Report Descriptor

The following is the result from the lsusb command on a CentOS Linux distribution with the ID Innovations devices blacklisted.

Bus 001 Device 005: ID 154a:0004
 Device Descriptor:
  bLength                18
  bDescriptorType         1
  bcdUSB               1.10
  bDeviceClass            0 (Defined at Interface level)
  bDeviceSubClass         0
  bDeviceProtocol         0
  bMaxPacketSize0         8
  idVendor           0x154a
  idProduct          0x0004
  bcdDevice            1.06
  iManufacturer           1 ID Innovations Inc.
  iProduct                2 Magnetic Card Reader
  iSerial                 0
  bNumConfigurations      1
  Configuration Descriptor:
    bLength                 9
    bDescriptorType         2
    wTotalLength           59
    bNumInterfaces          2
    bConfigurationValue     1
    iConfiguration          4 Input Device
    bmAttributes         0x80
    MaxPower              100mA
    Interface Descriptor:
      bLength                 9
      bDescriptorType         4
      bInterfaceNumber        0
      bAlternateSetting       0
      bNumEndpoints           1
      bInterfaceClass         3 Human Interface Devices
      bInterfaceSubClass      1 Boot Interface Subclass
      bInterfaceProtocol      1 Keyboard
      iInterface              5 HID Keyboard Interface
        HID Device Descriptor:
          bLength                 9
          bDescriptorType        33
          bcdHID               1.00
          bCountryCode            0 Not supported
          bNumDescriptors         1
          bDescriptorType        34 Report
          wDescriptorLength      59
          Report Descriptor: (length is 59)
            Item(Global): Usage Page, data= [ 0x01 ] 1
                            Generic Desktop Controls
            Item(Local ): Usage, data= [ 0x06 ] 6
                            Keyboard
            Item(Main  ): Collection, data= [ 0x01 ] 1
                            Application
            Item(Global): Report ID, data= [ 0x01 ] 1
            Item(Global): Usage Page, data= [ 0x07 ] 7
                            Keyboard
            Item(Local ): Usage Minimum, data= [ 0xe0 ] 224
                            Control Left
            Item(Local ): Usage Maximum, data= [ 0xe7 ] 231
                            GUI Right
            Item(Global): Logical Minimum, data= [ 0x00 ] 0
            Item(Global): Logical Maximum, data= [ 0x01 ] 1
            Item(Global): Report Size, data= [ 0x01 ] 1
            Item(Global): Report Count, data= [ 0x08 ] 8
            Item(Main  ): Input, data= [ 0x02 ] 2
                            Data Variable Absolute No_Wrap Linear
                            Preferred_State No_Null_Position Non_Volatile Bitfield
            Item(Global): Usage Page, data= [ 0x08 ] 8
                            LEDs
            Item(Local ): Usage Minimum, data= [ 0x01 ] 1
                            NumLock
            Item(Local ): Usage Maximum, data= [ 0x05 ] 5
                            Kana
            Item(Global): Report Size, data= [ 0x01 ] 1
            Item(Global): Report Count, data= [ 0x05 ] 5
            Item(Main  ): Output, data= [ 0x02 ] 2
                            Data Variable Absolute No_Wrap Linear
                            Preferred_State No_Null_Position Non_Volatile Bitfield
            Item(Global): Report Size, data= [ 0x03 ] 3
            Item(Global): Report Count, data= [ 0x01 ] 1
            Item(Main  ): Output, data= [ 0x01 ] 1
                            Constant Array Absolute No_Wrap Linear
                            Preferred_State No_Null_Position Non_Volatile Bitfield
            Item(Global): Report Size, data= [ 0x08 ] 8
            Item(Global): Report Count, data= [ 0x06 ] 6
            Item(Global): Logical Minimum, data= [ 0x00 ] 0
            Item(Global): Logical Maximum, data= [ 0x68 ] 104
            Item(Global): Usage Page, data= [ 0x07 ] 7
                            Keyboard
            Item(Local ): Usage Minimum, data= [ 0x00 ] 0
                            No Event
            Item(Local ): Usage Maximum, data= [ 0x68 ] 104
                            F13
            Item(Main  ): Input, data= [ 0x00 ] 0
                            Data Array Absolute No_Wrap Linear
                            Preferred_State No_Null_Position Non_Volatile Bitfield
            Item(Main  ): End Collection, data=none
      Endpoint Descriptor:
        bLength                 7
        bDescriptorType         5
        bEndpointAddress     0x81  EP 1 IN

References