Skip to content

Commit e5aaac5

Browse files
committed
platform/avr: implement lufa hid driver and hid hal
Signed-off-by: Rafael Silva <perigoso@riseup.net>
1 parent 4966b27 commit e5aaac5

File tree

6 files changed

+209
-138
lines changed

6 files changed

+209
-138
lines changed

config/families/avr.toml

+1
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ source = [
1616
'boot.c',
1717
'usb.c',
1818
'usb_descriptors.c',
19+
'hal/hid.c',
1920
]
2021

2122
[dependencies]

src/platform/avr/hal/hid.c

+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
/*
2+
* SPDX-License-Identifier: MIT
3+
* SPDX-FileCopyrightText: 2021 Rafael Silva <silvagracarafael@gmail.com>
4+
*/
5+
6+
#include "platform/avr/hal/hid.h"
7+
#include "platform/avr/usb.h"
8+
9+
int hid_hal_send(struct hid_hal_t interface, u8 *buffer, size_t buffer_size)
10+
{
11+
usb_write_descriptor(0, buffer, buffer_size);
12+
}
13+
14+
struct hid_hal_t hid_hal_init(void)
15+
{
16+
struct hid_hal_t hal = {
17+
.send = hid_hal_send,
18+
.drv_data = NULL,
19+
};
20+
return hal;
21+
}

src/platform/avr/hal/hid.h

+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
/*
2+
* SPDX-License-Identifier: MIT
3+
* SPDX-FileCopyrightText: 2021 Rafael Silva <silvagracarafael@gmail.com>
4+
*/
5+
6+
#pragma once
7+
8+
#include "hal/hid.h"
9+
#include "util/types.h"
10+
11+
struct hid_hal_t hid_hal_init(void);

src/platform/avr/usb.c

+154-138
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,73 @@
1212

1313
#include <USB.h>
1414

15+
/** Buffer to hold the previously generated HID report, for comparison purposes inside the HID class driver. */
16+
static u8 openinput_hid_report_buff[sizeof(struct oi_report_t)];
17+
static u8 mouse_hid_report_buff[sizeof(struct mouse_report)];
18+
static u8 keyboard_hid_report_buff[sizeof(struct keyboard_report)];
19+
20+
static u8 new_oi_report;
21+
static struct oi_report_t oi_report;
22+
static u8 oi_report_size;
23+
24+
static u8 new_mouse_report;
25+
static struct mouse_report mouse_report;
26+
static u8 mouse_report_size;
27+
28+
static u8 new_keyboard_report;
29+
static struct keyboard_report keyboard_report;
30+
static u8 keyboard_report_size;
31+
1532
static struct protocol_config_t protocol_config;
1633

17-
void usb_attach_protocol_config(struct protocol_config_t config)
18-
{
19-
protocol_config = config;
20-
}
34+
/** LUFA HID Class driver interface configuration and state information. This structure is
35+
* passed to all HID Class driver functions, so that multiple instances of the same class
36+
* within a device can be differentiated from one another.
37+
*/
38+
USB_ClassInfo_HID_Device_t openinput_hid_interface = {
39+
.Config =
40+
{
41+
.InterfaceNumber = 0,
42+
.ReportINEndpoint =
43+
{
44+
.Address = 0x81,
45+
.Size = 64,
46+
.Banks = 1,
47+
},
48+
.PrevReportINBuffer = openinput_hid_report_buff,
49+
.PrevReportINBufferSize = sizeof(openinput_hid_report_buff),
50+
},
51+
};
52+
53+
USB_ClassInfo_HID_Device_t mouse_hid_interface = {
54+
.Config =
55+
{
56+
.InterfaceNumber = 1,
57+
.ReportINEndpoint =
58+
{
59+
.Address = 0x83,
60+
.Size = 64,
61+
.Banks = 1,
62+
},
63+
.PrevReportINBuffer = mouse_hid_report_buff,
64+
.PrevReportINBufferSize = sizeof(mouse_hid_report_buff),
65+
},
66+
};
67+
68+
USB_ClassInfo_HID_Device_t keyboard_hid_interface = {
69+
.Config =
70+
{
71+
.InterfaceNumber = 2,
72+
.ReportINEndpoint =
73+
{
74+
.Address = 0x84,
75+
.Size = 64,
76+
.Banks = 1,
77+
},
78+
.PrevReportINBuffer = keyboard_hid_report_buff,
79+
.PrevReportINBufferSize = sizeof(keyboard_hid_report_buff),
80+
},
81+
};
2182

