Skip to content

Commit

Permalink
platform/avr: implement lufa hid driver and hid hal
Browse files Browse the repository at this point in the history
Signed-off-by: Rafael Silva <[email protected]>
  • Loading branch information
perigoso committed Jun 9, 2022
1 parent 13e841a commit 6d3bfb0
Show file tree
Hide file tree
Showing 6 changed files with 209 additions and 138 deletions.
1 change: 1 addition & 0 deletions config/families/avr.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ source = [
'boot.c',
'usb.c',
'usb_descriptors.c',
'hal/hid.c',
]

[dependencies]
Expand Down
21 changes: 21 additions & 0 deletions src/platform/avr/hal/hid.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
/*
* SPDX-License-Identifier: MIT
* SPDX-FileCopyrightText: 2021 Rafael Silva <[email protected]>
*/

#include "platform/avr/hal/hid.h"
#include "platform/avr/usb.h"

int hid_hal_send(struct hid_hal_t interface, u8 *buffer, size_t buffer_size)
{
usb_write_descriptor(0, buffer, buffer_size);
}

struct hid_hal_t hid_hal_init(void)
{
struct hid_hal_t hal = {
.send = hid_hal_send,
.drv_data = NULL,
};
return hal;
}
11 changes: 11 additions & 0 deletions src/platform/avr/hal/hid.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
/*
* SPDX-License-Identifier: MIT
* SPDX-FileCopyrightText: 2021 Rafael Silva <[email protected]>
*/

#pragma once

#include "hal/hid.h"
#include "util/types.h"

struct hid_hal_t hid_hal_init(void);
292 changes: 154 additions & 138 deletions src/platform/avr/usb.c
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,73 @@

#include <USB.h>

/** Buffer to hold the previously generated HID report, for comparison purposes inside the HID class driver. */
static u8 openinput_hid_report_buff[sizeof(struct oi_report_t)];
static u8 mouse_hid_report_buff[sizeof(struct mouse_report)];
static u8 keyboard_hid_report_buff[sizeof(struct keyboard_report)];

static u8 new_oi_report;
static struct oi_report_t oi_report;
static u8 oi_report_size;

static u8 new_mouse_report;
static struct mouse_report mouse_report;
static u8 mouse_report_size;

static u8 new_keyboard_report;
static struct keyboard_report keyboard_report;
static u8 keyboard_report_size;

static struct protocol_config_t protocol_config;

void usb_attach_protocol_config(struct protocol_config_t config)
{
protocol_config = config;
}
/** LUFA HID Class driver interface configuration and state information. This structure is
* passed to all HID Class driver functions, so that multiple instances of the same class
* within a device can be differentiated from one another.
*/
USB_ClassInfo_HID_Device_t openinput_hid_interface = {
.Config =
{
.InterfaceNumber = 0,
.ReportINEndpoint =
{
.Address = 0x81,
.Size = 64,
.Banks = 1,
},
.PrevReportINBuffer = openinput_hid_report_buff,
.PrevReportINBufferSize = sizeof(openinput_hid_report_buff),
},
};

USB_ClassInfo_HID_Device_t mouse_hid_interface = {
.Config =
{
.InterfaceNumber = 1,
.ReportINEndpoint =
{
.Address = 0x83,
.Size = 64,
.Banks = 1,
},
.PrevReportINBuffer = mouse_hid_report_buff,
.PrevReportINBufferSize = sizeof(mouse_hid_report_buff),
},
};

USB_ClassInfo_HID_Device_t keyboard_hid_interface = {
.Config =
{
.InterfaceNumber = 2,
.ReportINEndpoint =
{
.Address = 0x84,
.Size = 64,
.Banks = 1,
},
.PrevReportINBuffer = keyboard_hid_report_buff,
.PrevReportINBufferSize = sizeof(keyboard_hid_report_buff),
},
};

