payment slip reader

Probably the first time I got in contact with one of the pen style payment slip readers, was when I was working for TCG. They only come with drivers for Windows and in the meantime also for Mac. I contacted their support more than once, asking for a linux driver. No success so far. So I decided to get one cheap from ricardo.ch (similar to ebay.com). I was really lucky, and got one that makes noise when shaking for CHF 5. A new one would cost more than CHF 200. They have a very effective way of making sure people buy new ones from time to time. They just don’t release drivers for the older devices on newer versions of Windows. Well, that happens a lot in the Windows world, that people are forced to buy new devices. So there are a lot of devices floating around on ricardo.ch which only run on WindowsXP 32bit. Mine is one of those, but since I want to use it on linux that should be no problem.

When I first plugged it in, the USB id was recognized correctly:

$ lsusb
...
Bus 002 Device 010: ID 0a93:0002 C Technologies AB C-Pen 10

But that was about it.

Trying to capture the communication on the USB port worked nicely with WireShark under ubuntu. But as I had no driver for it, there was not much communication to monitor. So I had to capture on a Windows box. Not so easy in a Windows-free zone. I have a VMWare virtual machine on my harddisk that I used some time ago to maintain an ancient project. But the outdated WMWare-Player could not run with my current installation. I had to upgrade it. It compiled the kernel modules with some minor help. But then the VM wouldn’t boot. I suspect, they changed the hardware they emulate. That would be no problem with linux, but Windows has real trouble with changing hardware. That was the same reason, I could not migrate that VM to VirtualBox some years ago. So, I installed a new Windows VM with VirtualBox. But now I could not figure out how to make the USB device accessible to the guest OS. The next try was qemu. It’s not as point and clicky as the other two products, but it’s really powerful and comes with loads of features. I grow to like it ever more. Although there are some very good tutorials on qemu, some commands changed with the latest upgrade, so I list them here. In fact the whole thing runs faster if you create an image from your installation media in advance.

sudo umount /media/windows
dd if=/dev/sr1 of=windows.iso
qemu-img create -f qcow windows_2k.img 4G
qemu-system-i386 -localtime -cdrom windows.iso -m 384 -boot d -usb -usbdevice host:0a93:0002 -net nic,model=ne2k_pci -net user windows_2k.img

I don’t know why, but the installation took very long. Then I installed the driver software, and it was really recognized, and pressing the button on the device generated a return keystroke as it was configured to do. But when I tried to scan something, it would appear to process some data with the OCR software, but I didn’t get any output. Well, I tried it on what I had laying on my desk. That was a business card. It contained letters and numbers in varying sizes. But nothing of it was recognized. Then I grabbed a payment slip from the drawer. After all, that’s what the device is designed for. It contains OCR-B digits in exactly the size that’s expected. And …. it worked!

Next thing was installing usbsnoop for capturing the USB traffic. But there were also some minor road blockers ahead. Ah right, Windows 2000 didn’t have anything to unzip a file. That was the era when everybody had a shareware version of WinZip. Oh, cool the sourceforge download page doesn’t work with Internet Exploder 5.0.

The log file is actually quite large, and a guy at the sane mailing list told me, I’m going to spend a lot of time looking at these logs.

