changeset 2:c3b2eaa4a89d

Significant progress made. - Only need to decode a bunch more of the matrix to get the proper key assignments - All of the infrastructure is in place for decoding like matrices for the teensy
author Jacob Alexander <triplehaata@gmail.com>
date Wed, 09 Mar 2011 22:49:34 -0800
parents 0f88e9aad77a
children 7b9bde7ba7ef
files Makefile main.c print.c print.h usb_keyboard_debug.c usb_keyboard_debug.h
diffstat 6 files changed, 1240 insertions(+), 28 deletions(-) [+]
line wrap: on
line diff
--- a/Makefile	Mon Mar 07 10:42:32 2011 -0800
+++ b/Makefile	Wed Mar 09 22:49:34 2011 -0800
@@ -46,7 +46,9 @@
 
 # List C source files here. (C dependencies are automatically generated.)
 SRC =	$(TARGET).c \
-	usb_keyboard.c
+	print.c \
+	usb_keyboard_debug.c \
+	#usb_keyboard.c 
 
 
 # MCU name, you MUST set this to match the board you are using
--- a/main.c	Mon Mar 07 10:42:32 2011 -0800
+++ b/main.c	Wed Mar 09 22:49:34 2011 -0800
@@ -23,12 +23,17 @@
 #include <avr/pgmspace.h>
 #include <avr/interrupt.h>
 #include <util/delay.h>
-#include "usb_keyboard.h"
+//#include "usb_keyboard.h"
+
+// TEMP INCLUDES
+#include "usb_keyboard_debug.h"
+#include <print.h>
 
 #define CPU_PRESCALE(n)	(CLKPR = 0x80, CLKPR = (n))
 
-#define PRE_DRIVE_SLEEP
-#define POST_DRIVE_SLEEP
+// Sleep defined in milliseconds
+#define PRE_DRIVE_SLEEP  50
+#define POST_DRIVE_SLEEP 50
 
 
 #define DRIVE_reg_1 PORTB
@@ -57,39 +62,67 @@
 #define DRIVE_pin_11 <blank>
 #define DRIVE_pin_12 <blank>
 
-#define DETECT_group_1 0
-#define DETECT_group_2 0
-#define DETECT_group_3 0
-#define DETECT_group_4 0
-#define DETECT_group_5 0
-#define DETECT_group_6 0
-#define DETECT_group_7 0
-#define DETECT_group_8 0
-#define DETECT_group_9 0
+#define DETECT_group_1 1
+#define DETECT_group_2 2
+#define DETECT_group_3 3
+#define DETECT_group_4 4
+#define DETECT_group_5 5
+#define DETECT_group_6 6
+#define DETECT_group_7 7
+#define DETECT_group_8 8
+#define DETECT_group_9 9
 #define DETECT_group_10 <blank>
 #define DETECT_group_11 <blank>
 #define DETECT_group_12 <blank>
 
-// Change number of ORDs if number of lines differ
+#define DETECT_group_size_1 7
+#define DETECT_group_size_2 8
+#define DETECT_group_size_3 8
+#define DETECT_group_size_4 4
+#define DETECT_group_size_5 8
+#define DETECT_group_size_6 7
+#define DETECT_group_size_7 7
+#define DETECT_group_size_8 6
+#define DETECT_group_size_9 7
+#define DETECT_group_size_10 <blank>
+#define DETECT_group_size_11 <blank>
+#define DETECT_group_size_12 <blank>
+
+#define DETECT_group_array_1 {{KEY_SLASH,KEY_RIGHT_BRACE,KEY_ENTER,KEY_D,KEY_2,KEY_Q,KEY_C},{0,0,0,0,0,0,0}}
+#define DETECT_group_array_2 {{KEY_TILDE,KEY_DELETE,KEY_LEFT,KEY_SPACE,KEY_X,KEY_S,KEY_TAB,KEY_1},{0,0,0,0,0,0,0,0}}
+#define DETECT_group_array_3 {{KEY_BACKSPACE,KEY_UP,KEY_DOWN,KEY_A,KEY_INSERT,KEY_ALT,KEY_Z,KEY_RIGHT},{0,0,0,0,0,1,0,0}}
+#define DETECT_group_array_4 {{KEY_ESC  ,KEY_CTRL,KEY_CAPS_LOCK,KEY_SHIFT}                  ,{0,1,0,1}}
+#define DETECT_group_array_5 0
+#define DETECT_group_array_6 0
+#define DETECT_group_array_7 {{KEY_L    ,KEY_O   ,KEY_0        ,KEY_N    ,KEY_H,KEY_R,KEY_5},{0,0,0,0,0,0,0}}
+#define DETECT_group_array_8 0
+#define DETECT_group_array_9 0
+#define DETECT_group_array_10 <blank>
+#define DETECT_group_array_11 <blank>
+#define DETECT_group_array_12 <blank>
+
+
+
+
+
+
+
+// XXX Change number of ORDs if number of lines differ
 #define DD_LOOP \
