Background
A few days ago, I was able to get one of the Densha de Go! Ryojōhen Controller (電車でGO! 旅情編コントローラ) similar to the picture shown below from an online auction on eBay. The model number is TCPP-20014. It was released by TAITO in 2002 and was designed for the Densha de Go! Ryojōhen game on Sony PlayStation 2 accoring to the controller documentation by @marcriera on GitHub .
Surprisingly, the controller does have a USB 1.1 connector. However, upon connecting to my computer, the operating systems (Windows / Ubuntu) can't read data from it as it claims to be a Human Interface Device while failed to provide the needed HID report descriptor.
If you are using Windows, some work already has been done to support this controller. You can try to use the controller convertor tool (電車でGo!コントローラー変換器) provided by @autotraintas to test your controller and play games with it. More details can be found here .
However, as a gamer on Linux using PCSX2 emulator, I would need to write a custom user space driver to connect my controller with the Densha de Go! game running on the emulator.
USB Descriptor
As an effort to familar myself with the controller, I first dumped its USB descriptor using the lsusb
tool.
Bus 003 Device 007: ID 0ae4:0007 Taito Corp. TAITO_DENSYA_CON_T03
Device Descriptor:
bLength 18
bDescriptorType 1
bcdUSB 1.10
bDeviceClass 255 Vendor Specific Class
bDeviceSubClass 255 Vendor Specific Subclass
bDeviceProtocol 0
bMaxPacketSize0 8
idVendor 0x0ae4 Taito Corp.
idProduct 0x0007
bcdDevice 1.00
iManufacturer 1 TAITO
iProduct 2 TAITO_DENSYA_CON_T03
iSerial 3 TCPP20014
bNumConfigurations 1
Configuration Descriptor:
bLength 9
bDescriptorType 2
wTotalLength 0x0019
bNumInterfaces 1
bConfigurationValue 1
iConfiguration 0
bmAttributes 0xa0
(Bus Powered)
Remote Wakeup
MaxPower 500mA
Interface Descriptor:
bLength 9
bDescriptorType 4
bInterfaceNumber 0
bAlternateSetting 0
bNumEndpoints 1
bInterfaceClass 3 Human Interface Device
bInterfaceSubClass 0
bInterfaceProtocol 0
iInterface 0
Endpoint Descriptor:
bLength 7
bDescriptorType 5
bEndpointAddress 0x81 EP 1 IN
bmAttributes 3
Transfer Type Interrupt
Synch Type None
Usage Type Data
wMaxPacketSize 0x0008 1x 8 bytes
bInterval 20
Device Status: 0x0002
(Bus Powered)
Remote Wakeup Enabled
C++ and libusb
Based on the USB descritor, we can see that the controller data has a maximum of 8 bytes and can be accessed through endpoint address 0x81
via interrupt transfer. With these data in mind, I wrote a C++ program to retrive these data using libusb
.
#include <array>
#include <cstdio>
#include <signal.h>
#include "libusb-1.0/libusb.h"
#define BUFFER_SIZE 8
bool quit = false;
void quit_handler(int s);
int main()
{
signal(SIGINT, quit_handler);
libusb_context *ctx = nullptr;
libusb_init(&ctx);
libusb_device_handle *deviceHandle = libusb_open_device_with_vid_pid(ctx, 0x0ae4, 0x0007);
libusb_set_configuration(deviceHandle, 1);
libusb_claim_interface(deviceHandle, 0);
while (!quit)
{
std::array<unsigned char, BUFFER_SIZE> buffer;
// Get controller data
libusb_interrupt_transfer(deviceHandle, 0x81, buffer.data(), BUFFER_SIZE, NULL, 100);
for (const unsigned char &data : buffer)
{
std::printf("%02X ", data);
}
std::printf("\n");
usleep(20 * 1000);
}
libusb_release_interface(deviceHandle, 0);
libusb_close(deviceHandle);
libusb_exit(ctx);
}
void quit_handler(int s)
{
quit = true;
}
Demo
We can now read the controller data in Linux after compiling and running the above program.
Byte Number | Data | Items | Meaning |
---|---|---|---|
1 | 0x24 | Brake | Released |
2 | 0x00 | Power | Neutral |
3 | 0xFF | Pedal | Released |
4 | 0x08 | DPad | Center |
5 | 0x00 | Buttons | Released |
6 - 8 | 0x000000 | N/A | N/A |
Future Steps
- Emulate this HID controller as a standard gamepad using the Linux kernel module called
uinput
.