[0 ms] UsbSnoop compiled on Jan 18 2003 22:41:32 loading
[0 ms] UsbSnoop - DriverEntry(f2342c40) : Windows NT WDM version 1.16
[27 ms] UsbSnoop - AddDevice(f2342f50) : DriverObject 827873d0, pdo 825ffaf0
[27 ms] UsbSnoop - DispatchAny(f2340610) : IRP_MJ_PNP (0x00000018)
[27 ms] UsbSnoop - MyDispatchPNP(f2342ee0) : IRP_MJ_PNP (0x00000018)
[27 ms] UsbSnoop - DispatchAny(f2340610) : IRP_MJ_PNP (IRP_MN_QUERY_RESOURCE_REQUIREMENTS)
[27 ms] UsbSnoop - MyDispatchPNP(f2342ee0) : IRP_MJ_PNP (IRP_MN_QUERY_RESOURCE_REQUIREMENTS)
[28 ms] UsbSnoop - DispatchAny(f2340610) : IRP_MJ_PNP (IRP_MN_FILTER_RESOURCE_REQUIREMENTS)
[28 ms] UsbSnoop - MyDispatchPNP(f2342ee0) : IRP_MJ_PNP (IRP_MN_FILTER_RESOURCE_REQUIREMENTS)
[28 ms] UsbSnoop - DispatchAny(f2340610) : IRP_MJ_PNP (IRP_MN_START_DEVICE)
[28 ms] UsbSnoop - MyDispatchPNP(f2342ee0) : IRP_MJ_PNP (IRP_MN_START_DEVICE)
[28 ms] UsbSnoop - DispatchAny(f2340610) : IRP_MJ_INTERNAL_DEVICE_CONTROL
[28 ms] UsbSnoop - MyDispatchInternalIOCTL(f2341e80) : fdo=825ffaf0, Irp=82521608, IRQL=0
[28 ms] >>> URB 1 going down >>>
-- URB_FUNCTION_GET_DESCRIPTOR_FROM_DEVICE:
TransferBufferLength = 00000012
TransferBuffer = 8252f068
TransferBufferMDL = 00000000
Index = 00000000
DescriptorType = 00000001 (USB_DEVICE_DESCRIPTOR_TYPE)
LanguageId = 00000000
[33 ms] UsbSnoop - MyInternalIOCTLCompletion(f2341db0) : fido=00000000, Irp=82521608, Context=8251e948, IRQL=2
[33 ms] <<< URB 1 coming back <<<
-- URB_FUNCTION_CONTROL_TRANSFER:
PipeHandle = 824f2b74
TransferFlags = 005c0077 (USBD_TRANSFER_DIRECTION_IN, USBD_SHORT_TRANSFER_OK)
TransferBufferLength = 00000012
TransferBuffer = 8252f068
TransferBufferMDL = 82644068
00000000: 12 01 00 02 ff 00 00 08 93 0a 02 00 17 01 01 02
00000010: 03 01
UrbLink = 00000000
SetupPacket =
00000000: 80 06 00 01 00 00 12 00
[33 ms] UsbSnoop - DispatchAny(f2340610) : IRP_MJ_INTERNAL_DEVICE_CONTROL
[33 ms] UsbSnoop - MyDispatchInternalIOCTL(f2341e80) : fdo=825ffaf0, Irp=82521608, IRQL=0
[33 ms] >>> URB 2 going down >>>
-- URB_FUNCTION_GET_DESCRIPTOR_FROM_DEVICE:
TransferBufferLength = 00000209
TransferBuffer = 824f3008
TransferBufferMDL = 00000000
Index = 00000000
DescriptorType = 00000002 (USB_CONFIGURATION_DESCRIPTOR_TYPE)
LanguageId = 00000000
[43 ms] UsbSnoop - MyInternalIOCTLCompletion(f2341db0) : fido=00000000, Irp=82521608, Context=826386a8, IRQL=2
[43 ms] <<< URB 2 coming back <<<
-- URB_FUNCTION_CONTROL_TRANSFER:
PipeHandle = 824f2b74
TransferFlags = 005c0077 (USBD_TRANSFER_DIRECTION_IN, USBD_SHORT_TRANSFER_OK)
TransferBufferLength = 00000028
TransferBuffer = 824f3008
TransferBufferMDL = 82644068
00000000: 09 02 20 00 01 01 00 a0 64 09 04 00 00 02 ff 00
00000010: ff 00 07 05 81 03 08 00 01 07 05 82 03 40 00 01
00000020: 00 00 00 00 00 00 00 00
UrbLink = 00000000
SetupPacket =
00000000: 80 06 00 02 00 00 09 02
[43 ms] UsbSnoop - DispatchAny(f2340610) : IRP_MJ_INTERNAL_DEVICE_CONTROL
[43 ms] UsbSnoop - MyDispatchInternalIOCTL(f2341e80) : fdo=825ffaf0, Irp=82521608, IRQL=0
[43 ms] >>> URB 3 going down >>>
-- URB_FUNCTION_SELECT_CONFIGURATION:
ConfigurationDescriptor = 0x824f3008 (configure)
ConfigurationDescriptor : bLength = 9
ConfigurationDescriptor : bDescriptorType = 0x00000002
ConfigurationDescriptor : wTotalLength = 0x00000020
ConfigurationDescriptor : bNumInterfaces = 0x00000001
ConfigurationDescriptor : bConfigurationValue = 0x00000001
ConfigurationDescriptor : iConfiguration = 0x00000000
ConfigurationDescriptor : bmAttributes = 0x000000a0
ConfigurationDescriptor : MaxPower = 0x00000064
ConfigurationHandle = 0x005c0077
Interface[0]: Length = 56
Interface[0]: InterfaceNumber = 0
Interface[0]: AlternateSetting = 0
[46 ms] UsbSnoop - MyInternalIOCTLCompletion(f2341db0) : fido=00000000, Irp=82521608, Context=82561c08, IRQL=0
[46 ms] <<< URB 3 coming back <<<
-- URB_FUNCTION_SELECT_CONFIGURATION:
ConfigurationDescriptor = 0x824f3008 (configure)
ConfigurationDescriptor : bLength = 9
ConfigurationDescriptor : bDescriptorType = 0x00000002
ConfigurationDescriptor : wTotalLength = 0x00000020
ConfigurationDescriptor : bNumInterfaces = 0x00000001
ConfigurationDescriptor : bConfigurationValue = 0x00000001
ConfigurationDescriptor : iConfiguration = 0x00000000
ConfigurationDescriptor : bmAttributes = 0x000000a0
ConfigurationDescriptor : MaxPower = 0x00000064
ConfigurationHandle = 0xe11e4bc8
Interface[0]: Length = 56
Interface[0]: InterfaceNumber = 0
Interface[0]: AlternateSetting = 0
Interface[0]: Class = 0x000000ff
Interface[0]: SubClass = 0x00000000
Interface[0]: Protocol = 0x000000ff
Interface[0]: InterfaceHandle = 0x82563828
Interface[0]: NumberOfPipes = 2
Interface[0]: Pipes[0] : MaximumPacketSize = 0x00000008
Interface[0]: Pipes[0] : EndpointAddress = 0x00000081
Interface[0]: Pipes[0] : Interval = 0x00000001
Interface[0]: Pipes[0] : PipeType = 0x00000003 (UsbdPipeTypeInterrupt)
Interface[0]: Pipes[0] : PipeHandle = 0x82563840
Interface[0]: Pipes[0] : MaxTransferSize = 0x00001000
Interface[0]: Pipes[0] : PipeFlags = 0x00000000
Interface[0]: Pipes[1] : MaximumPacketSize = 0x00000040
Interface[0]: Pipes[1] : EndpointAddress = 0x00000082
Interface[0]: Pipes[1] : Interval = 0x00000001
Interface[0]: Pipes[1] : PipeType = 0x00000003 (UsbdPipeTypeInterrupt)
Interface[0]: Pipes[1] : PipeHandle = 0x8256385c
Interface[0]: Pipes[1] : MaxTransferSize = 0x00001000
Interface[0]: Pipes[1] : PipeFlags = 0x00000000
[47 ms] UsbSnoop - DispatchAny(f2340610) : IRP_MJ_PNP (IRP_MN_QUERY_CAPABILITIES)
[47 ms] UsbSnoop - MyDispatchPNP(f2342ee0) : IRP_MJ_PNP (IRP_MN_QUERY_CAPABILITIES)
[47 ms] UsbSnoop - DispatchAny(f2340610) : IRP_MJ_PNP (IRP_MN_QUERY_PNP_DEVICE_STATE)
[47 ms] UsbSnoop - MyDispatchPNP(f2342ee0) : IRP_MJ_PNP (IRP_MN_QUERY_PNP_DEVICE_STATE)
[47 ms] UsbSnoop - DispatchAny(f2340610) : IRP_MJ_PNP (IRP_MN_QUERY_DEVICE_RELATIONS)
[47 ms] UsbSnoop - MyDispatchPNP(f2342ee0) : IRP_MJ_PNP (IRP_MN_QUERY_DEVICE_RELATIONS)
[47 ms] UsbSnoop - DispatchAny(f2340610) : IRP_MJ_PNP (IRP_MN_QUERY_DEVICE_RELATIONS)
[47 ms] UsbSnoop - MyDispatchPNP(f2342ee0) : IRP_MJ_PNP (IRP_MN_QUERY_DEVICE_RELATIONS)
[49 ms] UsbSnoop - DispatchAny(f2340610) : IRP_MJ_INTERNAL_DEVICE_CONTROL
[49 ms] UsbSnoop - MyDispatchInternalIOCTL(f2341e80) : fdo=825ffaf0, Irp=82521608, IRQL=0
[49 ms] >>> URB 4 going down >>>
-- URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER:
PipeHandle = 82563840 [endpoint 0x00000081]
TransferFlags = 00000003 (USBD_TRANSFER_DIRECTION_IN, USBD_SHORT_TRANSFER_OK)
TransferBufferLength = 00000008
TransferBuffer = 82546168
TransferBufferMDL = 00000000
UrbLink = 00000000
[50 ms] UsbSnoop - DispatchAny(f2340610) : IRP_MJ_INTERNAL_DEVICE_CONTROL
[50 ms] UsbSnoop - MyDispatchInternalIOCTL(f2341e80) : fdo=825ffaf0, Irp=82701008, IRQL=0
[50 ms] >>> URB 5 going down >>>
-- URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER:
PipeHandle = 8256385c [endpoint 0x00000082]
TransferFlags = 00000003 (USBD_TRANSFER_DIRECTION_IN, USBD_SHORT_TRANSFER_OK)
TransferBufferLength = 0000041c
TransferBuffer = 826de3e8
TransferBufferMDL = 00000000
UrbLink = 00000000
[50 ms] UsbSnoop - DispatchAny(f2340610) : IRP_MJ_INTERNAL_DEVICE_CONTROL
[50 ms] UsbSnoop - MyDispatchInternalIOCTL(f2341e80) : fdo=825ffaf0, Irp=82609848, IRQL=0
[50 ms] >>> URB 6 going down >>>
-- URB_FUNCTION_VENDOR_DEVICE:
TransferFlags = 00000000 (USBD_TRANSFER_DIRECTION_OUT, ~USBD_SHORT_TRANSFER_OK)
TransferBufferLength = 00000000
TransferBuffer = 00000000
TransferBufferMDL = 00000000