-			for ( int c = 0;; c++ ) { \
+			for ( int c = 1;; c++ ) { \
 				switch ( c ) { \
 					DD_CASE_ORD(1) \
 					DD_CASE_ORD(2) \
 					DD_CASE_ORD(3) \
-					DD_CASE_ORD(4) \
-					DD_CASE_ORD(5) \
-					DD_CASE_ORD(6) \
-					DD_CASE_ORD(7) \
-					DD_CASE_ORD(8) \
-					DD_CASE_END(9,c) \
+					DD_CASE_END(4,c) \
 				} \
 			}
 
 #define DRIVE_DETECT(reg,pin,group) \
-			reg |= (1 << pin);\
-			detection(group);\
-			reg &= (0 << pin);
+			reg &= ~(1 << pin); \
+			detection(group); \
+			reg |= (1 << pin); \
+			_delay_ms(POST_DRIVE_SLEEP);
 
 #define DD_CASE(number) \
 			case number:\
@@ -101,18 +134,164 @@
 
 #define DD_CASE_END(number,var) \
 			DD_CASE(number) \
-			default: \
 			var = -1; \
 			break;
 
-int main(void)
+// Determine if key is either normal or a modifier
+#define DET_GROUP_CHECK(index) \
+			{ \
+			if ( groupArray[1][index] ) \
+				curDetect.modifiers |= groupArray[0][index]; \
+			else \
+				curDetect.keyDetectArray[curDetect.keyDetectCount++] = groupArray[0][index]; \
+			}
+
+// XXX - Detection Groups
+// Checks each of the specified pins, and then if press detected, determine if the key is normal or a modifier
+// Inverse logic applies for the PINs
+
+// Used for 1 detection group
+#define DET_GROUP_1 \
+			if ( !( PINB & (1 << 3) ) ) \
+				DET_GROUP_CHECK(3) \
+			if ( !( PINF & (1 << 1) ) ) \
+				DET_GROUP_CHECK(2) \
+			if ( !( PINF & (1 << 2) ) ) \
+				DET_GROUP_CHECK(1) \
+			if ( !( PINF & (1 << 3) ) ) \
+				DET_GROUP_CHECK(0)
+
+// Used for 4 detection groups
+#define DET_GROUP_2 \
+			if ( !( PINC & (1 << 0) ) ) \
+				DET_GROUP_CHECK(0) \
+			if ( !( PINC & (1 << 1) ) ) \
+				DET_GROUP_CHECK(1) \
+			if ( !( PINC & (1 << 2) ) ) \
+				DET_GROUP_CHECK(2) \
+			if ( !( PINC & (1 << 3) ) ) \
+				DET_GROUP_CHECK(3) \
+			if ( !( PINC & (1 << 4) ) ) \
+				DET_GROUP_CHECK(4) \
+			if ( !( PINC & (1 << 5) ) ) \
+				DET_GROUP_CHECK(5) \
+			if ( !( PINC & (1 << 6) ) ) \
+				DET_GROUP_CHECK(6) \
+
+// Used for 1 detection group
+#define DET_GROUP_3 \
+			if ( !( PINC & (1 << 0) ) ) \
+				DET_GROUP_CHECK(0) \
+			if ( !( PINC & (1 << 1) ) ) \
+				DET_GROUP_CHECK(1) \
+			if ( !( PINC & (1 << 2) ) ) \
+				DET_GROUP_CHECK(3) \
+			if ( !( PINC & (1 << 4) ) ) \
+				DET_GROUP_CHECK(4) \
+			if ( !( PINC & (1 << 5) ) ) \
+				DET_GROUP_CHECK(5) \
+			if ( !( PINC & (1 << 6) ) ) \
+				DET_GROUP_CHECK(6) \
+
+// Used for 3 detection groups
+#define DET_GROUP_4 \
+			if ( !( PINC & (1 << 0) ) ) \
+				DET_GROUP_CHECK(0) \
+			if ( !( PINC & (1 << 1) ) ) \
+				DET_GROUP_CHECK(1) \
+			if ( !( PINC & (1 << 2) ) ) \
+				DET_GROUP_CHECK(2) \
+			if ( !( PINC & (1 << 3) ) ) \
+				DET_GROUP_CHECK(3) \
+			if ( !( PINC & (1 << 4) ) ) \
+				DET_GROUP_CHECK(4) \
+			if ( !( PINC & (1 << 5) ) ) \
+				DET_GROUP_CHECK(5) \
+			if ( !( PINC & (1 << 6) ) ) \
+				DET_GROUP_CHECK(6) \
+			if ( !( PINE & (1 << 1) ) ) \
+				DET_GROUP_CHECK(7) \
+
+// Combines the DET_GROUP_Xs above for the given groupArray
+#define DET_GROUP(group,det_group) \
+			case group: \
+				{ \
+					uint8_t groupArray[2][DETECT_group_size##_##group] = DETECT_group_array##_##group; \
+					DET_GROUP##_##det_group \
+				} \
+				break;
+
+struct keys {
+	uint8_t keyDetectCount;
+	uint8_t keyDetectArray[40];
+	uint8_t modifiers;
+} curDetect, prevDetect;
+
+void detection( int group )
+{
+	_delay_ms(PRE_DRIVE_SLEEP);
+	curDetect.keyDetectCount = 0;
+	curDetect.modifiers = 0;
+
+	// XXX Modify for different detection groups <-> groupArray mappings
+	switch ( group ) {
+		DET_GROUP(1,2)
+		DET_GROUP(2,4)
+		DET_GROUP(3,4)
+		DET_GROUP(4,1)
+		//DET_GROUP(5,4)
+		//DET_GROUP(6,2)
+		//DET_GROUP(7,2)
+		//DET_GROUP(8,3)
+		//DET_GROUP(9,2)
+	}
+
+
+	// Print out the current keys pressed
+	if ( curDetect.keyDetectCount > 0 ) {
+		print("Keys: ");
+		for ( int c = 0; c < curDetect.keyDetectCount; c++ ) {
+			phex( curDetect.keyDetectArray[c] );
+			print(" ");
+		}
+		print("\n");
+	}
+	if ( curDetect.modifiers ) {
+		print("Modifiers: ");
+		phex( curDetect.modifiers );
+		print("\n");
+	}
+}
+
+
+
+// XXX This part is configurable
+void pinSetup(void)
+{
+	// For each pin, 0=input, 1=output
+	DDRA = 0x00;
+	DDRB = 0x07;
+	DDRC = 0x80;
+	DDRD = 0x00;
+	DDRE = 0xC0;
+	DDRF = 0x31;
+
+	// Setting pins to either high or pull-up resistor
+	PORTA = 0x00;
+	PORTB = 0xFF;
+	PORTC = 0xFF;
+	PORTD = 0x00;
+	PORTE = 0xFF;
+	PORTF = 0xFF;
+}
+
+int main( void )
 {
 	// set for 16 MHz clock
 	CPU_PRESCALE( 0 );
 
 	// Configuring Pins
-
-	// TODO
+	pinSetup();
 
 	// Initialize the USB, and then wait for the host to set configuration.
 	// If the Teensy is powered without a PC connected to the USB port,
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/print.c	Wed Mar 09 22:49:34 2011 -0800
@@ -0,0 +1,62 @@
+/* Very basic print functions, intended to be used with usb_debug_only.c
+ * http://www.pjrc.com/teensy/
+ * Copyright (c) 2008 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.
+ */
+
+// Version 1.0: Initial Release
+
+#include <avr/io.h>
+#include <avr/pgmspace.h>
+
+#include "print.h"
+
+void print_P(const char *s)
+{
+	char c;
+
+	while (1) {
+		c = pgm_read_byte(s++);
+		if (!c) break;
+		if (c == '\n') usb_debug_putchar('\r');
+		usb_debug_putchar(c);
+	}
+}
+
+void phex1(unsigned char c)
+{
+	usb_debug_putchar(c + ((c < 10) ? '0' : 'A' - 10));
+}
+
+void phex(unsigned char c)
+{
+	phex1(c >> 4);
+	phex1(c & 15);
+}
+
+void phex16(unsigned int i)
+{
+	phex(i >> 8);
+	phex(i);
+}
+
+
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/print.h	Wed Mar 09 22:49:34 2011 -0800
@@ -0,0 +1,16 @@
+#ifndef print_h__
+#define print_h__
+
+#include <avr/pgmspace.h>
+#include "usb_keyboard_debug.h"
+
+// this macro allows you to write print("some text") and
+// the string is automatically placed into flash memory :)
+#define print(s) print_P(PSTR(s))
+#define pchar(c) usb_debug_putchar(c)
+
+void print_P(const char *s);
+void phex(unsigned char c);
+void phex16(unsigned int i);
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usb_keyboard_debug.c	Wed Mar 09 22:49:34 2011 -0800
@@ -0,0 +1,750 @@
+/* USB Keyboard Plus Debug Channel Example for Teensy USB Development Board
+ * http://www.pjrc.com/teensy/usb_keyboard.html
+ * 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.
+ */
+
+// Version 1.0: Initial Release
+// Version 1.1: Add support for Teensy 2.0
+
+#define USB_SERIAL_PRIVATE_INCLUDE
+#include "usb_keyboard_debug.h"
+
+/**************************************************************************
+ *
+ *  Configurable Options
+ *
+ **************************************************************************/
+
+// You can change these to give your code its own name.
+#define STR_MANUFACTURER	L"MfgName"
+#define STR_PRODUCT		L"Keyboard"
+
+
+// Mac OS-X and Linux automatically load the correct drivers.  On
+// Windows, even though the driver is supplied by Microsoft, an
+// INF file is needed to load the driver.  These numbers need to
+// match the INF file.
+#define VENDOR_ID		0x16C0
+#define PRODUCT_ID		0x047D
+
+
+// USB devices are supposed to implment a halt feature, which is
+// rarely (if ever) used.  If you comment this line out, the halt
+// code will be removed, saving 102 bytes of space (gcc 4.3.0).
+// This is not strictly USB compliant, but works with all major
+// operating systems.
+#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
+ *
+ **************************************************************************/
+
+// Descriptors are the data that your computer reads when it auto-detects
+// this USB device (called "enumeration" in USB lingo).  The most commonly
+// changed items are editable at the top of this file.  Changing things
+// in here should only be done by those who've read chapter 9 of the USB
+// spec and relevant portions of any USB class specifications!
+
+
+static uint8_t PROGMEM device_descriptor[] = {
+	18,					// bLength
+	1,					// bDescriptorType
+	0x00, 0x02,				// bcdUSB
+	0,					// bDeviceClass
+	0,					// bDeviceSubClass
+	0,					// bDeviceProtocol
+	ENDPOINT0_SIZE,				// bMaxPacketSize0
+	LSB(VENDOR_ID), MSB(VENDOR_ID),		// idVendor
+	LSB(PRODUCT_ID), MSB(PRODUCT_ID),	// idProduct
+	0x00, 0x01,				// bcdDevice
+	1,					// iManufacturer
+	2,					// iProduct
+	0,					// iSerialNumber
+	1					// bNumConfigurations
+};
+
+// Keyboard Protocol 1, HID 1.11 spec, Appendix B, page 59-60
+static uint8_t PROGMEM keyboard_hid_report_desc[] = {
+        0x05, 0x01,          // Usage Page (Generic Desktop),
+        0x09, 0x06,          // Usage (Keyboard),
+        0xA1, 0x01,          // Collection (Application),
+        0x75, 0x01,          //   Report Size (1),
+        0x95, 0x08,          //   Report Count (8),
+        0x05, 0x07,          //   Usage Page (Key Codes),
+        0x19, 0xE0,          //   Usage Minimum (224),
+        0x29, 0xE7,          //   Usage Maximum (231),
+        0x15, 0x00,          //   Logical Minimum (0),
+        0x25, 0x01,          //   Logical Maximum (1),
+        0x81, 0x02,          //   Input (Data, Variable, Absolute), ;Modifier byte
+        0x95, 0x01,          //   Report Count (1),
+        0x75, 0x08,          //   Report Size (8),
+        0x81, 0x03,          //   Input (Constant),                 ;Reserved byte
+        0x95, 0x05,          //   Report Count (5),
+        0x75, 0x01,          //   Report Size (1),
+        0x05, 0x08,          //   Usage Page (LEDs),
+        0x19, 0x01,          //   Usage Minimum (1),
+        0x29, 0x05,          //   Usage Maximum (5),
+        0x91, 0x02,          //   Output (Data, Variable, Absolute), ;LED report
+        0x95, 0x01,          //   Report Count (1),
+        0x75, 0x03,          //   Report Size (3),
+        0x91, 0x03,          //   Output (Constant),                 ;LED report padding
+        0x95, 0x06,          //   Report Count (6),
+        0x75, 0x08,          //   Report Size (8),
+        0x15, 0x00,          //   Logical Minimum (0),
+        0x25, 0x68,          //   Logical Maximum(104),
+        0x05, 0x07,          //   Usage Page (Key Codes),
+        0x19, 0x00,          //   Usage Minimum (0),
+        0x29, 0x68,          //   Usage Maximum (104),
+        0x81, 0x00,          //   Input (Data, Array),
+        0xc0                 // End Collection
+};
+
+static uint8_t PROGMEM debug_hid_report_desc[] = {
+	0x06, 0x31, 0xFF,			// Usage Page 0xFF31 (vendor defined)
+	0x09, 0x74,				// Usage 0x74
+	0xA1, 0x53,				// Collection 0x53
+	0x75, 0x08,				// report size = 8 bits
+	0x15, 0x00,				// logical minimum = 0
+	0x26, 0xFF, 0x00,			// logical maximum = 255
+	0x95, DEBUG_TX_SIZE,			// report count
+	0x09, 0x75,				// usage
+	0x81, 0x02,				// Input (array)
+	0xC0					// end collection
+};
+
+#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] = {
+	// configuration descriptor, USB spec 9.6.3, page 264-266, Table 9-10
+	9, 					// bLength;
+	2,					// bDescriptorType;
+	LSB(CONFIG1_DESC_SIZE),			// wTotalLength
+	MSB(CONFIG1_DESC_SIZE),
+	2,					// bNumInterfaces
+	1,					// bConfigurationValue
+	0,					// iConfiguration
+	0xC0,					// bmAttributes
+	50,					// bMaxPower
+	// interface descriptor, USB spec 9.6.5, page 267-269, Table 9-12
+	9,					// bLength
+	4,					// bDescriptorType
+	KEYBOARD_INTERFACE,			// bInterfaceNumber
+	0,					// bAlternateSetting
+	1,					// bNumEndpoints
+	0x03,					// bInterfaceClass (0x03 = HID)
+	0x01,					// bInterfaceSubClass (0x01 = Boot)
+	0x01,					// bInterfaceProtocol (0x01 = Keyboard)
+	0,					// iInterface
+	// HID interface descriptor, HID 1.11 spec, section 6.2.1
+	9,					// bLength
+	0x21,					// bDescriptorType
+	0x11, 0x01,				// bcdHID
+	0,					// bCountryCode
+	1,					// bNumDescriptors
+	0x22,					// bDescriptorType
+	sizeof(keyboard_hid_report_desc),	// wDescriptorLength
+	0,
+	// endpoint descriptor, USB spec 9.6.6, page 269-271, Table 9-13
+	7,					// bLength
+	5,					// bDescriptorType
+	KEYBOARD_ENDPOINT | 0x80,		// bEndpointAddress
+	0x03,					// bmAttributes (0x03=intr)
+	KEYBOARD_SIZE, 0,			// wMaxPacketSize
+	1,					// bInterval
+	// interface descriptor, USB spec 9.6.5, page 267-269, Table 9-12
+	9,					// bLength
+	4,					// bDescriptorType
+	DEBUG_INTERFACE,			// bInterfaceNumber
+	0,					// bAlternateSetting
+	1,					// bNumEndpoints
+	0x03,					// bInterfaceClass (0x03 = HID)
+	0x00,					// bInterfaceSubClass
+	0x00,					// bInterfaceProtocol
+	0,					// iInterface
+	// HID interface descriptor, HID 1.11 spec, section 6.2.1
+	9,					// bLength
+	0x21,					// bDescriptorType
+	0x11, 0x01,				// bcdHID
+	0,					// bCountryCode
+	1,					// bNumDescriptors
+	0x22,					// bDescriptorType
+	sizeof(debug_hid_report_desc),		// wDescriptorLength
+	0,
+	// endpoint descriptor, USB spec 9.6.6, page 269-271, Table 9-13
+	7,					// bLength
+	5,					// bDescriptorType
+	DEBUG_TX_ENDPOINT | 0x80,		// bEndpointAddress
+	0x03,					// bmAttributes (0x03=intr)
+	DEBUG_TX_SIZE, 0,			// wMaxPacketSize
+	1					// bInterval
+};
+
+// If you're desperate for a little extra code memory, these strings
+// can be completely removed if iManufacturer, iProduct, iSerialNumber
+// in the device desciptor are changed to zeros.
+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
+};
+
+// This table defines which descriptor data is sent for each specific
+// request from the host (in wValue and wIndex).
+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
+ *
+ **************************************************************************/
+
+// 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 debug_flush_timer=0;
+
+// which modifier keys are currently pressed
+// 1=left ctrl,    2=left shift,   4=left alt,    8=left gui
+// 16=right ctrl, 32=right shift, 64=right alt, 128=right gui
+uint8_t keyboard_modifier_keys=0;
+
+// which keys are currently pressed, up to 6 keys may be down at once
+uint8_t keyboard_keys[6]={0,0,0,0,0,0};
+
+// protocol setting from the host.  We use exactly the same report
+// either way, so this variable only stores the setting since we
+// are required to be able to report which setting is in use.
+static uint8_t keyboard_protocol=1;
+
+// the idle configuration, how often we send the report to the
+// host (ms * 4) even when it hasn't changed
+static uint8_t keyboard_idle_config=125;
+
+// count until idle timeout
+static uint8_t keyboard_idle_count=0;
+
+// 1=num lock, 2=caps lock, 4=scroll lock, 8=compose, 16=kana
+volatile uint8_t keyboard_leds=0;
+
+
+/**************************************************************************
+ *
+ *  Public Functions - these are the API intended for the user
+ *
+ **************************************************************************/
+
+
+// initialize USB
+void usb_init(void)
+{
+	HW_CONFIG();
+	USB_FREEZE();				// enable USB
+	PLL_CONFIG();				// config PLL
+        while (!(PLLCSR & (1<<PLOCK))) ;	// wait for PLL lock
+        USB_CONFIG();				// start USB clock
+        UDCON = 0;				// enable attach resistor
+	usb_configuration = 0;
+        UDIEN = (1<<EORSTE)|(1<<SOFE);
+	sei();
+}
+
+// return 0 if the USB is not configured, or the configuration
+// number selected by the HOST
+uint8_t usb_configured(void)
+{
+	return usb_configuration;
+}
+
+
+// perform a single keystroke
+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();
+}
+
+// send the contents of keyboard_keys and keyboard_modifier_keys
+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) {
+		// are we ready to transmit?
+		if (UEINTX & (1<<RWAL)) break;
+		SREG = intr_state;
+		// has the USB gone offline?
+		if (!usb_configuration) return -1;
+		// have we waited too long?
+		if (UDFNUML == timeout) return -1;
+		// get ready to try checking again
+		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;
+}
+
+// transmit a character.  0 returned on success, -1 on error
+int8_t usb_debug_putchar(uint8_t c)
+{
+	static uint8_t previous_timeout=0;
+	uint8_t timeout, intr_state;
+
+	// if we're not online (enumerated and configured), error
+	if (!usb_configuration) return -1;
+	// 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();
+	UENUM = DEBUG_TX_ENDPOINT;
+	// if we gave up due to timeout before, don't wait again
+	if (previous_timeout) {
+		if (!(UEINTX & (1<<RWAL))) {
+			SREG = intr_state;
+			return -1;
+		}
+		previous_timeout = 0;
+	}
+	// wait for the FIFO to be ready to accept data
+	timeout = UDFNUML + 4;
+	while (1) {
+		// are we ready to transmit?
+		if (UEINTX & (1<<RWAL)) break;
+		SREG = intr_state;
+		// have we waited too long?
+		if (UDFNUML == timeout) {
+			previous_timeout = 1;
+			return -1;
+		}
+		// has the USB gone offline?
+		if (!usb_configuration) return -1;
+		// get ready to try checking again
+		intr_state = SREG;
+		cli();
+		UENUM = DEBUG_TX_ENDPOINT;
+	}
+	// actually write the byte into the FIFO
+	UEDATX = c;
+	// if this completed a packet, transmit it now!
+	if (!(UEINTX & (1<<RWAL))) {
+		UEINTX = 0x3A;
+		debug_flush_timer = 0;
+	} else {
+		debug_flush_timer = 2;
+	}
+	SREG = intr_state;
+	return 0;
+}
+
+
+// immediately transmit any buffered output.
+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....
+ *
+ **************************************************************************/
+
+
+
+// USB Device Interrupt - handle all device-level events
+// the transmit buffer flushing is triggered by the start of frame
+//
+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;
+				}
+			}
+		}
+	}
+}
+
+
+
+// Misc functions to wait for ready and send/receive packets
+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);
+}
+
+
+
+// USB Endpoint Interrupt - endpoint 0 is handled here.  The
+// other endpoints are manipulated by the user-callable
+// functions, and the start-of-frame interrupt.
+//
+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);  //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<<TXINI)|(1<<RXOUTI))));
+				if (i & (1<<RXOUTI)) return;	// abort
+				// send IN packet
+				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_wait_in_ready();
+					usb_send_in();
+					return;
+				}
+				if (bRequest == HID_SET_PROTOCOL) {
+					keyboard_protocol = wValue;
+					//usb_wait_in_ready();
+					usb_send_in();
+					return;
+				}
+			}
+		}
+		if (wIndex == DEBUG_INTERFACE) {
+			if (bRequest == HID_GET_REPORT && bmRequestType == 0xA1) {
+				len = wLength;
+				do {
+					// wait for host ready for IN packet
+					do {
+						i = UEINTX;
+					} while (!(i & ((1<<TXINI)|(1<<RXOUTI))));
+					if (i & (1<<RXOUTI)) return;	// abort
+					// send IN packet
+					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);	// stall
+}
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usb_keyboard_debug.h	Wed Mar 09 22:49:34 2011 -0800
@@ -0,0 +1,203 @@
+#ifndef usb_serial_h__
+#define usb_serial_h__
+
+#include <stdint.h>
+
+void usb_init(void);			// initialize everything
+uint8_t usb_configured(void);		// is the USB port configured
+
+int8_t usb_keyboard_press(uint8_t key, uint8_t modifier);
+int8_t usb_keyboard_send(void);
+extern uint8_t keyboard_modifier_keys;
+extern uint8_t keyboard_keys[6];
+extern volatile uint8_t keyboard_leds;
+
+int8_t usb_debug_putchar(uint8_t c);	// transmit a character
+void usb_debug_flush_output(void);	// immediately transmit any buffered output
+#define USB_DEBUG_HID
+
+#define KEY_CTRL	0x01
+#define KEY_SHIFT	0x02
+#define KEY_ALT		0x04
+#define KEY_GUI		0x08
+#define KEY_LEFT_CTRL	0x01
+#define KEY_LEFT_SHIFT	0x02
+#define KEY_LEFT_ALT	0x04
+#define KEY_LEFT_GUI	0x08
+#define KEY_RIGHT_CTRL	0x10
+#define KEY_RIGHT_SHIFT	0x20
+#define KEY_RIGHT_ALT	0x40
+#define KEY_RIGHT_GUI	0x80
+
+#define KEY_A		4
+#define KEY_B		5
+#define KEY_C		6
+#define KEY_D		7
+#define KEY_E		8
+#define KEY_F		9
+#define KEY_G		10
+#define KEY_H		11
+#define KEY_I		12
+#define KEY_J		13
+#define KEY_K		14
+#define KEY_L		15
+#define KEY_M		16
+#define KEY_N		17
+#define KEY_O		18
+#define KEY_P		19
+#define KEY_Q		20
+#define KEY_R		21
+#define KEY_S		22
+#define KEY_T		23
+#define KEY_U		24
+#define KEY_V		25
+#define KEY_W		26
+#define KEY_X		27
+#define KEY_Y		28
+#define KEY_Z		29
+#define KEY_1		30
+#define KEY_2		31
+#define KEY_3		32
+#define KEY_4		33
+#define KEY_5		34
+#define KEY_6		35
+#define KEY_7		36
+#define KEY_8		37
+#define KEY_9		38
+#define KEY_0		39
+#define KEY_ENTER	40	
+#define KEY_ESC		41
+#define KEY_BACKSPACE	42	
+#define KEY_TAB		43
+#define KEY_SPACE	44	
+#define KEY_MINUS	45
+#define KEY_EQUAL	46
+#define KEY_LEFT_BRACE	47
+#define KEY_RIGHT_BRACE	48
+#define KEY_BACKSLASH	49
+#define KEY_NUMBER	50
+#define KEY_SEMICOLON	51
+#define KEY_QUOTE	52
+#define KEY_TILDE	53
+#define KEY_COMMA	54
+#define KEY_PERIOD	55
+#define KEY_SLASH	56
+#define KEY_CAPS_LOCK	57
+#define KEY_F1		58
+#define KEY_F2		59
+#define KEY_F3		60
+#define KEY_F4		61
+#define KEY_F5		62
+#define KEY_F6		63
+#define KEY_F7		64
+#define KEY_F8		65
+#define KEY_F9		66
+#define KEY_F10		67
+#define KEY_F11		68
+#define KEY_F12		69
+#define KEY_PRINTSCREEN	70		
+#define KEY_SCROLL_LOCK	71		
+#define KEY_PAUSE	72
+#define KEY_INSERT	73	
+#define KEY_HOME	74
+#define KEY_PAGE_UP	75
+#define KEY_DELETE	76
+#define KEY_END		77
+#define KEY_PAGE_DOWN	78	
+#define KEY_RIGHT	79
+#define KEY_LEFT	80
+#define KEY_DOWN	81
+#define KEY_UP		82
+#define KEY_NUM_LOCK	83
+#define KEYPAD_SLASH	84	
+#define KEYPAD_ASTERIX	85	
+#define KEYPAD_MINUS	86	
+#define KEYPAD_PLUS	87	
+#define KEYPAD_ENTER	88	
+#define KEYPAD_1	89
+#define KEYPAD_2	90
+#define KEYPAD_3	91	
+#define KEYPAD_4	92	
+#define KEYPAD_5	93	
+#define KEYPAD_6	94	
+#define KEYPAD_7	95	
+#define KEYPAD_8	96	
+#define KEYPAD_9	97	
+#define KEYPAD_0	98		
+#define KEYPAD_PERIOD	99		
+
+
+
+
+// Everything below this point is only intended for usb_serial.c
+#ifdef USB_SERIAL_PRIVATE_INCLUDE
+#include <avr/io.h>
+#include <avr/pgmspace.h>
+#include <avr/interrupt.h>
+
+#define EP_TYPE_CONTROL			0x00
+#define EP_TYPE_BULK_IN			0x81
+#define EP_TYPE_BULK_OUT		0x80
+#define EP_TYPE_INTERRUPT_IN		0xC1
+#define EP_TYPE_INTERRUPT_OUT		0xC0
+#define EP_TYPE_ISOCHRONOUS_IN		0x41
+#define EP_TYPE_ISOCHRONOUS_OUT		0x40
+
+#define EP_SINGLE_BUFFER		0x02
+#define EP_DOUBLE_BUFFER		0x06
+
+#define EP_SIZE(s)	((s) == 64 ? 0x30 :	\
+			((s) == 32 ? 0x20 :	\
+			((s) == 16 ? 0x10 :	\
+			             0x00)))
+
+#define MAX_ENDPOINT		4
+
+#define LSB(n) (n & 255)
+#define MSB(n) ((n >> 8) & 255)
+
+#if defined(__AVR_AT90USB162__)
+#define HW_CONFIG() 
+#define PLL_CONFIG() (PLLCSR = ((1<<PLLE)|(1<<PLLP0)))
+#define USB_CONFIG() (USBCON = (1<<USBE))
+#define USB_FREEZE() (USBCON = ((1<<USBE)|(1<<FRZCLK)))
+#elif defined(__AVR_ATmega32U4__)
+#define HW_CONFIG() (UHWCON = 0x01)
+#define PLL_CONFIG() (PLLCSR = 0x12)
+#define USB_CONFIG() (USBCON = ((1<<USBE)|(1<<OTGPADE)))
+#define USB_FREEZE() (USBCON = ((1<<USBE)|(1<<FRZCLK)))
+#elif defined(__AVR_AT90USB646__)
+#define HW_CONFIG() (UHWCON = 0x81)
+#define PLL_CONFIG() (PLLCSR = 0x1A)
+#define USB_CONFIG() (USBCON = ((1<<USBE)|(1<<OTGPADE)))
+#define USB_FREEZE() (USBCON = ((1<<USBE)|(1<<FRZCLK)))
+#elif defined(__AVR_AT90USB1286__)
+#define HW_CONFIG() (UHWCON = 0x81)
+#define PLL_CONFIG() (PLLCSR = 0x16)
+#define USB_CONFIG() (USBCON = ((1<<USBE)|(1<<OTGPADE)))
+#define USB_FREEZE() (USBCON = ((1<<USBE)|(1<<FRZCLK)))
+#endif
+
+// standard control endpoint request types
+#define GET_STATUS			0
+#define CLEAR_FEATURE			1
+#define SET_FEATURE			3
+#define SET_ADDRESS			5
+#define GET_DESCRIPTOR			6
+#define GET_CONFIGURATION		8
+#define SET_CONFIGURATION		9
+#define GET_INTERFACE			10
+#define SET_INTERFACE			11
+// HID (human interface device)
+#define HID_GET_REPORT			1
+#define HID_GET_IDLE			2
+#define HID_GET_PROTOCOL		3
+#define HID_SET_REPORT			9
+#define HID_SET_IDLE			10
+#define HID_SET_PROTOCOL		11
+// CDC (communication class device)
+#define CDC_SET_LINE_CODING		0x20
+#define CDC_GET_LINE_CODING		0x21
+#define CDC_SET_CONTROL_LINE_STATE	0x22
+#endif
+#endif