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