/* USB Keyboard and CDC Serial Device for Teensy USB Development Board * Copyright (c) 2009 PJRC.COM, LLC * Modifications by Jacob Alexander (2011-2014) * * 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. */ // Local Includes #include "usb_keyboard_serial.h" #include // ----- Variables ----- // zero when we are not configured, non-zero when enumerated static volatile uint8_t usb_configuration = 0; // the time remaining before we transmit any partially full // packet, or send a zero length packet. static volatile uint8_t transmit_flush_timer = 0; static uint8_t transmit_previous_timeout = 0; // serial port settings (baud rate, control signals, etc) set // by the PC. These are ignored, but kept in RAM. static uint8_t cdc_line_coding[7] = {0x00, 0xE1, 0x00, 0x00, 0x00, 0x00, 0x08}; static uint8_t cdc_line_rtsdtr = 0; // ----- USB Keyboard Functions ----- // Sends normal keyboard out to host // NOTE: Make sure to match the descriptor void usb_keyboard_toHost() { uint8_t i; // Modifiers UEDATX = USBKeys_Modifiers; // Reserved Byte UEDATX = 0x00; // Normal Keys, only supports 6 in Boot mode for ( i = 0; i < 6; i++) { UEDATX = USBKeys_Keys[i]; } UEINTX = 0x00; } // send the contents of USBKeys_Keys and USBKeys_Modifiers inline void usb_keyboard_send() { uint8_t intr_state, timeout; intr_state = SREG; timeout = UDFNUML + 50; // Ready to transmit keypresses? do { SREG = intr_state; // has the USB gone offline? or exceeded timeout? if ( !usb_configuration || UDFNUML == timeout ) { erro_print("USB Offline? Timeout?"); return; } // get ready to try checking again intr_state = SREG; cli(); // If not using Boot protocol, send NKRO UENUM = USBKeys_Protocol ? KEYBOARD_NKRO_ENDPOINT : KEYBOARD_ENDPOINT; } while ( !( UEINTX & (1 << RWAL) ) ); switch ( USBKeys_Protocol ) { // Send boot keyboard interrupt packet(s) case 0: usb_keyboard_toHost(); USBKeys_Changed = USBKeyChangeState_None; break; // Send NKRO keyboard interrupts packet(s) case 1: // Check system control keys if ( USBKeys_Changed & USBKeyChangeState_System ) { UEDATX = 0x02; // ID UEDATX = USBKeys_SysCtrl; UEINTX = 0; // Finished with ID USBKeys_Changed &= ~USBKeyChangeState_System; // Mark sent } // Check consumer control keys if ( USBKeys_Changed & USBKeyChangeState_Consumer ) { UEDATX = 0x03; // ID UEDATX = (uint8_t)(USBKeys_ConsCtrl & 0x00FF); UEDATX = (uint8_t)(USBKeys_ConsCtrl >> 8); UEINTX = 0; // Finished with ID USBKeys_Changed &= ~USBKeyChangeState_Consumer; // Mark sent } // Standard HID Keyboard if ( USBKeys_Changed ) { UEDATX = 0x01; // ID // Modifiers UEDATX = USBKeys_Modifiers; // 4-49 (first 6 bytes) for ( uint8_t byte = 0; byte < 6; byte++ ) UEDATX = USBKeys_Keys[ byte ]; // 51-155 (Middle 14 bytes) for ( uint8_t byte = 6; byte < 20; byte++ ) UEDATX = USBKeys_Keys[ byte ]; // 157-164 (Next byte) for ( uint8_t byte = 20; byte < 21; byte++ ) UEDATX = USBKeys_Keys[ byte ]; // 176-221 (last 6 bytes) for ( uint8_t byte = 21; byte < 27; byte++ ) UEDATX = USBKeys_Keys[ byte ]; UEINTX = 0; // Finished with ID USBKeys_Changed = USBKeyChangeState_None; // Mark sent } break; } USBKeys_Idle_Count = 0; SREG = intr_state; } // ----- USB Virtual Serial Port (CDC) Functions ----- // get the next character, or -1 if nothing received int16_t usb_serial_getchar() { uint8_t c, intr_state; // interrupts are disabled so these functions can be // used from the main program or interrupt context, // even both in the same program! intr_state = SREG; cli(); if (!usb_configuration) { SREG = intr_state; return -1; } UENUM = CDC_RX_ENDPOINT; retry: c = UEINTX; if (!(c & (1< size) write_size = size; size -= write_size; // write the packet switch (write_size) { #if (CDC_TX_SIZE == 64) case 64: UEDATX = *buffer++; case 63: UEDATX = *buffer++; case 62: UEDATX = *buffer++; case 61: UEDATX = *buffer++; case 60: UEDATX = *buffer++; case 59: UEDATX = *buffer++; case 58: UEDATX = *buffer++; case 57: UEDATX = *buffer++; case 56: UEDATX = *buffer++; case 55: UEDATX = *buffer++; case 54: UEDATX = *buffer++; case 53: UEDATX = *buffer++; case 52: UEDATX = *buffer++; case 51: UEDATX = *buffer++; case 50: UEDATX = *buffer++; case 49: UEDATX = *buffer++; case 48: UEDATX = *buffer++; case 47: UEDATX = *buffer++; case 46: UEDATX = *buffer++; case 45: UEDATX = *buffer++; case 44: UEDATX = *buffer++; case 43: UEDATX = *buffer++; case 42: UEDATX = *buffer++; case 41: UEDATX = *buffer++; case 40: UEDATX = *buffer++; case 39: UEDATX = *buffer++; case 38: UEDATX = *buffer++; case 37: UEDATX = *buffer++; case 36: UEDATX = *buffer++; case 35: UEDATX = *buffer++; case 34: UEDATX = *buffer++; case 33: UEDATX = *buffer++; #endif #if (CDC_TX_SIZE >= 32) case 32: UEDATX = *buffer++; case 31: UEDATX = *buffer++; case 30: UEDATX = *buffer++; case 29: UEDATX = *buffer++; case 28: UEDATX = *buffer++; case 27: UEDATX = *buffer++; case 26: UEDATX = *buffer++; case 25: UEDATX = *buffer++; case 24: UEDATX = *buffer++; case 23: UEDATX = *buffer++; case 22: UEDATX = *buffer++; case 21: UEDATX = *buffer++; case 20: UEDATX = *buffer++; case 19: UEDATX = *buffer++; case 18: UEDATX = *buffer++; case 17: UEDATX = *buffer++; #endif #if (CDC_TX_SIZE >= 16) case 16: UEDATX = *buffer++; case 15: UEDATX = *buffer++; case 14: UEDATX = *buffer++; case 13: UEDATX = *buffer++; case 12: UEDATX = *buffer++; case 11: UEDATX = *buffer++; case 10: UEDATX = *buffer++; case 9: UEDATX = *buffer++; #endif case 8: UEDATX = *buffer++; case 7: UEDATX = *buffer++; case 6: UEDATX = *buffer++; case 5: UEDATX = *buffer++; case 4: UEDATX = *buffer++; case 3: UEDATX = *buffer++; case 2: UEDATX = *buffer++; default: case 1: UEDATX = *buffer++; case 0: break; } // if this completed a packet, transmit it now! if (!(UEINTX & (1<= NUM_DESC_LIST ) { UECONX = (1 << STALLRQ) | (1 << EPEN); //stall 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 { // wait for host ready for IN packet do { i = UEINTX; } while (!(i & ((1<> 8); USBKeys_Idle_Count = 0; usb_send_in(); //print("HID IDLE"); return; } if ( bRequest == HID_SET_PROTOCOL ) { usb_wait_in_ready(); USBKeys_Protocol = wValue; // 0 - Boot Mode, 1 - NKRO Mode usb_send_in(); //print("HID SET"); return; } } } if (bRequest == CDC_GET_LINE_CODING && bmRequestType == 0xA1) { usb_wait_in_ready(); p = cdc_line_coding; for (i=0; i<7; i++) { UEDATX = *p++; } usb_send_in(); return; } if (bRequest == CDC_SET_LINE_CODING && bmRequestType == 0x21) { usb_wait_receive_out(); p = cdc_line_coding; for (i=0; i<7; i++) { *p++ = UEDATX; } usb_ack_out(); usb_send_in(); return; } if (bRequest == CDC_SET_CONTROL_LINE_STATE && bmRequestType == 0x21) { cdc_line_rtsdtr = wValue; usb_wait_in_ready(); usb_send_in(); return; } if (bRequest == GET_STATUS) { usb_wait_in_ready(); i = 0; if (bmRequestType == 0x82) { UENUM = wIndex; if (UECONX & (1<= 1 && i <= MAX_ENDPOINT) { usb_send_in(); UENUM = i; if (bRequest == SET_FEATURE) { UECONX = (1<