[vc_row][vc_column width=”1/1″][vc_column_text]In modem life, our hands are locked by computers. Could we make computers smarter by designing a better human-computer interface? In this tutorial, we present a solution with pcDuino. Gathering gesture signals by various Arduino compatible sensors, pcDuino can achieve all functions of current keyboards and mouse.
[/vc_column_text][vc_tour][vc_tab title=”Modify Kernel” tab_id=”1387431558-1-23″][vc_column_text]We need to modify the kernel by adding some structures and few lines of code in to file: linux-sunxi/drivers/usb/gadget/hid.c.
The structures and lines of code is shown below (it can also be downloaded from here):
static LIST_HEAD(hidg_func_list);
/* hid descriptor for a keyboard */
static struct hidg_func_descriptor pcduino_keyboard_date = {
.subclass = 0, /* No subclass */
.protocol = 1, /* Keyboard */
.report_length = 8,
.report_desc_length = 63,
.report_desc = {
0×05, 0×01, /* USAGE_PAGE (Generic Desktop) */
0×09, 0×06, /* USAGE (Keyboard) */
0xa1, 0×01, /* COLLECTION (Application) */
0×05, 0×07, /* USAGE_PAGE (Keyboard) */
0×19, 0xe0, /* USAGE_MINIMUM (Keyboard LeftControl) */
0×29, 0xe7, /* USAGE_MAXIMUM (Keyboard Right GUI) */
0×15, 0×00, /* LOGICAL_MINIMUM (0) */
0×25, 0×01, /* LOGICAL_MAXIMUM (1) */
0×75, 0×01, /* REPORT_SIZE (1) */
0×95, 0×08, /* REPORT_COUNT (8) */
0×81, 0×02, /* INPUT (Data,Var,Abs) */
0×95, 0×01, /* REPORT_COUNT (1) */
0×75, 0×08, /* REPORT_SIZE (8) */
0×81, 0×03, /* INPUT (Cnst,Var,Abs) */
0×95, 0×05, /* REPORT_COUNT (5) */
0×75, 0×01, /* REPORT_SIZE (1) */
0×05, 0×08, /* USAGE_PAGE (LEDs) */
0×19, 0×01, /* USAGE_MINIMUM (Num Lock) */
0×29, 0×05, /* USAGE_MAXIMUM (Kana) */
0×91, 0×02, /* OUTPUT (Data,Var,Abs) */
0×95, 0×01, /* REPORT_COUNT (1) */
0×75, 0×03, /* REPORT_SIZE (3) */
0×91, 0×03, /* OUTPUT (Cnst,Var,Abs) */
0×95, 0×06, /* REPORT_COUNT (6) */
0×75, 0×08, /* REPORT_SIZE (8) */
0×15, 0×00, /* LOGICAL_MINIMUM (0) */
0×25, 0×65, /* LOGICAL_MAXIMUM (101) */
0×05, 0×07, /* USAGE_PAGE (Keyboard) */
0×19, 0×00, /* USAGE_MINIMUM (Reserved) */
0×29, 0×65, /* USAGE_MAXIMUM (Keyboard Application) */
0×81, 0×00, /* INPUT (Data,Ary,Abs) */
0xc0 /* END_COLLECTION */
}
};
static struct platform_device pcduino_hid_keyboard = {
.name = “hidg”,
.id = 0,
.num_resources = 0,
.resource = 0,
.dev.platform_data = pcduino_keyboard_date,
};
/* hid descriptor for a mouse */
static struct hidg_func_descriptor pcduino_mouse_data = {
.subclass = 0, //No SubClass
.protocol = 2, //Mouse
.report_length = 4,
.report_desc_length = 52,
.report_desc = {
0×05, 0×01, //Usage Page(Generic Desktop Controls)
0×09, 0×02, //Usage (Mouse)
0xa1, 0×01, //Collction (Application)
0×09, 0×01, //Usage (pointer)
0xa1, 0×00, //Collction (Physical)
0×05, 0×09, //Usage Page (Button)
0×19, 0×01, //Usage Minimum(1)
0×29, 0×05, //Usage Maximum(5)
0×15, 0×00, //Logical Minimum(1)
0×25, 0×01, //Logical Maximum(1)
0×95, 0×05, //Report Count(5)
0×75, 0×01, //Report Size(1)
0×81, 0×02, //Input(Data,Variable,Absolute,BitField)
0×95, 0×01, //Report Count(1)
0×75, 0×03, //Report Size(3)
0×81, 0×01, //Input(Constant,Array,Absolute,BitField)
0×05, 0×01, //Usage Page(Generic Desktop Controls)
0×09, 0×30, //Usage(x)
0×09, 0×31, //Usage(y)
0×09, 0×38, //Usage(Wheel)
0×15, 0×81, //Logical Minimum(-127)
0×25, 0x7F, //Logical Maximum(127)
0×75, 0×08, //Report Size(8)
0×95, 0×03, //Report Count(3)
0×81, 0×06, //Input(Data,Variable,Relative,BitField)
0xc0, //End Collection
0xc0 //End Collection
}
};
static struct platform_device pcduino_hid_mouse = {
.name = “hidg”,
.id = 1,
.num_resources = 0,
.resource = 0,
.dev.platform_data =pcduino_mouse_data,
};
static int __init hidg_init(void)
{
int status;
status = platform_device_register(pcduino_hid_keyboard);
if (status < 0) {
printk(“hid keyboard reg failed\n”);
platform_device_unregister(pcduino_hid_keyboard);
return status;
}
status = platform_device_register(pcduino_hid_mouse);
if (status <0) {
printk(“hid mouse reg failed\n”);
platform_device_unregister(pcduino_hid_mouse);
return status;
}
status = platform_driver_probe(hidg_plat_driver,
hidg_plat_driver_probe);
if (status < 0)
return status;
status = usb_composite_probe(hidg_driver, hid_bind);
if (status < 0)
platform_driver_unregister(hidg_plat_driver);
return status;
}
module_init(hidg_init);
static void __exit hidg_cleanup(void)
{
platform_driver_unregister(hidg_plat_driver);
platform_device_unregister(pcduino_hid_keyboard);
platform_device_unregister(pcduino_hid_mouse);
usb_composite_unregister(hidg_driver);
}
Structures need to be added. We also need to register the structures the two functions. Please be noted according to USB protocol, each device has a descriptor. The two structures are the descriptors of the HID mouse and keyboard. In the next step, we are going to configure the kernel. It can also be downloaded from here. config_kernel
Device Drivers —>
[*] USB support —>
<M> USB Gadget Support —>
<M> SoftWinner SUN4I USB Peripheral Controller
< > Dummy HCD (DEVELOPMENT)
USB Gadget Drivers
< > Gadget Zero (DEVELOPMENT)
< > Audio Gadget (EXPERIMENTAL)
<M> Ethernet Gadget (with CDC Ethernet support)
[*] RNDIS support
[ ] Ethernet Emulation Model (EEM) support
< > Network Control Model (NCM) support
< > Gadget Filesystem (EXPERIMENTAL)
< > Function Filesystem (EXPERIMENTAL)
< > File-backed Storage Gadget (DEPRECATED)
< > Mass Storage Gadget
<M> Serial Gadget (with CDC ACM and CDC OBEX support)
<M> MIDI Gadget (EXPERIMENTAL)
<M> Printer Gadget
< > CDC Composite Device (Ethernet and ACM)
< > CDC Composite Device (ACM and mass storage)
< > Multifunction Composite Gadget (EXPERIMENTAL)
<M> HID Gadget
< > EHCI Debug Device Gadget
< > USB Webcam Gadget
[/vc_column_text][/vc_tab][vc_tab title=”Load the new Kernel” tab_id=”1387431558-2-48″][vc_column_text]
For how to build kernel, please refer to other articles.
Here we briefly review the steps:
$sudo mount /dev/nanda /mnt
$tar xvf pcduino_a10_hwpack_20131129.tar.xz
$cp kernel/* /mnt -f
$cp rootfs/lib/modules/3.4.29+ /lib/modules/
Then we append the following content to /etc/modules:
vim /etc/modules #add the following content
sw_usb_udc
g_hid
[/vc_column_text][/vc_tab][vc_tab title=”Test the driver” tab_id=”1387432810305-2-0″][vc_column_text]We’re going to use the test program from linux-sunxi/Documentation/usb.
The code is shown below (it can also be downloaded from here):
static LIST_HEAD(hidg_func_list);
/* hid descriptor for a keyboard */
static struct hidg_func_descriptor pcduino_keyboard_date = {
.subclass = 0, /* No subclass */
.protocol = 1, /* Keyboard */
.report_length = 8,
.report_desc_length = 63,
.report_desc = {
0×05, 0×01, /* USAGE_PAGE (Generic Desktop) */
0×09, 0×06, /* USAGE (Keyboard) */
0xa1, 0×01, /* COLLECTION (Application) */
0×05, 0×07, /* USAGE_PAGE (Keyboard) */
0×19, 0xe0, /* USAGE_MINIMUM (Keyboard LeftControl) */
0×29, 0xe7, /* USAGE_MAXIMUM (Keyboard Right GUI) */
0×15, 0×00, /* LOGICAL_MINIMUM (0) */
0×25, 0×01, /* LOGICAL_MAXIMUM (1) */
0×75, 0×01, /* REPORT_SIZE (1) */
0×95, 0×08, /* REPORT_COUNT (8) */
0×81, 0×02, /* INPUT (Data,Var,Abs) */
0×95, 0×01, /* REPORT_COUNT (1) */
0×75, 0×08, /* REPORT_SIZE (8) */
0×81, 0×03, /* INPUT (Cnst,Var,Abs) */
0×95, 0×05, /* REPORT_COUNT (5) */
0×75, 0×01, /* REPORT_SIZE (1) */
0×05, 0×08, /* USAGE_PAGE (LEDs) */
0×19, 0×01, /* USAGE_MINIMUM (Num Lock) */
0×29, 0×05, /* USAGE_MAXIMUM (Kana) */
0×91, 0×02, /* OUTPUT (Data,Var,Abs) */
0×95, 0×01, /* REPORT_COUNT (1) */
0×75, 0×03, /* REPORT_SIZE (3) */
0×91, 0×03, /* OUTPUT (Cnst,Var,Abs) */
0×95, 0×06, /* REPORT_COUNT (6) */
0×75, 0×08, /* REPORT_SIZE (8) */
0×15, 0×00, /* LOGICAL_MINIMUM (0) */
0×25, 0×65, /* LOGICAL_MAXIMUM (101) */
0×05, 0×07, /* USAGE_PAGE (Keyboard) */
0×19, 0×00, /* USAGE_MINIMUM (Reserved) */
0×29, 0×65, /* USAGE_MAXIMUM (Keyboard Application) */
0×81, 0×00, /* INPUT (Data,Ary,Abs) */
0xc0 /* END_COLLECTION */
}
};
static struct platform_device pcduino_hid_keyboard = {
.name = “hidg”,
.id = 0,
.num_resources = 0,
.resource = 0,
.dev.platform_data = &amp;pcduino_keyboard_date,
};
/* hid descriptor for a mouse */
static struct hidg_func_descriptor pcduino_mouse_data = {
.subclass = 0, //No SubClass
.protocol = 2, //Mouse
.report_length = 4,
.report_desc_length = 52,
.report_desc = {
0×05, 0×01, //Usage Page(Generic Desktop Controls)
0×09, 0×02, //Usage (Mouse)
0xa1, 0×01, //Collction (Application)
0×09, 0×01, //Usage (pointer)
0xa1, 0×00, //Collction (Physical)
0×05, 0×09, //Usage Page (Button)
0×19, 0×01, //Usage Minimum(1)
0×29, 0×05, //Usage Maximum(5)
0×15, 0×00, //Logical Minimum(1)
0×25, 0×01, //Logical Maximum(1)
0×95, 0×05, //Report Count(5)
0×75, 0×01, //Report Size(1)
0×81, 0×02, //Input(Data,Variable,Absolute,BitField)
0×95, 0×01, //Report Count(1)
0×75, 0×03, //Report Size(3)
0×81, 0×01, //Input(Constant,Array,Absolute,BitField)
0×05, 0×01, //Usage Page(Generic Desktop Controls)
0×09, 0×30, //Usage(x)
0×09, 0×31, //Usage(y)
0×09, 0×38, //Usage(Wheel)
0×15, 0×81, //Logical Minimum(-127)
0×25, 0x7F, //Logical Maximum(127)
0×75, 0×08, //Report Size(8)
0×95, 0×03, //Report Count(3)
0×81, 0×06, //Input(Data,Variable,Relative,BitField)
0xc0, //End Collection
0xc0 //End Collection
}
};
static struct platform_device pcduino_hid_mouse = {
.name = “hidg”,
.id = 1,
.num_resources = 0,
.resource = 0,
.dev.platform_data = &amp;pcduino_mouse_data,
};
static int __init hidg_init(void)
{
int status;
status = platform_device_register(&amp;pcduino_hid_keyboard);
if (status &lt; 0) {
printk(“hid keyboard reg failed\n”);
platform_device_unregister(&amp;pcduino_hid_keyboard);
return status;
}
status = platform_device_register(&amp;pcduino_hid_mouse);
if (status &lt; 0) {
printk(“hid mouse reg failed\n”);
platform_device_unregister(&amp;pcduino_hid_mouse);
return status;
}
status = platform_driver_probe(&amp;hidg_plat_driver,
hidg_plat_driver_probe);
if (status &lt; 0)
return status;
status = usb_composite_probe(&amp;hidg_driver, hid_bind);
if (status &lt; 0)
platform_driver_unregister(&amp;hidg_plat_driver);
return status;
}
module_init(hidg_init);
static void __exit hidg_cleanup(void)
{
platform_driver_unregister(&amp;hidg_plat_driver);
platform_device_unregister(&amp;pcduino_hid_keyboard);
platform_device_unregister(&amp;pcduino_hid_mouse);
usb_composite_unregister(&amp;hidg_driver);
}
Compile:
$gcc gadget_hid.c
By connect pcDuino to a PC through USB OTG, and then run the following command on pcDuino:
root@ubuntu:/home/ubuntu# ./a.out /dev/hidg0 k #keyboard
keyboard options:
–hold
–left-ctrl
–right-ctrl
–left-shift
–right-shift
–left-alt
–right-alt
–left-meta
–right-meta
keyboard values:
[a-z] or
–return –esc
–bckspc –tab
–spacebar –caps-lock
–f1 –f2
–f3 –f4
–f5 –f6
–f7 –f8
–f9 –f10
–f11 –f12
–insert –home
–pageup –del
–end –pagedown
–right –left
–down –kp-enter
–up –num-lock
Please enter: a b c d e f
Now you can see something showing up on the screen of PC.
When run the following commands on pcDunio:
root@ubuntu:/home/ubuntu# ./a.out /dev/hidg1 m #keyboard
mouse options:
–hold
–b1
–b2
–b3
mouse values:
Two signed numbers
–quit to close
Here is a little explanation:
–b1 10 10
when you are running this, it acts like left button of mouse.
–b2 1
when you are running this, it acts like right button of mouse.
–b3 -10 100
when you are running this, it acts like moving mouse around.[/vc_column_text][/vc_tab][vc_tab title=”Make Joystick a mouse” tab_id=”1387433399903-3-3″][vc_column_text]The code is hosted at:
https://github.com/Pillar1989/arduino
Then run the program at output/test/usb.
Connect your joystick module to pin A4 and A5 on pcDuino, as there is a delay(500), it won’t work perfectly when moving it around.[/vc_column_text][/vc_tab][/vc_tour][/vc_column][/vc_row]
Leave a Reply
You must be logged in to post a comment.