2283
void usb_init()
2384
{
@@ -29,64 +90,30 @@ void usb_task()
2990
{
3091
USB_USBTask();
3192

32-
/* openinput IN */
33-
Endpoint_SelectEndpoint(0x81);
34-
35-
/* Check if Endpoint Ready for Read/Write */
36-
if (Endpoint_IsReadWriteAllowed()) {
37-
/* Write Report Data */
38-
// Endpoint_Write_Stream_LE(&report_data, sizeof(report_data), NULL);
39-
40-
/* Finalize the stream transfer to send the last packet */
41-
// Endpoint_ClearIN();
42-
}
43-
44-
/* openinput OUT */
45-
Endpoint_SelectEndpoint(0x02);
46-
47-
/* Check if Endpoint Ready for Read/Write */
48-
if (Endpoint_IsReadWriteAllowed()) {
49-
/* Write Report Data */
50-
// Keyboard_ProcessLEDReport(Endpoint_Read_8());
51-
52-
/* Handshake the OUT Endpoint - clear endpoint and ready for next report */
53-
Endpoint_ClearOUT();
54-
}
55-
56-
/* mouse IN */
57-
Endpoint_SelectEndpoint(0x83);
58-
59-
/* Check if Endpoint Ready for Read/Write */
60-
if (Endpoint_IsReadWriteAllowed()) {
61-
/* Write Report Data */
62-
// Endpoint_Write_Stream_LE(&report_data, sizeof(report_data), NULL);
63-
64-
/* Finalize the stream transfer to send the last packet */
65-
// Endpoint_ClearIN();
66-
}
67-
68-
/* keyboard IN */
69-
Endpoint_SelectEndpoint(0x84);
70-
71-
/* Check if Endpoint Ready for Read/Write */
72-
if (Endpoint_IsReadWriteAllowed()) {
73-
/* Write Report Data */
74-
// Endpoint_Write_Stream_LE(&report_data, sizeof(report_data), NULL);
75-
76-
/* Finalize the stream transfer to send the last packet */
77-
// Endpoint_ClearIN();
78-
}
79-
80-
/* keyboard OUT */
81-
Endpoint_SelectEndpoint(0x05);
93+
HID_Device_USBTask(&openinput_hid_interface);
94+
HID_Device_USBTask(&mouse_hid_interface);
95+
HID_Device_USBTask(&keyboard_hid_interface);
96+
}
8297

83-
/* Check if Endpoint Ready for Read/Write */
84-
if (Endpoint_IsReadWriteAllowed()) {
85-
/* Write Report Data */
86-
// Keyboard_ProcessLEDReport(Endpoint_Read_8());
98+
void usb_attach_protocol_config(struct protocol_config_t config)
99+
{
100+
protocol_config = config;
101+
}
87102

88-
/* Handshake the OUT Endpoint - clear endpoint and ready for next report */
89-
Endpoint_ClearOUT();
103+
void usb_write_descriptor(u8 interface, u8 *report_data, u16 report_size)
104+
{
105+
if (interface == openinput_hid_interface.Config.InterfaceNumber) {
106+
memcpy(&oi_report, report_data, report_size);
107+
oi_report_size = report_size;
108+
new_oi_report = 1;
109+
} else if (interface == mouse_hid_interface.Config.InterfaceNumber) {
110+
memcpy(&mouse_report, report_data, report_size);
111+
mouse_report_size = report_size;
112+
new_mouse_report = 1;
113+
} else if (interface == keyboard_hid_interface.Config.InterfaceNumber) {
114+
memcpy(&keyboard_report, report_data, report_size);
115+
keyboard_report_size = report_size;
116+
new_keyboard_report = 1;
90117
}
91118
}
92119

@@ -104,90 +131,79 @@ void EVENT_USB_Device_Disconnect(void)
104131
{
105132
}
106133

107-
struct oi_report_t oi_rep;
108-
struct mouse_report mouse_rep;
109-
struct keyboard_report keyb_rep;
134+
/** Event handler for the library USB Configuration Changed event. */
135+
void EVENT_USB_Device_ConfigurationChanged(void)
136+
{
137+
HID_Device_ConfigureEndpoints(&openinput_hid_interface);
138+
HID_Device_ConfigureEndpoints(&mouse_hid_interface);
139+
HID_Device_ConfigureEndpoints(&keyboard_hid_interface);
140+
}
110141

111-
/** Event handler for the USB_ControlRequest event. This is used to catch and process control requests sent to
112-
* the device from the USB host before passing along unhandled control requests to the library for processing
113-
* internally.
142+
/** HID class driver callback function for the creation of HID reports to the host.
143+
*
144+
* \param[in] HIDInterfaceInfo Pointer to the HID class interface configuration structure being referenced
145+
* \param[in,out] ReportID Report ID requested by the host if non-zero, otherwise callback should set to the generated report ID
146+
* \param[in] ReportType Type of the report to create, either HID_REPORT_ITEM_In or HID_REPORT_ITEM_Feature
147+
* \param[out] ReportData Pointer to a buffer where the created report should be stored
148+
* \param[out] ReportSize Number of bytes written in the report (or zero if no report is to be sent)
149+
*
150+
* \return Boolean \c true to force the sending of the report, \c false to let the library determine if it needs to be sent
114151
*/
115-
void EVENT_USB_Device_ControlRequest(void)
152+
bool CALLBACK_HID_Device_CreateHIDReport(
153+
USB_ClassInfo_HID_Device_t *const HIDInterfaceInfo,
154+
uint8_t *const ReportID,
155+
const uint8_t ReportType,
156+
void *ReportData,
157+
uint16_t *const ReportSize)
116158
{
117-
struct oi_report_t oi_report;
118-
uint8_t *ReportData;
119-
uint8_t ReportSize;
120-
121-
/* Handle HID Class specific requests */
122-
switch (USB_ControlRequest.bRequest) {
123-
case HID_REQ_GetReport:
124-
if (USB_ControlRequest.bmRequestType == (REQDIR_DEVICETOHOST | REQTYPE_CLASS | REQREC_INTERFACE)) {
125-
Endpoint_ClearSETUP();
126-
127-
// /* Determine if it is the mouse or the keyboard data that is being requested */
128-
// if (USB_ControlRequest.wIndex == 0) { // openinput
129-
// ReportData = (uint8_t *) &oi_rep;
130-
// ReportSize = sizeof(struct oi_report_t);
131-
// } else if (USB_ControlRequest.wIndex == 1) { // mouse
132-
// ReportData = (uint8_t *) &mouse_rep;
133-
// ReportSize = sizeof(struct mouse_report);
134-
// } else if (USB_ControlRequest.wIndex == 2) { // keyboard
135-
// ReportData = (uint8_t *) &keyb_rep;
136-
// ReportSize = sizeof(struct keyboard_report);
137-
// }
138-
139-
// /* Write the report data to the control endpoint */
140-
// Endpoint_Write_Control_Stream_LE(ReportData, ReportSize);
141-
Endpoint_ClearOUT();
142-
}
143-
144-
break;
145-
case HID_REQ_SetReport:
146-
if (USB_ControlRequest.bmRequestType == (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE)) {
147-
Endpoint_ClearSETUP();
148-
149-
/* Wait until the report has been sent by the host */
150-
while (!(Endpoint_IsOUTReceived())) {
151-
if (USB_DeviceState == DEVICE_STATE_Unattached)
152-
return;
153-
}
154-
155-
// if (USB_ControlRequest.wIndex == 0) {
156-
// // for (size_t i = 0; i < USB_ControlRequest.wLength; i++)
157-
// // {
158-
// // ((uint8_t *)(&oi_report))[i] = Endpoint_Read_8();
159-
// // }
160-
// // protocol_dispatch(protocol_config, (uint8_t *)(&oi_report), USB_ControlRequest.wLength);
161-
162-
// } else if (USB_ControlRequest.wIndex == 2) {
163-
// /* Read in the LED report from the host */
164-
// uint8_t LEDStatus = Endpoint_Read_8();
165-
// }
166-
167-
/* Read in the LED report from the host */
168-
uint8_t LEDStatus = Endpoint_Read_8();
169-
170-
Endpoint_ClearOUT();
171-
Endpoint_ClearStatusStage();
172-
}
173-
174-
break;
159+
/* Determine which interface must have its report generated */
160+
if (HIDInterfaceInfo == &openinput_hid_interface) {
161+
if (new_oi_report == 1) {
162+
memcpy(ReportData, &oi_report, oi_report_size);
163+
*ReportSize = oi_report_size;
164+
new_oi_report = 0;
165+
return true;
166+
} else {
167+
return false;
168+
}
169+
} else if (HIDInterfaceInfo == &mouse_hid_interface) {
170+
if (new_mouse_report == 1) {
171+
memcpy(ReportData, &mouse_report, mouse_report_size);
172+
*ReportSize = mouse_report_size;
173+
new_mouse_report = 0;
174+
return true;
175+
} else {
176+
return false;
177+
}
178+
} else if (HIDInterfaceInfo == &keyboard_hid_interface) {
179+
if (new_keyboard_report == 1) {
180+
memcpy(ReportData, &keyboard_report, keyboard_report_size);
181+
*ReportSize = keyboard_report_size;
182+
new_keyboard_report = 0;
183+
return true;
184+
} else {
185+
return false;
186+
}
175187
}
176188
}
177189

178-
/** Event handler for the USB_ConfigurationChanged event. This is fired when the host sets the current configuration
179-
* of the USB device after enumeration, and configures the keyboard and mouse device endpoints.
190+
/** HID class driver callback function for the processing of HID reports from the host.
191+
*
192+
* \param[in] HIDInterfaceInfo Pointer to the HID class interface configuration structure being referenced
193+
* \param[in] ReportID Report ID of the received report from the host
194+
* \param[in] ReportType The type of report that the host has sent, either HID_REPORT_ITEM_Out or HID_REPORT_ITEM_Feature
195+
* \param[in] ReportData Pointer to a buffer where the received report has been stored
196+
* \param[in] ReportSize Size in bytes of the received HID report
180197
*/
181-
void EVENT_USB_Device_ConfigurationChanged(void)
198+
void CALLBACK_HID_Device_ProcessHIDReport(
199+
USB_ClassInfo_HID_Device_t *const HIDInterfaceInfo,
200+
const uint8_t ReportID,
201+
const uint8_t ReportType,
202+
const void *ReportData,
203+
const uint16_t ReportSize)
182204
{
183-
/* Setup Openinput Report Endpoints */
184-
Endpoint_ConfigureEndpoint(0x81, EP_TYPE_INTERRUPT, 0x40, 1); // IN
185-
Endpoint_ConfigureEndpoint(0x02, EP_TYPE_INTERRUPT, 0x40, 1); // OUT
186-
187-
/* Setup Mouse HID Report Endpoint */
188-
Endpoint_ConfigureEndpoint(0x83, EP_TYPE_INTERRUPT, 0x40, 1); // IN
189-
190-
/* Setup Keyboard HID Report Endpoints */
191-
Endpoint_ConfigureEndpoint(0x84, EP_TYPE_INTERRUPT, 0x40, 1); // IN
192-
Endpoint_ConfigureEndpoint(0x05, EP_TYPE_INTERRUPT, 0x40, 1); // OUT
205+
if (HIDInterfaceInfo == &openinput_hid_interface) {
206+
} else if (HIDInterfaceInfo == &keyboard_hid_interface) {
207+
protocol_dispatch(protocol_config, (u8 *) ReportData, ReportSize);
208+
}
193209
}

src/platform/avr/usb.h

+1
Original file line numberDiff line numberDiff line change
@@ -10,3 +10,4 @@
1010
void usb_init();
1111
void usb_task();
1212
void usb_attach_protocol_config(struct protocol_config_t config);
13+
void usb_write_descriptor(u8 interface, u8 *report_data, u16 report_size);

0 commit comments

Comments
 (0)