forked from mirrors/qmk_userspace
		
	add hid_raw feature to VUSB (#8380)
* rewrite usbhid feature on vusb * Apply suggestions from code review Co-Authored-By: Ryan <fauxpark@gmail.com> * fix typo * fix typo again * Update tmk_core/protocol/vusb/vusb.c Co-Authored-By: Ryan <fauxpark@gmail.com> * clean up defines Co-authored-by: Ryan <fauxpark@gmail.com>
This commit is contained in:
		
					parent
					
						
							
								b892a1429d
							
						
					
				
			
			
				commit
				
					
						89a675d57c
					
				
			
		
					 3 changed files with 174 additions and 1 deletions
				
			
		| 
						 | 
				
			
			@ -108,6 +108,13 @@ int main(void) {
 | 
			
		|||
                keyboard_task();
 | 
			
		||||
            }
 | 
			
		||||
            vusb_transfer_keyboard();
 | 
			
		||||
#ifdef RAW_ENABLE
 | 
			
		||||
            usbPoll();
 | 
			
		||||
 | 
			
		||||
            if (usbConfiguration && usbInterruptIsReady3()) {
 | 
			
		||||
                raw_hid_task();
 | 
			
		||||
            }
 | 
			
		||||
#endif
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -28,6 +28,14 @@ along with this program.  If not, see <http://www.gnu.org/licenses/>.
 | 
			
		|||
#include "vusb.h"
 | 
			
		||||
#include <util/delay.h>
 | 
			
		||||
 | 
			
		||||
#if defined(RAW_ENABLE)
 | 
			
		||||
#    include "raw_hid.h"
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#if (defined(MOUSE_ENABLE) || defined(EXTRAKEY_ENABLE)) && defined(RAW_ENABLE)
 | 
			
		||||
#    error "Enabling Mousekeys/Extrakeys and Raw HID at the same time is not currently supported on V-USB."
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
static uint8_t vusb_keyboard_leds = 0;
 | 
			
		||||
static uint8_t vusb_idle_rate     = 0;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -71,6 +79,52 @@ void vusb_transfer_keyboard(void) {
 | 
			
		|||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*------------------------------------------------------------------*
 | 
			
		||||
 * RAW HID
 | 
			
		||||
 *------------------------------------------------------------------*/
 | 
			
		||||
#ifdef RAW_ENABLE
 | 
			
		||||
#    define RAW_BUFFER_SIZE 32
 | 
			
		||||
#    define RAW_EPSIZE 8
 | 
			
		||||
 | 
			
		||||
static uint8_t raw_output_buffer[RAW_BUFFER_SIZE];
 | 
			
		||||
static uint8_t raw_output_received_bytes = 0;
 | 
			
		||||
 | 
			
		||||
void raw_hid_send(uint8_t *data, uint8_t length) {
 | 
			
		||||
    if (length != RAW_BUFFER_SIZE) {
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    uint8_t *temp = data;
 | 
			
		||||
    for (uint8_t i = 0; i < 4; i++) {
 | 
			
		||||
        while (!usbInterruptIsReady3()) {
 | 
			
		||||
            usbPoll();
 | 
			
		||||
        }
 | 
			
		||||
        usbSetInterrupt3(temp, 8);
 | 
			
		||||
        temp += 8;
 | 
			
		||||
    }
 | 
			
		||||
    while (!usbInterruptIsReady3()) {
 | 
			
		||||
        usbPoll();
 | 
			
		||||
    }
 | 
			
		||||
    usbSetInterrupt3(0, 0);
 | 
			
		||||
    usbPoll();
 | 
			
		||||
    _delay_ms(1);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
__attribute__((weak)) void raw_hid_receive(uint8_t *data, uint8_t length) {
 | 
			
		||||
    // Users should #include "raw_hid.h" in their own code
 | 
			
		||||
    // and implement this function there. Leave this as weak linkage
 | 
			
		||||
    // so users can opt to not handle data coming in.
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void raw_hid_task(void) {
 | 
			
		||||
    if (raw_output_received_bytes == RAW_BUFFER_SIZE) {
 | 
			
		||||
        raw_hid_receive(raw_output_buffer, RAW_BUFFER_SIZE);
 | 
			
		||||
        raw_output_received_bytes = 0;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
/*------------------------------------------------------------------*
 | 
			
		||||
 * Host driver
 | 
			
		||||
 *------------------------------------------------------------------*/
 | 
			
		||||
| 
						 | 
				
			
			@ -206,6 +260,27 @@ uchar usbFunctionWrite(uchar *data, uchar len) {
 | 
			
		|||
    return 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void usbFunctionWriteOut(uchar *data, uchar len) {
 | 
			
		||||
#ifdef RAW_ENABLE
 | 
			
		||||
    // Data from host must be divided every 8bytes
 | 
			
		||||
    if (len != 8) {
 | 
			
		||||
        debug("RAW: invalid length");
 | 
			
		||||
        raw_output_received_bytes = 0;
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (raw_output_received_bytes + len > RAW_BUFFER_SIZE) {
 | 
			
		||||
        debug("RAW: buffer full");
 | 
			
		||||
        raw_output_received_bytes = 0;
 | 
			
		||||
    } else {
 | 
			
		||||
        for (uint8_t i = 0; i < 8; i++) {
 | 
			
		||||
            raw_output_buffer[raw_output_received_bytes + i] = data[i];
 | 
			
		||||
        }
 | 
			
		||||
        raw_output_received_bytes += len;
 | 
			
		||||
    }
 | 
			
		||||
#endif
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*------------------------------------------------------------------*
 | 
			
		||||
 * Descriptors                                                      *
 | 
			
		||||
 *------------------------------------------------------------------*/
 | 
			
		||||
| 
						 | 
				
			
			@ -335,6 +410,29 @@ const PROGMEM uchar mouse_extra_hid_report[] = {
 | 
			
		|||
};
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#if defined(RAW_ENABLE)
 | 
			
		||||
const PROGMEM uchar raw_hid_report[] = {
 | 
			
		||||
    0x06, 0x60, 0xFF,  // Usage Page (Vendor Defined)
 | 
			
		||||
    0x09, 0x61,        // Usage (Vendor Defined)
 | 
			
		||||
    0xA1, 0x01,        // Collection (Application)
 | 
			
		||||
    // Data to host
 | 
			
		||||
    0x09, 0x62,             //   Usage (Vendor Defined)
 | 
			
		||||
    0x15, 0x00,             //   Logical Minimum (0)
 | 
			
		||||
    0x26, 0xFF, 0x00,       //   Logical Maximum (255)
 | 
			
		||||
    0x95, RAW_BUFFER_SIZE,  //   Report Count
 | 
			
		||||
    0x75, 0x08,             //   Report Size (8)
 | 
			
		||||
    0x81, 0x02,             //   Input (Data, Variable, Absolute)
 | 
			
		||||
    // Data from host
 | 
			
		||||
    0x09, 0x63,             //   Usage (Vendor Defined)
 | 
			
		||||
    0x15, 0x00,             //   Logical Minimum (0)
 | 
			
		||||
    0x26, 0xFF, 0x00,       //   Logical Maximum (255)
 | 
			
		||||
    0x95, RAW_BUFFER_SIZE,  //   Report Count
 | 
			
		||||
    0x75, 0x08,             //   Report Size (8)
 | 
			
		||||
    0x91, 0x02,             //   Output (Data, Variable, Absolute)
 | 
			
		||||
    0xC0,                   // End Collection
 | 
			
		||||
};
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#ifndef SERIAL_NUMBER
 | 
			
		||||
#    define SERIAL_NUMBER 0
 | 
			
		||||
#endif
 | 
			
		||||
| 
						 | 
				
			
			@ -416,7 +514,7 @@ const PROGMEM usbConfigurationDescriptor_t usbConfigurationDescriptor = {
 | 
			
		|||
            .bDescriptorType = USBDESCR_CONFIG
 | 
			
		||||
        },
 | 
			
		||||
        .wTotalLength        = sizeof(usbConfigurationDescriptor_t),
 | 
			
		||||
#    if defined(MOUSE_ENABLE) || defined(EXTRAKEY_ENABLE)
 | 
			
		||||
#    if defined(MOUSE_ENABLE) || defined(EXTRAKEY_ENABLE) || defined(RAW_ENABLE)
 | 
			
		||||
        .bNumInterfaces      = 2,
 | 
			
		||||
#    else
 | 
			
		||||
        .bNumInterfaces      = 1,
 | 
			
		||||
| 
						 | 
				
			
			@ -511,6 +609,53 @@ const PROGMEM usbConfigurationDescriptor_t usbConfigurationDescriptor = {
 | 
			
		|||
        .bInterval           = USB_POLLING_INTERVAL_MS
 | 
			
		||||
    }
 | 
			
		||||
#        endif
 | 
			
		||||
#    elif defined(RAW_ENABLE)
 | 
			
		||||
    .rawInterface = {
 | 
			
		||||
        .header = {
 | 
			
		||||
            .bLength         = sizeof(usbInterfaceDescriptor_t),
 | 
			
		||||
            .bDescriptorType = USBDESCR_INTERFACE
 | 
			
		||||
        },
 | 
			
		||||
        .bInterfaceNumber    = 1,
 | 
			
		||||
        .bAlternateSetting   = 0x00,
 | 
			
		||||
        .bNumEndpoints       = 2,
 | 
			
		||||
        .bInterfaceClass     = 0x03,
 | 
			
		||||
        .bInterfaceSubClass  = 0x00,
 | 
			
		||||
        .bInterfaceProtocol  = 0x00,
 | 
			
		||||
        .iInterface          = 0x00
 | 
			
		||||
    },
 | 
			
		||||
    .rawHID = {
 | 
			
		||||
        .header = {
 | 
			
		||||
            .bLength         = sizeof(usbHIDDescriptor_t),
 | 
			
		||||
            .bDescriptorType = USBDESCR_HID
 | 
			
		||||
        },
 | 
			
		||||
        .bcdHID              = 0x0101,
 | 
			
		||||
        .bCountryCode        = 0x00,
 | 
			
		||||
        .bNumDescriptors     = 2,
 | 
			
		||||
        .bDescriptorType     = USBDESCR_HID_REPORT,
 | 
			
		||||
        .wDescriptorLength   = sizeof(raw_hid_report)
 | 
			
		||||
    },
 | 
			
		||||
#        if USB_CFG_HAVE_INTRIN_ENDPOINT3
 | 
			
		||||
    .rawINEndpoint = {
 | 
			
		||||
        .header = {
 | 
			
		||||
            .bLength         = sizeof(usbEndpointDescriptor_t),
 | 
			
		||||
            .bDescriptorType = USBDESCR_ENDPOINT
 | 
			
		||||
        },
 | 
			
		||||
        .bEndpointAddress    = (USBRQ_DIR_DEVICE_TO_HOST | USB_CFG_EP3_NUMBER),
 | 
			
		||||
        .bmAttributes        = 0x03,
 | 
			
		||||
        .wMaxPacketSize      = RAW_EPSIZE,
 | 
			
		||||
        .bInterval           = USB_POLLING_INTERVAL_MS
 | 
			
		||||
    },
 | 
			
		||||
    .rawOUTEndpoint = {
 | 
			
		||||
        .header = {
 | 
			
		||||
            .bLength         = sizeof(usbEndpointDescriptor_t),
 | 
			
		||||
            .bDescriptorType = USBDESCR_ENDPOINT
 | 
			
		||||
        },
 | 
			
		||||
        .bEndpointAddress    = (USBRQ_DIR_HOST_TO_DEVICE | USB_CFG_EP3_NUMBER),
 | 
			
		||||
        .bmAttributes        = 0x03,
 | 
			
		||||
        .wMaxPacketSize      = RAW_EPSIZE,
 | 
			
		||||
        .bInterval           = USB_POLLING_INTERVAL_MS
 | 
			
		||||
    }
 | 
			
		||||
#        endif
 | 
			
		||||
#    endif
 | 
			
		||||
};
 | 
			
		||||
#endif
 | 
			
		||||
| 
						 | 
				
			
			@ -572,6 +717,11 @@ USB_PUBLIC usbMsgLen_t usbFunctionDescriptor(struct usbRequest *rq) {
 | 
			
		|||
                    usbMsgPtr = (unsigned char *)&usbConfigurationDescriptor.mouseExtraHID;
 | 
			
		||||
                    len       = sizeof(usbHIDDescriptor_t);
 | 
			
		||||
                    break;
 | 
			
		||||
#elif defined(RAW_ENABLE)
 | 
			
		||||
                case 1:
 | 
			
		||||
                    usbMsgPtr = (unsigned char *)&usbConfigurationDescriptor.rawHID;
 | 
			
		||||
                    len       = sizeof(usbHIDDescriptor_t);
 | 
			
		||||
                    break;
 | 
			
		||||
#endif
 | 
			
		||||
            }
 | 
			
		||||
            break;
 | 
			
		||||
| 
						 | 
				
			
			@ -587,6 +737,11 @@ USB_PUBLIC usbMsgLen_t usbFunctionDescriptor(struct usbRequest *rq) {
 | 
			
		|||
                    usbMsgPtr = (unsigned char *)mouse_extra_hid_report;
 | 
			
		||||
                    len       = sizeof(mouse_extra_hid_report);
 | 
			
		||||
                    break;
 | 
			
		||||
#elif defined(RAW_ENABLE)
 | 
			
		||||
                case 1:
 | 
			
		||||
                    usbMsgPtr = (unsigned char *)raw_hid_report;
 | 
			
		||||
                    len       = sizeof(raw_hid_report);
 | 
			
		||||
                    break;
 | 
			
		||||
#endif
 | 
			
		||||
            }
 | 
			
		||||
            break;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -97,6 +97,13 @@ typedef struct usbConfigurationDescriptor {
 | 
			
		|||
#    ifdef USB_CFG_HAVE_INTRIN_ENDPOINT3
 | 
			
		||||
    usbEndpointDescriptor_t mouseExtraINEndpoint;
 | 
			
		||||
#    endif
 | 
			
		||||
#elif defined(RAW_ENABLE)
 | 
			
		||||
    usbInterfaceDescriptor_t rawInterface;
 | 
			
		||||
    usbHIDDescriptor_t       rawHID;
 | 
			
		||||
#    ifdef USB_CFG_HAVE_INTRIN_ENDPOINT3
 | 
			
		||||
    usbEndpointDescriptor_t rawINEndpoint;
 | 
			
		||||
    usbEndpointDescriptor_t rawOUTEndpoint;
 | 
			
		||||
#    endif
 | 
			
		||||
#endif
 | 
			
		||||
} __attribute__((packed)) usbConfigurationDescriptor_t;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -104,3 +111,7 @@ typedef struct usbConfigurationDescriptor {
 | 
			
		|||
 | 
			
		||||
host_driver_t *vusb_driver(void);
 | 
			
		||||
void           vusb_transfer_keyboard(void);
 | 
			
		||||
 | 
			
		||||
#if defined(RAW_ENABLE)
 | 
			
		||||
void raw_hid_task(void);
 | 
			
		||||
#endif
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue