ID Innovations
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
- Does exist Report ID 0x00 ?
- Where to send USB Feature Report?
- Is possible to send a sequence of bytes instead
memcpy struct-usb-feature \\-> arrary
?- 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
- http://www.idinnovations.com
- http://pyusb.berlios.de
- http://www.usb.org/developers/docs/
- http://www.usb.org/developers/docs/usb_20_122208.zip
- http://www.nabble.com/How-to-dump-HID-report-descriptor-under-Linux-td19609562.html
- http://lists.alioth.debian.org/pipermail/libhid-discuss/2009-February/000582.html
- http://www.cyberciti.biz/tips/avoid-linux-kernel-module-driver-autoloading.html