Skip to content

Commit

Permalink
get an initial HID driver going
Browse files Browse the repository at this point in the history
  • Loading branch information
Schievel1 committed Dec 25, 2023
1 parent cd95ce6 commit 453657d
Show file tree
Hide file tree
Showing 16 changed files with 898 additions and 15 deletions.
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,4 @@
*.log
tmp/

build/
pico-firmware/build/
5 changes: 4 additions & 1 deletion .gitmodules
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
[submodule "pico-sdk"]
path = pico-sdk
path = pico-firmware/pico-sdk
url = https://github.com/raspberrypi/pico-sdk.git
[submodule "pico-firmware/pico-sdk"]
path = pico-firmware/pico-sdk
url = https://github.com/raspberrypi/pico-sdk.git
674 changes: 674 additions & 0 deletions kernel-module/LICENSE

Large diffs are not rendered by default.

18 changes: 18 additions & 0 deletions kernel-module/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
TARGET := hid_pcmeter
SRCDIR := src
KERNEL := /lib/modules/$(shell uname -r)/build

obj-m := $(TARGET).o
$(TARGET)-y += $(SRCDIR)/hid_pcmeter.o

HEADERS := $(PWD)/include
ccflags-y := -I$(HEADERS)
ccflags-y += -Wall

all: module

module:
make -C $(KERNEL) M=$(PWD) modules

clean:
make -C $(KERNEL) M=$(PWD) clean
2 changes: 2 additions & 0 deletions kernel-module/include/core.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
#include <linux/module.h>
#include <linux/kernel.h>
187 changes: 187 additions & 0 deletions kernel-module/src/hid_pcmeter.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,187 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Simple USB CPU load meter driver
*
* Copyright 2023 Pascal Jaeger
* Based on drivers/hid/hid-led.c
*/

#define DEBUG
#include "core.h"
#include <linux/hid.h>
#include <linux/hidraw.h>
#include <linux/mutex.h>
#include <linux/delay.h>

#define USB_VENDOR_ID_PC_METER_PICO 0x2e8a
#define USB_DEVICE_ID_PC_METER_PICO 0xc011

enum hidpcmeter_report_type {
RAW_REQUEST,
OUTPUT_REPORT
};

enum hidpcmeter_type {
PC_METER_PICO,
};

struct hidpcmeter_device;

struct hidpcmeter_config {
enum hidpcmeter_type type;
const char *name;
const char *short_name;
size_t report_size;
enum hidpcmeter_report_type report_type;
ssize_t (*write)(struct file *filp, const char __user *buf, size_t count,loff_t *f_pos);
};

struct hidpcmeter_device {
const struct hidpcmeter_config *config;
struct hid_device *hdev;
u8 *buf;
struct mutex lock;
};

#define MAX_REPORT_SIZE 64

static int hidpcmeter_send(struct hidpcmeter_device *ldev, __u8 *buf)
{
int ret;

mutex_lock(&ldev->lock);

/*
* buffer provided to hid_hw_raw_request must not be on the stack
* and must not be part of a data structure
*/
memcpy(ldev->buf, buf, ldev->config->report_size);

if (ldev->config->report_type == RAW_REQUEST) { // TODO do we even need RAW_REQUESTS?
ret = hid_hw_raw_request(ldev->hdev, buf[0], ldev->buf,
ldev->config->report_size,
HID_FEATURE_REPORT,
HID_REQ_SET_REPORT);
}
else if (ldev->config->report_type == OUTPUT_REPORT)
{
ret = hid_hw_output_report(ldev->hdev, ldev->buf,
ldev->config->report_size);
}
else
ret = -EINVAL;

mutex_unlock(&ldev->lock);

if (ret < 0)
return ret;

return ret == ldev->config->report_size ? 0 : -EMSGSIZE;
}

static ssize_t pcmeter_pico_write(struct file *filp, const char __user *buf, size_t count,loff_t *f_pos)
{
__u8 mybuf[MAX_REPORT_SIZE] = {};

// TODO for debug only. Later get actual mem and cpu data
mybuf[1] = 50;
mybuf[2] = 90;

return 0;
/* return hidpcmeter_send(rgb->ldev, buf); */
}

static const struct hidpcmeter_config hidpcmeter_configs[] = {
{
.type = PC_METER_PICO,
.name = "PC Meter Pico v1",
.short_name = "pcmeter-pico",
.report_size = 64,
.report_type = OUTPUT_REPORT,
.write = pcmeter_pico_write,
}
};

static int hidpcmeter_probe(struct hid_device *hdev, const struct hid_device_id *id)
{
struct hidpcmeter_device *ldev;
unsigned int minor;
int ret, i;

ldev = devm_kzalloc(&hdev->dev, sizeof(*ldev), GFP_KERNEL);
if (!ldev)
return -ENOMEM;

ldev->buf = devm_kmalloc(&hdev->dev, MAX_REPORT_SIZE, GFP_KERNEL);
if (!ldev->buf)
return -ENOMEM;

ret = hid_parse(hdev);
if (ret)
return ret;

ldev->hdev = hdev;
mutex_init(&ldev->lock);

for (i = 0; !ldev->config && i < ARRAY_SIZE(hidpcmeter_configs); i++) {
if (hidpcmeter_configs[i].type == id->driver_data) {
ldev->config = &hidpcmeter_configs[i];
}
}

if (!ldev->config)
return -EINVAL;

ret = hid_hw_start(hdev, HID_CONNECT_HIDRAW);
if (ret)
return ret;

ret = hid_hw_open(hdev);
if (ret) {
hid_err(hdev,
"%s:hid_hw_open\n",
__func__);
return ret;
}

hid_info(hdev, "%s initialized\n", ldev->config->name);

// TODO test
/* hid_device_io_start(hdev); */

__u8 mybuf[MAX_REPORT_SIZE] = {};
mybuf[1] = 'C';
mybuf[2] = 45;
mybuf[3] = 'M';
mybuf[4] = 90;
msleep(100);
hidpcmeter_send(ldev, mybuf);

return 0;
}