void usb_init()
{
Expand All @@ -29,64 +90,30 @@ void usb_task()
{
USB_USBTask();

/* openinput IN */
Endpoint_SelectEndpoint(0x81);

/* Check if Endpoint Ready for Read/Write */
if (Endpoint_IsReadWriteAllowed()) {
/* Write Report Data */
// Endpoint_Write_Stream_LE(&report_data, sizeof(report_data), NULL);

/* Finalize the stream transfer to send the last packet */
// Endpoint_ClearIN();
}

/* openinput OUT */
Endpoint_SelectEndpoint(0x02);

/* Check if Endpoint Ready for Read/Write */
if (Endpoint_IsReadWriteAllowed()) {
/* Write Report Data */
// Keyboard_ProcessLEDReport(Endpoint_Read_8());

/* Handshake the OUT Endpoint - clear endpoint and ready for next report */
Endpoint_ClearOUT();
}

/* mouse IN */
Endpoint_SelectEndpoint(0x83);

/* Check if Endpoint Ready for Read/Write */
if (Endpoint_IsReadWriteAllowed()) {
/* Write Report Data */
// Endpoint_Write_Stream_LE(&report_data, sizeof(report_data), NULL);

/* Finalize the stream transfer to send the last packet */
// Endpoint_ClearIN();
}

/* keyboard IN */
Endpoint_SelectEndpoint(0x84);

/* Check if Endpoint Ready for Read/Write */
if (Endpoint_IsReadWriteAllowed()) {
/* Write Report Data */
// Endpoint_Write_Stream_LE(&report_data, sizeof(report_data), NULL);

/* Finalize the stream transfer to send the last packet */
// Endpoint_ClearIN();
}

/* keyboard OUT */
Endpoint_SelectEndpoint(0x05);
HID_Device_USBTask(&openinput_hid_interface);
HID_Device_USBTask(&mouse_hid_interface);
HID_Device_USBTask(&keyboard_hid_interface);
}

/* Check if Endpoint Ready for Read/Write */
if (Endpoint_IsReadWriteAllowed()) {
/* Write Report Data */
// Keyboard_ProcessLEDReport(Endpoint_Read_8());
void usb_attach_protocol_config(struct protocol_config_t config)
{
protocol_config = config;
}

/* Handshake the OUT Endpoint - clear endpoint and ready for next report */
Endpoint_ClearOUT();
void usb_write_descriptor(u8 interface, u8 *report_data, u16 report_size)
{
if (interface == openinput_hid_interface.Config.InterfaceNumber) {
memcpy(&oi_report, report_data, report_size);
oi_report_size = report_size;
new_oi_report = 1;
} else if (interface == mouse_hid_interface.Config.InterfaceNumber) {
memcpy(&mouse_report, report_data, report_size);
mouse_report_size = report_size;
new_mouse_report = 1;
} else if (interface == keyboard_hid_interface.Config.InterfaceNumber) {
memcpy(&keyboard_report, report_data, report_size);
keyboard_report_size = report_size;
new_keyboard_report = 1;
}
}

Expand All @@ -104,90 +131,79 @@ void EVENT_USB_Device_Disconnect(void)
{
}

struct oi_report_t oi_rep;
struct mouse_report mouse_rep;
struct keyboard_report keyb_rep;
/** Event handler for the library USB Configuration Changed event. */
void EVENT_USB_Device_ConfigurationChanged(void)
{
HID_Device_ConfigureEndpoints(&openinput_hid_interface);
HID_Device_ConfigureEndpoints(&mouse_hid_interface);
HID_Device_ConfigureEndpoints(&keyboard_hid_interface);
}

/** Event handler for the USB_ControlRequest event. This is used to catch and process control requests sent to
* the device from the USB host before passing along unhandled control requests to the library for processing
* internally.
/** HID class driver callback function for the creation of HID reports to the host.
*
* \param[in] HIDInterfaceInfo Pointer to the HID class interface configuration structure being referenced
* \param[in,out] ReportID Report ID requested by the host if non-zero, otherwise callback should set to the generated report ID
* \param[in] ReportType Type of the report to create, either HID_REPORT_ITEM_In or HID_REPORT_ITEM_Feature
* \param[out] ReportData Pointer to a buffer where the created report should be stored
* \param[out] ReportSize Number of bytes written in the report (or zero if no report is to be sent)
*
* \return Boolean \c true to force the sending of the report, \c false to let the library determine if it needs to be sent
*/
void EVENT_USB_Device_ControlRequest(void)
bool CALLBACK_HID_Device_CreateHIDReport(
USB_ClassInfo_HID_Device_t *const HIDInterfaceInfo,
uint8_t *const ReportID,
const uint8_t ReportType,
void *ReportData,
uint16_t *const ReportSize)
{
struct oi_report_t oi_report;
uint8_t *ReportData;
uint8_t ReportSize;

/* Handle HID Class specific requests */
switch (USB_ControlRequest.bRequest) {
case HID_REQ_GetReport:
if (USB_ControlRequest.bmRequestType == (REQDIR_DEVICETOHOST | REQTYPE_CLASS | REQREC_INTERFACE)) {
Endpoint_ClearSETUP();

// /* Determine if it is the mouse or the keyboard data that is being requested */
// if (USB_ControlRequest.wIndex == 0) { // openinput
// ReportData = (uint8_t *) &oi_rep;
// ReportSize = sizeof(struct oi_report_t);
// } else if (USB_ControlRequest.wIndex == 1) { // mouse
// ReportData = (uint8_t *) &mouse_rep;
// ReportSize = sizeof(struct mouse_report);
// } else if (USB_ControlRequest.wIndex == 2) { // keyboard
// ReportData = (uint8_t *) &keyb_rep;
// ReportSize = sizeof(struct keyboard_report);
// }

// /* Write the report data to the control endpoint */
// Endpoint_Write_Control_Stream_LE(ReportData, ReportSize);
Endpoint_ClearOUT();
}

break;
case HID_REQ_SetReport:
if (USB_ControlRequest.bmRequestType == (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE)) {
Endpoint_ClearSETUP();

/* Wait until the report has been sent by the host */
while (!(Endpoint_IsOUTReceived())) {
if (USB_DeviceState == DEVICE_STATE_Unattached)
return;
}

// if (USB_ControlRequest.wIndex == 0) {
// // for (size_t i = 0; i < USB_ControlRequest.wLength; i++)
// // {
// // ((uint8_t *)(&oi_report))[i] = Endpoint_Read_8();
// // }
// // protocol_dispatch(protocol_config, (uint8_t *)(&oi_report), USB_ControlRequest.wLength);

// } else if (USB_ControlRequest.wIndex == 2) {
// /* Read in the LED report from the host */
// uint8_t LEDStatus = Endpoint_Read_8();
// }

/* Read in the LED report from the host */
uint8_t LEDStatus = Endpoint_Read_8();

Endpoint_ClearOUT();
Endpoint_ClearStatusStage();
}

break;
/* Determine which interface must have its report generated */
if (HIDInterfaceInfo == &openinput_hid_interface) {
if (new_oi_report == 1) {
memcpy(ReportData, &oi_report, oi_report_size);
*ReportSize = oi_report_size;
new_oi_report = 0;
return true;
} else {
return false;
}
} else if (HIDInterfaceInfo == &mouse_hid_interface) {
if (new_mouse_report == 1) {
memcpy(ReportData, &mouse_report, mouse_report_size);
*ReportSize = mouse_report_size;
new_mouse_report = 0;
return true;
} else {
return false;
}
} else if (HIDInterfaceInfo == &keyboard_hid_interface) {
if (new_keyboard_report == 1) {
memcpy(ReportData, &keyboard_report, keyboard_report_size);
*ReportSize = keyboard_report_size;
new_keyboard_report = 0;
return true;
} else {
return false;
}
}
}

/** Event handler for the USB_ConfigurationChanged event. This is fired when the host sets the current configuration
* of the USB device after enumeration, and configures the keyboard and mouse device endpoints.
/** HID class driver callback function for the processing of HID reports from the host.
*
* \param[in] HIDInterfaceInfo Pointer to the HID class interface configuration structure being referenced
* \param[in] ReportID Report ID of the received report from the host
* \param[in] ReportType The type of report that the host has sent, either HID_REPORT_ITEM_Out or HID_REPORT_ITEM_Feature
* \param[in] ReportData Pointer to a buffer where the received report has been stored
* \param[in] ReportSize Size in bytes of the received HID report
*/
void EVENT_USB_Device_ConfigurationChanged(void)
void CALLBACK_HID_Device_ProcessHIDReport(
USB_ClassInfo_HID_Device_t *const HIDInterfaceInfo,
const uint8_t ReportID,
const uint8_t ReportType,
const void *ReportData,
const uint16_t ReportSize)
{
/* Setup Openinput Report Endpoints */
Endpoint_ConfigureEndpoint(0x81, EP_TYPE_INTERRUPT, 0x40, 1); // IN
Endpoint_ConfigureEndpoint(0x02, EP_TYPE_INTERRUPT, 0x40, 1); // OUT

/* Setup Mouse HID Report Endpoint */
Endpoint_ConfigureEndpoint(0x83, EP_TYPE_INTERRUPT, 0x40, 1); // IN

/* Setup Keyboard HID Report Endpoints */
Endpoint_ConfigureEndpoint(0x84, EP_TYPE_INTERRUPT, 0x40, 1); // IN
Endpoint_ConfigureEndpoint(0x05, EP_TYPE_INTERRUPT, 0x40, 1); // OUT
if (HIDInterfaceInfo == &openinput_hid_interface) {
} else if (HIDInterfaceInfo == &keyboard_hid_interface) {
protocol_dispatch(protocol_config, (u8 *) ReportData, ReportSize);
}
}
1 change: 1 addition & 0 deletions src/platform/avr/usb.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,4 @@
void usb_init();
void usb_task();
void usb_attach_protocol_config(struct protocol_config_t config);
void usb_write_descriptor(u8 interface, u8 *report_data, u16 report_size);
Loading

0 comments on commit 6d3bfb0

Please sign in to comment.