├── README.md ├── hidmouse.c ├── hidtest.c ├── keys.py ├── mouse.c ├── pair.sh └── setuphid.sh /README.md: -------------------------------------------------------------------------------- 1 | # pihidproxy 2 | Bridge Bluetooth keyboard and mouse to USB (hid proxy) 3 | 4 | ![Imgur](https://i.imgur.com/cpGkjXw.png) 5 | 6 | If you have a bluetooth keyboard, you can't access BIOS or OS without a BT stack. 7 | This project acts as a bridge so the PC only sees a USB keyboard and so works without drivers. 8 | It works by copying keypresses from the bluetooth keyboard to the piZero's USB. 9 | 10 | Requirements: 11 | 12 | Raspberry Pi Zero 13 | Bluetooth keyboard 14 | 15 | Initial setup: 16 | 17 | echo "dtoverlay=dwc2" | sudo tee -a /boot/config.txt 18 | echo "dwc2" | sudo tee -a /etc/modules 19 | echo "libcomposite" | sudo tee -a /etc/modules 20 | 21 | put the following in /etc/rc.local 22 | 23 | pair.sh 24 | setuphid.sh 25 | keys.py 26 | 27 | pair.sh - bash script to pair & connect bluetooth on boot. 28 | 29 | setuphid.sh - installs the USB keybaord driver 30 | 31 | keys.py - reads keyboard (e.g. bluetooth) and translates keycodes, then sends it over USB. 32 | 33 | 34 | -------------------------------------------------------------------------------- /hidmouse.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #define BUF_LEN 512 12 | 13 | struct options { 14 | const char *opt; 15 | unsigned char val; 16 | }; 17 | 18 | static struct options mmod[] = { 19 | {.opt = "--b1", .val = 0x01}, 20 | {.opt = "--b2", .val = 0x02}, 21 | {.opt = "--b3", .val = 0x04}, 22 | {.opt = NULL} 23 | }; 24 | 25 | int mouse_fill_report(char report[8], char buf[BUF_LEN], int *hold) 26 | { 27 | char *tok = strtok(buf, " "); 28 | int mvt = 0; 29 | int i = 0; 30 | for (; tok != NULL; tok = strtok(NULL, " ")) { 31 | 32 | if (strcmp(tok, "--quit") == 0) 33 | return -1; 34 | 35 | if (strcmp(tok, "--hold") == 0) { 36 | *hold = 1; 37 | continue; 38 | } 39 | 40 | for (i = 0; mmod[i].opt != NULL; i++) 41 | if (strcmp(tok, mmod[i].opt) == 0) { 42 | report[0] = report[0] | mmod[i].val; 43 | break; 44 | } 45 | if (mmod[i].opt != NULL) 46 | continue; 47 | 48 | if (!(tok[0] == '-' && tok[1] == '-') && mvt < 2) { 49 | errno = 0; 50 | report[1 + mvt++] = (char)strtol(tok, NULL, 0); 51 | if (errno != 0) { 52 | fprintf(stderr, "Bad value:'%s'\n", tok); 53 | report[1 + mvt--] = 0; 54 | } 55 | continue; 56 | } 57 | fprintf(stderr, "unknown option: %s\n", tok); 58 | } 59 | return 3; 60 | } 61 | 62 | int main(int argc, const char *argv[]) 63 | { 64 | const char *filename = NULL; 65 | int fd = 0; 66 | char buf[BUF_LEN]; 67 | int cmd_len; 68 | char report[8]; 69 | int to_send = 8; 70 | int hold = 0; 71 | fd_set rfds; 72 | int retval, i; 73 | 74 | if (argc < 3) { 75 | fprintf(stderr, "Usage: %s devname x y\n", 76 | argv[0]); 77 | return 1; 78 | } 79 | 80 | filename = argv[1]; 81 | 82 | if ((fd = open(filename, O_RDWR, 0666)) == -1) { 83 | perror(filename); 84 | return 3; 85 | } 86 | 87 | memset(report, 0x0, sizeof(report)); 88 | 89 | cmd_len = sprintf(buf,"%s %s",argv[2],argv[3]); 90 | hold = 0; 91 | 92 | memset(report, 0x0, sizeof(report)); 93 | 94 | to_send = mouse_fill_report(report, buf, &hold); 95 | 96 | if (write(fd, report, to_send) != to_send) { 97 | perror(filename); 98 | return 5; 99 | } 100 | close(fd); 101 | return 0; 102 | } 103 | -------------------------------------------------------------------------------- /hidtest.c: -------------------------------------------------------------------------------- 1 | /* hid_gadget_test */ 2 | # from https://www.kernel.org/doc/Documentation/usb/gadget_hid.txt 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | #define BUF_LEN 512 15 | 16 | struct options { 17 | const char *opt; 18 | unsigned char val; 19 | }; 20 | 21 | static struct options kmod[] = { 22 | {.opt = "--left-ctrl", .val = 0x01}, 23 | {.opt = "--right-ctrl", .val = 0x10}, 24 | {.opt = "--left-shift", .val = 0x02}, 25 | {.opt = "--right-shift", .val = 0x20}, 26 | {.opt = "--left-alt", .val = 0x04}, 27 | {.opt = "--right-alt", .val = 0x40}, 28 | {.opt = "--left-meta", .val = 0x08}, 29 | {.opt = "--right-meta", .val = 0x80}, 30 | {.opt = NULL} 31 | }; 32 | 33 | static struct options kval[] = { 34 | {.opt = "--return", .val = 0x28}, 35 | {.opt = "--esc", .val = 0x29}, 36 | {.opt = "--bckspc", .val = 0x2a}, 37 | {.opt = "--tab", .val = 0x2b}, 38 | {.opt = "--spacebar", .val = 0x2c}, 39 | {.opt = "--caps-lock", .val = 0x39}, 40 | {.opt = "--f1", .val = 0x3a}, 41 | {.opt = "--f2", .val = 0x3b}, 42 | {.opt = "--f3", .val = 0x3c}, 43 | {.opt = "--f4", .val = 0x3d}, 44 | {.opt = "--f5", .val = 0x3e}, 45 | {.opt = "--f6", .val = 0x3f}, 46 | {.opt = "--f7", .val = 0x40}, 47 | {.opt = "--f8", .val = 0x41}, 48 | {.opt = "--f9", .val = 0x42}, 49 | {.opt = "--f10", .val = 0x43}, 50 | {.opt = "--f11", .val = 0x44}, 51 | {.opt = "--f12", .val = 0x45}, 52 | {.opt = "--insert", .val = 0x49}, 53 | {.opt = "--home", .val = 0x4a}, 54 | {.opt = "--pageup", .val = 0x4b}, 55 | {.opt = "--del", .val = 0x4c}, 56 | {.opt = "--end", .val = 0x4d}, 57 | {.opt = "--pagedown", .val = 0x4e}, 58 | {.opt = "--right", .val = 0x4f}, 59 | {.opt = "--left", .val = 0x50}, 60 | {.opt = "--down", .val = 0x51}, 61 | {.opt = "--kp-enter", .val = 0x58}, 62 | {.opt = "--up", .val = 0x52}, 63 | {.opt = "--num-lock", .val = 0x53}, 64 | {.opt = NULL} 65 | }; 66 | 67 | int keyboard_fill_report(char report[8], char buf[BUF_LEN], int *hold) 68 | { 69 | char *tok = strtok(buf, " "); 70 | int key = 0; 71 | int i = 0; 72 | 73 | for (; tok != NULL; tok = strtok(NULL, " ")) { 74 | 75 | if (strcmp(tok, "--quit") == 0) 76 | return -1; 77 | 78 | if (strcmp(tok, "--hold") == 0) { 79 | *hold = 1; 80 | continue; 81 | } 82 | 83 | if (key < 6) { 84 | for (i = 0; kval[i].opt != NULL; i++) 85 | if (strcmp(tok, kval[i].opt) == 0) { 86 | report[2 + key++] = kval[i].val; 87 | break; 88 | } 89 | if (kval[i].opt != NULL) 90 | continue; 91 | } 92 | 93 | if (key < 6) 94 | if (islower(tok[0])) { 95 | report[2 + key++] = (tok[0] - ('a' - 0x04)); 96 | continue; 97 | } 98 | 99 | for (i = 0; kmod[i].opt != NULL; i++) 100 | if (strcmp(tok, kmod[i].opt) == 0) { 101 | report[0] = report[0] | kmod[i].val; 102 | break; 103 | } 104 | if (kmod[i].opt != NULL) 105 | continue; 106 | 107 | if (key < 6) 108 | fprintf(stderr, "unknown option: %s\n", tok); 109 | } 110 | return 8; 111 | } 112 | 113 | static struct options mmod[] = { 114 | {.opt = "--b1", .val = 0x01}, 115 | {.opt = "--b2", .val = 0x02}, 116 | {.opt = "--b3", .val = 0x04}, 117 | {.opt = NULL} 118 | }; 119 | 120 | int mouse_fill_report(char report[8], char buf[BUF_LEN], int *hold) 121 | { 122 | char *tok = strtok(buf, " "); 123 | int mvt = 0; 124 | int i = 0; 125 | for (; tok != NULL; tok = strtok(NULL, " ")) { 126 | 127 | if (strcmp(tok, "--quit") == 0) 128 | return -1; 129 | 130 | if (strcmp(tok, "--hold") == 0) { 131 | *hold = 1; 132 | continue; 133 | } 134 | 135 | for (i = 0; mmod[i].opt != NULL; i++) 136 | if (strcmp(tok, mmod[i].opt) == 0) { 137 | report[0] = report[0] | mmod[i].val; 138 | break; 139 | } 140 | if (mmod[i].opt != NULL) 141 | continue; 142 | 143 | if (!(tok[0] == '-' && tok[1] == '-') && mvt < 2) { 144 | errno = 0; 145 | report[1 + mvt++] = (char)strtol(tok, NULL, 0); 146 | if (errno != 0) { 147 | fprintf(stderr, "Bad value:'%s'\n", tok); 148 | report[1 + mvt--] = 0; 149 | } 150 | continue; 151 | } 152 | 153 | fprintf(stderr, "unknown option: %s\n", tok); 154 | } 155 | return 3; 156 | } 157 | 158 | static struct options jmod[] = { 159 | {.opt = "--b1", .val = 0x10}, 160 | {.opt = "--b2", .val = 0x20}, 161 | {.opt = "--b3", .val = 0x40}, 162 | {.opt = "--b4", .val = 0x80}, 163 | {.opt = "--hat1", .val = 0x00}, 164 | {.opt = "--hat2", .val = 0x01}, 165 | {.opt = "--hat3", .val = 0x02}, 166 | {.opt = "--hat4", .val = 0x03}, 167 | {.opt = "--hatneutral", .val = 0x04}, 168 | {.opt = NULL} 169 | }; 170 | 171 | int joystick_fill_report(char report[8], char buf[BUF_LEN], int *hold) 172 | { 173 | char *tok = strtok(buf, " "); 174 | int mvt = 0; 175 | int i = 0; 176 | 177 | *hold = 1; 178 | 179 | /* set default hat position: neutral */ 180 | report[3] = 0x04; 181 | 182 | for (; tok != NULL; tok = strtok(NULL, " ")) { 183 | 184 | if (strcmp(tok, "--quit") == 0) 185 | return -1; 186 | 187 | for (i = 0; jmod[i].opt != NULL; i++) 188 | if (strcmp(tok, jmod[i].opt) == 0) { 189 | report[3] = (report[3] & 0xF0) | jmod[i].val; 190 | break; 191 | } 192 | if (jmod[i].opt != NULL) 193 | continue; 194 | 195 | if (!(tok[0] == '-' && tok[1] == '-') && mvt < 3) { 196 | errno = 0; 197 | report[mvt++] = (char)strtol(tok, NULL, 0); 198 | if (errno != 0) { 199 | fprintf(stderr, "Bad value:'%s'\n", tok); 200 | report[mvt--] = 0; 201 | } 202 | continue; 203 | } 204 | 205 | fprintf(stderr, "unknown option: %s\n", tok); 206 | } 207 | return 4; 208 | } 209 | 210 | void print_options(char c) 211 | { 212 | int i = 0; 213 | 214 | if (c == 'k') { 215 | printf(" keyboard options:\n" 216 | " --hold\n"); 217 | for (i = 0; kmod[i].opt != NULL; i++) 218 | printf("\t\t%s\n", kmod[i].opt); 219 | printf("\n keyboard values:\n" 220 | " [a-z] or\n"); 221 | for (i = 0; kval[i].opt != NULL; i++) 222 | printf("\t\t%-8s%s", kval[i].opt, i % 2 ? "\n" : ""); 223 | printf("\n"); 224 | } else if (c == 'm') { 225 | printf(" mouse options:\n" 226 | " --hold\n"); 227 | for (i = 0; mmod[i].opt != NULL; i++) 228 | printf("\t\t%s\n", mmod[i].opt); 229 | printf("\n mouse values:\n" 230 | " Two signed numbers\n" 231 | "--quit to close\n"); 232 | } else { 233 | printf(" joystick options:\n"); 234 | for (i = 0; jmod[i].opt != NULL; i++) 235 | printf("\t\t%s\n", jmod[i].opt); 236 | printf("\n joystick values:\n" 237 | " three signed numbers\n" 238 | "--quit to close\n"); 239 | } 240 | } 241 | 242 | int main(int argc, const char *argv[]) 243 | { 244 | const char *filename = NULL; 245 | int fd = 0; 246 | char buf[BUF_LEN]; 247 | int cmd_len; 248 | char report[8]; 249 | int to_send = 8; 250 | int hold = 0; 251 | fd_set rfds; 252 | int retval, i; 253 | 254 | if (argc < 3) { 255 | fprintf(stderr, "Usage: %s devname mouse|keyboard|joystick\n", 256 | argv[0]); 257 | return 1; 258 | } 259 | 260 | if (argv[2][0] != 'k' && argv[2][0] != 'm' && argv[2][0] != 'j') 261 | return 2; 262 | 263 | filename = argv[1]; 264 | 265 | if ((fd = open(filename, O_RDWR, 0666)) == -1) { 266 | perror(filename); 267 | return 3; 268 | } 269 | 270 | print_options(argv[2][0]); 271 | 272 | while (42) { 273 | 274 | FD_ZERO(&rfds); 275 | FD_SET(STDIN_FILENO, &rfds); 276 | FD_SET(fd, &rfds); 277 | 278 | retval = select(fd + 1, &rfds, NULL, NULL, NULL); 279 | if (retval == -1 && errno == EINTR) 280 | continue; 281 | if (retval < 0) { 282 | perror("select()"); 283 | return 4; 284 | } 285 | 286 | if (FD_ISSET(fd, &rfds)) { 287 | cmd_len = read(fd, buf, BUF_LEN - 1); 288 | printf("recv report:"); 289 | for (i = 0; i < cmd_len; i++) 290 | printf(" %02x", buf[i]); 291 | printf("\n"); 292 | } 293 | 294 | if (FD_ISSET(STDIN_FILENO, &rfds)) { 295 | memset(report, 0x0, sizeof(report)); 296 | cmd_len = read(STDIN_FILENO, buf, BUF_LEN - 1); 297 | 298 | if (cmd_len == 0) 299 | break; 300 | 301 | buf[cmd_len - 1] = '\0'; 302 | hold = 0; 303 | 304 | memset(report, 0x0, sizeof(report)); 305 | if (argv[2][0] == 'k') 306 | to_send = keyboard_fill_report(report, buf, &hold); 307 | else if (argv[2][0] == 'm') 308 | to_send = mouse_fill_report(report, buf, &hold); 309 | else 310 | to_send = joystick_fill_report(report, buf, &hold); 311 | 312 | if (to_send == -1) 313 | break; 314 | 315 | if (write(fd, report, to_send) != to_send) { 316 | perror(filename); 317 | return 5; 318 | } 319 | if (!hold) { 320 | memset(report, 0x0, sizeof(report)); 321 | if (write(fd, report, to_send) != to_send) { 322 | perror(filename); 323 | return 6; 324 | } 325 | } 326 | } 327 | } 328 | 329 | close(fd); 330 | return 0; 331 | } 332 | -------------------------------------------------------------------------------- /keys.py: -------------------------------------------------------------------------------- 1 | import evdev, time 2 | from evdev import InputDevice, categorize, ecodes 3 | 4 | dev = None 5 | while dev is None: 6 | try: 7 | dev = InputDevice('/dev/input/event0') 8 | except: 9 | print "No keyboard - waiting..." 10 | time.sleep (10) 11 | 12 | def write_report(report): 13 | with open('/dev/hidg0', 'rb+') as fd: 14 | fd.write(report.encode()) 15 | 16 | scancodes = { 17 | # Scancode: ASCIICode 18 | 0: None, 1: u'ESC', 2: u'1', 3: u'2', 4: u'3', 5: u'4', 6: u'5', 7: u'6', 8: u'7', 9: u'8', 19 | 10: u'9', 11: u'0', 12: u'-', 13: u'=', 14: u'BKSP', 15: u'TAB', 16: u'q', 17: u'w', 18: u'e', 19: u'r', 20 | 20: u't', 21: u'y', 22: u'u', 23: u'i', 24: u'o', 25: u'p', 26: u'[', 27: u']', 28: u'CRLF', 29: u'LCTRL', 21 | 30: u'a', 31: u's', 32: u'd', 33: u'f', 34: u'g', 35: u'h', 36: u'j', 37: u'k', 38: u'l', 39: u';', 22 | 40: u'"', 41: u'`', 42: u'LSHFT', 43: u'\\', 44: u'z', 45: u'x', 46: u'c', 47: u'v', 48: u'b', 49: u'n', 23 | 50: u'm', 51: u',', 52: u'.', 53: u'/', 54: u'RSHFT', 56: u'LALT', 57: u' ', 100: u'RALT' 24 | } 25 | # hidcodes from http://www.usb.org/developers/hidpage/Hut1_12v2.pdf p53 26 | 27 | #grab provides exclusive access to the device 28 | dev.grab() 29 | 30 | deadkey=False 31 | caps= False 32 | hidkey =0 33 | 34 | #loop 35 | for event in dev.read_loop(): 36 | if event.type == ecodes.EV_KEY: 37 | data = categorize(event) 38 | if data.scancode == 42: 39 | if data.keystate == 1: 40 | caps = True 41 | if data.keystate == 0: 42 | caps = False 43 | continue # don't send 44 | if data.keystate == 1: # Down events only 45 | key_lookup = u'{}'.format(scancodes.get(data.scancode)) 46 | 47 | # print key_lookup, data.scancode 48 | 49 | if len(key_lookup) == 1 : 50 | hidkey = ord(key_lookup) - 93 # a-z 51 | if hidkey < 0: # 1-9 52 | hidkey = 0 53 | 54 | 55 | if data.scancode == 2: hidkey = 30 # 1 56 | if data.scancode == 3: hidkey = 31 # 2 57 | if data.scancode == 4: hidkey = 32 # 3 58 | if data.scancode == 5: hidkey = 33 # 4 59 | if data.scancode == 6: hidkey = 34 # 5 60 | if data.scancode == 7: hidkey = 35 # 6 61 | if data.scancode == 8: hidkey = 36 # 7 62 | if data.scancode == 9: hidkey = 37 # 8 63 | if data.scancode == 10: hidkey = 38 # 9 64 | if data.scancode == 11: hidkey = 39 # 0 65 | 66 | 67 | if data.scancode == 57: hidkey = 44 # space 68 | if data.scancode == 14: hidkey = 42 # bkspc 69 | if data.scancode == 28: hidkey = 40 # enter 70 | if data.scancode == 1: hidkey = 41 # ESC 71 | 72 | if data.scancode == 106: hidkey = 79 # RIGHT 73 | if data.scancode == 105: hidkey = 80 # LEFT 74 | if data.scancode == 108: hidkey = 81 # DOWN 75 | if data.scancode == 103: hidkey = 82 # UP 76 | 77 | if data.scancode == 59: hidkey = 58 # F1 78 | if data.scancode == 60: hidkey = 59 # F2 79 | if data.scancode == 61: hidkey = 60 # F3 80 | if data.scancode == 62: hidkey = 61 # F4 81 | if data.scancode == 63: hidkey = 62 # F5 82 | if data.scancode == 64: hidkey = 63 # F6 83 | if data.scancode == 65: hidkey = 64 # F7 84 | if data.scancode == 66: hidkey = 65 # F8 85 | if data.scancode == 67: hidkey = 66 # F9 86 | if data.scancode == 68: hidkey = 67 # F10 87 | if data.scancode == 69: hidkey = 68 # F11 88 | if data.scancode == 70: hidkey = 69 # F12 89 | 90 | if data.scancode == 12: hidkey = 45 # - 91 | if data.scancode == 13: hidkey = 46 # = 92 | if data.scancode == 15: hidkey = 43 # TAB 93 | 94 | if data.scancode == 26: hidkey = 47 # { 95 | if data.scancode == 27: hidkey = 48 # ] 96 | 97 | if data.scancode == 39: hidkey = 51 # : 98 | if data.scancode == 40: hidkey = 52 # " 99 | 100 | if data.scancode == 51: hidkey = 54 # < 101 | if data.scancode == 52: hidkey = 55 # > 102 | if data.scancode == 53: hidkey = 56 # ? 103 | 104 | if data.scancode == 41: hidkey = 50 # # 105 | if data.scancode == 43: hidkey = 49 # \ 106 | 107 | # print key_lookup, data.scancode, hidkey 108 | 109 | if caps: 110 | write_report(chr(32)+NULL_CHAR + chr (hidkey) + NULL_CHAR*5) 111 | else: 112 | write_report(NULL_CHAR*2 + chr (hidkey) + NULL_CHAR*5) 113 | 114 | write_report(NULL_CHAR*8) 115 | -------------------------------------------------------------------------------- /mouse.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | int main(int argc, char** argv) 6 | { 7 | int fd, bytes; 8 | unsigned char data[3]; 9 | 10 | const char *pDevice = "/dev/input/mice"; 11 | //const char *pDevice = "/dev/input/mouse0"; 12 | 13 | // Open Mouse 14 | fd = open(pDevice, O_RDWR); 15 | if(fd == -1) 16 | { 17 | printf("ERROR Opening %s\n", pDevice); 18 | return -1; 19 | } 20 | 21 | int left, middle, right; 22 | signed char x, y; 23 | while(1) 24 | { 25 | // Read Mouse 26 | bytes = read(fd, data, sizeof(data)); 27 | 28 | if(bytes > 0) 29 | { 30 | left = data[0] & 0x1; 31 | right = data[0] & 0x2; 32 | middle = data[0] & 0x4; 33 | 34 | x = data[1]; 35 | y = data[2]; 36 | printf("x=%d, y=%d, left=%d, middle=%d, right=%d\n", x, y, left, middle, right); 37 | } 38 | } 39 | return 0; 40 | } 41 | -------------------------------------------------------------------------------- /pair.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | devicename="NexDock" 3 | 4 | echo "Finding BT device *$devicename* ..." 5 | scan=$(sudo hcitool scan) 6 | found=$(grep $devicename <<< $scan) 7 | if [ $? -eq 0 ] 8 | then 9 | mac=$(cut -f 2 <<< $found) 10 | echo $mac 11 | echo " 12 | agent on 13 | scan on 14 | pair $mac 15 | connect $mac" | sudo bluetoothctl 16 | 17 | 18 | else 19 | echo not found 20 | fi 21 | -------------------------------------------------------------------------------- /setuphid.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | cd /sys/kernel/config/usb_gadget/ 3 | mkdir -p piproxy 4 | cd piproxy 5 | echo 0x1d6b > idVendor # Linux Foundation 6 | echo 0x0104 > idProduct # Multifunction Composite Gadget 7 | echo 0x0100 > bcdDevice # v1.0.0 8 | echo 0x0200 > bcdUSB # USB2 9 | mkdir -p strings/0x409 10 | echo "fedcba9876543210" > strings/0x409/serialnumber 11 | echo "Raspberry Pi" > strings/0x409/manufacturer 12 | echo "pizero keyboard Device" > strings/0x409/product 13 | mkdir -p configs/c.1/strings/0x409 14 | echo "Config 1: ECM network" > configs/c.1/strings/0x409/configuration 15 | echo 250 > configs/c.1/MaxPower 16 | 17 | # Add functions here 18 | 19 | #keyboard 20 | mkdir -p functions/hid.usb0 21 | echo 1 > functions/hid.usb0/protocol 22 | echo 1 > functions/hid.usb0/subclass 23 | echo 8 > functions/hid.usb0/report_length 24 | echo -ne \\x05\\x01\\x09\\x06\\xa1\\x01\\x05\\x07\\x19\\xe0\\x29\\xe7\\x15\\x00\\x25\\x01\\x75\\x01\\x95\\x08\\x81\\x02\\x95\\x01\\x75\\x08\\x81\\x03\\x95\\x05\\x75\\x01\\x05\\x08\\x19\\x01\\x29\\x05\\x91\\x02\\x95\\x01\\x75\\x03\\x91\\x03\\x95\\x06\\x75\\x08\\x15\\x00\\x25\\x65\\x05\\x07\\x19\\x00\\x29\\x65\\x81\\x00\\xc0 > functions/hid.usb0/report_desc 25 | ln -s functions/hid.usb0 configs/c.1/ 26 | 27 | # mouse 28 | mkdir -p functions/hid.usb1 29 | echo 2 > functions/hid.usb1/protocol 30 | echo 1 > functions/hid.usb1/subclass 31 | echo 4 > functions/hid.usb1/report_length 32 | echo -ne \\x05\\x01\\x09\\x02\\xa1\\x01\\x09\\x01\\xa1\\x00\\x05\\x09\\x19\\x01\\x29\\x05\\x15\\x00\\x25\\x01\\x95\\x05\\x75\\x01\\x81\\x02\\x95\\x01\\x75\\x03\\x81\\x01\\x05\\x01\\x09\\x30\\x09\\x31\\x09\\x38\\x15\\x81\\x25\\x7f\\x75\\x08\\x95\\x03\\x81\\x06\\xc0\\xc0 > functions/hid.usb1/report_desc 33 | ln -s functions/hid.usb1 configs/c.1/ 34 | # End functions 35 | 36 | ls /sys/class/udc > UDC 37 | 38 | --------------------------------------------------------------------------------