static void hidpcmeter_remove(struct hid_device *hdev)
{
printk("module: removed!!!");
hid_hw_stop(hdev);
}

static const struct hid_device_id hidpcmeter_table[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_PC_METER_PICO,
USB_DEVICE_ID_PC_METER_PICO), .driver_data = PC_METER_PICO },
{ }
};
MODULE_DEVICE_TABLE(hid, hidpcmeter_table);

static struct hid_driver hidpcmeter_driver = {
.name = "hid-pc-meter",
.probe = hidpcmeter_probe,
.id_table = hidpcmeter_table,
.remove = hidpcmeter_remove,
};

module_hid_driver(hidpcmeter_driver);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("Pascal Jaeger <[email protected]");
MODULE_DESCRIPTION("Simple USB CPU load meter driver");
File renamed without changes.
File renamed without changes.
File renamed without changes.
1 change: 1 addition & 0 deletions src/main.c → pico-firmware/src/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,7 @@ void tud_hid_set_report_cb(uint8_t itf, uint8_t report_id, hid_report_type_t rep
}
updateLastTimeReceived();
}
printf("HID got: %c%d%c%d\n", buffer);
// echo back anything we received from host
tud_hid_report(0, buffer, bufsize);
}
Expand Down
1 change: 1 addition & 0 deletions src/meters.c → pico-firmware/src/meters.c
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,7 @@ void meters_receiveSerialData(void)
receivedChars[ndx] = '\0'; // terminate the string
ndx = 0;
newData = true;
printf("ACM got: %s\n", receivedChars);
}

}
Expand Down
File renamed without changes.
File renamed without changes.
23 changes: 10 additions & 13 deletions src/usb_descriptors.c → pico-firmware/src/usb_descriptors.c
Original file line number Diff line number Diff line change
Expand Up @@ -164,19 +164,19 @@ static const tusb_desc_device_t usbd_desc_device = {
// | Virtual Serial Port |
// `--------------------------------------------------------------------------'

#define EPNUM_CDC_CMD (0x81)
#define EPNUM_CDC_DATA (0x82)
#define EPNUM_CDC_NOTIF ( 0x84 )
#define EPNUM_CDC_OUT ( 0x05 )
#define EPNUM_CDC_IN ( 0x85 )

#define USBD_CDC_CMD_SIZE (64)
#define USBD_CDC_NOTIF_SIZE (64)
#define USBD_CDC_DATA_SIZE (64)

// .--------------------------------------------------------------------------.
// | HID Device |
// `--------------------------------------------------------------------------'

#define EPNUM_HID (0x83)
#define EPNUM_HID (0x01)

#define USBD_HID_BUFSIZE (16)
#define USBD_HID_POLL_INTERVAL (10)

#define REPORT_ID_KEYBOARD (1)
Expand Down Expand Up @@ -216,16 +216,13 @@ static const uint8_t usbd_desc_cfg[USBD_DESC_LEN] = {
TUSB_DESC_CONFIG_ATT_REMOTE_WAKEUP,
USBD_MAX_POWER_MA),


TUD_HID_INOUT_DESCRIPTOR(ITF_NUM_HID, USBD_STR_HID_NAME, HID_ITF_PROTOCOL_NONE, sizeof(desc_hid_report), EPNUM_HID, 0x80 | EPNUM_HID, CFG_TUD_HID_EP_BUFSIZE, USBD_HID_POLL_INTERVAL),
TUD_CDC_DESCRIPTOR(ITF_NUM_CDC,
USBD_STR_CDC_NAME,
EPNUM_CDC_CMD, USBD_CDC_CMD_SIZE,
EPNUM_CDC_DATA & 0x7F,
EPNUM_CDC_DATA, USBD_CDC_DATA_SIZE),

/* TUD_HID_DESCRIPTOR(ITF_NUM_HID, */
/* USBD_STR_HID_NAME, HID_ITF_PROTOCOL_NONE, sizeof(desc_hid_report), */
/* EPNUM_HID, USBD_HID_BUFSIZE, USBD_HID_POLL_INTERVAL), */
TUD_HID_INOUT_DESCRIPTOR(ITF_NUM_HID, USBD_STR_HID_NAME, HID_ITF_PROTOCOL_NONE, sizeof(desc_hid_report), EPNUM_HID, 0x80 | EPNUM_HID, CFG_TUD_HID_EP_BUFSIZE, USBD_HID_POLL_INTERVAL)
EPNUM_CDC_NOTIF, USBD_CDC_NOTIF_SIZE,
EPNUM_CDC_OUT,
EPNUM_CDC_IN, USBD_CDC_DATA_SIZE)
};

// ****************************************************************************
Expand Down
File renamed without changes.

0 comments on commit 453657d

Please sign in to comment.