-
-
Save yairgd/26da61da37c641e3c63f5a870f5c7c02 to your computer and use it in GitHub Desktop.
USB driver for Linux user space using kernel hid gadget sub system
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* ===================================================================================== | |
* | |
* 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 | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
new link to the post https://yairgadelov.me/linux-gadget-device./