Skip to content

Instantly share code, notes, and snippets.

@Gadgetoid

Gadgetoid/Makefile Secret

Last active Nov 8, 2020
Embed
What would you like to do?
Pi 400 KB

Raspberry Pi 400 as a USB HID Keyboard

Hook your Pi 400 up to your PC somehow, using a USB Type-C cable into the power port. Anker make good ones- I used a 3m white one for my tests.

Setup

Add dtoverlay=dwc2 to /boot/config.txt

Reboot!

Run sudo modprobe libcomposite

RUn wget https://gist.github.com/Gadgetoid/5a8ceb714de8e630059d30612503653f/raw/35fde8da7fcd88e7ccd3913c729f2b14bbd4a0a7/pi400kb

Run sudo ./pi400kb

YOUR PI 400 IS NOW A FREAKING KEYBOARD FOR YOUR PC WHAAAAT!?

Your keyboard input will be detached from your Pi while it's forwarded to your host computer.

Press Ctrl + Raspberry to exit and restore your keyboard on the Pi.

#include "gadget-hid.h"
#include <errno.h>
#include <stdio.h>
#include <linux/usb/ch9.h>
#include <usbg/usbg.h>
#include <usbg/function/hid.h>
#include <usbg/function/midi.h>
static char report_desc[] = {
0x05, 0x01,
0x09, 0x06,
0xA1, 0x01,
0x05, 0x07,
0x19, 0xe0,
0x29, 0xe7,
0x15, 0x00,
0x25, 0x01,
0x75, 0x01,
0x95, 0x08,
0x81, 0x02,
0x95, 0x01,
0x75, 0x08,
0x81, 0x01,
0x95, 0x03,
0x75, 0x01,
0x05, 0x08,
0x19, 0x01,
0x29, 0x03,
0x91, 0x02,
0x95, 0x05,
0x75, 0x01,
0x91, 0x01,
0x95, 0x06,
0x75, 0x08,
0x15, 0x00,
0x26, 0xff,
0x00, 0x05,
0x07, 0x19,
0x00, 0x2a,
0xff, 0x00,
0x81, 0x00, // Input (Data, Array, Abs)
0xc0 // End collection
};
int initUSB() {
int ret = -EINVAL;
int usbg_ret;
struct usbg_gadget_attrs g_attrs = {
.bcdUSB = 0x0200,
.bDeviceClass = USB_CLASS_PER_INTERFACE,
.bDeviceSubClass = 0x00,
.bDeviceProtocol = 0x00,
.bMaxPacketSize0 = 64, /* Max allowed ep0 packet size */
.idVendor = VENDOR,
.idProduct = PRODUCT,
.bcdDevice = 0x0001, /* Verson of device */
};
struct usbg_gadget_strs g_strs = {
.serial = "0123456789", /* Serial number */
.manufacturer = "Pimoroni", /* Manufacturer */
.product = "Keybow" /* Product string */
};
struct usbg_config_strs c_strs = {
.configuration = "1xHID"
};
struct usbg_f_midi_attrs midi_attrs = {
.index = 1,
.id = "usb1",
.buflen = 128,
.qlen = 16,
.in_ports = 1,
.out_ports = 1
};
struct usbg_f_hid_attrs f_attrs = {
.protocol = 1,
.report_desc = {
.desc = report_desc,
.len = sizeof(report_desc),
},
.report_length = 16,
.subclass = 0,
};
usbg_ret = usbg_init("/sys/kernel/config", &s);
if (usbg_ret != USBG_SUCCESS) {
fprintf(stderr, "Error on usbg init\n");
fprintf(stderr, "Error: %s : %s\n", usbg_error_name(usbg_ret),
usbg_strerror(usbg_ret));
goto out1;
}
usbg_ret = usbg_create_gadget(s, "g1", &g_attrs, &g_strs, &g);
if (usbg_ret != USBG_SUCCESS) {
fprintf(stderr, "Error creating gadget\n");
fprintf(stderr, "Error: %s : %s\n", usbg_error_name(usbg_ret),
usbg_strerror(usbg_ret));
goto out2;
}
usbg_ret = usbg_create_function(g, USBG_F_HID, "usb0", &f_attrs, &f_hid);
if (usbg_ret != USBG_SUCCESS) {
fprintf(stderr, "Error creating function: USBG_F_HID\n");
fprintf(stderr, "Error: %s : %s\n", usbg_error_name(usbg_ret),
usbg_strerror(usbg_ret));
goto out2;
}
usbg_ret = usbg_create_config(g, 1, "config", NULL, &c_strs, &c);
if (usbg_ret != USBG_SUCCESS) {
fprintf(stderr, "Error creating config\n");
fprintf(stderr, "Error: %s : %s\n", usbg_error_name(usbg_ret),
usbg_strerror(usbg_ret));
goto out2;
}
usbg_ret = usbg_add_config_function(c, "keyboard", f_hid);
if (usbg_ret != USBG_SUCCESS) {
fprintf(stderr, "Error adding function: keyboard\n");
fprintf(stderr, "Error: %s : %s\n", usbg_error_name(usbg_ret),
usbg_strerror(usbg_ret));
goto out2;
}
usbg_ret = usbg_enable_gadget(g, DEFAULT_UDC);
if (usbg_ret != USBG_SUCCESS) {
fprintf(stderr, "Error enabling gadget\n");
fprintf(stderr, "Error: %s : %s\n", usbg_error_name(usbg_ret),
usbg_strerror(usbg_ret));
goto out2;
}
ret = 0;
out2:
usbg_cleanup(s);
s = NULL;
out1:
return ret;
}
int cleanupUSB(){
if(g){
usbg_disable_gadget(g);
usbg_rm_gadget(g, USBG_RM_RECURSE);
}
if(s){
usbg_cleanup(s);
}
return 0;
}
#include <linux/usb/ch9.h>
#include <usbg/usbg.h>
#include <usbg/function/hid.h>
#define VENDOR 0x04d9
#define PRODUCT 0x0007
#define HID_REPORT_SIZE 8
usbg_state *s;
usbg_gadget *g;
usbg_config *c;
usbg_function *f_hid;
int initUSB();
int cleanupUSB();
CFLAGS_ALL=-I../libusbgx/build/include -I../bcm2835-1.68/build/include -L../bcm2835-1.68/build/lib -I../lua-5.4.0/src -L../libusbgx/build/lib -L../libserialport/build/lib -L../lua-5.4.0/src -lpng -lz -lpthread -llua -lm -lbcm2835 -ldl
pi400: CFLAGS+=-static $(CFLAGS_ALL) -lusbgx -lconfig -DPI400_USB
pi400: pi400.c gadget-hid.c
$(CC) $^ $(CFLAGS) -o $@
pi400test: CFLAGS+=-static $(CFLAGS_ALL) -lusbgx -lconfig
pi400test: pi400.c gadget-hid.c
$(CC) $^ $(CFLAGS) -o $@
clean:
-rm pi400
-rm pi400test
#include "pi400.h"
#include "gadget-hid.h"
#include <sys/ioctl.h>
#include <linux/hidraw.h>
#include <linux/input.h>
#include <signal.h>
#include <errno.h>
#include <stdio.h>
#include <fcntl.h>
#include <stdio.h>
#include <lua.h>
#include <lualib.h>
#include <lauxlib.h>
#include <unistd.h>
#define KEYBOARD_DEV "/dev/input/by-id/usb-_Raspberry_Pi_Internal_Keyboard-event-kbd"
#define HID_REPORT_SIZE 8
#define GRAB 1
#define UNGRAB 0
int hid_output;
volatile int running = 0;
int key_index = 0;
void signal_handler(int dummy) {
running = 0;
}
int find_hidraw_device() {
int fd;
int ret;
struct hidraw_devinfo hidinfo;
char path[20];
for(int x = 0; x < 16; x++){
sprintf(path, "/dev/hidraw%d", x);
if ((fd = open(path, O_RDWR | O_NONBLOCK)) == -1) {
continue;
}
ret = ioctl(fd, HIDIOCGRAWINFO, &hidinfo);
if(hidinfo.vendor == VENDOR && hidinfo.product == PRODUCT) {
printf("Found keyboard at: %s\n", path);
return fd;
}
close(fd);
}
return -1;
}
int main() {
int ret;
int fd;
int uinput_fd;
unsigned char buf[HID_REPORT_SIZE];
fd = find_hidraw_device();
if(fd == -1) {
printf("Failed to open keyboard device\n");
return 1;
}
ret = initUSB();
uinput_fd = open(KEYBOARD_DEV, O_RDONLY);
ioctl(uinput_fd, EVIOCGRAB, UNGRAB);
usleep(500000);
ioctl(uinput_fd, EVIOCGRAB, GRAB);
do {
hid_output = open("/dev/hidg0", O_WRONLY | O_NDELAY);
} while (hid_output == -1 && errno == EINTR);
if (hid_output == -1){
printf("Error opening /dev/hidg0 for writing.\n");
return 1;
}
printf("Running...\n");
running = 1;
signal(SIGINT, signal_handler);
while (running){
int c = read(fd, buf, HID_REPORT_SIZE);
if(c != HID_REPORT_SIZE){
continue;
}
for(int x = 0; x < HID_REPORT_SIZE; x++)
{
printf("%x ", buf[x]);
}
printf("\n");
write(hid_output, buf, HID_REPORT_SIZE);
usleep(1000);
if(buf[0] == 0x09){
running = 0;
break;
}
}
for(int x = 0; x < HID_REPORT_SIZE; x++){
buf[x] = 0;
};
write(hid_output, buf, HID_REPORT_SIZE);
ioctl(uinput_fd, EVIOCGRAB, UNGRAB);
close(uinput_fd);
printf("Cleanup USB\n");
cleanupUSB();
return 0;
}
#include <bcm2835.h>
#include <pthread.h>
int initUSB();
int main();
void sendHIDReport();
This file has been truncated, but you can view the full file.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.