no data supplied
UrbLink = 00000000
RequestTypeReservedBits = 00000000
Request = 000000fe
Value = 000000de
Index = 00000005
[53 ms] UsbSnoop - MyInternalIOCTLCompletion(f2341db0) : fido=00000000, Irp=82609848, Context=82542268, IRQL=2
[53 ms] <<< URB 6 coming back <<<
-- URB_FUNCTION_CONTROL_TRANSFER:
PipeHandle = 824f2b74
TransferFlags = 00000002 (USBD_TRANSFER_DIRECTION_OUT, USBD_SHORT_TRANSFER_OK)
TransferBufferLength = 00000000
TransferBuffer = 00000000
TransferBufferMDL = 00000000
UrbLink = 00000000
SetupPacket =
00000000: 40 fe de 00 05 00 00 00
[7930 ms] UsbSnoop - MyInternalIOCTLCompletion(f2341db0) : fido=00000000, Irp=82521608, Context=825a32e8, IRQL=2
[7930 ms] <<< URB 4 coming back <<<
-- URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER:
PipeHandle = 82563840 [endpoint 0x00000081]
TransferFlags = 00000003 (USBD_TRANSFER_DIRECTION_IN, USBD_SHORT_TRANSFER_OK)
TransferBufferLength = 00000007
TransferBuffer = 82546168
TransferBufferMDL = 82644068
00000000: 01 01 17 01 00 30 05
UrbLink = 00000000
[7930 ms] UsbSnoop - DispatchAny(f2340610) : IRP_MJ_INTERNAL_DEVICE_CONTROL
[7930 ms] UsbSnoop - MyDispatchInternalIOCTL(f2341e80) : fdo=825ffaf0, Irp=82521608, IRQL=2
[7930 ms] >>> URB 7 going down >>>
-- URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER:
PipeHandle = 82563840 [endpoint 0x00000081]
TransferFlags = 00000003 (USBD_TRANSFER_DIRECTION_IN, USBD_SHORT_TRANSFER_OK)
TransferBufferLength = 00000008
TransferBuffer = 82546168
TransferBufferMDL = 00000000
UrbLink = 00000000
[7941 ms] UsbSnoop - MyInternalIOCTLCompletion(f2341db0) : fido=00000000, Irp=82701008, Context=825364a8, IRQL=2
[7941 ms] <<< URB 5 coming back <<<
-- URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER:
PipeHandle = 8256385c [endpoint 0x00000082]
TransferFlags = 00000003 (USBD_TRANSFER_DIRECTION_IN, USBD_SHORT_TRANSFER_OK)
TransferBufferLength = 00000006
TransferBuffer = 826de3e8
TransferBufferMDL = 8255c128
00000000: 01 01 17 01 01 20
UrbLink = 00000000
[7941 ms] UsbSnoop - DispatchAny(f2340610) : IRP_MJ_INTERNAL_DEVICE_CONTROL
[7941 ms] UsbSnoop - MyDispatchInternalIOCTL(f2341e80) : fdo=825ffaf0, Irp=82701008, IRQL=2
[7941 ms] >>> URB 8 going down >>>
-- URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER:
PipeHandle = 8256385c [endpoint 0x00000082]
TransferFlags = 00000003 (USBD_TRANSFER_DIRECTION_IN, USBD_SHORT_TRANSFER_OK)
TransferBufferLength = 0000041c
TransferBuffer = 826de3e8
TransferBufferMDL = 00000000
UrbLink = 00000000
[7978 ms] UsbSnoop - MyInternalIOCTLCompletion(f2341db0) : fido=00000000, Irp=82701008, Context=82546768, IRQL=2
[7978 ms] <<< URB 8 coming back <<<
-- URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER:
PipeHandle = 8256385c [endpoint 0x00000082]
TransferFlags = 00000003 (USBD_TRANSFER_DIRECTION_IN, USBD_SHORT_TRANSFER_OK)
TransferBufferLength = 0000014e
TransferBuffer = 826de3e8
TransferBufferMDL = 8255c128
00000000: 01 01 17 01 00 20 00 00 00 00 00 00 00 00 68 00
00000010: 50 00 00 00 38 01 f0 ff ff ff ff ff ff ff ff ff
00000020: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
00000030: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
00000040: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
00000050: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
00000060: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
00000070: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
00000080: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff 75
00000090: ff ff ff e3 ff ff df 2f ff ff cf 3f ff ff af 5f
000000a0: ff ff 9f 5f ff ff 8f 68 f7 ff ff 78 78 ff ff 7f
000000b0: 96 f7 ff ff 67 6a ff ff 6f a7 f6 ff ff 76 7a ff
000000c0: ff 5f a7 f7 ff ff 75 7a ff ff 5f a7 f7 ff ff 75
000000d0: 7a ff ff 6f a6 f7 ff ff 66 7a ff ff 5f a7 f7 ff
000000e0: ff 75 7a ff ff 5f a7 f7 ff ff 75 7a ff ff 6f a6
000000f0: f7 ff ff 75 7a ff ff 5f a7 f6 ff ff 67 6a ff ff
00000100: 7f 97 f6 ff ff 77 78 ff ff 7f 68 f8 ff ff f7 f6
00000110: ff ff f9 f5 ff ff f9 f5 ff 1f f7 f2 f3 ff ff fc
00000120: f1 ff ff 0f fc ff ff ff ff ff ff ff ff ff ff ff
00000130: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
00000140: ff ff ff ff ff ff ff ff ff ff ff ff ff ff
UrbLink = 00000000
[7978 ms] UsbSnoop - DispatchAny(f2340610) : IRP_MJ_INTERNAL_DEVICE_CONTROL
[7978 ms] UsbSnoop - MyDispatchInternalIOCTL(f2341e80) : fdo=825ffaf0, Irp=82701008, IRQL=2
[7978 ms] >>> URB 9 going down >>>
-- URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER:
PipeHandle = 8256385c [endpoint 0x00000082]
TransferFlags = 00000003 (USBD_TRANSFER_DIRECTION_IN, USBD_SHORT_TRANSFER_OK)
TransferBufferLength = 0000041c
TransferBuffer = 826de3e8
TransferBufferMDL = 00000000
UrbLink = 00000000
[8329 ms] UsbSnoop - MyInternalIOCTLCompletion(f2341db0) : fido=00000000, Irp=82701008, Context=827cc288, IRQL=2
[8329 ms] <<< URB 9 coming back <<<
-- URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER:
PipeHandle = 8256385c [endpoint 0x00000082]
TransferFlags = 00000003 (USBD_TRANSFER_DIRECTION_IN, USBD_SHORT_TRANSFER_OK)
TransferBufferLength = 00000162
TransferBuffer = 826de3e8
TransferBufferMDL = 8255c128
00000000: 01 01 17 01 00 20 0d 00 00 00 02 00 00 00 68 00
00000010: 50 00 00 00 4c 01 f0 ff ff ff ff ff ff ff ff ff
00000020: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
00000030: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
00000040: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
00000050: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
00000060: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
00000070: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
00000080: ff ff ff ff ff 2b ff ff d7 3f f6 ff 5f 2f 0f f7
00000090: ff 5f 3f 8d ff ff f4 b5 f9 ff 4f 5f 9b ff ff a3
000000a0: 92 8a ff ff 75 68 7a ff ff 86 77 79 ff ff 75 79
000000b0: 69 ff ff 76 6a 69 ff ff 76 7a 68 ff ff 76 7a 68
000000c0: ff ff 76 7a 68 ff ff 66 7b 68 ff ff 66 7b 68 ff
000000d0: ff 66 7b 68 ff ff 76 7a 68 ff ff 66 7b 68 ff ff
000000e0: 66 7b 68 ff ff 66 7b 68 ff ff 76 7a 68 ff ff 76
000000f0: 7a 68 ff ff 76 7a 68 ff ff 76 7a 78 ff ff 75 6a
00000100: 79 ff ff 75 6a 79 ff ff 76 78 79 ff ff 76 78 8a
00000110: ff ff 94 94 9a ff ff f3 b6 f9 ff 4f 5f 8c ff ff
00000120: f4 c5 f8 ff 5f 3f 7e ff ff f7 f0 52 ff 9f 87 f9
00000130: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
00000140: ff ff ff ff ff ff ff ff ff ff ff ff ff ff bf f1
00000150: ff ff ff ff ff ff ff ff ff ff ff ff ff ff 11 f1

To be continued …

Leave a Reply

Your email address will not be published. Required fields are marked *