|
@@ -0,0 +1,750 @@
|
|
|
+
|
|
|
+ * http:
|
|
|
+ * Copyright (c) 2009 PJRC.COM, LLC
|
|
|
+ *
|
|
|
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
|
+ * of this software and associated documentation files (the "Software"), to deal
|
|
|
+ * in the Software without restriction, including without limitation the rights
|
|
|
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
|
+ * copies of the Software, and to permit persons to whom the Software is
|
|
|
+ * furnished to do so, subject to the following conditions:
|
|
|
+ *
|
|
|
+ * The above copyright notice and this permission notice shall be included in
|
|
|
+ * all copies or substantial portions of the Software.
|
|
|
+ *
|
|
|
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
|
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
|
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
|
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
|
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
|
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
|
+ * THE SOFTWARE.
|
|
|
+ */
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+#define USB_SERIAL_PRIVATE_INCLUDE
|
|
|
+#include "usb_keyboard_debug.h"
|
|
|
+
|
|
|
+
|
|
|
+ *
|
|
|
+ * Configurable Options
|
|
|
+ *
|
|
|
+ **************************************************************************/
|
|
|
+
|
|
|
+
|
|
|
+#define STR_MANUFACTURER L"MfgName"
|
|
|
+#define STR_PRODUCT L"Keyboard"
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+#define VENDOR_ID 0x16C0
|
|
|
+#define PRODUCT_ID 0x047D
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+#define SUPPORT_ENDPOINT_HALT
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ *
|
|
|
+ * Endpoint Buffer Configuration
|
|
|
+ *
|
|
|
+ **************************************************************************/
|
|
|
+
|
|
|
+#define ENDPOINT0_SIZE 32
|
|
|
+
|
|
|
+#define KEYBOARD_INTERFACE 0
|
|
|
+#define KEYBOARD_ENDPOINT 3
|
|
|
+#define KEYBOARD_SIZE 8
|
|
|
+#define KEYBOARD_BUFFER EP_DOUBLE_BUFFER
|
|
|
+
|
|
|
+#define DEBUG_INTERFACE 1
|
|
|
+#define DEBUG_TX_ENDPOINT 4
|
|
|
+#define DEBUG_TX_SIZE 32
|
|
|
+#define DEBUG_TX_BUFFER EP_DOUBLE_BUFFER
|
|
|
+
|
|
|
+static const uint8_t PROGMEM endpoint_config_table[] = {
|
|
|
+ 0,
|
|
|
+ 0,
|
|
|
+ 1, EP_TYPE_INTERRUPT_IN, EP_SIZE(KEYBOARD_SIZE) | KEYBOARD_BUFFER,
|
|
|
+ 1, EP_TYPE_INTERRUPT_IN, EP_SIZE(DEBUG_TX_SIZE) | DEBUG_TX_BUFFER
|
|
|
+};
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ *
|
|
|
+ * Descriptor Data
|
|
|
+ *
|
|
|
+ **************************************************************************/
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+static uint8_t PROGMEM device_descriptor[] = {
|
|
|
+ 18,
|
|
|
+ 1,
|
|
|
+ 0x00, 0x02,
|
|
|
+ 0,
|
|
|
+ 0,
|
|
|
+ 0,
|
|
|
+ ENDPOINT0_SIZE,
|
|
|
+ LSB(VENDOR_ID), MSB(VENDOR_ID),
|
|
|
+ LSB(PRODUCT_ID), MSB(PRODUCT_ID),
|
|
|
+ 0x00, 0x01,
|
|
|
+ 1,
|
|
|
+ 2,
|
|
|
+ 0,
|
|
|
+ 1
|
|
|
+};
|
|
|
+
|
|
|
+
|
|
|
+static uint8_t PROGMEM keyboard_hid_report_desc[] = {
|
|
|
+ 0x05, 0x01,
|
|
|
+ 0x09, 0x06,
|
|
|
+ 0xA1, 0x01,
|
|
|
+ 0x75, 0x01,
|
|
|
+ 0x95, 0x08,
|
|
|
+ 0x05, 0x07,
|
|
|
+ 0x19, 0xE0,
|
|
|
+ 0x29, 0xE7,
|
|
|
+ 0x15, 0x00,
|
|
|
+ 0x25, 0x01,
|
|
|
+ 0x81, 0x02,
|
|
|
+ 0x95, 0x01,
|
|
|
+ 0x75, 0x08,
|
|
|
+ 0x81, 0x03,
|
|
|
+ 0x95, 0x05,
|
|
|
+ 0x75, 0x01,
|
|
|
+ 0x05, 0x08,
|
|
|
+ 0x19, 0x01,
|
|
|
+ 0x29, 0x05,
|
|
|
+ 0x91, 0x02,
|
|
|
+ 0x95, 0x01,
|
|
|
+ 0x75, 0x03,
|
|
|
+ 0x91, 0x03,
|
|
|
+ 0x95, 0x06,
|
|
|
+ 0x75, 0x08,
|
|
|
+ 0x15, 0x00,
|
|
|
+ 0x25, 0x68,
|
|
|
+ 0x05, 0x07,
|
|
|
+ 0x19, 0x00,
|
|
|
+ 0x29, 0x68,
|
|
|
+ 0x81, 0x00,
|
|
|
+ 0xc0
|
|
|
+};
|
|
|
+
|
|
|
+static uint8_t PROGMEM debug_hid_report_desc[] = {
|
|
|
+ 0x06, 0x31, 0xFF,
|
|
|
+ 0x09, 0x74,
|
|
|
+ 0xA1, 0x53,
|
|
|
+ 0x75, 0x08,
|
|
|
+ 0x15, 0x00,
|
|
|
+ 0x26, 0xFF, 0x00,
|
|
|
+ 0x95, DEBUG_TX_SIZE,
|
|
|
+ 0x09, 0x75,
|
|
|
+ 0x81, 0x02,
|
|
|
+ 0xC0
|
|
|
+};
|
|
|
+
|
|
|
+#define CONFIG1_DESC_SIZE (9+9+9+7+9+9+7)
|
|
|
+#define KEYBOARD_HID_DESC_OFFSET (9+9)
|
|
|
+#define DEBUG_HID_DESC_OFFSET (9+9+9+7+9)
|
|
|
+static uint8_t PROGMEM config1_descriptor[CONFIG1_DESC_SIZE] = {
|
|
|
+
|
|
|
+ 9,
|
|
|
+ 2,
|
|
|
+ LSB(CONFIG1_DESC_SIZE),
|
|
|
+ MSB(CONFIG1_DESC_SIZE),
|
|
|
+ 2,
|
|
|
+ 1,
|
|
|
+ 0,
|
|
|
+ 0xC0,
|
|
|
+ 50,
|
|
|
+
|
|
|
+ 9,
|
|
|
+ 4,
|
|
|
+ KEYBOARD_INTERFACE,
|
|
|
+ 0,
|
|
|
+ 1,
|
|
|
+ 0x03,
|
|
|
+ 0x01,
|
|
|
+ 0x01,
|
|
|
+ 0,
|
|
|
+
|
|
|
+ 9,
|
|
|
+ 0x21,
|
|
|
+ 0x11, 0x01,
|
|
|
+ 0,
|
|
|
+ 1,
|
|
|
+ 0x22,
|
|
|
+ sizeof(keyboard_hid_report_desc),
|
|
|
+ 0,
|
|
|
+
|
|
|
+ 7,
|
|
|
+ 5,
|
|
|
+ KEYBOARD_ENDPOINT | 0x80,
|
|
|
+ 0x03,
|
|
|
+ KEYBOARD_SIZE, 0,
|
|
|
+ 1,
|
|
|
+
|
|
|
+ 9,
|
|
|
+ 4,
|
|
|
+ DEBUG_INTERFACE,
|
|
|
+ 0,
|
|
|
+ 1,
|
|
|
+ 0x03,
|
|
|
+ 0x00,
|
|
|
+ 0x00,
|
|
|
+ 0,
|
|
|
+
|
|
|
+ 9,
|
|
|
+ 0x21,
|
|
|
+ 0x11, 0x01,
|
|
|
+ 0,
|
|
|
+ 1,
|
|
|
+ 0x22,
|
|
|
+ sizeof(debug_hid_report_desc),
|
|
|
+ 0,
|
|
|
+
|
|
|
+ 7,
|
|
|
+ 5,
|
|
|
+ DEBUG_TX_ENDPOINT | 0x80,
|
|
|
+ 0x03,
|
|
|
+ DEBUG_TX_SIZE, 0,
|
|
|
+ 1
|
|
|
+};
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+struct usb_string_descriptor_struct {
|
|
|
+ uint8_t bLength;
|
|
|
+ uint8_t bDescriptorType;
|
|
|
+ int16_t wString[];
|
|
|
+};
|
|
|
+static struct usb_string_descriptor_struct PROGMEM string0 = {
|
|
|
+ 4,
|
|
|
+ 3,
|
|
|
+ {0x0409}
|
|
|
+};
|
|
|
+static struct usb_string_descriptor_struct PROGMEM string1 = {
|
|
|
+ sizeof(STR_MANUFACTURER),
|
|
|
+ 3,
|
|
|
+ STR_MANUFACTURER
|
|
|
+};
|
|
|
+static struct usb_string_descriptor_struct PROGMEM string2 = {
|
|
|
+ sizeof(STR_PRODUCT),
|
|
|
+ 3,
|
|
|
+ STR_PRODUCT
|
|
|
+};
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+static struct descriptor_list_struct {
|
|
|
+ uint16_t wValue;
|
|
|
+ uint16_t wIndex;
|
|
|
+ const uint8_t *addr;
|
|
|
+ uint8_t length;
|
|
|
+} PROGMEM descriptor_list[] = {
|
|
|
+ {0x0100, 0x0000, device_descriptor, sizeof(device_descriptor)},
|
|
|
+ {0x0200, 0x0000, config1_descriptor, sizeof(config1_descriptor)},
|
|
|
+ {0x2200, KEYBOARD_INTERFACE, keyboard_hid_report_desc, sizeof(keyboard_hid_report_desc)},
|
|
|
+ {0x2100, KEYBOARD_INTERFACE, config1_descriptor+KEYBOARD_HID_DESC_OFFSET, 9},
|
|
|
+ {0x2200, DEBUG_INTERFACE, debug_hid_report_desc, sizeof(debug_hid_report_desc)},
|
|
|
+ {0x2100, DEBUG_INTERFACE, config1_descriptor+DEBUG_HID_DESC_OFFSET, 9},
|
|
|
+ {0x0300, 0x0000, (const uint8_t *)&string0, 4},
|
|
|
+ {0x0301, 0x0409, (const uint8_t *)&string1, sizeof(STR_MANUFACTURER)},
|
|
|
+ {0x0302, 0x0409, (const uint8_t *)&string2, sizeof(STR_PRODUCT)}
|
|
|
+};
|
|
|
+#define NUM_DESC_LIST (sizeof(descriptor_list)/sizeof(struct descriptor_list_struct))
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ *
|
|
|
+ * Variables - these are the only non-stack RAM usage
|
|
|
+ *
|
|
|
+ **************************************************************************/
|
|
|
+
|
|
|
+
|
|
|
+static volatile uint8_t usb_configuration=0;
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+static volatile uint8_t debug_flush_timer=0;
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+uint8_t keyboard_modifier_keys=0;
|
|
|
+
|
|
|
+
|
|
|
+uint8_t keyboard_keys[6]={0,0,0,0,0,0};
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+static uint8_t keyboard_protocol=1;
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+static uint8_t keyboard_idle_config=125;
|
|
|
+
|
|
|
+
|
|
|
+static uint8_t keyboard_idle_count=0;
|
|
|
+
|
|
|
+
|
|
|
+volatile uint8_t keyboard_leds=0;
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ *
|
|
|
+ * Public Functions - these are the API intended for the user
|
|
|
+ *
|
|
|
+ **************************************************************************/
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+void usb_init(void)
|
|
|
+{
|
|
|
+ HW_CONFIG();
|
|
|
+ USB_FREEZE();
|
|
|
+ PLL_CONFIG();
|
|
|
+ while (!(PLLCSR & (1<<PLOCK))) ;
|
|
|
+ USB_CONFIG();
|
|
|
+ UDCON = 0;
|
|
|
+ usb_configuration = 0;
|
|
|
+ UDIEN = (1<<EORSTE)|(1<<SOFE);
|
|
|
+ sei();
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+uint8_t usb_configured(void)
|
|
|
+{
|
|
|
+ return usb_configuration;
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+int8_t usb_keyboard_press(uint8_t key, uint8_t modifier)
|
|
|
+{
|
|
|
+ int8_t r;
|
|
|
+
|
|
|
+ keyboard_modifier_keys = modifier;
|
|
|
+ keyboard_keys[0] = key;
|
|
|
+ r = usb_keyboard_send();
|
|
|
+ if (r) return r;
|
|
|
+ keyboard_modifier_keys = 0;
|
|
|
+ keyboard_keys[0] = 0;
|
|
|
+ return usb_keyboard_send();
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+int8_t usb_keyboard_send(void)
|
|
|
+{
|
|
|
+ uint8_t i, intr_state, timeout;
|
|
|
+
|
|
|
+ if (!usb_configuration) return -1;
|
|
|
+ intr_state = SREG;
|
|
|
+ cli();
|
|
|
+ UENUM = KEYBOARD_ENDPOINT;
|
|
|
+ timeout = UDFNUML + 50;
|
|
|
+ while (1) {
|
|
|
+
|
|
|
+ if (UEINTX & (1<<RWAL)) break;
|
|
|
+ SREG = intr_state;
|
|
|
+
|
|
|
+ if (!usb_configuration) return -1;
|
|
|
+
|
|
|
+ if (UDFNUML == timeout) return -1;
|
|
|
+
|
|
|
+ intr_state = SREG;
|
|
|
+ cli();
|
|
|
+ UENUM = KEYBOARD_ENDPOINT;
|
|
|
+ }
|
|
|
+ UEDATX = keyboard_modifier_keys;
|
|
|
+ UEDATX = 0;
|
|
|
+ for (i=0; i<6; i++) {
|
|
|
+ UEDATX = keyboard_keys[i];
|
|
|
+ }
|
|
|
+ UEINTX = 0x3A;
|
|
|
+ keyboard_idle_count = 0;
|
|
|
+ SREG = intr_state;
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+int8_t usb_debug_putchar(uint8_t c)
|
|
|
+{
|
|
|
+ static uint8_t previous_timeout=0;
|
|
|
+ uint8_t timeout, intr_state;
|
|
|
+
|
|
|
+
|
|
|
+ if (!usb_configuration) return -1;
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ intr_state = SREG;
|
|
|
+ cli();
|
|
|
+ UENUM = DEBUG_TX_ENDPOINT;
|
|
|
+
|
|
|
+ if (previous_timeout) {
|
|
|
+ if (!(UEINTX & (1<<RWAL))) {
|
|
|
+ SREG = intr_state;
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+ previous_timeout = 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ timeout = UDFNUML + 4;
|
|
|
+ while (1) {
|
|
|
+
|
|
|
+ if (UEINTX & (1<<RWAL)) break;
|
|
|
+ SREG = intr_state;
|
|
|
+
|
|
|
+ if (UDFNUML == timeout) {
|
|
|
+ previous_timeout = 1;
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!usb_configuration) return -1;
|
|
|
+
|
|
|
+ intr_state = SREG;
|
|
|
+ cli();
|
|
|
+ UENUM = DEBUG_TX_ENDPOINT;
|
|
|
+ }
|
|
|
+
|
|
|
+ UEDATX = c;
|
|
|
+
|
|
|
+ if (!(UEINTX & (1<<RWAL))) {
|
|
|
+ UEINTX = 0x3A;
|
|
|
+ debug_flush_timer = 0;
|
|
|
+ } else {
|
|
|
+ debug_flush_timer = 2;
|
|
|
+ }
|
|
|
+ SREG = intr_state;
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+void usb_debug_flush_output(void)
|
|
|
+{
|
|
|
+ uint8_t intr_state;
|
|
|
+
|
|
|
+ intr_state = SREG;
|
|
|
+ cli();
|
|
|
+ if (debug_flush_timer) {
|
|
|
+ UENUM = DEBUG_TX_ENDPOINT;
|
|
|
+ while ((UEINTX & (1<<RWAL))) {
|
|
|
+ UEDATX = 0;
|
|
|
+ }
|
|
|
+ UEINTX = 0x3A;
|
|
|
+ debug_flush_timer = 0;
|
|
|
+ }
|
|
|
+ SREG = intr_state;
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ *
|
|
|
+ * Private Functions - not intended for general user consumption....
|
|
|
+ *
|
|
|
+ **************************************************************************/
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ISR(USB_GEN_vect)
|
|
|
+{
|
|
|
+ uint8_t intbits, t, i;
|
|
|
+ static uint8_t div4=0;
|
|
|
+
|
|
|
+ intbits = UDINT;
|
|
|
+ UDINT = 0;
|
|
|
+ if (intbits & (1<<EORSTI)) {
|
|
|
+ UENUM = 0;
|
|
|
+ UECONX = 1;
|
|
|
+ UECFG0X = EP_TYPE_CONTROL;
|
|
|
+ UECFG1X = EP_SIZE(ENDPOINT0_SIZE) | EP_SINGLE_BUFFER;
|
|
|
+ UEIENX = (1<<RXSTPE);
|
|
|
+ usb_configuration = 0;
|
|
|
+ }
|
|
|
+ if ((intbits & (1<<SOFI)) && usb_configuration) {
|
|
|
+ t = debug_flush_timer;
|
|
|
+ if (t) {
|
|
|
+ debug_flush_timer = -- t;
|
|
|
+ if (!t) {
|
|
|
+ UENUM = DEBUG_TX_ENDPOINT;
|
|
|
+ while ((UEINTX & (1<<RWAL))) {
|
|
|
+ UEDATX = 0;
|
|
|
+ }
|
|
|
+ UEINTX = 0x3A;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (keyboard_idle_config && (++div4 & 3) == 0) {
|
|
|
+ UENUM = KEYBOARD_ENDPOINT;
|
|
|
+ if (UEINTX & (1<<RWAL)) {
|
|
|
+ keyboard_idle_count++;
|
|
|
+ if (keyboard_idle_count == keyboard_idle_config) {
|
|
|
+ keyboard_idle_count = 0;
|
|
|
+ UEDATX = keyboard_modifier_keys;
|
|
|
+ UEDATX = 0;
|
|
|
+ for (i=0; i<6; i++) {
|
|
|
+ UEDATX = keyboard_keys[i];
|
|
|
+ }
|
|
|
+ UEINTX = 0x3A;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+static inline void usb_wait_in_ready(void)
|
|
|
+{
|
|
|
+ while (!(UEINTX & (1<<TXINI))) ;
|
|
|
+}
|
|
|
+static inline void usb_send_in(void)
|
|
|
+{
|
|
|
+ UEINTX = ~(1<<TXINI);
|
|
|
+}
|
|
|
+static inline void usb_wait_receive_out(void)
|
|
|
+{
|
|
|
+ while (!(UEINTX & (1<<RXOUTI))) ;
|
|
|
+}
|
|
|
+static inline void usb_ack_out(void)
|
|
|
+{
|
|
|
+ UEINTX = ~(1<<RXOUTI);
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ISR(USB_COM_vect)
|
|
|
+{
|
|
|
+ uint8_t intbits;
|
|
|
+ const uint8_t *list;
|
|
|
+ const uint8_t *cfg;
|
|
|
+ uint8_t i, n, len, en;
|
|
|
+ uint8_t bmRequestType;
|
|
|
+ uint8_t bRequest;
|
|
|
+ uint16_t wValue;
|
|
|
+ uint16_t wIndex;
|
|
|
+ uint16_t wLength;
|
|
|
+ uint16_t desc_val;
|
|
|
+ const uint8_t *desc_addr;
|
|
|
+ uint8_t desc_length;
|
|
|
+
|
|
|
+ UENUM = 0;
|
|
|
+ intbits = UEINTX;
|
|
|
+ if (intbits & (1<<RXSTPI)) {
|
|
|
+ bmRequestType = UEDATX;
|
|
|
+ bRequest = UEDATX;
|
|
|
+ wValue = UEDATX;
|
|
|
+ wValue |= (UEDATX << 8);
|
|
|
+ wIndex = UEDATX;
|
|
|
+ wIndex |= (UEDATX << 8);
|
|
|
+ wLength = UEDATX;
|
|
|
+ wLength |= (UEDATX << 8);
|
|
|
+ UEINTX = ~((1<<RXSTPI) | (1<<RXOUTI) | (1<<TXINI));
|
|
|
+ if (bRequest == GET_DESCRIPTOR) {
|
|
|
+ list = (const uint8_t *)descriptor_list;
|
|
|
+ for (i=0; ; i++) {
|
|
|
+ if (i >= NUM_DESC_LIST) {
|
|
|
+ UECONX = (1<<STALLRQ)|(1<<EPEN);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ desc_val = pgm_read_word(list);
|
|
|
+ if (desc_val != wValue) {
|
|
|
+ list += sizeof(struct descriptor_list_struct);
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ list += 2;
|
|
|
+ desc_val = pgm_read_word(list);
|
|
|
+ if (desc_val != wIndex) {
|
|
|
+ list += sizeof(struct descriptor_list_struct)-2;
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ list += 2;
|
|
|
+ desc_addr = (const uint8_t *)pgm_read_word(list);
|
|
|
+ list += 2;
|
|
|
+ desc_length = pgm_read_byte(list);
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ len = (wLength < 256) ? wLength : 255;
|
|
|
+ if (len > desc_length) len = desc_length;
|
|
|
+ do {
|
|
|
+
|
|
|
+ do {
|
|
|
+ i = UEINTX;
|
|
|
+ } while (!(i & ((1<<TXINI)|(1<<RXOUTI))));
|
|
|
+ if (i & (1<<RXOUTI)) return;
|
|
|
+
|
|
|
+ n = len < ENDPOINT0_SIZE ? len : ENDPOINT0_SIZE;
|
|
|
+ for (i = n; i; i--) {
|
|
|
+ UEDATX = pgm_read_byte(desc_addr++);
|
|
|
+ }
|
|
|
+ len -= n;
|
|
|
+ usb_send_in();
|
|
|
+ } while (len || n == ENDPOINT0_SIZE);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ if (bRequest == SET_ADDRESS) {
|
|
|
+ usb_send_in();
|
|
|
+ usb_wait_in_ready();
|
|
|
+ UDADDR = wValue | (1<<ADDEN);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ if (bRequest == SET_CONFIGURATION && bmRequestType == 0) {
|
|
|
+ usb_configuration = wValue;
|
|
|
+ usb_send_in();
|
|
|
+ cfg = endpoint_config_table;
|
|
|
+ for (i=1; i<5; i++) {
|
|
|
+ UENUM = i;
|
|
|
+ en = pgm_read_byte(cfg++);
|
|
|
+ UECONX = en;
|
|
|
+ if (en) {
|
|
|
+ UECFG0X = pgm_read_byte(cfg++);
|
|
|
+ UECFG1X = pgm_read_byte(cfg++);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ UERST = 0x1E;
|
|
|
+ UERST = 0;
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ if (bRequest == GET_CONFIGURATION && bmRequestType == 0x80) {
|
|
|
+ usb_wait_in_ready();
|
|
|
+ UEDATX = usb_configuration;
|
|
|
+ usb_send_in();
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (bRequest == GET_STATUS) {
|
|
|
+ usb_wait_in_ready();
|
|
|
+ i = 0;
|
|
|
+ #ifdef SUPPORT_ENDPOINT_HALT
|
|
|
+ if (bmRequestType == 0x82) {
|
|
|
+ UENUM = wIndex;
|
|
|
+ if (UECONX & (1<<STALLRQ)) i = 1;
|
|
|
+ UENUM = 0;
|
|
|
+ }
|
|
|
+ #endif
|
|
|
+ UEDATX = i;
|
|
|
+ UEDATX = 0;
|
|
|
+ usb_send_in();
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ #ifdef SUPPORT_ENDPOINT_HALT
|
|
|
+ if ((bRequest == CLEAR_FEATURE || bRequest == SET_FEATURE)
|
|
|
+ && bmRequestType == 0x02 && wValue == 0) {
|
|
|
+ i = wIndex & 0x7F;
|
|
|
+ if (i >= 1 && i <= MAX_ENDPOINT) {
|
|
|
+ usb_send_in();
|
|
|
+ UENUM = i;
|
|
|
+ if (bRequest == SET_FEATURE) {
|
|
|
+ UECONX = (1<<STALLRQ)|(1<<EPEN);
|
|
|
+ } else {
|
|
|
+ UECONX = (1<<STALLRQC)|(1<<RSTDT)|(1<<EPEN);
|
|
|
+ UERST = (1 << i);
|
|
|
+ UERST = 0;
|
|
|
+ }
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ #endif
|
|
|
+ if (wIndex == KEYBOARD_INTERFACE) {
|
|
|
+ if (bmRequestType == 0xA1) {
|
|
|
+ if (bRequest == HID_GET_REPORT) {
|
|
|
+ usb_wait_in_ready();
|
|
|
+ UEDATX = keyboard_modifier_keys;
|
|
|
+ UEDATX = 0;
|
|
|
+ for (i=0; i<6; i++) {
|
|
|
+ UEDATX = keyboard_keys[i];
|
|
|
+ }
|
|
|
+ usb_send_in();
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ if (bRequest == HID_GET_IDLE) {
|
|
|
+ usb_wait_in_ready();
|
|
|
+ UEDATX = keyboard_idle_config;
|
|
|
+ usb_send_in();
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ if (bRequest == HID_GET_PROTOCOL) {
|
|
|
+ usb_wait_in_ready();
|
|
|
+ UEDATX = keyboard_protocol;
|
|
|
+ usb_send_in();
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (bmRequestType == 0x21) {
|
|
|
+ if (bRequest == HID_SET_REPORT) {
|
|
|
+ usb_wait_receive_out();
|
|
|
+ keyboard_leds = UEDATX;
|
|
|
+ usb_ack_out();
|
|
|
+ usb_send_in();
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ if (bRequest == HID_SET_IDLE) {
|
|
|
+ keyboard_idle_config = (wValue >> 8);
|
|
|
+ keyboard_idle_count = 0;
|
|
|
+
|
|
|
+ usb_send_in();
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ if (bRequest == HID_SET_PROTOCOL) {
|
|
|
+ keyboard_protocol = wValue;
|
|
|
+
|
|
|
+ usb_send_in();
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (wIndex == DEBUG_INTERFACE) {
|
|
|
+ if (bRequest == HID_GET_REPORT && bmRequestType == 0xA1) {
|
|
|
+ len = wLength;
|
|
|
+ do {
|
|
|
+
|
|
|
+ do {
|
|
|
+ i = UEINTX;
|
|
|
+ } while (!(i & ((1<<TXINI)|(1<<RXOUTI))));
|
|
|
+ if (i & (1<<RXOUTI)) return;
|
|
|
+
|
|
|
+ n = len < ENDPOINT0_SIZE ? len : ENDPOINT0_SIZE;
|
|
|
+ for (i = n; i; i--) {
|
|
|
+ UEDATX = 0;
|
|
|
+ }
|
|
|
+ len -= n;
|
|
|
+ usb_send_in();
|
|
|
+ } while (len || n == ENDPOINT0_SIZE);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ UECONX = (1<<STALLRQ) | (1<<EPEN);
|
|
|
+}
|
|
|
+
|
|
|
+
|