Skip to content

Instantly share code, notes, and snippets.

@yairgd
Last active February 21, 2023 10:35
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save yairgd/26da61da37c641e3c63f5a870f5c7c02 to your computer and use it in GitHub Desktop.
Save yairgd/26da61da37c641e3c63f5a870f5c7c02 to your computer and use it in GitHub Desktop.
USB driver for Linux user space using kernel hid gadget sub system
/*
* =====================================================================================
*
* Filename: usb_driver.c
*
* Description:
*
* Version: 1.0
* Created: 12/31/2020 02:37:05 PM
* Revision: none
* Compiler: gcc
*
* Author: Yair Gadelov (yg), yair.gadelov@gmail.com
* Company: Israel
*
* =====================================================================================
*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <sys/stat.h>
#include <unistd.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include "usb_driver.h"
#define DEVICE_NAME "/dev/hidg0"
static char keyb_report_desc[] = {
0x05, 0x01, // Usage Page (Generic Desktop Ctrls)
0x09, 0x06, // Usage (Keyboard)
0xA1, 0x01, // Collection (Application)
0x05, 0x07, // Usage Page (Kbrd/Keypad)
0x19, 0xE0, // Usage Minimum (0xE0)
0x29, 0xE7, // Usage Maximum (0xE7)
0x15, 0x00, // Logical Minimum (0)
0x25, 0x01, // Logical Maximum (1)
0x75, 0x01, // Report Size (1)
0x95, 0x08, // Report Count (8)
0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
0x95, 0x01, // Report Count (1)
0x75, 0x08, // Report Size (8)
0x81, 0x03, // Input (Const,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
0x95, 0x05, // Report Count (5)
0x75, 0x01, // Report Size (1)
0x05, 0x08, // Usage Page (LEDs)
0x19, 0x01, // Usage Minimum (Num Lock)
0x29, 0x05, // Usage Maximum (Kana)
0x91, 0x02, // Output (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x95, 0x01, // Report Count (1)
0x75, 0x03, // Report Size (3)
0x91, 0x03, // Output (Const,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x95, 0x06, // Report Count (6)
0x75, 0x08, // Report Size (8)
0x15, 0x00, // Logical Minimum (0)
0x25, 0x65, // Logical Maximum (101)
0x05, 0x07, // Usage Page (Kbrd/Keypad)
0x19, 0x00, // Usage Minimum (0x00)
0x29, 0x65, // Usage Maximum (0x65)
0x81, 0x00, // Input (Data,Array,Abs,No Wrap,Linear,Preferred State,No Null Position)
0xC0, // End Collection
// 63 bytes
};
static int mkpath(char *p) {
char *path = strdup(p);
char *save_path = path;
char *sep1;
char *sep2=0;
do {
int idx = (sep2-path)<0 ? 0 : sep2-path;
sep1 = strchr(path + idx , '/');
sep2 = strchr(sep1+1, '/');
if (sep2) {
path[sep2-path]=0;
}
if(mkdir(path, 0777) && errno != EEXIST)
return -1;
if (sep2) {
path[sep2-path]='/';
}
} while (sep2);
free(save_path);
return 0;
}
static int mkfile (char *filename,char *value) {
int fd = open (filename,O_RDWR);
if (fd<0)
return -1;
int n = write (fd,value,strlen(value));
close(fd);
return n;
}
static int mkfile1 (char *filename,char *value,int len) {
int fd = open (filename,O_RDWR);
if (fd<0)
return -1;
int n = write (fd,value,len);
close(fd);
return n;
}
static int usbhid_setup() {
FILE *pipe;
char line[128];
int linenr;
pipe = popen("modprobe usb_f_mass_storage;modprobe configfs;modprobe libcomposite;", "r");
if (pipe == NULL) { /* check for errors */
// perror(argv[0]); /* report error message */
return -1; /* return with exit code indicating error */
}
/* Read script output from the pipe line by line */
linenr = 1;
while (fgets(line, 128, pipe) != NULL) {
printf("Script output line %d: %s", linenr, line);
+linenr;
}
pclose(pipe);
mkpath ("/sys/kernel/config/usb_gadget/g1");
mkfile ("/sys/kernel/config/usb_gadget/g1/bMaxPacketSize0","64");
mkfile ("/sys/kernel/config/usb_gadget/g1/bcdUSB","0x200");
mkfile ("/sys/kernel/config/usb_gadget/g1/idVendor","0x13bb");
mkfile ("/sys/kernel/config/usb_gadget/g1/idProduct","0x7801");
mkpath ("/sys/kernel/config/usb_gadget/g1/configs/c1.1/strings/0x409");
mkfile ("/sys/kernel/config/usb_gadget/g1/strings/c1.1/MaxPower","120");
mkfile ("/sys/kernel/config/usb_gadget/g1/configs/c1.1/strings/0x409/configuration","Test Device");
mkpath ("/sys/kernel/config/usb_gadget/g1/strings/0x409");
mkfile ("/sys/kernel/config/usb_gadget/g1/strings/0x409/manufacturer","Test Device INC ...");
mkfile ("/sys/kernel/config/usb_gadget/g1/strings/0x409/product","BISx");
mkfile ("/sys/kernel/config/usb_gadget/g1/strings/0x409/serialnumber","0");
// mass storage
mkpath ("/sys/kernel/config/usb_gadget/g1/functions/mass_storage.ms0/lun.0");
mkfile ("/sys/kernel/config/usb_gadget/g1/functions/mass_storage.ms0/lun.0/file","/home/root/fat.fs");
mkfile ("/sys/kernel/config/usb_gadget/g1/functions/mass_storage.ms0/lun.0/removable","1");
symlink("/sys/kernel/config/usb_gadget/g1/functions/mass_storage.ms0", "/sys/kernel/config/usb_gadget/g1/configs/c1.1/mass_storage.ms0");// functions/mass_storage.ms0->configs/c1.1
// hid
mkpath ("/sys/kernel/config/usb_gadget/g1/functions/hid.0");
mkfile ("/sys/kernel/config/usb_gadget/g1/functions/hid.0/protocol","1");
mkfile ("/sys/kernel/config/usb_gadget/g1/functions/hid.0/subclass","1");
mkfile ("/sys/kernel/config/usb_gadget/g1/functions/hid.0/report_length","8");
mkfile1 ("/sys/kernel/config/usb_gadget/g1/functions/hid.0/report_desc",keyb_report_desc,sizeof (keyb_report_desc));
symlink("/sys/kernel/config/usb_gadget/g1/functions/hid.0", "/sys/kernel/config/usb_gadget/g1/configs/c1.1/hid.0");// functions/hid.0->configs/c1.1
mkfile ("/sys/kernel/config/usb_gadget/g1/UDC","49000000.usb-otg");
}
int usbhid_diable() {
mkfile ("/sys/kernel/config/usb_gadget/g1/UDC","");
}
int usbhid_enable() {
mkfile ("/sys/kernel/config/usb_gadget/g1/UDC","49000000.usb-otg");
}
int usbhid_open() {
int fd;
usbhid_setup();
usleep(500000);
if ((fd = open(DEVICE_NAME, O_RDWR, 0666)) == -1) {
perror(DEVICE_NAME);
return -1;
}
return fd;
}
int usbhid_read(int fd,char *buffer,int length) {
int n = read(fd, buffer,length);
return n;
}
int usbhid_write(int fd,char *buffer,int length) {
int n = write(fd, buffer,length);
return n;
}
#define CONFIG_SETUP_USB_DRIVER
#ifdef CONFIG_SETUP_USB_DRIVER
int main(int argc, char *argv[] ) {
char report[8];
int fd = usbhid_open()
if (fd <0)
exit(1);
// send message from device (usually embbeded linux device) to host (it can be a PC for example)
for (int i=0;i<10;i++) {
report[0]=0x12;
report[1]=0x34;
report[2]=0x56;
report[3]=0x78;
report[4]=0x9a;
report[5]=0xbc;
report[6]=0xde;
report[7]=0xf0;
usbhid_write (fd, report, 8);
memset(report, 0x0, sizeof(report));write(fd, report, 8);
sleep(1);
}
}
#endif
@yairgd
Copy link
Author

yairgd commented Apr 3, 2021

A simple example of how to uses HID gadget subsystem in Embbeed Linux device. The device has to include a USB OTG HW to be a USB device. This example uses HID devices to send communication data between HOST and embedded Linux devices. See this post for further details.

@Testato
Copy link

Testato commented Jun 11, 2022

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment