mirror of
				https://github.com/mfulz/qmk_firmware.git
				synced 2025-10-31 13:22:31 +01:00 
			
		
		
		
	encoder, dip update, adds bootloader
This commit is contained in:
		
							parent
							
								
									d24132ce71
								
							
						
					
					
						commit
						0236f6a8ac
					
				| @ -285,11 +285,11 @@ void encoder_update(uint8_t index, bool clockwise) { | |||||||
|       } |       } | ||||||
|     } else { |     } else { | ||||||
|       if (clockwise) { |       if (clockwise) { | ||||||
|         register_code(KC_MS_WH_DOWN); |         register_code(KC_MS_DOWN); | ||||||
|         unregister_code(KC_MS_WH_DOWN); |         unregister_code(KC_MS_DOWN); | ||||||
|       } else { |       } else { | ||||||
|         register_code(KC_MS_WH_UP); |         register_code(KC_MS_UP); | ||||||
|         unregister_code(KC_MS_WH_UP); |         unregister_code(KC_MS_UP); | ||||||
|       } |       } | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
|  | |||||||
							
								
								
									
										124
									
								
								keyboards/planck/thk/bootloader/bootloaderconfig.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										124
									
								
								keyboards/planck/thk/bootloader/bootloaderconfig.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,124 @@ | |||||||
|  | /* Name: bootloaderconfig.h
 | ||||||
|  |  * Project: AVR bootloader HID | ||||||
|  |  * Author: Christian Starkjohann | ||||||
|  |  * Creation Date: 2007-03-19 | ||||||
|  |  * Tabsize: 4 | ||||||
|  |  * Copyright: (c) 2007 by OBJECTIVE DEVELOPMENT Software GmbH | ||||||
|  |  * License: GNU GPL v2 (see License.txt) | ||||||
|  |  * This Revision: $Id$ | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | #ifndef __bootloaderconfig_h_included__ | ||||||
|  | #define __bootloaderconfig_h_included__ | ||||||
|  | 
 | ||||||
|  | /*
 | ||||||
|  | General Description: | ||||||
|  | This file (together with some settings in Makefile) configures the boot loader | ||||||
|  | according to the hardware. | ||||||
|  | 
 | ||||||
|  | This file contains (besides the hardware configuration normally found in | ||||||
|  | usbconfig.h) two functions or macros: bootLoaderInit() and | ||||||
|  | bootLoaderCondition(). Whether you implement them as macros or as static | ||||||
|  | inline functions is up to you, decide based on code size and convenience. | ||||||
|  | 
 | ||||||
|  | bootLoaderInit() is called as one of the first actions after reset. It should | ||||||
|  | be a minimum initialization of the hardware so that the boot loader condition | ||||||
|  | can be read. This will usually consist of activating a pull-up resistor for an | ||||||
|  | external jumper which selects boot loader mode. You may call leaveBootloader() | ||||||
|  | from this function if you know that the main code should run. | ||||||
|  | 
 | ||||||
|  | bootLoaderCondition() is called immediately after initialization and in each | ||||||
|  | main loop iteration. If it returns TRUE, the boot loader will be active. If it | ||||||
|  | returns FALSE, the boot loader jumps to address 0 (the loaded application) | ||||||
|  | immediately. | ||||||
|  | 
 | ||||||
|  | For compatibility with Thomas Fischl's avrusbboot, we also support the macro | ||||||
|  | names BOOTLOADER_INIT and BOOTLOADER_CONDITION for this functionality. If | ||||||
|  | these macros are defined, the boot loader usees them. | ||||||
|  | */ | ||||||
|  | 
 | ||||||
|  | /* ---------------------------- Hardware Config ---------------------------- */ | ||||||
|  | 
 | ||||||
|  | #define USB_CFG_IOPORTNAME      D | ||||||
|  | /* This is the port where the USB bus is connected. When you configure it to
 | ||||||
|  |  * "B", the registers PORTB, PINB and DDRB will be used. | ||||||
|  |  */ | ||||||
|  | #define USB_CFG_DMINUS_BIT      3 | ||||||
|  | /* This is the bit number in USB_CFG_IOPORT where the USB D- line is connected.
 | ||||||
|  |  * This may be any bit in the port. | ||||||
|  |  */ | ||||||
|  | #define USB_CFG_DPLUS_BIT       2 | ||||||
|  | /* This is the bit number in USB_CFG_IOPORT where the USB D+ line is connected.
 | ||||||
|  |  * This may be any bit in the port. Please note that D+ must also be connected | ||||||
|  |  * to interrupt pin INT0! [You can also use other interrupts, see section | ||||||
|  |  * "Optional MCU Description" below, or you can connect D- to the interrupt, as | ||||||
|  |  * it is required if you use the USB_COUNT_SOF feature. If you use D- for the | ||||||
|  |  * interrupt, the USB interrupt will also be triggered at Start-Of-Frame | ||||||
|  |  * markers every millisecond.] | ||||||
|  |  */ | ||||||
|  | #define USB_CFG_CLOCK_KHZ       (F_CPU/1000) | ||||||
|  | /* Clock rate of the AVR in MHz. Legal values are 12000, 12800, 15000, 16000,
 | ||||||
|  |  * 16500 and 20000. The 12.8 MHz and 16.5 MHz versions of the code require no | ||||||
|  |  * crystal, they tolerate +/- 1% deviation from the nominal frequency. All | ||||||
|  |  * other rates require a precision of 2000 ppm and thus a crystal! | ||||||
|  |  * Default if not specified: 12 MHz | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | /* ----------------------- Optional Hardware Config ------------------------ */ | ||||||
|  | 
 | ||||||
|  | /* #define USB_CFG_PULLUP_IOPORTNAME   D */ | ||||||
|  | /* If you connect the 1.5k pullup resistor from D- to a port pin instead of
 | ||||||
|  |  * V+, you can connect and disconnect the device from firmware by calling | ||||||
|  |  * the macros usbDeviceConnect() and usbDeviceDisconnect() (see usbdrv.h). | ||||||
|  |  * This constant defines the port on which the pullup resistor is connected. | ||||||
|  |  */ | ||||||
|  | /* #define USB_CFG_PULLUP_BIT          4 */ | ||||||
|  | /* This constant defines the bit number in USB_CFG_PULLUP_IOPORT (defined
 | ||||||
|  |  * above) where the 1.5k pullup resistor is connected. See description | ||||||
|  |  * above for details. | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | /* --------------------------- Functional Range ---------------------------- */ | ||||||
|  | 
 | ||||||
|  | #define BOOTLOADER_CAN_EXIT     1 | ||||||
|  | /* If this macro is defined to 1, the boot loader command line utility can
 | ||||||
|  |  * initiate a reboot after uploading the FLASH when the "-r" command line | ||||||
|  |  * option is given. If you define it to 0 or leave it undefined, the "-r" | ||||||
|  |  * option won't work and you save a couple of bytes in the boot loader. This | ||||||
|  |  * may be of advantage if you compile with gcc 4 instead of gcc 3 because it | ||||||
|  |  * generates slightly larger code. | ||||||
|  |  * If you need to save even more memory, consider using your own vector table. | ||||||
|  |  * Since only the reset vector and INT0 (the first two vectors) are used, | ||||||
|  |  * this saves quite a bit of flash. See Alexander Neumann's boot loader for | ||||||
|  |  * an example: http://git.lochraster.org:2080/?p=fd0/usbload;a=tree
 | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | /* ------------------------------------------------------------------------- */ | ||||||
|  | 
 | ||||||
|  | /* Example configuration: Port D bit 3 is connected to a jumper which ties
 | ||||||
|  |  * this pin to GND if the boot loader is requested. Initialization allows | ||||||
|  |  * several clock cycles for the input voltage to stabilize before | ||||||
|  |  * bootLoaderCondition() samples the value. | ||||||
|  |  * We use a function for bootLoaderInit() for convenience and a macro for | ||||||
|  |  * bootLoaderCondition() for efficiency. | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | #ifndef __ASSEMBLER__   /* assembler cannot parse function definitions */ | ||||||
|  | #include <util/delay.h> | ||||||
|  | 
 | ||||||
|  | static inline void  bootLoaderInit(void) | ||||||
|  | { | ||||||
|  | 	DDRA |= (1 << 6); | ||||||
|  |     PORTA &= ~(1 << 6); /* activate pull-up for key */ | ||||||
|  |     DDRD &= ~(1 << 7); | ||||||
|  |     PORTD |= (1 << 7); | ||||||
|  |     _delay_us(10);  /* wait for levels to stabilize */ | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | #define bootLoaderCondition()   ((PIND & (1 << 7)) != 0)   /* True if jumper is set */ | ||||||
|  | 
 | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
|  | /* ------------------------------------------------------------------------- */ | ||||||
|  | 
 | ||||||
|  | #endif /* __bootloader_h_included__ */ | ||||||
							
								
								
									
										250
									
								
								keyboards/planck/thk/bootloader/main.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										250
									
								
								keyboards/planck/thk/bootloader/main.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,250 @@ | |||||||
|  | /* Name: main.c
 | ||||||
|  |  * Project: AVR bootloader HID | ||||||
|  |  * Author: Christian Starkjohann | ||||||
|  |  * Creation Date: 2007-03-19 | ||||||
|  |  * Tabsize: 4 | ||||||
|  |  * Copyright: (c) 2007 by OBJECTIVE DEVELOPMENT Software GmbH | ||||||
|  |  * License: GNU GPL v2 (see License.txt) | ||||||
|  |  * This Revision: $Id$ | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | #include <avr/io.h> | ||||||
|  | #include <avr/interrupt.h> | ||||||
|  | #include <avr/pgmspace.h> | ||||||
|  | #include <avr/wdt.h> | ||||||
|  | #include <avr/boot.h> | ||||||
|  | #include <string.h> | ||||||
|  | #include <util/delay.h> | ||||||
|  | 
 | ||||||
|  | static void leaveBootloader() __attribute__((__noreturn__)); | ||||||
|  | 
 | ||||||
|  | #include "bootloaderconfig.h" | ||||||
|  | #include "usbdrv.c" | ||||||
|  | 
 | ||||||
|  | /* ------------------------------------------------------------------------ */ | ||||||
|  | 
 | ||||||
|  | #ifndef ulong | ||||||
|  | #   define ulong    unsigned long | ||||||
|  | #endif | ||||||
|  | #ifndef uint | ||||||
|  | #   define uint     unsigned int | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
|  | #if (FLASHEND) > 0xffff /* we need long addressing */ | ||||||
|  | #   define addr_t           ulong | ||||||
|  | #else | ||||||
|  | #   define addr_t           uint | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
|  | static addr_t           currentAddress; /* in bytes */ | ||||||
|  | static uchar            offset;         /* data already processed in current transfer */ | ||||||
|  | #if BOOTLOADER_CAN_EXIT | ||||||
|  | static uchar            exitMainloop; | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | const PROGMEM char usbHidReportDescriptor[33] = { | ||||||
|  |     0x06, 0x00, 0xff,              // USAGE_PAGE (Generic Desktop)
 | ||||||
|  |     0x09, 0x01,                    // USAGE (Vendor Usage 1)
 | ||||||
|  |     0xa1, 0x01,                    // COLLECTION (Application)
 | ||||||
|  |     0x15, 0x00,                    //   LOGICAL_MINIMUM (0)
 | ||||||
|  |     0x26, 0xff, 0x00,              //   LOGICAL_MAXIMUM (255)
 | ||||||
|  |     0x75, 0x08,                    //   REPORT_SIZE (8)
 | ||||||
|  | 
 | ||||||
|  |     0x85, 0x01,                    //   REPORT_ID (1)
 | ||||||
|  |     0x95, 0x06,                    //   REPORT_COUNT (6)
 | ||||||
|  |     0x09, 0x00,                    //   USAGE (Undefined)
 | ||||||
|  |     0xb2, 0x02, 0x01,              //   FEATURE (Data,Var,Abs,Buf)
 | ||||||
|  | 
 | ||||||
|  |     0x85, 0x02,                    //   REPORT_ID (2)
 | ||||||
|  |     0x95, 0x83,                    //   REPORT_COUNT (131)
 | ||||||
|  |     0x09, 0x00,                    //   USAGE (Undefined)
 | ||||||
|  |     0xb2, 0x02, 0x01,              //   FEATURE (Data,Var,Abs,Buf)
 | ||||||
|  |     0xc0                           // END_COLLECTION
 | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | /* allow compatibility with avrusbboot's bootloaderconfig.h: */ | ||||||
|  | #ifdef BOOTLOADER_INIT | ||||||
|  | #   define bootLoaderInit()         BOOTLOADER_INIT | ||||||
|  | #endif | ||||||
|  | #ifdef BOOTLOADER_CONDITION | ||||||
|  | #   define bootLoaderCondition()    BOOTLOADER_CONDITION | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
|  | /* compatibility with ATMega88 and other new devices: */ | ||||||
|  | #ifndef TCCR0 | ||||||
|  | #define TCCR0   TCCR0B | ||||||
|  | #endif | ||||||
|  | #ifndef GICR | ||||||
|  | #define GICR    MCUCR | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
|  | static void (*nullVector)(void) __attribute__((__noreturn__)); | ||||||
|  | 
 | ||||||
|  | static void leaveBootloader() | ||||||
|  | { | ||||||
|  |     DBG1(0x01, 0, 0); | ||||||
|  |     cli(); | ||||||
|  |     boot_rww_enable(); | ||||||
|  |     USB_INTR_ENABLE = 0; | ||||||
|  |     USB_INTR_CFG = 0;       /* also reset config bits */ | ||||||
|  | #if F_CPU == 12800000 | ||||||
|  |     TCCR0 = 0;              /* default value */ | ||||||
|  | #endif | ||||||
|  |     GICR = (1 << IVCE);     /* enable change of interrupt vectors */ | ||||||
|  |     GICR = (0 << IVSEL);    /* move interrupts to application flash section */ | ||||||
|  | /* We must go through a global function pointer variable instead of writing
 | ||||||
|  |  *  ((void (*)(void))0)(); | ||||||
|  |  * because the compiler optimizes a constant 0 to "rcall 0" which is not | ||||||
|  |  * handled correctly by the assembler. | ||||||
|  |  */ | ||||||
|  |     nullVector(); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | uchar   usbFunctionSetup(uchar data[8]) | ||||||
|  | { | ||||||
|  | usbRequest_t    *rq = (void *)data; | ||||||
|  | static uchar    replyBuffer[7] = { | ||||||
|  |         1,                              /* report ID */ | ||||||
|  |         SPM_PAGESIZE & 0xff, | ||||||
|  |         SPM_PAGESIZE >> 8, | ||||||
|  |         ((long)FLASHEND + 1) & 0xff, | ||||||
|  |         (((long)FLASHEND + 1) >> 8) & 0xff, | ||||||
|  |         (((long)FLASHEND + 1) >> 16) & 0xff, | ||||||
|  |         (((long)FLASHEND + 1) >> 24) & 0xff | ||||||
|  |     }; | ||||||
|  | 
 | ||||||
|  |     if(rq->bRequest == USBRQ_HID_SET_REPORT){ | ||||||
|  |         if(rq->wValue.bytes[0] == 2){ | ||||||
|  |             offset = 0; | ||||||
|  |             return USB_NO_MSG; | ||||||
|  |         } | ||||||
|  | #if BOOTLOADER_CAN_EXIT | ||||||
|  |         else{ | ||||||
|  |             exitMainloop = 1; | ||||||
|  |         } | ||||||
|  | #endif | ||||||
|  |     }else if(rq->bRequest == USBRQ_HID_GET_REPORT){ | ||||||
|  |         usbMsgPtr = (usbMsgPtr_t)replyBuffer; | ||||||
|  |         return 7; | ||||||
|  |     } | ||||||
|  |     return 0; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | uchar usbFunctionWrite(uchar *data, uchar len) | ||||||
|  | { | ||||||
|  | union { | ||||||
|  |     addr_t  l; | ||||||
|  |     uint    s[sizeof(addr_t)/2]; | ||||||
|  |     uchar   c[sizeof(addr_t)]; | ||||||
|  | }       address; | ||||||
|  | uchar   isLast; | ||||||
|  | 
 | ||||||
|  |     address.l = currentAddress; | ||||||
|  |     if(offset == 0){ | ||||||
|  |         DBG1(0x30, data, 3); | ||||||
|  |         address.c[0] = data[1]; | ||||||
|  |         address.c[1] = data[2]; | ||||||
|  | #if (FLASHEND) > 0xffff /* we need long addressing */ | ||||||
|  |         address.c[2] = data[3]; | ||||||
|  |         address.c[3] = 0; | ||||||
|  | #endif | ||||||
|  |         data += 4; | ||||||
|  |         len -= 4; | ||||||
|  |     } | ||||||
|  |     DBG1(0x31, (void *)¤tAddress, 4); | ||||||
|  |     offset += len; | ||||||
|  |     isLast = offset & 0x80; /* != 0 if last block received */ | ||||||
|  |     do{ | ||||||
|  |         addr_t prevAddr; | ||||||
|  | #if SPM_PAGESIZE > 256 | ||||||
|  |         uint pageAddr; | ||||||
|  | #else | ||||||
|  |         uchar pageAddr; | ||||||
|  | #endif | ||||||
|  |         DBG1(0x32, 0, 0); | ||||||
|  |         pageAddr = address.s[0] & (SPM_PAGESIZE - 1); | ||||||
|  |         if(pageAddr == 0){              /* if page start: erase */ | ||||||
|  |             DBG1(0x33, 0, 0); | ||||||
|  | #ifndef TEST_MODE | ||||||
|  |             cli(); | ||||||
|  |             boot_page_erase(address.l); /* erase page */ | ||||||
|  |             sei(); | ||||||
|  |             boot_spm_busy_wait();       /* wait until page is erased */ | ||||||
|  | #endif | ||||||
|  |         } | ||||||
|  |         cli(); | ||||||
|  |         boot_page_fill(address.l, *(short *)data); | ||||||
|  |         sei(); | ||||||
|  |         prevAddr = address.l; | ||||||
|  |         address.l += 2; | ||||||
|  |         data += 2; | ||||||
|  |         /* write page when we cross page boundary */ | ||||||
|  |         pageAddr = address.s[0] & (SPM_PAGESIZE - 1); | ||||||
|  |         if(pageAddr == 0){ | ||||||
|  |             DBG1(0x34, 0, 0); | ||||||
|  | #ifndef TEST_MODE | ||||||
|  |             cli(); | ||||||
|  |             boot_page_write(prevAddr); | ||||||
|  |             sei(); | ||||||
|  |             boot_spm_busy_wait(); | ||||||
|  | #endif | ||||||
|  |         } | ||||||
|  |         len -= 2; | ||||||
|  |     }while(len); | ||||||
|  |     currentAddress = address.l; | ||||||
|  |     DBG1(0x35, (void *)¤tAddress, 4); | ||||||
|  |     return isLast; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static void initForUsbConnectivity(void) | ||||||
|  | { | ||||||
|  | uchar   i = 0; | ||||||
|  | 
 | ||||||
|  | #if F_CPU == 12800000 | ||||||
|  |     TCCR0 = 3;          /* 1/64 prescaler */ | ||||||
|  | #endif | ||||||
|  |     usbInit(); | ||||||
|  |     /* enforce USB re-enumerate: */ | ||||||
|  |     usbDeviceDisconnect();  /* do this while interrupts are disabled */ | ||||||
|  |     do{             /* fake USB disconnect for > 250 ms */ | ||||||
|  |         wdt_reset(); | ||||||
|  |         _delay_ms(1); | ||||||
|  |     }while(--i); | ||||||
|  |     usbDeviceConnect(); | ||||||
|  |     sei(); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | int __attribute__((noreturn)) main(void) | ||||||
|  | { | ||||||
|  |     /* initialize hardware */ | ||||||
|  |     bootLoaderInit(); | ||||||
|  |     odDebugInit(); | ||||||
|  |     DBG1(0x00, 0, 0); | ||||||
|  |     /* jump to application if jumper is set */ | ||||||
|  |     if(bootLoaderCondition()){ | ||||||
|  |         uchar i = 0, j = 0; | ||||||
|  | #ifndef TEST_MODE | ||||||
|  |         GICR = (1 << IVCE);  /* enable change of interrupt vectors */ | ||||||
|  |         GICR = (1 << IVSEL); /* move interrupts to boot flash section */ | ||||||
|  | #endif | ||||||
|  |         initForUsbConnectivity(); | ||||||
|  |         do{ /* main event loop */ | ||||||
|  |             wdt_reset(); | ||||||
|  |             usbPoll(); | ||||||
|  | #if BOOTLOADER_CAN_EXIT | ||||||
|  |             if(exitMainloop){ | ||||||
|  | #if F_CPU == 12800000 | ||||||
|  |                 break;  /* memory is tight at 12.8 MHz, save exit delay below */ | ||||||
|  | #endif | ||||||
|  |                 if(--i == 0){ | ||||||
|  |                     if(--j == 0) | ||||||
|  |                         break; | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  | #endif | ||||||
|  |         }while(bootLoaderCondition()); | ||||||
|  |     } | ||||||
|  |     leaveBootloader(); | ||||||
|  | } | ||||||
|  | 
 | ||||||
							
								
								
									
										275
									
								
								keyboards/planck/thk/bootloader/usbconfig.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										275
									
								
								keyboards/planck/thk/bootloader/usbconfig.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,275 @@ | |||||||
|  | /* Name: usbconfig.h
 | ||||||
|  |  * Project: AVR USB driver | ||||||
|  |  * Author: Christian Starkjohann | ||||||
|  |  * Creation Date: 2007-03-13 | ||||||
|  |  * Tabsize: 4 | ||||||
|  |  * Copyright: (c) 2007 by OBJECTIVE DEVELOPMENT Software GmbH | ||||||
|  |  * License: GNU GPL v2 (see License.txt) | ||||||
|  |  * This Revision: $Id$ | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | #ifndef __usbconfig_h_included__ | ||||||
|  | #define __usbconfig_h_included__ | ||||||
|  | 
 | ||||||
|  | /*
 | ||||||
|  | General Description: | ||||||
|  | This file contains the configuration options for the USB driver. | ||||||
|  | 
 | ||||||
|  | Please note that the usbdrv contains a usbconfig-prototype.h file now. We | ||||||
|  | recommend that you use that file as a template because it will always list | ||||||
|  | the newest features and options. | ||||||
|  | */ | ||||||
|  | 
 | ||||||
|  | /* Fetch the hardware configuration from bootloaderconfig.h so that we have a
 | ||||||
|  |  * single file where hardware settings are stored. | ||||||
|  |  * Do not edit the functional settings below. | ||||||
|  |  */ | ||||||
|  | #include "bootloaderconfig.h" | ||||||
|  | 
 | ||||||
|  | #define USB_PUBLIC static | ||||||
|  | /* Use the define above if you #include usbdrv.c instead of linking against it.
 | ||||||
|  |  * This technique saves a couple of bytes in flash memory. | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | /* --------------------------- Functional Range ---------------------------- */ | ||||||
|  | 
 | ||||||
|  | #define USB_CFG_HAVE_INTRIN_ENDPOINT    1 | ||||||
|  | /* Define this to 1 if you want to compile a version with two endpoints: The
 | ||||||
|  |  * default control endpoint 0 and an interrupt-in endpoint 1. | ||||||
|  |  */ | ||||||
|  | #define USB_CFG_HAVE_INTRIN_ENDPOINT3   0 | ||||||
|  | /* Define this to 1 if you want to compile a version with three endpoints: The
 | ||||||
|  |  * default control endpoint 0, an interrupt-in endpoint 1 and an interrupt-in | ||||||
|  |  * endpoint 3. You must also enable endpoint 1 above. | ||||||
|  |  */ | ||||||
|  | #define USB_CFG_SUPPRESS_INTR_CODE      1 | ||||||
|  | /* Define this to 1 if you want to declare interrupt-in endpoints, but don't
 | ||||||
|  |  * want to send any data over them. If this macro is defined to 1, functions | ||||||
|  |  * usbSetInterrupt() and usbSetInterrupt3() are omitted. This is useful if | ||||||
|  |  * you need the interrupt-in endpoints in order to comply to an interface | ||||||
|  |  * (e.g. HID), but never want to send any data. This option saves a couple | ||||||
|  |  * of bytes in flash memory and the transmit buffers in RAM. | ||||||
|  |  */ | ||||||
|  | #define USB_CFG_IMPLEMENT_HALT          0 | ||||||
|  | /* Define this to 1 if you also want to implement the ENDPOINT_HALT feature
 | ||||||
|  |  * for endpoint 1 (interrupt endpoint). Although you may not need this feature, | ||||||
|  |  * it is required by the standard. We have made it a config option because it | ||||||
|  |  * bloats the code considerably. | ||||||
|  |  */ | ||||||
|  | #define USB_CFG_INTR_POLL_INTERVAL      200 | ||||||
|  | /* If you compile a version with endpoint 1 (interrupt-in), this is the poll
 | ||||||
|  |  * interval. The value is in milliseconds and must not be less than 10 ms for | ||||||
|  |  * low speed devices. | ||||||
|  |  */ | ||||||
|  | #define USB_CFG_IS_SELF_POWERED         0 | ||||||
|  | /* Define this to 1 if the device has its own power supply. Set it to 0 if the
 | ||||||
|  |  * device is powered from the USB bus. | ||||||
|  |  */ | ||||||
|  | #define USB_CFG_MAX_BUS_POWER           100 | ||||||
|  | /* Set this variable to the maximum USB bus power consumption of your device.
 | ||||||
|  |  * The value is in milliamperes. [It will be divided by two since USB | ||||||
|  |  * communicates power requirements in units of 2 mA.] | ||||||
|  |  */ | ||||||
|  | #define USB_CFG_IMPLEMENT_FN_WRITE      1 | ||||||
|  | /* Set this to 1 if you want usbFunctionWrite() to be called for control-out
 | ||||||
|  |  * transfers. Set it to 0 if you don't need it and want to save a couple of | ||||||
|  |  * bytes. | ||||||
|  |  */ | ||||||
|  | #define USB_CFG_IMPLEMENT_FN_READ       0 | ||||||
|  | /* Set this to 1 if you need to send control replies which are generated
 | ||||||
|  |  * "on the fly" when usbFunctionRead() is called. If you only want to send | ||||||
|  |  * data from a static buffer, set it to 0 and return the data from | ||||||
|  |  * usbFunctionSetup(). This saves a couple of bytes. | ||||||
|  |  */ | ||||||
|  | #define USB_CFG_IMPLEMENT_FN_WRITEOUT   0 | ||||||
|  | /* Define this to 1 if you want to use interrupt-out (or bulk out) endpoint 1.
 | ||||||
|  |  * You must implement the function usbFunctionWriteOut() which receives all | ||||||
|  |  * interrupt/bulk data sent to endpoint 1. | ||||||
|  |  */ | ||||||
|  | #define USB_CFG_HAVE_FLOWCONTROL        0 | ||||||
|  | /* Define this to 1 if you want flowcontrol over USB data. See the definition
 | ||||||
|  |  * of the macros usbDisableAllRequests() and usbEnableAllRequests() in | ||||||
|  |  * usbdrv.h. | ||||||
|  |  */ | ||||||
|  | #define TIMER0_PRESCALING           64 /* must match the configuration for TIMER0 in main */ | ||||||
|  | #define TOLERATED_DEVIATION_PPT     5  /* max clock deviation before we tune in 1/10 % */ | ||||||
|  | /* derived constants: */ | ||||||
|  | #define EXPECTED_TIMER0_INCREMENT   ((F_CPU / (1000 * TIMER0_PRESCALING)) & 0xff) | ||||||
|  | #define TOLERATED_DEVIATION         (TOLERATED_DEVIATION_PPT * F_CPU / (1000000 * TIMER0_PRESCALING)) | ||||||
|  | #ifdef __ASSEMBLER__ | ||||||
|  | macro tuneOsccal | ||||||
|  |     push    YH                              ;[0] | ||||||
|  |     clr     YH                              ;[2] | ||||||
|  |     in      YL, TCNT0                       ;[3] | ||||||
|  |     out     TCNT0, YH                       ;[4] | ||||||
|  |     subi    YL, EXPECTED_TIMER0_INCREMENT   ;[5] | ||||||
|  | #if OSCCAL > 0x3f | ||||||
|  |     lds     YH, OSCCAL                      ;[6] | ||||||
|  | #else | ||||||
|  |     in      YH, OSCCAL                      ;[6] | ||||||
|  | #endif | ||||||
|  |     cpi     YL, TOLERATED_DEVIATION + 1     ;[7] | ||||||
|  |     brmi    notTooHigh                      ;[8] | ||||||
|  |     subi    YH, 1                           ;[9] clock rate was too high | ||||||
|  |     rjmp    osctuneDone                     ;[10] | ||||||
|  | notTooHigh: | ||||||
|  |     cpi     YL, -TOLERATED_DEVIATION        ;[10] | ||||||
|  |     brpl    osctuneDone                     ;[11] not too low | ||||||
|  |     inc     YH                              ;[12] clock rate was too low | ||||||
|  | osctuneDone: | ||||||
|  | #if OSCCAL > 0x3f | ||||||
|  |     sts     OSCCAL, YH                      ;[12-13] store tuned value | ||||||
|  | #else | ||||||
|  |     out     OSCCAL, YH                      ;[12-13] store tuned value | ||||||
|  | #endif | ||||||
|  | tuningOverflow: | ||||||
|  |     pop     YH                              ;[14] | ||||||
|  |     endm                                    ;[16] max number of cycles | ||||||
|  | #endif | ||||||
|  | #if F_CPU == 12800000 | ||||||
|  | #   define USB_SOF_HOOK        tuneOsccal | ||||||
|  | #endif | ||||||
|  | /* This macro (if defined) is executed in the assembler module when a
 | ||||||
|  |  * Start Of Frame condition is detected. It is recommended to define it to | ||||||
|  |  * the name of an assembler macro which is defined here as well so that more | ||||||
|  |  * than one assembler instruction can be used. The macro may use the register | ||||||
|  |  * YL and modify SREG. If it lasts longer than a couple of cycles, USB messages | ||||||
|  |  * immediately after an SOF pulse may be lost and must be retried by the host. | ||||||
|  |  * What can you do with this hook? Since the SOF signal occurs exactly every | ||||||
|  |  * 1 ms (unless the host is in sleep mode), you can use it to tune OSCCAL in | ||||||
|  |  * designs running on the internal RC oscillator. | ||||||
|  |  * Please note that Start Of Frame detection works only if D- is wired to the | ||||||
|  |  * interrupt, not D+. THIS IS DIFFERENT THAN MOST EXAMPLES! | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | /* -------------------------- Device Description --------------------------- */ | ||||||
|  | 
 | ||||||
|  | #define  USB_CFG_VENDOR_ID       0xc0, 0x16 | ||||||
|  | /* USB vendor ID for the device, low byte first. If you have registered your
 | ||||||
|  |  * own Vendor ID, define it here. Otherwise you use obdev's free shared | ||||||
|  |  * VID/PID pair. Be sure to read USBID-License.txt for rules! | ||||||
|  |  */ | ||||||
|  | #define  USB_CFG_DEVICE_ID       0xdf, 0x05 | ||||||
|  | /* This is the ID of the product, low byte first. It is interpreted in the
 | ||||||
|  |  * scope of the vendor ID. If you have registered your own VID with usb.org | ||||||
|  |  * or if you have licensed a PID from somebody else, define it here. Otherwise | ||||||
|  |  * you use obdev's free shared VID/PID pair. Be sure to read the rules in | ||||||
|  |  * USBID-License.txt! | ||||||
|  |  */ | ||||||
|  | #define USB_CFG_DEVICE_VERSION  0x00, 0x01 | ||||||
|  | /* Version number of the device: Minor number first, then major number.
 | ||||||
|  |  */ | ||||||
|  | #define USB_CFG_VENDOR_NAME     'o', 'b', 'd', 'e', 'v', '.', 'a', 't' | ||||||
|  | #define USB_CFG_VENDOR_NAME_LEN 8 | ||||||
|  | /* These two values define the vendor name returned by the USB device. The name
 | ||||||
|  |  * must be given as a list of characters under single quotes. The characters | ||||||
|  |  * are interpreted as Unicode (UTF-16) entities. | ||||||
|  |  * If you don't want a vendor name string, undefine these macros. | ||||||
|  |  * ALWAYS define a vendor name containing your Internet domain name if you use | ||||||
|  |  * obdev's free shared VID/PID pair. See the file USBID-License.txt for | ||||||
|  |  * details. | ||||||
|  |  */ | ||||||
|  | #define USB_CFG_DEVICE_NAME     'H', 'I', 'D', 'B', 'o', 'o', 't' | ||||||
|  | #define USB_CFG_DEVICE_NAME_LEN 7 | ||||||
|  | /* Same as above for the device name. If you don't want a device name, undefine
 | ||||||
|  |  * the macros. See the file USBID-License.txt before you assign a name if you | ||||||
|  |  * use a shared VID/PID. | ||||||
|  |  */ | ||||||
|  | /*#define USB_CFG_SERIAL_NUMBER   'N', 'o', 'n', 'e' */ | ||||||
|  | /*#define USB_CFG_SERIAL_NUMBER_LEN   0 */ | ||||||
|  | /* Same as above for the serial number. If you don't want a serial number,
 | ||||||
|  |  * undefine the macros. | ||||||
|  |  * It may be useful to provide the serial number through other means than at | ||||||
|  |  * compile time. See the section about descriptor properties below for how | ||||||
|  |  * to fine tune control over USB descriptors such as the string descriptor | ||||||
|  |  * for the serial number. | ||||||
|  |  */ | ||||||
|  | #define USB_CFG_DEVICE_CLASS        0 | ||||||
|  | #define USB_CFG_DEVICE_SUBCLASS     0 | ||||||
|  | /* See USB specification if you want to conform to an existing device class.
 | ||||||
|  |  */ | ||||||
|  | #define USB_CFG_INTERFACE_CLASS     3   /* HID */ | ||||||
|  | #define USB_CFG_INTERFACE_SUBCLASS  0 | ||||||
|  | #define USB_CFG_INTERFACE_PROTOCOL  0 | ||||||
|  | /* See USB specification if you want to conform to an existing device class or
 | ||||||
|  |  * protocol. | ||||||
|  |  */ | ||||||
|  | #define USB_CFG_HID_REPORT_DESCRIPTOR_LENGTH    33  /* total length of report descriptor */ | ||||||
|  | /* Define this to the length of the HID report descriptor, if you implement
 | ||||||
|  |  * an HID device. Otherwise don't define it or define it to 0. | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | /* ------------------- Fine Control over USB Descriptors ------------------- */ | ||||||
|  | /* If you don't want to use the driver's default USB descriptors, you can
 | ||||||
|  |  * provide our own. These can be provided as (1) fixed length static data in | ||||||
|  |  * flash memory, (2) fixed length static data in RAM or (3) dynamically at | ||||||
|  |  * runtime in the function usbFunctionDescriptor(). See usbdrv.h for more | ||||||
|  |  * information about this function. | ||||||
|  |  * Descriptor handling is configured through the descriptor's properties. If | ||||||
|  |  * no properties are defined or if they are 0, the default descriptor is used. | ||||||
|  |  * Possible properties are: | ||||||
|  |  *   + USB_PROP_IS_DYNAMIC: The data for the descriptor should be fetched | ||||||
|  |  *     at runtime via usbFunctionDescriptor(). | ||||||
|  |  *   + USB_PROP_IS_RAM: The data returned by usbFunctionDescriptor() or found | ||||||
|  |  *     in static memory is in RAM, not in flash memory. | ||||||
|  |  *   + USB_PROP_LENGTH(len): If the data is in static memory (RAM or flash), | ||||||
|  |  *     the driver must know the descriptor's length. The descriptor itself is | ||||||
|  |  *     found at the address of a well known identifier (see below). | ||||||
|  |  * List of static descriptor names (must be declared PROGMEM if in flash): | ||||||
|  |  *   char usbDescriptorDevice[]; | ||||||
|  |  *   char usbDescriptorConfiguration[]; | ||||||
|  |  *   char usbDescriptorHidReport[]; | ||||||
|  |  *   char usbDescriptorString0[]; | ||||||
|  |  *   int usbDescriptorStringVendor[]; | ||||||
|  |  *   int usbDescriptorStringDevice[]; | ||||||
|  |  *   int usbDescriptorStringSerialNumber[]; | ||||||
|  |  * Other descriptors can't be provided statically, they must be provided | ||||||
|  |  * dynamically at runtime. | ||||||
|  |  * | ||||||
|  |  * Descriptor properties are or-ed or added together, e.g.: | ||||||
|  |  * #define USB_CFG_DESCR_PROPS_DEVICE   (USB_PROP_IS_RAM | USB_PROP_LENGTH(18)) | ||||||
|  |  * | ||||||
|  |  * The following descriptors are defined: | ||||||
|  |  *   USB_CFG_DESCR_PROPS_DEVICE | ||||||
|  |  *   USB_CFG_DESCR_PROPS_CONFIGURATION | ||||||
|  |  *   USB_CFG_DESCR_PROPS_STRINGS | ||||||
|  |  *   USB_CFG_DESCR_PROPS_STRING_0 | ||||||
|  |  *   USB_CFG_DESCR_PROPS_STRING_VENDOR | ||||||
|  |  *   USB_CFG_DESCR_PROPS_STRING_PRODUCT | ||||||
|  |  *   USB_CFG_DESCR_PROPS_STRING_SERIAL_NUMBER | ||||||
|  |  *   USB_CFG_DESCR_PROPS_HID | ||||||
|  |  *   USB_CFG_DESCR_PROPS_HID_REPORT | ||||||
|  |  *   USB_CFG_DESCR_PROPS_UNKNOWN (for all descriptors not handled by the driver) | ||||||
|  |  * | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | #define USB_CFG_DESCR_PROPS_DEVICE                  0 | ||||||
|  | #define USB_CFG_DESCR_PROPS_CONFIGURATION           0 | ||||||
|  | #define USB_CFG_DESCR_PROPS_STRINGS                 0 | ||||||
|  | #define USB_CFG_DESCR_PROPS_STRING_0                0 | ||||||
|  | #define USB_CFG_DESCR_PROPS_STRING_VENDOR           0 | ||||||
|  | #define USB_CFG_DESCR_PROPS_STRING_PRODUCT          0 | ||||||
|  | #define USB_CFG_DESCR_PROPS_STRING_SERIAL_NUMBER    0 | ||||||
|  | #define USB_CFG_DESCR_PROPS_HID                     0 | ||||||
|  | #define USB_CFG_DESCR_PROPS_HID_REPORT              0 | ||||||
|  | #define USB_CFG_DESCR_PROPS_UNKNOWN                 0 | ||||||
|  | 
 | ||||||
|  | #define usbMsgPtr_t unsigned short  /* Use scalar type in order to save a couple of bytes */ | ||||||
|  | 
 | ||||||
|  | /* ----------------------- Optional MCU Description ------------------------ */ | ||||||
|  | 
 | ||||||
|  | /* The following configurations have working defaults in usbdrv.h. You
 | ||||||
|  |  * usually don't need to set them explicitly. Only if you want to run | ||||||
|  |  * the driver on a device which is not yet supported or with a compiler | ||||||
|  |  * which is not fully supported (such as IAR C) or if you use a differnt | ||||||
|  |  * interrupt than INT0, you may have to define some of these. | ||||||
|  |  */ | ||||||
|  | /* #define USB_INTR_CFG            MCUCR */ | ||||||
|  | /* #define USB_INTR_CFG_SET        ((1 << ISC00) | (1 << ISC01)) */ | ||||||
|  | /* #define USB_INTR_CFG_CLR        0 */ | ||||||
|  | /* #define USB_INTR_ENABLE         GIMSK */ | ||||||
|  | /* #define USB_INTR_ENABLE_BIT     INT0 */ | ||||||
|  | /* #define USB_INTR_PENDING        GIFR */ | ||||||
|  | /* #define USB_INTR_PENDING_BIT    INTF0 */ | ||||||
|  | 
 | ||||||
|  | #endif /* __usbconfig_h_included__ */ | ||||||
							
								
								
									
										329
									
								
								keyboards/planck/thk/bootloader/usbdrv/Changelog.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										329
									
								
								keyboards/planck/thk/bootloader/usbdrv/Changelog.txt
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,329 @@ | |||||||
|  | This file documents changes in the firmware-only USB driver for atmel's AVR | ||||||
|  | microcontrollers. New entries are always appended to the end of the file. | ||||||
|  | Scroll down to the bottom to see the most recent changes. | ||||||
|  | 
 | ||||||
|  | 2005-04-01: | ||||||
|  |   - Implemented endpoint 1 as interrupt-in endpoint. | ||||||
|  |   - Moved all configuration options to usbconfig.h which is not part of the | ||||||
|  |     driver. | ||||||
|  |   - Changed interface for usbVendorSetup(). | ||||||
|  |   - Fixed compatibility with ATMega8 device. | ||||||
|  |   - Various minor optimizations. | ||||||
|  | 
 | ||||||
|  | 2005-04-11: | ||||||
|  |   - Changed interface to application: Use usbFunctionSetup(), usbFunctionRead() | ||||||
|  |     and usbFunctionWrite() now. Added configuration options to choose which | ||||||
|  |     of these functions to compile in. | ||||||
|  |   - Assembler module delivers receive data non-inverted now. | ||||||
|  |   - Made register and bit names compatible with more AVR devices. | ||||||
|  | 
 | ||||||
|  | 2005-05-03: | ||||||
|  |   - Allow address of usbRxBuf on any memory page as long as the buffer does | ||||||
|  |     not cross 256 byte page boundaries. | ||||||
|  |   - Better device compatibility: works with Mega88 now. | ||||||
|  |   - Code optimization in debugging module. | ||||||
|  |   - Documentation updates. | ||||||
|  | 
 | ||||||
|  | 2006-01-02: | ||||||
|  |   - Added (free) default Vendor- and Product-IDs bought from voti.nl. | ||||||
|  |   - Added USBID-License.txt file which defines the rules for using the free | ||||||
|  |     shared VID/PID pair. | ||||||
|  |   - Added Readme.txt to the usbdrv directory which clarifies administrative | ||||||
|  |     issues. | ||||||
|  | 
 | ||||||
|  | 2006-01-25: | ||||||
|  |   - Added "configured state" to become more standards compliant. | ||||||
|  |   - Added "HALT" state for interrupt endpoint. | ||||||
|  |   - Driver passes the "USB Command Verifier" test from usb.org now. | ||||||
|  |   - Made "serial number" a configuration option. | ||||||
|  |   - Minor optimizations, we now recommend compiler option "-Os" for best | ||||||
|  |     results. | ||||||
|  |   - Added a version number to usbdrv.h | ||||||
|  | 
 | ||||||
|  | 2006-02-03: | ||||||
|  |   - New configuration variable USB_BUFFER_SECTION for the memory section where | ||||||
|  |     the USB rx buffer will go. This defaults to ".bss" if not defined. Since | ||||||
|  |     this buffer MUST NOT cross 256 byte pages (not even touch a page at the | ||||||
|  |     end), the user may want to pass a linker option similar to | ||||||
|  |     "-Wl,--section-start=.mybuffer=0x800060". | ||||||
|  |   - Provide structure for usbRequest_t. | ||||||
|  |   - New defines for USB constants. | ||||||
|  |   - Prepared for HID implementations. | ||||||
|  |   - Increased data size limit for interrupt transfers to 8 bytes. | ||||||
|  |   - New macro usbInterruptIsReady() to query interrupt buffer state. | ||||||
|  | 
 | ||||||
|  | 2006-02-18: | ||||||
|  |   - Ensure that the data token which is sent as an ack to an OUT transfer is | ||||||
|  |     always zero sized. This fixes a bug where the host reports an error after | ||||||
|  |     sending an out transfer to the device, although all data arrived at the | ||||||
|  |     device. | ||||||
|  |   - Updated docs in usbdrv.h to reflect changed API in usbFunctionWrite(). | ||||||
|  | 
 | ||||||
|  | * Release 2006-02-20 | ||||||
|  | 
 | ||||||
|  |   - Give a compiler warning when compiling with debugging turned on. | ||||||
|  |   - Added Oleg Semyonov's changes for IAR-cc compatibility. | ||||||
|  |   - Added new (optional) functions usbDeviceConnect() and usbDeviceDisconnect() | ||||||
|  |     (also thanks to Oleg!). | ||||||
|  |   - Rearranged tests in usbPoll() to save a couple of instructions in the most | ||||||
|  |     likely case that no actions are pending. | ||||||
|  |   - We need a delay between the SET ADDRESS request until the new address | ||||||
|  |     becomes active. This delay was handled in usbPoll() until now. Since the | ||||||
|  |     spec says that the delay must not exceed 2ms, previous versions required | ||||||
|  |     aggressive polling during the enumeration phase. We have now moved the | ||||||
|  |     handling of the delay into the interrupt routine. | ||||||
|  |   - We must not reply with NAK to a SETUP transaction. We can only achieve this | ||||||
|  |     by making sure that the rx buffer is empty when SETUP tokens are expected. | ||||||
|  |     We therefore don't pass zero sized data packets from the status phase of | ||||||
|  |     a transfer to usbPoll(). This change MAY cause troubles if you rely on | ||||||
|  |     receiving a less than 8 bytes long packet in usbFunctionWrite() to | ||||||
|  |     identify the end of a transfer. usbFunctionWrite() will NEVER be called | ||||||
|  |     with a zero length. | ||||||
|  | 
 | ||||||
|  | * Release 2006-03-14 | ||||||
|  | 
 | ||||||
|  |   - Improved IAR C support: tiny memory model, more devices | ||||||
|  |   - Added template usbconfig.h file under the name usbconfig-prototype.h | ||||||
|  | 
 | ||||||
|  | * Release 2006-03-26 | ||||||
|  | 
 | ||||||
|  |   - Added provision for one more interrupt-in endpoint (endpoint 3). | ||||||
|  |   - Added provision for one interrupt-out endpoint (endpoint 1). | ||||||
|  |   - Added flowcontrol macros for USB. | ||||||
|  |   - Added provision for custom configuration descriptor. | ||||||
|  |   - Allow ANY two port bits for D+ and D-. | ||||||
|  |   - Merged (optional) receive endpoint number into global usbRxToken variable. | ||||||
|  |   - Use USB_CFG_IOPORTNAME instead of USB_CFG_IOPORT. We now construct the | ||||||
|  |     variable name from the single port letter instead of computing the address | ||||||
|  |     of related ports from the output-port address. | ||||||
|  | 
 | ||||||
|  | * Release 2006-06-26 | ||||||
|  | 
 | ||||||
|  |   - Updated documentation in usbdrv.h and usbconfig-prototype.h to reflect the | ||||||
|  |     new features. | ||||||
|  |   - Removed "#warning" directives because IAR does not understand them. Use | ||||||
|  |     unused static variables instead to generate a warning. | ||||||
|  |   - Do not include <avr/io.h> when compiling with IAR. | ||||||
|  |   - Introduced USB_CFG_DESCR_PROPS_* in usbconfig.h to configure how each | ||||||
|  |     USB descriptor should be handled. It is now possible to provide descriptor | ||||||
|  |     data in Flash, RAM or dynamically at runtime. | ||||||
|  |   - STALL is now a status in usbTxLen* instead of a message. We can now conform | ||||||
|  |     to the spec and leave the stall status pending until it is cleared. | ||||||
|  |   - Made usbTxPacketCnt1 and usbTxPacketCnt3 public. This allows the | ||||||
|  |     application code to reset data toggling on interrupt pipes. | ||||||
|  | 
 | ||||||
|  | * Release 2006-07-18 | ||||||
|  | 
 | ||||||
|  |   - Added an #if !defined __ASSEMBLER__ to the warning in usbdrv.h. This fixes | ||||||
|  |     an assembler error. | ||||||
|  |   - usbDeviceDisconnect() takes pull-up resistor to high impedance now. | ||||||
|  | 
 | ||||||
|  | * Release 2007-02-01 | ||||||
|  | 
 | ||||||
|  |   - Merged in some code size improvements from usbtiny (thanks to Dick | ||||||
|  |     Streefland for these optimizations!) | ||||||
|  |   - Special alignment requirement for usbRxBuf not required any more. Thanks | ||||||
|  |     again to Dick Streefland for this hint! | ||||||
|  |   - Reverted to "#warning" instead of unused static variables -- new versions | ||||||
|  |     of IAR CC should handle this directive. | ||||||
|  |   - Changed Open Source license to GNU GPL v2 in order to make linking against | ||||||
|  |     other free libraries easier. We no longer require publication of the | ||||||
|  |     circuit diagrams, but we STRONGLY encourage it. If you improve the driver | ||||||
|  |     itself, PLEASE grant us a royalty free license to your changes for our | ||||||
|  |     commercial license. | ||||||
|  | 
 | ||||||
|  | * Release 2007-03-29 | ||||||
|  | 
 | ||||||
|  |   - New configuration option "USB_PUBLIC" in usbconfig.h. | ||||||
|  |   - Set USB version number to 1.10 instead of 1.01. | ||||||
|  |   - Code used USB_CFG_DESCR_PROPS_STRING_DEVICE and | ||||||
|  |     USB_CFG_DESCR_PROPS_STRING_PRODUCT inconsistently. Changed all occurrences | ||||||
|  |     to USB_CFG_DESCR_PROPS_STRING_PRODUCT. | ||||||
|  |   - New assembler module for 16.5 MHz RC oscillator clock with PLL in receiver | ||||||
|  |     code. | ||||||
|  |   - New assembler module for 16 MHz crystal. | ||||||
|  |   - usbdrvasm.S contains common code only, clock-specific parts have been moved | ||||||
|  |     to usbdrvasm12.S, usbdrvasm16.S and usbdrvasm165.S respectively. | ||||||
|  | 
 | ||||||
|  | * Release 2007-06-25 | ||||||
|  | 
 | ||||||
|  |   - 16 MHz module: Do SE0 check in stuffed bits as well. | ||||||
|  | 
 | ||||||
|  | * Release 2007-07-07 | ||||||
|  | 
 | ||||||
|  |   - Define hi8(x) for IAR compiler to limit result to 8 bits. This is necessary | ||||||
|  |     for negative values. | ||||||
|  |   - Added 15 MHz module contributed by V. Bosch. | ||||||
|  |   - Interrupt vector name can now be configured. This is useful if somebody | ||||||
|  |     wants to use a different hardware interrupt than INT0. | ||||||
|  | 
 | ||||||
|  | * Release 2007-08-07 | ||||||
|  | 
 | ||||||
|  |   - Moved handleIn3 routine in usbdrvasm16.S so that relative jump range is | ||||||
|  |     not exceeded. | ||||||
|  |   - More config options: USB_RX_USER_HOOK(), USB_INITIAL_DATATOKEN, | ||||||
|  |     USB_COUNT_SOF | ||||||
|  |   - USB_INTR_PENDING can now be a memory address, not just I/O | ||||||
|  | 
 | ||||||
|  | * Release 2007-09-19 | ||||||
|  | 
 | ||||||
|  |   - Split out common parts of assembler modules into separate include file | ||||||
|  |   - Made endpoint numbers configurable so that given interface definitions | ||||||
|  |     can be matched. See USB_CFG_EP3_NUMBER in usbconfig-prototype.h. | ||||||
|  |   - Store endpoint number for interrupt/bulk-out so that usbFunctionWriteOut() | ||||||
|  |     can handle any number of endpoints. | ||||||
|  |   - Define usbDeviceConnect() and usbDeviceDisconnect() even if no | ||||||
|  |     USB_CFG_PULLUP_IOPORTNAME is defined. Directly set D+ and D- to 0 in this | ||||||
|  |     case. | ||||||
|  | 
 | ||||||
|  | * Release 2007-12-01 | ||||||
|  | 
 | ||||||
|  |   - Optimize usbDeviceConnect() and usbDeviceDisconnect() for less code size | ||||||
|  |     when USB_CFG_PULLUP_IOPORTNAME is not defined. | ||||||
|  | 
 | ||||||
|  | * Release 2007-12-13 | ||||||
|  | 
 | ||||||
|  |   - Renamed all include-only assembler modules from *.S to *.inc so that | ||||||
|  |     people don't add them to their project sources. | ||||||
|  |   - Distribute leap bits in tx loop more evenly for 16 MHz module. | ||||||
|  |   - Use "macro" and "endm" instead of ".macro" and ".endm" for IAR | ||||||
|  |   - Avoid compiler warnings for constant expr range by casting some values in | ||||||
|  |     USB descriptors. | ||||||
|  | 
 | ||||||
|  | * Release 2008-01-21 | ||||||
|  | 
 | ||||||
|  |   - Fixed bug in 15 and 16 MHz module where the new address set with | ||||||
|  |     SET_ADDRESS was already accepted at the next NAK or ACK we send, not at | ||||||
|  |     the next data packet we send. This caused problems when the host polled | ||||||
|  |     too fast. Thanks to Alexander Neumann for his help and patience debugging | ||||||
|  |     this issue! | ||||||
|  | 
 | ||||||
|  | * Release 2008-02-05 | ||||||
|  | 
 | ||||||
|  |   - Fixed bug in 16.5 MHz module where a register was used in the interrupt | ||||||
|  |     handler before it was pushed. This bug was introduced with version | ||||||
|  |     2007-09-19 when common parts were moved to a separate file. | ||||||
|  |   - Optimized CRC routine (thanks to Reimar Doeffinger). | ||||||
|  | 
 | ||||||
|  | * Release 2008-02-16 | ||||||
|  | 
 | ||||||
|  |   - Removed outdated IAR compatibility stuff (code sections). | ||||||
|  |   - Added hook macros for USB_RESET_HOOK() and USB_SET_ADDRESS_HOOK(). | ||||||
|  |   - Added optional routine usbMeasureFrameLength() for calibration of the | ||||||
|  |     internal RC oscillator. | ||||||
|  | 
 | ||||||
|  | * Release 2008-02-28 | ||||||
|  | 
 | ||||||
|  |   - USB_INITIAL_DATATOKEN defaults to USBPID_DATA1 now, which means that we | ||||||
|  |     start with sending USBPID_DATA0. | ||||||
|  |   - Changed defaults in usbconfig-prototype.h | ||||||
|  |   - Added free USB VID/PID pair for MIDI class devices | ||||||
|  |   - Restructured AVR-USB as separate package, not part of PowerSwitch any more. | ||||||
|  | 
 | ||||||
|  | * Release 2008-04-18 | ||||||
|  | 
 | ||||||
|  |   - Restructured usbdrv.c so that it is easier to read and understand. | ||||||
|  |   - Better code optimization with gcc 4. | ||||||
|  |   - If a second interrupt in endpoint is enabled, also add it to config | ||||||
|  |     descriptor. | ||||||
|  |   - Added config option for long transfers (above 254 bytes), see | ||||||
|  |     USB_CFG_LONG_TRANSFERS in usbconfig.h. | ||||||
|  |   - Added 20 MHz module contributed by Jeroen Benschop. | ||||||
|  | 
 | ||||||
|  | * Release 2008-05-13 | ||||||
|  | 
 | ||||||
|  |   - Fixed bug in libs-host/hiddata.c function usbhidGetReport(): length | ||||||
|  |     was not incremented, pointer to length was incremented instead. | ||||||
|  |   - Added code to command line tool(s) which claims an interface. This code | ||||||
|  |     is disabled by default, but may be necessary on newer Linux kernels. | ||||||
|  |   - Added usbconfig.h option "USB_CFG_CHECK_DATA_TOGGLING". | ||||||
|  |   - New header "usbportability.h" prepares ports to other development | ||||||
|  |     environments. | ||||||
|  |   - Long transfers (above 254 bytes) did not work when usbFunctionRead() was | ||||||
|  |     used to supply the data. Fixed this bug. [Thanks to Alexander Neumann!] | ||||||
|  |   - In hiddata.c (example code for sending/receiving data over HID), use | ||||||
|  |     USB_RECIP_DEVICE instead of USB_RECIP_INTERFACE for control transfers so | ||||||
|  |     that we need not claim the interface. | ||||||
|  |   - in usbPoll() loop 20 times polling for RESET state instead of 10 times. | ||||||
|  |     This accounts for the higher clock rates we now support. | ||||||
|  |   - Added a module for 12.8 MHz RC oscillator with PLL in receiver loop. | ||||||
|  |   - Added hook to SOF code so that oscillator can be tuned to USB frame clock. | ||||||
|  |   - Added timeout to waitForJ loop. Helps preventing unexpected hangs. | ||||||
|  |   - Added example code for oscillator tuning to libs-device (thanks to | ||||||
|  |     Henrik Haftmann for the idea to this routine). | ||||||
|  |   - Implemented option USB_CFG_SUPPRESS_INTR_CODE. | ||||||
|  | 
 | ||||||
|  | * Release 2008-10-22 | ||||||
|  | 
 | ||||||
|  |   - Fixed libs-device/osctune.h: OSCCAL is memory address on ATMega88 and | ||||||
|  |     similar, not offset of 0x20 needs to be added. | ||||||
|  |   - Allow distribution under GPLv3 for those who have to link against other | ||||||
|  |     code distributed under GPLv3. | ||||||
|  | 
 | ||||||
|  | * Release 2008-11-26 | ||||||
|  | 
 | ||||||
|  |   - Removed libusb-win32 dependency for hid-data example in Makefile.windows. | ||||||
|  |     It was never required and confused many people. | ||||||
|  |   - Added extern uchar usbRxToken to usbdrv.h. | ||||||
|  |   - Integrated a module with CRC checks at 18 MHz by Lukas Schrittwieser. | ||||||
|  | 
 | ||||||
|  | * Release 2009-03-23 | ||||||
|  | 
 | ||||||
|  |   - Hid-mouse example used settings from hid-data example, fixed that. | ||||||
|  |   - Renamed project to V-USB due to a trademark issue with Atmel(r). | ||||||
|  |   - Changed CommercialLicense.txt and USBID-License.txt to make the | ||||||
|  |     background of USB ID registration clearer. | ||||||
|  | 
 | ||||||
|  | * Release 2009-04-15 | ||||||
|  | 
 | ||||||
|  |   - Changed CommercialLicense.txt to reflect the new range of PIDs from | ||||||
|  |     Jason Kotzin. | ||||||
|  |   - Removed USBID-License.txt in favor of USB-IDs-for-free.txt and | ||||||
|  |     USB-ID-FAQ.txt | ||||||
|  |   - Fixed a bug in the 12.8 MHz module: End Of Packet decection was made in | ||||||
|  |     the center between bit 0 and 1 of each byte. This is where the data lines | ||||||
|  |     are expected to change and the sampled data may therefore be nonsense. | ||||||
|  |     We therefore check EOP ONLY if bits 0 AND 1 have both been read as 0 on D-. | ||||||
|  |   - Fixed a bitstuffing problem in the 16 MHz module: If bit 6 was stuffed, | ||||||
|  |     the unstuffing code in the receiver routine was 1 cycle too long. If | ||||||
|  |     multiple bytes had the unstuffing in bit 6, the error summed up until the | ||||||
|  |     receiver was out of sync. | ||||||
|  |   - Included option for faster CRC routine. | ||||||
|  |     Thanks to Slawomir Fras (BoskiDialer) for this code! | ||||||
|  |   - Updated bits in Configuration Descriptor's bmAttributes according to | ||||||
|  |     USB 1.1 (in particular bit 7, it is a must-be-set bit now). | ||||||
|  | 
 | ||||||
|  | * Release 2009-08-22 | ||||||
|  | 
 | ||||||
|  |   - Moved first DBG1() after odDebugInit() in all examples. | ||||||
|  |   - Use vector INT0_vect instead of SIG_INTERRUPT0 if defined. This makes | ||||||
|  |     V-USB compatible with the new "p" suffix devices (e.g. ATMega328p). | ||||||
|  |   - USB_CFG_CLOCK_KHZ setting is now required in usbconfig.h (no default any | ||||||
|  |     more). | ||||||
|  |   - New option USB_CFG_DRIVER_FLASH_PAGE allows boot loaders on devices with | ||||||
|  |     more than 64 kB flash. | ||||||
|  |   - Built-in configuration descriptor allows custom definition for second | ||||||
|  |     endpoint now. | ||||||
|  | 
 | ||||||
|  | * Release 2010-07-15 | ||||||
|  | 
 | ||||||
|  |   - Fixed bug in usbDriverSetup() which prevented descriptor sizes above 255 | ||||||
|  |     bytes. | ||||||
|  |   - Avoid a compiler warning for unused parameter in usbHandleResetHook() when | ||||||
|  |     compiler option -Wextra is enabled. | ||||||
|  |   - Fixed wrong hex value for some IDs in USB-IDs-for-free.txt. | ||||||
|  |   - Keep a define for USBATTR_BUSPOWER, although the flag does not exist | ||||||
|  |     in USB 1.1 any more. Set it to 0. This is for backward compatibility. | ||||||
|  | 
 | ||||||
|  | * Release 2012-01-09 | ||||||
|  | 
 | ||||||
|  |   - Define a separate (defined) type for usbMsgPtr so that projects using a | ||||||
|  |     tiny memory model can define it to an 8 bit type in usbconfig.h. This | ||||||
|  |     change also saves a couple of bytes when using a scalar 16 bit type. | ||||||
|  |   - Inserted "const" keyword for all PROGMEM declarations because new GCC | ||||||
|  |     requires it. | ||||||
|  |   - Fixed problem with dependence of usbportability.h on usbconfig.h. This | ||||||
|  |     problem occurred with IAR CC only. | ||||||
|  |   - Prepared repository for github.com. | ||||||
|  | 
 | ||||||
|  | * Release 2012-12-06 | ||||||
							
								
								
									
										166
									
								
								keyboards/planck/thk/bootloader/usbdrv/CommercialLicense.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										166
									
								
								keyboards/planck/thk/bootloader/usbdrv/CommercialLicense.txt
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,166 @@ | |||||||
|  | V-USB Driver Software License Agreement | ||||||
|  | Version 2012-07-09 | ||||||
|  | 
 | ||||||
|  | THIS LICENSE AGREEMENT GRANTS YOU CERTAIN RIGHTS IN A SOFTWARE. YOU CAN | ||||||
|  | ENTER INTO THIS AGREEMENT AND ACQUIRE THE RIGHTS OUTLINED BELOW BY PAYING | ||||||
|  | THE AMOUNT ACCORDING TO SECTION 4 ("PAYMENT") TO OBJECTIVE DEVELOPMENT. | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | 1 DEFINITIONS | ||||||
|  | 
 | ||||||
|  | 1.1 "OBJECTIVE DEVELOPMENT" shall mean OBJECTIVE DEVELOPMENT Software GmbH, | ||||||
|  | Grosse Schiffgasse 1A/7, 1020 Wien, AUSTRIA. | ||||||
|  | 
 | ||||||
|  | 1.2 "You" shall mean the Licensee. | ||||||
|  | 
 | ||||||
|  | 1.3 "V-USB" shall mean all files included in the package distributed under | ||||||
|  | the name "vusb" by OBJECTIVE DEVELOPMENT (http://www.obdev.at/vusb/) | ||||||
|  | unless otherwise noted. This includes the firmware-only USB device | ||||||
|  | implementation for Atmel AVR microcontrollers, some simple device examples | ||||||
|  | and host side software examples and libraries. | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | 2 LICENSE GRANTS | ||||||
|  | 
 | ||||||
|  | 2.1 Source Code. OBJECTIVE DEVELOPMENT shall furnish you with the source | ||||||
|  | code of V-USB. | ||||||
|  | 
 | ||||||
|  | 2.2 Distribution and Use. OBJECTIVE DEVELOPMENT grants you the | ||||||
|  | non-exclusive right to use, copy and distribute V-USB with your hardware | ||||||
|  | product(s), restricted by the limitations in section 3 below. | ||||||
|  | 
 | ||||||
|  | 2.3 Modifications. OBJECTIVE DEVELOPMENT grants you the right to modify | ||||||
|  | the source code and your copy of V-USB according to your needs. | ||||||
|  | 
 | ||||||
|  | 2.4 USB IDs. OBJECTIVE DEVELOPMENT furnishes you with one or two USB | ||||||
|  | Product ID(s), sent to you in e-mail. These Product IDs are reserved | ||||||
|  | exclusively for you. OBJECTIVE DEVELOPMENT has obtained USB Product ID | ||||||
|  | ranges under the Vendor ID 5824 from Wouter van Ooijen (Van Ooijen | ||||||
|  | Technische Informatica, www.voti.nl) and under the Vendor ID 8352 from | ||||||
|  | Jason Kotzin (now flirc.tv, Inc.). Both owners of the Vendor IDs have | ||||||
|  | obtained these IDs from the USB Implementers Forum, Inc. (www.usb.org). | ||||||
|  | OBJECTIVE DEVELOPMENT disclaims all liability which might arise from the | ||||||
|  | assignment of USB IDs. | ||||||
|  | 
 | ||||||
|  | 2.5 USB Certification. Although not part of this agreement, we want to make | ||||||
|  | it clear that you cannot become USB certified when you use V-USB or a USB | ||||||
|  | Product ID assigned by OBJECTIVE DEVELOPMENT. AVR microcontrollers don't | ||||||
|  | meet the electrical specifications required by the USB specification and | ||||||
|  | the USB Implementers Forum certifies only members who bought a Vendor ID of | ||||||
|  | their own. | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | 3 LICENSE RESTRICTIONS | ||||||
|  | 
 | ||||||
|  | 3.1 Number of Units. Only one of the following three definitions is | ||||||
|  | applicable. Which one is determined by the amount you pay to OBJECTIVE | ||||||
|  | DEVELOPMENT, see section 4 ("Payment") below. | ||||||
|  | 
 | ||||||
|  | Hobby License: You may use V-USB according to section 2 above in no more | ||||||
|  | than 5 hardware units. These units must not be sold for profit. | ||||||
|  | 
 | ||||||
|  | Entry Level License: You may use V-USB according to section 2 above in no | ||||||
|  | more than 150 hardware units. | ||||||
|  | 
 | ||||||
|  | Professional License: You may use V-USB according to section 2 above in | ||||||
|  | any number of hardware units, except for large scale production ("unlimited | ||||||
|  | fair use"). Quantities below 10,000 units are not considered large scale | ||||||
|  | production. If your reach quantities which are obviously large scale | ||||||
|  | production, you must pay a license fee of 0.10 EUR per unit for all units | ||||||
|  | above 10,000. | ||||||
|  | 
 | ||||||
|  | 3.2 Rental. You may not rent, lease, or lend V-USB or otherwise encumber | ||||||
|  | any copy of V-USB, or any of the rights granted herein. | ||||||
|  | 
 | ||||||
|  | 3.3 Transfer. You may not transfer your rights under this Agreement to | ||||||
|  | another party without OBJECTIVE DEVELOPMENT's prior written consent. If | ||||||
|  | such consent is obtained, you may permanently transfer this License to | ||||||
|  | another party. The recipient of such transfer must agree to all terms and | ||||||
|  | conditions of this Agreement. | ||||||
|  | 
 | ||||||
|  | 3.4 Reservation of Rights. OBJECTIVE DEVELOPMENT retains all rights not | ||||||
|  | expressly granted. | ||||||
|  | 
 | ||||||
|  | 3.5 Non-Exclusive Rights. Your license rights under this Agreement are | ||||||
|  | non-exclusive. | ||||||
|  | 
 | ||||||
|  | 3.6 Third Party Rights. This Agreement cannot grant you rights controlled | ||||||
|  | by third parties. In particular, you are not allowed to use the USB logo or | ||||||
|  | other trademarks owned by the USB Implementers Forum, Inc. without their | ||||||
|  | consent. Since such consent depends on USB certification, it should be | ||||||
|  | noted that V-USB will not pass certification because it does not | ||||||
|  | implement checksum verification and the microcontroller ports do not meet | ||||||
|  | the electrical specifications. | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | 4 PAYMENT | ||||||
|  | 
 | ||||||
|  | The payment amount depends on the variation of this agreement (according to | ||||||
|  | section 3.1) into which you want to enter. Concrete prices are listed on | ||||||
|  | OBJECTIVE DEVELOPMENT's web site, usually at | ||||||
|  | http://www.obdev.at/vusb/license.html. You agree to pay the amount listed | ||||||
|  | there to OBJECTIVE DEVELOPMENT or OBJECTIVE DEVELOPMENT's payment processor | ||||||
|  | or reseller. | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | 5 COPYRIGHT AND OWNERSHIP | ||||||
|  | 
 | ||||||
|  | V-USB is protected by copyright laws and international copyright | ||||||
|  | treaties, as well as other intellectual property laws and treaties. V-USB | ||||||
|  | is licensed, not sold. | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | 6 TERM AND TERMINATION | ||||||
|  | 
 | ||||||
|  | 6.1 Term. This Agreement shall continue indefinitely. However, OBJECTIVE | ||||||
|  | DEVELOPMENT may terminate this Agreement and revoke the granted license and | ||||||
|  | USB-IDs if you fail to comply with any of its terms and conditions. | ||||||
|  | 
 | ||||||
|  | 6.2 Survival of Terms. All provisions regarding secrecy, confidentiality | ||||||
|  | and limitation of liability shall survive termination of this agreement. | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | 7 DISCLAIMER OF WARRANTY AND LIABILITY | ||||||
|  | 
 | ||||||
|  | LIMITED WARRANTY. V-USB IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY | ||||||
|  | KIND. TO THE MAXIMUM EXTENT PERMITTED BY APPLICABLE LAW, OBJECTIVE | ||||||
|  | DEVELOPMENT AND ITS SUPPLIERS HEREBY DISCLAIM ALL WARRANTIES, EITHER | ||||||
|  | EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES | ||||||
|  | OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE, AND | ||||||
|  | NON-INFRINGEMENT, WITH REGARD TO V-USB, AND THE PROVISION OF OR FAILURE | ||||||
|  | TO PROVIDE SUPPORT SERVICES. THIS LIMITED WARRANTY GIVES YOU SPECIFIC LEGAL | ||||||
|  | RIGHTS. YOU MAY HAVE OTHERS, WHICH VARY FROM STATE/JURISDICTION TO | ||||||
|  | STATE/JURISDICTION. | ||||||
|  | 
 | ||||||
|  | LIMITATION OF LIABILITY. TO THE MAXIMUM EXTENT PERMITTED BY APPLICABLE LAW, | ||||||
|  | IN NO EVENT SHALL OBJECTIVE DEVELOPMENT OR ITS SUPPLIERS BE LIABLE FOR ANY | ||||||
|  | SPECIAL, INCIDENTAL, INDIRECT, OR CONSEQUENTIAL DAMAGES WHATSOEVER | ||||||
|  | (INCLUDING, WITHOUT LIMITATION, DAMAGES FOR LOSS OF BUSINESS PROFITS, | ||||||
|  | BUSINESS INTERRUPTION, LOSS OF BUSINESS INFORMATION, OR ANY OTHER PECUNIARY | ||||||
|  | LOSS) ARISING OUT OF THE USE OF OR INABILITY TO USE V-USB OR THE | ||||||
|  | PROVISION OF OR FAILURE TO PROVIDE SUPPORT SERVICES, EVEN IF OBJECTIVE | ||||||
|  | DEVELOPMENT HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. IN ANY | ||||||
|  | CASE, OBJECTIVE DEVELOPMENT'S ENTIRE LIABILITY UNDER ANY PROVISION OF THIS | ||||||
|  | AGREEMENT SHALL BE LIMITED TO THE AMOUNT ACTUALLY PAID BY YOU FOR V-USB. | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | 8 MISCELLANEOUS TERMS | ||||||
|  | 
 | ||||||
|  | 8.1 Marketing. OBJECTIVE DEVELOPMENT has the right to mention for marketing | ||||||
|  | purposes that you entered into this agreement. | ||||||
|  | 
 | ||||||
|  | 8.2 Entire Agreement. This document represents the entire agreement between | ||||||
|  | OBJECTIVE DEVELOPMENT and you. It may only be modified in writing signed by | ||||||
|  | an authorized representative of both, OBJECTIVE DEVELOPMENT and you. | ||||||
|  | 
 | ||||||
|  | 8.3 Severability. In case a provision of these terms and conditions should | ||||||
|  | be or become partly or entirely invalid, ineffective, or not executable, | ||||||
|  | the validity of all other provisions shall not be affected. | ||||||
|  | 
 | ||||||
|  | 8.4 Applicable Law. This agreement is governed by the laws of the Republic | ||||||
|  | of Austria. | ||||||
|  | 
 | ||||||
|  | 8.5 Responsible Courts. The responsible courts in Vienna/Austria will have | ||||||
|  | exclusive jurisdiction regarding all disputes in connection with this | ||||||
|  | agreement. | ||||||
|  | 
 | ||||||
							
								
								
									
										361
									
								
								keyboards/planck/thk/bootloader/usbdrv/License.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										361
									
								
								keyboards/planck/thk/bootloader/usbdrv/License.txt
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,361 @@ | |||||||
|  | OBJECTIVE DEVELOPMENT GmbH's V-USB driver software is distributed under the | ||||||
|  | terms and conditions of the GNU GPL version 2 or the GNU GPL version 3. It is | ||||||
|  | your choice whether you apply the terms of version 2 or version 3. The full | ||||||
|  | text of GPLv2 is included below. In addition to the requirements in the GPL, | ||||||
|  | we STRONGLY ENCOURAGE you to do the following: | ||||||
|  | 
 | ||||||
|  | (1) Publish your entire project on a web site and drop us a note with the URL. | ||||||
|  | Use the form at http://www.obdev.at/vusb/feedback.html for your submission. | ||||||
|  | 
 | ||||||
|  | (2) Adhere to minimum publication standards. Please include AT LEAST: | ||||||
|  |     - a circuit diagram in PDF, PNG or GIF format | ||||||
|  |     - full source code for the host software | ||||||
|  |     - a Readme.txt file in ASCII format which describes the purpose of the | ||||||
|  |       project and what can be found in which directories and which files | ||||||
|  |     - a reference to http://www.obdev.at/vusb/ | ||||||
|  | 
 | ||||||
|  | (3) If you improve the driver firmware itself, please give us a free license | ||||||
|  | to your modifications for our commercial license offerings. | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  |                     GNU GENERAL PUBLIC LICENSE | ||||||
|  |                        Version 2, June 1991 | ||||||
|  | 
 | ||||||
|  |  Copyright (C) 1989, 1991 Free Software Foundation, Inc. | ||||||
|  |                        59 Temple Place, Suite 330, Boston, MA  02111-1307  USA | ||||||
|  |  Everyone is permitted to copy and distribute verbatim copies | ||||||
|  |  of this license document, but changing it is not allowed. | ||||||
|  | 
 | ||||||
|  |                             Preamble | ||||||
|  | 
 | ||||||
|  |   The licenses for most software are designed to take away your | ||||||
|  | freedom to share and change it.  By contrast, the GNU General Public | ||||||
|  | License is intended to guarantee your freedom to share and change free | ||||||
|  | software--to make sure the software is free for all its users.  This | ||||||
|  | General Public License applies to most of the Free Software | ||||||
|  | Foundation's software and to any other program whose authors commit to | ||||||
|  | using it.  (Some other Free Software Foundation software is covered by | ||||||
|  | the GNU Library General Public License instead.)  You can apply it to | ||||||
|  | your programs, too. | ||||||
|  | 
 | ||||||
|  |   When we speak of free software, we are referring to freedom, not | ||||||
|  | price.  Our General Public Licenses are designed to make sure that you | ||||||
|  | have the freedom to distribute copies of free software (and charge for | ||||||
|  | this service if you wish), that you receive source code or can get it | ||||||
|  | if you want it, that you can change the software or use pieces of it | ||||||
|  | in new free programs; and that you know you can do these things. | ||||||
|  | 
 | ||||||
|  |   To protect your rights, we need to make restrictions that forbid | ||||||
|  | anyone to deny you these rights or to ask you to surrender the rights. | ||||||
|  | These restrictions translate to certain responsibilities for you if you | ||||||
|  | distribute copies of the software, or if you modify it. | ||||||
|  | 
 | ||||||
|  |   For example, if you distribute copies of such a program, whether | ||||||
|  | gratis or for a fee, you must give the recipients all the rights that | ||||||
|  | you have.  You must make sure that they, too, receive or can get the | ||||||
|  | source code.  And you must show them these terms so they know their | ||||||
|  | rights. | ||||||
|  | 
 | ||||||
|  |   We protect your rights with two steps: (1) copyright the software, and | ||||||
|  | (2) offer you this license which gives you legal permission to copy, | ||||||
|  | distribute and/or modify the software. | ||||||
|  | 
 | ||||||
|  |   Also, for each author's protection and ours, we want to make certain | ||||||
|  | that everyone understands that there is no warranty for this free | ||||||
|  | software.  If the software is modified by someone else and passed on, we | ||||||
|  | want its recipients to know that what they have is not the original, so | ||||||
|  | that any problems introduced by others will not reflect on the original | ||||||
|  | authors' reputations. | ||||||
|  | 
 | ||||||
|  |   Finally, any free program is threatened constantly by software | ||||||
|  | patents.  We wish to avoid the danger that redistributors of a free | ||||||
|  | program will individually obtain patent licenses, in effect making the | ||||||
|  | program proprietary.  To prevent this, we have made it clear that any | ||||||
|  | patent must be licensed for everyone's free use or not licensed at all. | ||||||
|  | 
 | ||||||
|  |   The precise terms and conditions for copying, distribution and | ||||||
|  | modification follow. | ||||||
|  |  | ||||||
|  |                     GNU GENERAL PUBLIC LICENSE | ||||||
|  |    TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION | ||||||
|  | 
 | ||||||
|  |   0. This License applies to any program or other work which contains | ||||||
|  | a notice placed by the copyright holder saying it may be distributed | ||||||
|  | under the terms of this General Public License.  The "Program", below, | ||||||
|  | refers to any such program or work, and a "work based on the Program" | ||||||
|  | means either the Program or any derivative work under copyright law: | ||||||
|  | that is to say, a work containing the Program or a portion of it, | ||||||
|  | either verbatim or with modifications and/or translated into another | ||||||
|  | language.  (Hereinafter, translation is included without limitation in | ||||||
|  | the term "modification".)  Each licensee is addressed as "you". | ||||||
|  | 
 | ||||||
|  | Activities other than copying, distribution and modification are not | ||||||
|  | covered by this License; they are outside its scope.  The act of | ||||||
|  | running the Program is not restricted, and the output from the Program | ||||||
|  | is covered only if its contents constitute a work based on the | ||||||
|  | Program (independent of having been made by running the Program). | ||||||
|  | Whether that is true depends on what the Program does. | ||||||
|  | 
 | ||||||
|  |   1. You may copy and distribute verbatim copies of the Program's | ||||||
|  | source code as you receive it, in any medium, provided that you | ||||||
|  | conspicuously and appropriately publish on each copy an appropriate | ||||||
|  | copyright notice and disclaimer of warranty; keep intact all the | ||||||
|  | notices that refer to this License and to the absence of any warranty; | ||||||
|  | and give any other recipients of the Program a copy of this License | ||||||
|  | along with the Program. | ||||||
|  | 
 | ||||||
|  | You may charge a fee for the physical act of transferring a copy, and | ||||||
|  | you may at your option offer warranty protection in exchange for a fee. | ||||||
|  | 
 | ||||||
|  |   2. You may modify your copy or copies of the Program or any portion | ||||||
|  | of it, thus forming a work based on the Program, and copy and | ||||||
|  | distribute such modifications or work under the terms of Section 1 | ||||||
|  | above, provided that you also meet all of these conditions: | ||||||
|  | 
 | ||||||
|  |     a) You must cause the modified files to carry prominent notices | ||||||
|  |     stating that you changed the files and the date of any change. | ||||||
|  | 
 | ||||||
|  |     b) You must cause any work that you distribute or publish, that in | ||||||
|  |     whole or in part contains or is derived from the Program or any | ||||||
|  |     part thereof, to be licensed as a whole at no charge to all third | ||||||
|  |     parties under the terms of this License. | ||||||
|  | 
 | ||||||
|  |     c) If the modified program normally reads commands interactively | ||||||
|  |     when run, you must cause it, when started running for such | ||||||
|  |     interactive use in the most ordinary way, to print or display an | ||||||
|  |     announcement including an appropriate copyright notice and a | ||||||
|  |     notice that there is no warranty (or else, saying that you provide | ||||||
|  |     a warranty) and that users may redistribute the program under | ||||||
|  |     these conditions, and telling the user how to view a copy of this | ||||||
|  |     License.  (Exception: if the Program itself is interactive but | ||||||
|  |     does not normally print such an announcement, your work based on | ||||||
|  |     the Program is not required to print an announcement.) | ||||||
|  |  | ||||||
|  | These requirements apply to the modified work as a whole.  If | ||||||
|  | identifiable sections of that work are not derived from the Program, | ||||||
|  | and can be reasonably considered independent and separate works in | ||||||
|  | themselves, then this License, and its terms, do not apply to those | ||||||
|  | sections when you distribute them as separate works.  But when you | ||||||
|  | distribute the same sections as part of a whole which is a work based | ||||||
|  | on the Program, the distribution of the whole must be on the terms of | ||||||
|  | this License, whose permissions for other licensees extend to the | ||||||
|  | entire whole, and thus to each and every part regardless of who wrote it. | ||||||
|  | 
 | ||||||
|  | Thus, it is not the intent of this section to claim rights or contest | ||||||
|  | your rights to work written entirely by you; rather, the intent is to | ||||||
|  | exercise the right to control the distribution of derivative or | ||||||
|  | collective works based on the Program. | ||||||
|  | 
 | ||||||
|  | In addition, mere aggregation of another work not based on the Program | ||||||
|  | with the Program (or with a work based on the Program) on a volume of | ||||||
|  | a storage or distribution medium does not bring the other work under | ||||||
|  | the scope of this License. | ||||||
|  | 
 | ||||||
|  |   3. You may copy and distribute the Program (or a work based on it, | ||||||
|  | under Section 2) in object code or executable form under the terms of | ||||||
|  | Sections 1 and 2 above provided that you also do one of the following: | ||||||
|  | 
 | ||||||
|  |     a) Accompany it with the complete corresponding machine-readable | ||||||
|  |     source code, which must be distributed under the terms of Sections | ||||||
|  |     1 and 2 above on a medium customarily used for software interchange; or, | ||||||
|  | 
 | ||||||
|  |     b) Accompany it with a written offer, valid for at least three | ||||||
|  |     years, to give any third party, for a charge no more than your | ||||||
|  |     cost of physically performing source distribution, a complete | ||||||
|  |     machine-readable copy of the corresponding source code, to be | ||||||
|  |     distributed under the terms of Sections 1 and 2 above on a medium | ||||||
|  |     customarily used for software interchange; or, | ||||||
|  | 
 | ||||||
|  |     c) Accompany it with the information you received as to the offer | ||||||
|  |     to distribute corresponding source code.  (This alternative is | ||||||
|  |     allowed only for noncommercial distribution and only if you | ||||||
|  |     received the program in object code or executable form with such | ||||||
|  |     an offer, in accord with Subsection b above.) | ||||||
|  | 
 | ||||||
|  | The source code for a work means the preferred form of the work for | ||||||
|  | making modifications to it.  For an executable work, complete source | ||||||
|  | code means all the source code for all modules it contains, plus any | ||||||
|  | associated interface definition files, plus the scripts used to | ||||||
|  | control compilation and installation of the executable.  However, as a | ||||||
|  | special exception, the source code distributed need not include | ||||||
|  | anything that is normally distributed (in either source or binary | ||||||
|  | form) with the major components (compiler, kernel, and so on) of the | ||||||
|  | operating system on which the executable runs, unless that component | ||||||
|  | itself accompanies the executable. | ||||||
|  | 
 | ||||||
|  | If distribution of executable or object code is made by offering | ||||||
|  | access to copy from a designated place, then offering equivalent | ||||||
|  | access to copy the source code from the same place counts as | ||||||
|  | distribution of the source code, even though third parties are not | ||||||
|  | compelled to copy the source along with the object code. | ||||||
|  |  | ||||||
|  |   4. You may not copy, modify, sublicense, or distribute the Program | ||||||
|  | except as expressly provided under this License.  Any attempt | ||||||
|  | otherwise to copy, modify, sublicense or distribute the Program is | ||||||
|  | void, and will automatically terminate your rights under this License. | ||||||
|  | However, parties who have received copies, or rights, from you under | ||||||
|  | this License will not have their licenses terminated so long as such | ||||||
|  | parties remain in full compliance. | ||||||
|  | 
 | ||||||
|  |   5. You are not required to accept this License, since you have not | ||||||
|  | signed it.  However, nothing else grants you permission to modify or | ||||||
|  | distribute the Program or its derivative works.  These actions are | ||||||
|  | prohibited by law if you do not accept this License.  Therefore, by | ||||||
|  | modifying or distributing the Program (or any work based on the | ||||||
|  | Program), you indicate your acceptance of this License to do so, and | ||||||
|  | all its terms and conditions for copying, distributing or modifying | ||||||
|  | the Program or works based on it. | ||||||
|  | 
 | ||||||
|  |   6. Each time you redistribute the Program (or any work based on the | ||||||
|  | Program), the recipient automatically receives a license from the | ||||||
|  | original licensor to copy, distribute or modify the Program subject to | ||||||
|  | these terms and conditions.  You may not impose any further | ||||||
|  | restrictions on the recipients' exercise of the rights granted herein. | ||||||
|  | You are not responsible for enforcing compliance by third parties to | ||||||
|  | this License. | ||||||
|  | 
 | ||||||
|  |   7. If, as a consequence of a court judgment or allegation of patent | ||||||
|  | infringement or for any other reason (not limited to patent issues), | ||||||
|  | conditions are imposed on you (whether by court order, agreement or | ||||||
|  | otherwise) that contradict the conditions of this License, they do not | ||||||
|  | excuse you from the conditions of this License.  If you cannot | ||||||
|  | distribute so as to satisfy simultaneously your obligations under this | ||||||
|  | License and any other pertinent obligations, then as a consequence you | ||||||
|  | may not distribute the Program at all.  For example, if a patent | ||||||
|  | license would not permit royalty-free redistribution of the Program by | ||||||
|  | all those who receive copies directly or indirectly through you, then | ||||||
|  | the only way you could satisfy both it and this License would be to | ||||||
|  | refrain entirely from distribution of the Program. | ||||||
|  | 
 | ||||||
|  | If any portion of this section is held invalid or unenforceable under | ||||||
|  | any particular circumstance, the balance of the section is intended to | ||||||
|  | apply and the section as a whole is intended to apply in other | ||||||
|  | circumstances. | ||||||
|  | 
 | ||||||
|  | It is not the purpose of this section to induce you to infringe any | ||||||
|  | patents or other property right claims or to contest validity of any | ||||||
|  | such claims; this section has the sole purpose of protecting the | ||||||
|  | integrity of the free software distribution system, which is | ||||||
|  | implemented by public license practices.  Many people have made | ||||||
|  | generous contributions to the wide range of software distributed | ||||||
|  | through that system in reliance on consistent application of that | ||||||
|  | system; it is up to the author/donor to decide if he or she is willing | ||||||
|  | to distribute software through any other system and a licensee cannot | ||||||
|  | impose that choice. | ||||||
|  | 
 | ||||||
|  | This section is intended to make thoroughly clear what is believed to | ||||||
|  | be a consequence of the rest of this License. | ||||||
|  |  | ||||||
|  |   8. If the distribution and/or use of the Program is restricted in | ||||||
|  | certain countries either by patents or by copyrighted interfaces, the | ||||||
|  | original copyright holder who places the Program under this License | ||||||
|  | may add an explicit geographical distribution limitation excluding | ||||||
|  | those countries, so that distribution is permitted only in or among | ||||||
|  | countries not thus excluded.  In such case, this License incorporates | ||||||
|  | the limitation as if written in the body of this License. | ||||||
|  | 
 | ||||||
|  |   9. The Free Software Foundation may publish revised and/or new versions | ||||||
|  | of the General Public License from time to time.  Such new versions will | ||||||
|  | be similar in spirit to the present version, but may differ in detail to | ||||||
|  | address new problems or concerns. | ||||||
|  | 
 | ||||||
|  | Each version is given a distinguishing version number.  If the Program | ||||||
|  | specifies a version number of this License which applies to it and "any | ||||||
|  | later version", you have the option of following the terms and conditions | ||||||
|  | either of that version or of any later version published by the Free | ||||||
|  | Software Foundation.  If the Program does not specify a version number of | ||||||
|  | this License, you may choose any version ever published by the Free Software | ||||||
|  | Foundation. | ||||||
|  | 
 | ||||||
|  |   10. If you wish to incorporate parts of the Program into other free | ||||||
|  | programs whose distribution conditions are different, write to the author | ||||||
|  | to ask for permission.  For software which is copyrighted by the Free | ||||||
|  | Software Foundation, write to the Free Software Foundation; we sometimes | ||||||
|  | make exceptions for this.  Our decision will be guided by the two goals | ||||||
|  | of preserving the free status of all derivatives of our free software and | ||||||
|  | of promoting the sharing and reuse of software generally. | ||||||
|  | 
 | ||||||
|  |                             NO WARRANTY | ||||||
|  | 
 | ||||||
|  |   11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY | ||||||
|  | FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN | ||||||
|  | OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES | ||||||
|  | PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED | ||||||
|  | OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF | ||||||
|  | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS | ||||||
|  | TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE | ||||||
|  | PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, | ||||||
|  | REPAIR OR CORRECTION. | ||||||
|  | 
 | ||||||
|  |   12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING | ||||||
|  | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR | ||||||
|  | REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, | ||||||
|  | INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING | ||||||
|  | OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED | ||||||
|  | TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY | ||||||
|  | YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER | ||||||
|  | PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE | ||||||
|  | POSSIBILITY OF SUCH DAMAGES. | ||||||
|  | 
 | ||||||
|  |                      END OF TERMS AND CONDITIONS | ||||||
|  |  | ||||||
|  |             How to Apply These Terms to Your New Programs | ||||||
|  | 
 | ||||||
|  |   If you develop a new program, and you want it to be of the greatest | ||||||
|  | possible use to the public, the best way to achieve this is to make it | ||||||
|  | free software which everyone can redistribute and change under these terms. | ||||||
|  | 
 | ||||||
|  |   To do so, attach the following notices to the program.  It is safest | ||||||
|  | to attach them to the start of each source file to most effectively | ||||||
|  | convey the exclusion of warranty; and each file should have at least | ||||||
|  | the "copyright" line and a pointer to where the full notice is found. | ||||||
|  | 
 | ||||||
|  |     <one line to give the program's name and a brief idea of what it does.> | ||||||
|  |     Copyright (C) <year>  <name of author> | ||||||
|  | 
 | ||||||
|  |     This program is free software; you can redistribute it and/or modify | ||||||
|  |     it under the terms of the GNU General Public License as published by | ||||||
|  |     the Free Software Foundation; either version 2 of the License, or | ||||||
|  |     (at your option) any later version. | ||||||
|  | 
 | ||||||
|  |     This program is distributed in the hope that it will be useful, | ||||||
|  |     but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||||
|  |     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||||
|  |     GNU General Public License for more details. | ||||||
|  | 
 | ||||||
|  |     You should have received a copy of the GNU General Public License | ||||||
|  |     along with this program; if not, write to the Free Software | ||||||
|  |     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | Also add information on how to contact you by electronic and paper mail. | ||||||
|  | 
 | ||||||
|  | If the program is interactive, make it output a short notice like this | ||||||
|  | when it starts in an interactive mode: | ||||||
|  | 
 | ||||||
|  |     Gnomovision version 69, Copyright (C) year name of author | ||||||
|  |     Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. | ||||||
|  |     This is free software, and you are welcome to redistribute it | ||||||
|  |     under certain conditions; type `show c' for details. | ||||||
|  | 
 | ||||||
|  | The hypothetical commands `show w' and `show c' should show the appropriate | ||||||
|  | parts of the General Public License.  Of course, the commands you use may | ||||||
|  | be called something other than `show w' and `show c'; they could even be | ||||||
|  | mouse-clicks or menu items--whatever suits your program. | ||||||
|  | 
 | ||||||
|  | You should also get your employer (if you work as a programmer) or your | ||||||
|  | school, if any, to sign a "copyright disclaimer" for the program, if | ||||||
|  | necessary.  Here is a sample; alter the names: | ||||||
|  | 
 | ||||||
|  |   Yoyodyne, Inc., hereby disclaims all copyright interest in the program | ||||||
|  |   `Gnomovision' (which makes passes at compilers) written by James Hacker. | ||||||
|  | 
 | ||||||
|  |   <signature of Ty Coon>, 1 April 1989 | ||||||
|  |   Ty Coon, President of Vice | ||||||
|  | 
 | ||||||
|  | This General Public License does not permit incorporating your program into | ||||||
|  | proprietary programs.  If your program is a subroutine library, you may | ||||||
|  | consider it more useful to permit linking proprietary applications with the | ||||||
|  | library.  If this is what you want to do, use the GNU Library General | ||||||
|  | Public License instead of this License. | ||||||
							
								
								
									
										172
									
								
								keyboards/planck/thk/bootloader/usbdrv/Readme.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										172
									
								
								keyboards/planck/thk/bootloader/usbdrv/Readme.txt
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,172 @@ | |||||||
|  | This is the Readme file to Objective Development's firmware-only USB driver | ||||||
|  | for Atmel AVR microcontrollers. For more information please visit | ||||||
|  | http://www.obdev.at/vusb/ | ||||||
|  | 
 | ||||||
|  | This directory contains the USB firmware only. Copy it as-is to your own | ||||||
|  | project and add all .c and .S files to your project (these files are marked | ||||||
|  | with an asterisk in the list below). Then copy usbconfig-prototype.h as | ||||||
|  | usbconfig.h to your project and edit it according to your configuration. | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | TECHNICAL DOCUMENTATION | ||||||
|  | ======================= | ||||||
|  | The technical documentation (API) for the firmware driver is contained in the | ||||||
|  | file "usbdrv.h". Please read all of it carefully! Configuration options are | ||||||
|  | documented in "usbconfig-prototype.h". | ||||||
|  | 
 | ||||||
|  | The driver consists of the following files: | ||||||
|  |   Readme.txt ............. The file you are currently reading. | ||||||
|  |   Changelog.txt .......... Release notes for all versions of the driver. | ||||||
|  |   usbdrv.h ............... Driver interface definitions and technical docs. | ||||||
|  | * usbdrv.c ............... High level language part of the driver. Link this | ||||||
|  |                            module to your code! | ||||||
|  | * usbdrvasm.S ............ Assembler part of the driver. This module is mostly | ||||||
|  |                            a stub and includes one of the usbdrvasm*.S files | ||||||
|  |                            depending on processor clock. Link this module to | ||||||
|  |                            your code! | ||||||
|  |   usbdrvasm*.inc ......... Assembler routines for particular clock frequencies. | ||||||
|  |                            Included by usbdrvasm.S, don't link it directly! | ||||||
|  |   asmcommon.inc .......... Common assembler routines. Included by | ||||||
|  |                            usbdrvasm*.inc, don't link it directly! | ||||||
|  |   usbconfig-prototype.h .. Prototype for your own usbdrv.h file. | ||||||
|  | * oddebug.c .............. Debug functions. Only used when DEBUG_LEVEL is | ||||||
|  |                            defined to a value greater than 0. Link this module | ||||||
|  |                            to your code! | ||||||
|  |   oddebug.h .............. Interface definitions of the debug module. | ||||||
|  |   usbportability.h ....... Header with compiler-dependent stuff. | ||||||
|  |   usbdrvasm.asm .......... Compatibility stub for IAR-C-compiler. Use this | ||||||
|  |                            module instead of usbdrvasm.S when you assembler | ||||||
|  |                            with IAR's tools. | ||||||
|  |   License.txt ............ Open Source license for this driver. | ||||||
|  |   CommercialLicense.txt .. Optional commercial license for this driver. | ||||||
|  |   USB-ID-FAQ.txt ......... General infos about USB Product- and Vendor-IDs. | ||||||
|  |   USB-IDs-for-free.txt ... List and terms of use for free shared PIDs. | ||||||
|  | 
 | ||||||
|  | (*) ... These files should be linked to your project. | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | CPU CORE CLOCK FREQUENCY | ||||||
|  | ======================== | ||||||
|  | We supply assembler modules for clock frequencies of 12 MHz, 12.8 MHz, 15 MHz, | ||||||
|  | 16 MHz, 16.5 MHz 18 MHz and 20 MHz. Other clock rates are not supported. The | ||||||
|  | actual clock rate must be configured in usbconfig.h. | ||||||
|  | 
 | ||||||
|  | 12 MHz Clock | ||||||
|  | This is the traditional clock rate of V-USB because it's the lowest clock | ||||||
|  | rate where the timing constraints of the USB spec can be met. | ||||||
|  | 
 | ||||||
|  | 15 MHz Clock | ||||||
|  | Similar to 12 MHz, but some NOPs inserted. On the other hand, the higher clock | ||||||
|  | rate allows for some loops which make the resulting code size somewhat smaller | ||||||
|  | than the 12 MHz version. | ||||||
|  | 
 | ||||||
|  | 16 MHz Clock | ||||||
|  | This clock rate has been added for users of the Arduino board and other | ||||||
|  | ready-made boards which come with a fixed 16 MHz crystal. It's also an option | ||||||
|  | if you need the slightly higher clock rate for performance reasons. Since | ||||||
|  | 16 MHz is not divisible by the USB low speed bit clock of 1.5 MHz, the code | ||||||
|  | is somewhat tricky and has to insert a leap cycle every third byte. | ||||||
|  | 
 | ||||||
|  | 12.8 MHz and 16.5 MHz Clock | ||||||
|  | The assembler modules for these clock rates differ from the other modules | ||||||
|  | because they have been built for an RC oscillator with only 1% precision. The | ||||||
|  | receiver code inserts leap cycles to compensate for clock deviations. 1% is | ||||||
|  | also the precision which can be achieved by calibrating the internal RC | ||||||
|  | oscillator of the AVR. Please note that only AVRs with internal 64 MHz PLL | ||||||
|  | oscillator can reach 16.5 MHz with the RC oscillator. This includes the very | ||||||
|  | popular ATTiny25, ATTiny45, ATTiny85 series as well as the ATTiny26. Almost | ||||||
|  | all AVRs can reach 12.8 MHz, although this is outside the specified range. | ||||||
|  | 
 | ||||||
|  | See the EasyLogger example at http://www.obdev.at/vusb/easylogger.html for | ||||||
|  | code which calibrates the RC oscillator based on the USB frame clock. | ||||||
|  | 
 | ||||||
|  | 18 MHz Clock | ||||||
|  | This module is closer to the USB specification because it performs an on the | ||||||
|  | fly CRC check for incoming packets. Packets with invalid checksum are | ||||||
|  | discarded as required by the spec. If you also implement checks for data | ||||||
|  | PID toggling on application level (see option USB_CFG_CHECK_DATA_TOGGLING | ||||||
|  | in usbconfig.h for more info), this ensures data integrity. Due to the CRC | ||||||
|  | tables and alignment requirements, this code is bigger than modules for other | ||||||
|  | clock rates. To activate this module, you must define USB_CFG_CHECK_CRC to 1 | ||||||
|  | and USB_CFG_CLOCK_KHZ to 18000 in usbconfig.h. | ||||||
|  | 
 | ||||||
|  | 20 MHz Clock | ||||||
|  | This module is for people who won't do it with less than the maximum. Since | ||||||
|  | 20 MHz is not divisible by the USB low speed bit clock of 1.5 MHz, the code | ||||||
|  | uses similar tricks as the 16 MHz module to insert leap cycles. | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | USB IDENTIFIERS | ||||||
|  | =============== | ||||||
|  | Every USB device needs a vendor- and a product-identifier (VID and PID). VIDs | ||||||
|  | are obtained from usb.org for a price of 1,500 USD. Once you have a VID, you | ||||||
|  | can assign PIDs at will. | ||||||
|  | 
 | ||||||
|  | Since an entry level cost of 1,500 USD is too high for most small companies | ||||||
|  | and hobbyists, we provide some VID/PID pairs for free. See the file | ||||||
|  | USB-IDs-for-free.txt for details. | ||||||
|  | 
 | ||||||
|  | Objective Development also has some license offerings which include product | ||||||
|  | IDs. See http://www.obdev.at/vusb/ for details. | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | DEVELOPMENT SYSTEM | ||||||
|  | ================== | ||||||
|  | This driver has been developed and optimized for the GNU compiler version 3 | ||||||
|  | and 4. We recommend that you use the GNU compiler suite because it is freely | ||||||
|  | available. V-USB has also been ported to the IAR compiler and assembler. It | ||||||
|  | has been tested with IAR 4.10B/W32 and 4.12A/W32 on an ATmega8 with the | ||||||
|  | "small" and "tiny" memory model. Not every release is tested with IAR CC and | ||||||
|  | the driver may therefore fail to compile with IAR. Please note that gcc is | ||||||
|  | more efficient for usbdrv.c because this module has been deliberately | ||||||
|  | optimized for gcc. | ||||||
|  | 
 | ||||||
|  | Gcc version 3 produces smaller code than version 4 due to new optimizing | ||||||
|  | capabilities which don't always improve things on 8 bit CPUs. The code size | ||||||
|  | generated by gcc 4 can be reduced with the compiler options | ||||||
|  | -fno-move-loop-invariants, -fno-tree-scev-cprop and | ||||||
|  | -fno-inline-small-functions in addition to -Os. On devices with more than | ||||||
|  | 8k of flash memory, we also recommend the linker option --relax (written as | ||||||
|  | -Wl,--relax for gcc) to convert absolute calls into relative where possible. | ||||||
|  | 
 | ||||||
|  | For more information about optimizing options see: | ||||||
|  | 
 | ||||||
|  |     http://www.tty1.net/blog/2008-04-29-avr-gcc-optimisations_en.html | ||||||
|  | 
 | ||||||
|  | These optimizations are good for gcc 4.x. Version 3.x of gcc does not support | ||||||
|  | most of these options and produces good code anyway. | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | USING V-USB FOR FREE | ||||||
|  | ==================== | ||||||
|  | The AVR firmware driver is published under the GNU General Public License | ||||||
|  | Version 2 (GPL2) and the GNU General Public License Version 3 (GPL3). It is | ||||||
|  | your choice whether you apply the terms of version 2 or version 3. | ||||||
|  | 
 | ||||||
|  | If you decide for the free GPL2 or GPL3, we STRONGLY ENCOURAGE you to do the | ||||||
|  | following things IN ADDITION to the obligations from the GPL: | ||||||
|  | 
 | ||||||
|  | (1) Publish your entire project on a web site and drop us a note with the URL. | ||||||
|  | Use the form at http://www.obdev.at/vusb/feedback.html for your submission. | ||||||
|  | If you don't have a web site, you can publish the project in obdev's | ||||||
|  | documentation wiki at | ||||||
|  | http://www.obdev.at/goto.php?t=vusb-wiki&p=hosted-projects. | ||||||
|  | 
 | ||||||
|  | (2) Adhere to minimum publication standards. Please include AT LEAST: | ||||||
|  |     - a circuit diagram in PDF, PNG or GIF format | ||||||
|  |     - full source code for the host software | ||||||
|  |     - a Readme.txt file in ASCII format which describes the purpose of the | ||||||
|  |       project and what can be found in which directories and which files | ||||||
|  |     - a reference to http://www.obdev.at/vusb/ | ||||||
|  | 
 | ||||||
|  | (3) If you improve the driver firmware itself, please give us a free license | ||||||
|  | to your modifications for our commercial license offerings. | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | COMMERCIAL LICENSES FOR V-USB | ||||||
|  | ============================= | ||||||
|  | If you don't want to publish your source code under the terms of the GPL, | ||||||
|  | you can simply pay money for V-USB. As an additional benefit you get | ||||||
|  | USB PIDs for free, reserved exclusively to you. See the file | ||||||
|  | "CommercialLicense.txt" for details. | ||||||
|  | 
 | ||||||
							
								
								
									
										149
									
								
								keyboards/planck/thk/bootloader/usbdrv/USB-ID-FAQ.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										149
									
								
								keyboards/planck/thk/bootloader/usbdrv/USB-ID-FAQ.txt
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,149 @@ | |||||||
|  | Version 2012-07-09 | ||||||
|  | 
 | ||||||
|  | ========================== | ||||||
|  | WHY DO WE NEED THESE IDs? | ||||||
|  | ========================== | ||||||
|  | 
 | ||||||
|  | USB is more than a low level protocol for data transport. It also defines a | ||||||
|  | common set of requests which must be understood by all devices. And as part | ||||||
|  | of these common requests, the specification defines data structures, the | ||||||
|  | USB Descriptors, which are used to describe the properties of the device. | ||||||
|  | 
 | ||||||
|  | From the perspective of an operating system, it is therefore possible to find | ||||||
|  | out basic properties of a device (such as e.g. the manufacturer and the name | ||||||
|  | of the device) without a device-specific driver. This is essential because | ||||||
|  | the operating system can choose a driver to load based on this information | ||||||
|  | (Plug-And-Play). | ||||||
|  | 
 | ||||||
|  | Among the most important properties in the Device Descriptor are the USB | ||||||
|  | Vendor- and Product-ID. Both are 16 bit integers. The most simple form of | ||||||
|  | driver matching is based on these IDs. The driver announces the Vendor- and | ||||||
|  | Product-IDs of the devices it can handle and the operating system loads the | ||||||
|  | appropriate driver when the device is connected. | ||||||
|  | 
 | ||||||
|  | It is obvious that this technique only works if the pair Vendor- plus | ||||||
|  | Product-ID is unique: Only devices which require the same driver can have the | ||||||
|  | same pair of IDs. | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | ===================================================== | ||||||
|  | HOW DOES THE USB STANDARD ENSURE THAT IDs ARE UNIQUE? | ||||||
|  | ===================================================== | ||||||
|  | 
 | ||||||
|  | Since it is so important that USB IDs are unique, the USB Implementers Forum, | ||||||
|  | Inc. (usb.org) needs a way to enforce this legally. It is not forbidden by | ||||||
|  | law to build a device and assign it any random numbers as IDs. Usb.org | ||||||
|  | therefore needs an agreement to regulate the use of USB IDs. The agreement | ||||||
|  | binds only parties who agreed to it, of course. Everybody else is free to use | ||||||
|  | any numbers for their IDs. | ||||||
|  | 
 | ||||||
|  | So how can usb.org ensure that every manufacturer of USB devices enters into | ||||||
|  | an agreement with them? They do it via trademark licensing. Usb.org has | ||||||
|  | registered the trademark "USB", all associated logos and related terms. If | ||||||
|  | you want to put an USB logo on your product or claim that it is USB | ||||||
|  | compliant, you must license these trademarks from usb.org. And this is where | ||||||
|  | you enter into an agreement. See the "USB-IF Trademark License Agreement and | ||||||
|  | Usage Guidelines for the USB-IF Logo" at | ||||||
|  | http://www.usb.org/developers/logo_license/. | ||||||
|  | 
 | ||||||
|  | Licensing the USB trademarks requires that you buy a USB Vendor-ID from | ||||||
|  | usb.org (one-time fee of ca. 2,000 USD), that you become a member of usb.org | ||||||
|  | (yearly fee of ca. 4,000 USD) and that you meet all the technical | ||||||
|  | specifications from the USB spec. | ||||||
|  | 
 | ||||||
|  | This means that most hobbyists and small companies will never be able to | ||||||
|  | become USB compliant, just because membership is so expensive. And you can't | ||||||
|  | be compliant with a driver based on V-USB anyway, because the AVR's port pins | ||||||
|  | don't meet the electrical specifications for USB. So, in principle, all | ||||||
|  | hobbyists and small companies are free to choose any random numbers for their | ||||||
|  | IDs. They have nothing to lose... | ||||||
|  | 
 | ||||||
|  | There is one exception worth noting, though: If you use a sub-component which | ||||||
|  | implements USB, the vendor of the sub-components may guarantee USB | ||||||
|  | compliance. This might apply to some or all of FTDI's solutions. | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | ======================================================================= | ||||||
|  | WHY SHOULD YOU OBTAIN USB IDs EVEN IF YOU DON'T LICENSE USB TRADEMARKS? | ||||||
|  | ======================================================================= | ||||||
|  | 
 | ||||||
|  | You have learned in the previous section that you are free to choose any | ||||||
|  | numbers for your IDs anyway. So why not do exactly this? There is still the | ||||||
|  | technical issue. If you choose IDs which are already in use by somebody else, | ||||||
|  | operating systems will load the wrong drivers and your device won't work. | ||||||
|  | Even if you choose IDs which are not currently in use, they may be in use in | ||||||
|  | the next version of the operating system or even after an automatic update. | ||||||
|  | 
 | ||||||
|  | So what you need is a pair of Vendor- and Product-IDs for which you have the | ||||||
|  | guarantee that no USB compliant product uses them. This implies that no | ||||||
|  | operating system will ever ship with drivers responsible for these IDs. | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | ============================================== | ||||||
|  | HOW DOES OBJECTIVE DEVELOPMENT HANDLE USB IDs? | ||||||
|  | ============================================== | ||||||
|  | 
 | ||||||
|  | Objective Development gives away pairs of USB-IDs with their V-USB licenses. | ||||||
|  | In order to ensure that these IDs are unique, Objective Development has an | ||||||
|  | agreement with the company/person who has bought the USB Vendor-ID from | ||||||
|  | usb.org. This agreement ensures that a range of USB Product-IDs is reserved | ||||||
|  | for assignment by Objective Development and that the owner of the Vendor-ID | ||||||
|  | won't give it to anybody else. | ||||||
|  | 
 | ||||||
|  | This means that you have to trust three parties to ensure uniqueness of | ||||||
|  | your IDs: | ||||||
|  | 
 | ||||||
|  |   - Objective Development, that they don't give the same PID to more than | ||||||
|  |     one person. | ||||||
|  |   - The owner of the Vendor-ID that they don't assign PIDs from the range | ||||||
|  |     assigned to Objective Development to anybody else. | ||||||
|  |   - Usb.org that they don't assign the same Vendor-ID a second time. | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | ================================== | ||||||
|  | WHO IS THE OWNER OF THE VENDOR-ID? | ||||||
|  | ================================== | ||||||
|  | 
 | ||||||
|  | Objective Development has obtained ranges of USB Product-IDs under two | ||||||
|  | Vendor-IDs: Under Vendor-ID 5824 from Wouter van Ooijen (Van Ooijen | ||||||
|  | Technische Informatica, www.voti.nl) and under Vendor-ID 8352 from Jason | ||||||
|  | Kotzin (now flirc.tv, Inc.). Both VID owners have received their Vendor-ID | ||||||
|  | directly from usb.org. | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | ========================================================================= | ||||||
|  | CAN I USE USB-IDs FROM OBJECTIVE DEVELOPMENT WITH OTHER DRIVERS/HARDWARE? | ||||||
|  | ========================================================================= | ||||||
|  | 
 | ||||||
|  | The short answer is: Yes. All you get is a guarantee that the IDs are never | ||||||
|  | assigned to anybody else. What more do you need? | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | ============================ | ||||||
|  | WHAT ABOUT SHARED ID PAIRS? | ||||||
|  | ============================ | ||||||
|  | 
 | ||||||
|  | Objective Development has reserved some PID/VID pairs for shared use. You | ||||||
|  | have no guarantee of uniqueness for them, except that no USB compliant device | ||||||
|  | uses them. In order to avoid technical problems, we must ensure that all | ||||||
|  | devices with the same pair of IDs use the same driver on kernel level. For | ||||||
|  | details, see the file USB-IDs-for-free.txt. | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | ====================================================== | ||||||
|  | I HAVE HEARD THAT SUB-LICENSING OF USB-IDs IS ILLEGAL? | ||||||
|  | ====================================================== | ||||||
|  | 
 | ||||||
|  | A 16 bit integer number cannot be protected by copyright laws. It is not | ||||||
|  | sufficiently complex. And since none of the parties involved entered into the | ||||||
|  | USB-IF Trademark License Agreement, we are not bound by this agreement. So | ||||||
|  | there is no reason why it should be illegal to sub-license USB-IDs. | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | ============================================= | ||||||
|  | WHO IS LIABLE IF THERE ARE INCOMPATIBILITIES? | ||||||
|  | ============================================= | ||||||
|  | 
 | ||||||
|  | Objective Development disclaims all liabilities which might arise from the | ||||||
|  | assignment of IDs. If you guarantee product features to your customers | ||||||
|  | without proper disclaimer, YOU are liable for that. | ||||||
							
								
								
									
										154
									
								
								keyboards/planck/thk/bootloader/usbdrv/USB-IDs-for-free.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										154
									
								
								keyboards/planck/thk/bootloader/usbdrv/USB-IDs-for-free.txt
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,154 @@ | |||||||
|  | Version 2009-08-22 | ||||||
|  | 
 | ||||||
|  | =========================== | ||||||
|  | FREE USB-IDs FOR SHARED USE | ||||||
|  | =========================== | ||||||
|  | 
 | ||||||
|  | Objective Development has reserved a set of USB Product-IDs for use according | ||||||
|  | to the guidelines outlined below. For more information about the concept of | ||||||
|  | USB IDs please see the file USB-ID-FAQ.txt. Objective Development guarantees | ||||||
|  | that the IDs listed below are not used by any USB compliant devices. | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | ==================== | ||||||
|  | MECHANISM OF SHARING | ||||||
|  | ==================== | ||||||
|  | 
 | ||||||
|  | From a technical point of view, two different devices can share the same USB | ||||||
|  | Vendor- and Product-ID if they require the same driver on operating system | ||||||
|  | level. We make use of this fact by assigning separate IDs for various device | ||||||
|  | classes. On application layer, devices must be distinguished by their textual | ||||||
|  | name or serial number. We offer separate sets of IDs for discrimination by | ||||||
|  | textual name and for serial number. | ||||||
|  | 
 | ||||||
|  | Examples for shared use of USB IDs are included with V-USB in the "examples" | ||||||
|  | subdirectory. | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | ====================================== | ||||||
|  | IDs FOR DISCRIMINATION BY TEXTUAL NAME | ||||||
|  | ====================================== | ||||||
|  | 
 | ||||||
|  | If you use one of the IDs listed below, your device and host-side software | ||||||
|  | must conform to these rules: | ||||||
|  | 
 | ||||||
|  | (1) The USB device MUST provide a textual representation of the manufacturer | ||||||
|  | and product identification. The manufacturer identification MUST be available | ||||||
|  | at least in USB language 0x0409 (English/US). | ||||||
|  | 
 | ||||||
|  | (2) The textual manufacturer identification MUST contain either an Internet | ||||||
|  | domain name (e.g. "mycompany.com") registered and owned by you, or an e-mail | ||||||
|  | address under your control (e.g. "myname@gmx.net"). You can embed the domain | ||||||
|  | name or e-mail address in any string you like, e.g.  "Objective Development | ||||||
|  | http://www.obdev.at/vusb/". | ||||||
|  | 
 | ||||||
|  | (3) You are responsible for retaining ownership of the domain or e-mail | ||||||
|  | address for as long as any of your products are in use. | ||||||
|  | 
 | ||||||
|  | (4) You may choose any string for the textual product identification, as long | ||||||
|  | as this string is unique within the scope of your textual manufacturer | ||||||
|  | identification. | ||||||
|  | 
 | ||||||
|  | (5) Application side device look-up MUST be based on the textual manufacturer | ||||||
|  | and product identification in addition to VID/PID matching. The driver | ||||||
|  | matching MUST be a comparison of the entire strings, NOT a sub-string match. | ||||||
|  | 
 | ||||||
|  | (6) For devices which implement a particular USB device class (e.g. HID), the | ||||||
|  | operating system's default class driver MUST be used. If an operating system | ||||||
|  | driver for Vendor Class devices is needed, this driver must be libusb or | ||||||
|  | libusb-win32 (see http://libusb.org/ and | ||||||
|  | http://libusb-win32.sourceforge.net/). | ||||||
|  | 
 | ||||||
|  | Table if IDs for discrimination by textual name: | ||||||
|  | 
 | ||||||
|  | PID dec (hex) | VID dec (hex) | Description of use | ||||||
|  | ==============+===============+============================================ | ||||||
|  | 1500 (0x05dc) | 5824 (0x16c0) | For Vendor Class devices with libusb | ||||||
|  | --------------+---------------+-------------------------------------------- | ||||||
|  | 1503 (0x05df) | 5824 (0x16c0) | For generic HID class devices (which are | ||||||
|  |               |               | NOT mice, keyboards or joysticks) | ||||||
|  | --------------+---------------+-------------------------------------------- | ||||||
|  | 1505 (0x05e1) | 5824 (0x16c0) | For CDC-ACM class devices (modems) | ||||||
|  | --------------+---------------+-------------------------------------------- | ||||||
|  | 1508 (0x05e4) | 5824 (0x16c0) | For MIDI class devices | ||||||
|  | --------------+---------------+-------------------------------------------- | ||||||
|  | 
 | ||||||
|  | Note that Windows caches the textual product- and vendor-description for | ||||||
|  | mice, keyboards and joysticks. Name-bsed discrimination is therefore not | ||||||
|  | recommended for these device classes. | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | ======================================= | ||||||
|  | IDs FOR DISCRIMINATION BY SERIAL NUMBER | ||||||
|  | ======================================= | ||||||
|  | 
 | ||||||
|  | If you use one of the IDs listed below, your device and host-side software | ||||||
|  | must conform to these rules: | ||||||
|  | 
 | ||||||
|  | (1) The USB device MUST provide a textual representation of the serial | ||||||
|  | number, unless ONLY the operating system's default class driver is used. | ||||||
|  | The serial number string MUST be available at least in USB language 0x0409 | ||||||
|  | (English/US). | ||||||
|  | 
 | ||||||
|  | (2) The serial number MUST start with either an Internet domain name (e.g. | ||||||
|  | "mycompany.com") registered and owned by you, or an e-mail address under your | ||||||
|  | control (e.g. "myname@gmx.net"), both terminated with a colon (":") character. | ||||||
|  | You MAY append any string you like for further discrimination of your devices. | ||||||
|  | 
 | ||||||
|  | (3) You are responsible for retaining ownership of the domain or e-mail | ||||||
|  | address for as long as any of your products are in use. | ||||||
|  | 
 | ||||||
|  | (5) Application side device look-up MUST be based on the serial number string | ||||||
|  | in addition to VID/PID matching. The matching must start at the first | ||||||
|  | character of the serial number string and include the colon character | ||||||
|  | terminating your domain or e-mail address. It MAY stop anywhere after that. | ||||||
|  | 
 | ||||||
|  | (6) For devices which implement a particular USB device class (e.g. HID), the | ||||||
|  | operating system's default class driver MUST be used. If an operating system | ||||||
|  | driver for Vendor Class devices is needed, this driver must be libusb or | ||||||
|  | libusb-win32 (see http://libusb.org/ and | ||||||
|  | http://libusb-win32.sourceforge.net/). | ||||||
|  | 
 | ||||||
|  | (7) If ONLY the operating system's default class driver is used, e.g. for | ||||||
|  | mice, keyboards, joysticks, CDC or MIDI devices and no discrimination by an | ||||||
|  | application is needed, the serial number may be omitted. | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | Table if IDs for discrimination by serial number string: | ||||||
|  | 
 | ||||||
|  | PID dec (hex)  | VID dec (hex) | Description of use | ||||||
|  | ===============+===============+=========================================== | ||||||
|  | 10200 (0x27d8) | 5824 (0x16c0) | For Vendor Class devices with libusb | ||||||
|  | ---------------+---------------+------------------------------------------- | ||||||
|  | 10201 (0x27d9) | 5824 (0x16c0) | For generic HID class devices (which are | ||||||
|  |                |               | NOT mice, keyboards or joysticks) | ||||||
|  | ---------------+---------------+------------------------------------------- | ||||||
|  | 10202 (0x27da) | 5824 (0x16c0) | For USB Mice | ||||||
|  | ---------------+---------------+------------------------------------------- | ||||||
|  | 10203 (0x27db) | 5824 (0x16c0) | For USB Keyboards | ||||||
|  | ---------------+---------------+------------------------------------------- | ||||||
|  | 10204 (0x27dc) | 5824 (0x16c0) | For USB Joysticks | ||||||
|  | ---------------+---------------+------------------------------------------- | ||||||
|  | 10205 (0x27dd) | 5824 (0x16c0) | For CDC-ACM class devices (modems) | ||||||
|  | ---------------+---------------+------------------------------------------- | ||||||
|  | 10206 (0x27de) | 5824 (0x16c0) | For MIDI class devices | ||||||
|  | ---------------+---------------+------------------------------------------- | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | ================= | ||||||
|  | ORIGIN OF USB-IDs | ||||||
|  | ================= | ||||||
|  | 
 | ||||||
|  | OBJECTIVE DEVELOPMENT Software GmbH has obtained all VID/PID pairs listed | ||||||
|  | here from Wouter van Ooijen (see www.voti.nl) for exclusive disposition. | ||||||
|  | Wouter van Ooijen has obtained the VID from the USB Implementers Forum, Inc. | ||||||
|  | (see www.usb.org). The VID is registered for the company name "Van Ooijen | ||||||
|  | Technische Informatica". | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | ========== | ||||||
|  | DISCLAIMER | ||||||
|  | ========== | ||||||
|  | 
 | ||||||
|  | OBJECTIVE DEVELOPMENT Software GmbH disclaims all liability for any | ||||||
|  | problems which are caused by the shared use of these VID/PID pairs. | ||||||
							
								
								
									
										187
									
								
								keyboards/planck/thk/bootloader/usbdrv/asmcommon.inc
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										187
									
								
								keyboards/planck/thk/bootloader/usbdrv/asmcommon.inc
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,187 @@ | |||||||
|  | /* Name: asmcommon.inc | ||||||
|  |  * Project: V-USB, virtual USB port for Atmel's(r) AVR(r) microcontrollers | ||||||
|  |  * Author: Christian Starkjohann | ||||||
|  |  * Creation Date: 2007-11-05 | ||||||
|  |  * Tabsize: 4 | ||||||
|  |  * Copyright: (c) 2007 by OBJECTIVE DEVELOPMENT Software GmbH | ||||||
|  |  * License: GNU GPL v2 (see License.txt), GNU GPL v3 or proprietary (CommercialLicense.txt) | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | /* Do not link this file! Link usbdrvasm.S instead, which includes the | ||||||
|  |  * appropriate implementation! | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | /* | ||||||
|  | General Description: | ||||||
|  | This file contains assembler code which is shared among the USB driver | ||||||
|  | implementations for different CPU cocks. Since the code must be inserted | ||||||
|  | in the middle of the module, it's split out into this file and #included.
 | ||||||
|  | 
 | ||||||
|  | Jump destinations called from outside: | ||||||
|  |     sofError: Called when no start sequence was found. | ||||||
|  |     se0: Called when a package has been successfully received. | ||||||
|  |     overflow: Called when receive buffer overflows. | ||||||
|  |     doReturn: Called after sending data. | ||||||
|  | 
 | ||||||
|  | Outside jump destinations used by this module: | ||||||
|  |     waitForJ: Called to receive an already arriving packet. | ||||||
|  |     sendAckAndReti: | ||||||
|  |     sendNakAndReti: | ||||||
|  |     sendCntAndReti: | ||||||
|  |     usbSendAndReti: | ||||||
|  | 
 | ||||||
|  | The following macros must be defined before this file is included: | ||||||
|  |     .macro POP_STANDARD | ||||||
|  |     .endm | ||||||
|  |     .macro POP_RETI | ||||||
|  |     .endm | ||||||
|  | */ | ||||||
|  | 
 | ||||||
|  | #define token   x1
 | ||||||
|  | 
 | ||||||
|  | overflow: | ||||||
|  |     ldi     x2, 1<<USB_INTR_PENDING_BIT | ||||||
|  |     USB_STORE_PENDING(x2)       ; clear any pending interrupts | ||||||
|  | ignorePacket: | ||||||
|  |     clr     token | ||||||
|  |     rjmp    storeTokenAndReturn | ||||||
|  | 
 | ||||||
|  | ;---------------------------------------------------------------------------- | ||||||
|  | ; Processing of received packet (numbers in brackets are cycles after center of SE0) | ||||||
|  | ;---------------------------------------------------------------------------- | ||||||
|  | ;This is the only non-error exit point for the software receiver loop | ||||||
|  | ;we don't check any CRCs here because there is no time left. | ||||||
|  | se0: | ||||||
|  |     subi    cnt, USB_BUFSIZE    ;[5] | ||||||
|  |     neg     cnt                 ;[6] | ||||||
|  |     sub     YL, cnt             ;[7] | ||||||
|  |     sbci    YH, 0               ;[8] | ||||||
|  |     ldi     x2, 1<<USB_INTR_PENDING_BIT ;[9] | ||||||
|  |     USB_STORE_PENDING(x2)       ;[10] clear pending intr and check flag later. SE0 should be over. | ||||||
|  |     ld      token, y            ;[11] | ||||||
|  |     cpi     token, USBPID_DATA0 ;[13] | ||||||
|  |     breq    handleData          ;[14] | ||||||
|  |     cpi     token, USBPID_DATA1 ;[15] | ||||||
|  |     breq    handleData          ;[16] | ||||||
|  |     lds     shift, usbDeviceAddr;[17] | ||||||
|  |     ldd     x2, y+1             ;[19] ADDR and 1 bit endpoint number | ||||||
|  |     lsl     x2                  ;[21] shift out 1 bit endpoint number | ||||||
|  |     cpse    x2, shift           ;[22] | ||||||
|  |     rjmp    ignorePacket        ;[23] | ||||||
|  | /* only compute endpoint number in x3 if required later */ | ||||||
|  | #if USB_CFG_HAVE_INTRIN_ENDPOINT || USB_CFG_IMPLEMENT_FN_WRITEOUT
 | ||||||
|  |     ldd     x3, y+2             ;[24] endpoint number + crc | ||||||
|  |     rol     x3                  ;[26] shift in LSB of endpoint | ||||||
|  | #endif
 | ||||||
|  |     cpi     token, USBPID_IN    ;[27] | ||||||
|  |     breq    handleIn            ;[28] | ||||||
|  |     cpi     token, USBPID_SETUP ;[29] | ||||||
|  |     breq    handleSetupOrOut    ;[30] | ||||||
|  |     cpi     token, USBPID_OUT   ;[31] | ||||||
|  |     brne    ignorePacket        ;[32] must be ack, nak or whatever | ||||||
|  | ;   rjmp    handleSetupOrOut    ; fallthrough | ||||||
|  | 
 | ||||||
|  | ;Setup and Out are followed by a data packet two bit times (16 cycles) after | ||||||
|  | ;the end of SE0. The sync code allows up to 40 cycles delay from the start of | ||||||
|  | ;the sync pattern until the first bit is sampled. That's a total of 56 cycles. | ||||||
|  | handleSetupOrOut:               ;[32] | ||||||
|  | #if USB_CFG_IMPLEMENT_FN_WRITEOUT   /* if we have data for endpoint != 0, set usbCurrentTok to address */
 | ||||||
|  |     andi    x3, 0xf             ;[32] | ||||||
|  |     breq    storeTokenAndReturn ;[33] | ||||||
|  |     mov     token, x3           ;[34] indicate that this is endpoint x OUT | ||||||
|  | #endif
 | ||||||
|  | storeTokenAndReturn: | ||||||
|  |     sts     usbCurrentTok, token;[35] | ||||||
|  | doReturn: | ||||||
|  |     POP_STANDARD                ;[37] 12...16 cycles | ||||||
|  |     USB_LOAD_PENDING(YL)        ;[49] | ||||||
|  |     sbrc    YL, USB_INTR_PENDING_BIT;[50] check whether data is already arriving | ||||||
|  |     rjmp    waitForJ            ;[51] save the pops and pushes -- a new interrupt is already pending | ||||||
|  | sofError: | ||||||
|  |     POP_RETI                    ;macro call | ||||||
|  |     reti | ||||||
|  | 
 | ||||||
|  | handleData: | ||||||
|  | #if USB_CFG_CHECK_CRC
 | ||||||
|  |     CRC_CLEANUP_AND_CHECK       ; jumps to ignorePacket if CRC error | ||||||
|  | #endif
 | ||||||
|  |     lds     shift, usbCurrentTok;[18] | ||||||
|  |     tst     shift               ;[20] | ||||||
|  |     breq    doReturn            ;[21] | ||||||
|  |     lds     x2, usbRxLen        ;[22] | ||||||
|  |     tst     x2                  ;[24] | ||||||
|  |     brne    sendNakAndReti      ;[25] | ||||||
|  | ; 2006-03-11: The following two lines fix a problem where the device was not | ||||||
|  | ; recognized if usbPoll() was called less frequently than once every 4 ms. | ||||||
|  |     cpi     cnt, 4              ;[26] zero sized data packets are status phase only -- ignore and ack | ||||||
|  |     brmi    sendAckAndReti      ;[27] keep rx buffer clean -- we must not NAK next SETUP | ||||||
|  | #if USB_CFG_CHECK_DATA_TOGGLING
 | ||||||
|  |     sts     usbCurrentDataToken, token  ; store for checking by C code | ||||||
|  | #endif
 | ||||||
|  |     sts     usbRxLen, cnt       ;[28] store received data, swap buffers | ||||||
|  |     sts     usbRxToken, shift   ;[30] | ||||||
|  |     lds     x2, usbInputBufOffset;[32] swap buffers | ||||||
|  |     ldi     cnt, USB_BUFSIZE    ;[34] | ||||||
|  |     sub     cnt, x2             ;[35] | ||||||
|  |     sts     usbInputBufOffset, cnt;[36] buffers now swapped | ||||||
|  |     rjmp    sendAckAndReti      ;[38] 40 + 17 = 57 until SOP | ||||||
|  | 
 | ||||||
|  | handleIn: | ||||||
|  | ;We don't send any data as long as the C code has not processed the current | ||||||
|  | ;input data and potentially updated the output data. That's more efficient | ||||||
|  | ;in terms of code size than clearing the tx buffers when a packet is received. | ||||||
|  |     lds     x1, usbRxLen        ;[30] | ||||||
|  |     cpi     x1, 1               ;[32] negative values are flow control, 0 means "buffer free" | ||||||
|  |     brge    sendNakAndReti      ;[33] unprocessed input packet? | ||||||
|  |     ldi     x1, USBPID_NAK      ;[34] prepare value for usbTxLen | ||||||
|  | #if USB_CFG_HAVE_INTRIN_ENDPOINT
 | ||||||
|  |     andi    x3, 0xf             ;[35] x3 contains endpoint | ||||||
|  | #if USB_CFG_SUPPRESS_INTR_CODE
 | ||||||
|  |     brne    sendNakAndReti      ;[36] | ||||||
|  | #else
 | ||||||
|  |     brne    handleIn1           ;[36] | ||||||
|  | #endif
 | ||||||
|  | #endif
 | ||||||
|  |     lds     cnt, usbTxLen       ;[37] | ||||||
|  |     sbrc    cnt, 4              ;[39] all handshake tokens have bit 4 set | ||||||
|  |     rjmp    sendCntAndReti      ;[40] 42 + 16 = 58 until SOP | ||||||
|  |     sts     usbTxLen, x1        ;[41] x1 == USBPID_NAK from above | ||||||
|  |     ldi     YL, lo8(usbTxBuf)   ;[43] | ||||||
|  |     ldi     YH, hi8(usbTxBuf)   ;[44] | ||||||
|  |     rjmp    usbSendAndReti      ;[45] 57 + 12 = 59 until SOP | ||||||
|  | 
 | ||||||
|  | ; Comment about when to set usbTxLen to USBPID_NAK: | ||||||
|  | ; We should set it back when we receive the ACK from the host. This would | ||||||
|  | ; be simple to implement: One static variable which stores whether the last | ||||||
|  | ; tx was for endpoint 0 or 1 and a compare in the receiver to distinguish the | ||||||
|  | ; ACK. However, we set it back immediately when we send the package, | ||||||
|  | ; assuming that no error occurs and the host sends an ACK. We save one byte | ||||||
|  | ; RAM this way and avoid potential problems with endless retries. The rest of | ||||||
|  | ; the driver assumes error-free transfers anyway. | ||||||
|  | 
 | ||||||
|  | #if !USB_CFG_SUPPRESS_INTR_CODE && USB_CFG_HAVE_INTRIN_ENDPOINT /* placed here due to relative jump range */
 | ||||||
|  | handleIn1:                      ;[38] | ||||||
|  | #if USB_CFG_HAVE_INTRIN_ENDPOINT3
 | ||||||
|  | ; 2006-06-10 as suggested by O.Tamura: support second INTR IN / BULK IN endpoint | ||||||
|  |     cpi     x3, USB_CFG_EP3_NUMBER;[38] | ||||||
|  |     breq    handleIn3           ;[39] | ||||||
|  | #endif
 | ||||||
|  |     lds     cnt, usbTxLen1      ;[40] | ||||||
|  |     sbrc    cnt, 4              ;[42] all handshake tokens have bit 4 set | ||||||
|  |     rjmp    sendCntAndReti      ;[43] 47 + 16 = 63 until SOP | ||||||
|  |     sts     usbTxLen1, x1       ;[44] x1 == USBPID_NAK from above | ||||||
|  |     ldi     YL, lo8(usbTxBuf1)  ;[46] | ||||||
|  |     ldi     YH, hi8(usbTxBuf1)  ;[47] | ||||||
|  |     rjmp    usbSendAndReti      ;[48] 50 + 12 = 62 until SOP | ||||||
|  | 
 | ||||||
|  | #if USB_CFG_HAVE_INTRIN_ENDPOINT3
 | ||||||
|  | handleIn3: | ||||||
|  |     lds     cnt, usbTxLen3      ;[41] | ||||||
|  |     sbrc    cnt, 4              ;[43] | ||||||
|  |     rjmp    sendCntAndReti      ;[44] 49 + 16 = 65 until SOP | ||||||
|  |     sts     usbTxLen3, x1       ;[45] x1 == USBPID_NAK from above | ||||||
|  |     ldi     YL, lo8(usbTxBuf3)  ;[47] | ||||||
|  |     ldi     YH, hi8(usbTxBuf3)  ;[48] | ||||||
|  |     rjmp    usbSendAndReti      ;[49] 51 + 12 = 63 until SOP | ||||||
|  | #endif
 | ||||||
|  | #endif
 | ||||||
							
								
								
									
										49
									
								
								keyboards/planck/thk/bootloader/usbdrv/oddebug.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										49
									
								
								keyboards/planck/thk/bootloader/usbdrv/oddebug.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,49 @@ | |||||||
|  | /* Name: oddebug.c
 | ||||||
|  |  * Project: AVR library | ||||||
|  |  * Author: Christian Starkjohann | ||||||
|  |  * Creation Date: 2005-01-16 | ||||||
|  |  * Tabsize: 4 | ||||||
|  |  * Copyright: (c) 2005 by OBJECTIVE DEVELOPMENT Software GmbH | ||||||
|  |  * License: GNU GPL v2 (see License.txt), GNU GPL v3 or proprietary (CommercialLicense.txt) | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | #include "oddebug.h" | ||||||
|  | 
 | ||||||
|  | #if DEBUG_LEVEL > 0 | ||||||
|  | 
 | ||||||
|  | #warning "Never compile production devices with debugging enabled" | ||||||
|  | 
 | ||||||
|  | static void uartPutc(char c) | ||||||
|  | { | ||||||
|  |     while(!(ODDBG_USR & (1 << ODDBG_UDRE)));    /* wait for data register empty */ | ||||||
|  |     ODDBG_UDR = c; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static uchar    hexAscii(uchar h) | ||||||
|  | { | ||||||
|  |     h &= 0xf; | ||||||
|  |     if(h >= 10) | ||||||
|  |         h += 'a' - (uchar)10 - '0'; | ||||||
|  |     h += '0'; | ||||||
|  |     return h; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static void printHex(uchar c) | ||||||
|  | { | ||||||
|  |     uartPutc(hexAscii(c >> 4)); | ||||||
|  |     uartPutc(hexAscii(c)); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void    odDebug(uchar prefix, uchar *data, uchar len) | ||||||
|  | { | ||||||
|  |     printHex(prefix); | ||||||
|  |     uartPutc(':'); | ||||||
|  |     while(len--){ | ||||||
|  |         uartPutc(' '); | ||||||
|  |         printHex(*data++); | ||||||
|  |     } | ||||||
|  |     uartPutc('\r'); | ||||||
|  |     uartPutc('\n'); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | #endif | ||||||
							
								
								
									
										122
									
								
								keyboards/planck/thk/bootloader/usbdrv/oddebug.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										122
									
								
								keyboards/planck/thk/bootloader/usbdrv/oddebug.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,122 @@ | |||||||
|  | /* Name: oddebug.h
 | ||||||
|  |  * Project: AVR library | ||||||
|  |  * Author: Christian Starkjohann | ||||||
|  |  * Creation Date: 2005-01-16 | ||||||
|  |  * Tabsize: 4 | ||||||
|  |  * Copyright: (c) 2005 by OBJECTIVE DEVELOPMENT Software GmbH | ||||||
|  |  * License: GNU GPL v2 (see License.txt), GNU GPL v3 or proprietary (CommercialLicense.txt) | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | #ifndef __oddebug_h_included__ | ||||||
|  | #define __oddebug_h_included__ | ||||||
|  | 
 | ||||||
|  | /*
 | ||||||
|  | General Description: | ||||||
|  | This module implements a function for debug logs on the serial line of the | ||||||
|  | AVR microcontroller. Debugging can be configured with the define | ||||||
|  | 'DEBUG_LEVEL'. If this macro is not defined or defined to 0, all debugging | ||||||
|  | calls are no-ops. If it is 1, DBG1 logs will appear, but not DBG2. If it is | ||||||
|  | 2, DBG1 and DBG2 logs will be printed. | ||||||
|  | 
 | ||||||
|  | A debug log consists of a label ('prefix') to indicate which debug log created | ||||||
|  | the output and a memory block to dump in hex ('data' and 'len'). | ||||||
|  | */ | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | #ifndef F_CPU | ||||||
|  | #   define  F_CPU   12000000    /* 12 MHz */ | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
|  | /* make sure we have the UART defines: */ | ||||||
|  | #include "usbportability.h" | ||||||
|  | 
 | ||||||
|  | #ifndef uchar | ||||||
|  | #   define  uchar   unsigned char | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
|  | #if DEBUG_LEVEL > 0 && !(defined TXEN || defined TXEN0) /* no UART in device */ | ||||||
|  | #   warning "Debugging disabled because device has no UART" | ||||||
|  | #   undef   DEBUG_LEVEL | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
|  | #ifndef DEBUG_LEVEL | ||||||
|  | #   define  DEBUG_LEVEL 0 | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
|  | /* ------------------------------------------------------------------------- */ | ||||||
|  | 
 | ||||||
|  | #if DEBUG_LEVEL > 0 | ||||||
|  | #   define  DBG1(prefix, data, len) odDebug(prefix, data, len) | ||||||
|  | #else | ||||||
|  | #   define  DBG1(prefix, data, len) | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
|  | #if DEBUG_LEVEL > 1 | ||||||
|  | #   define  DBG2(prefix, data, len) odDebug(prefix, data, len) | ||||||
|  | #else | ||||||
|  | #   define  DBG2(prefix, data, len) | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
|  | /* ------------------------------------------------------------------------- */ | ||||||
|  | 
 | ||||||
|  | #if DEBUG_LEVEL > 0 | ||||||
|  | extern void odDebug(uchar prefix, uchar *data, uchar len); | ||||||
|  | 
 | ||||||
|  | /* Try to find our control registers; ATMEL likes to rename these */ | ||||||
|  | 
 | ||||||
|  | #if defined UBRR | ||||||
|  | #   define  ODDBG_UBRR  UBRR | ||||||
|  | #elif defined UBRRL | ||||||
|  | #   define  ODDBG_UBRR  UBRRL | ||||||
|  | #elif defined UBRR0 | ||||||
|  | #   define  ODDBG_UBRR  UBRR0 | ||||||
|  | #elif defined UBRR0L | ||||||
|  | #   define  ODDBG_UBRR  UBRR0L | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
|  | #if defined UCR | ||||||
|  | #   define  ODDBG_UCR   UCR | ||||||
|  | #elif defined UCSRB | ||||||
|  | #   define  ODDBG_UCR   UCSRB | ||||||
|  | #elif defined UCSR0B | ||||||
|  | #   define  ODDBG_UCR   UCSR0B | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
|  | #if defined TXEN | ||||||
|  | #   define  ODDBG_TXEN  TXEN | ||||||
|  | #else | ||||||
|  | #   define  ODDBG_TXEN  TXEN0 | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
|  | #if defined USR | ||||||
|  | #   define  ODDBG_USR   USR | ||||||
|  | #elif defined UCSRA | ||||||
|  | #   define  ODDBG_USR   UCSRA | ||||||
|  | #elif defined UCSR0A | ||||||
|  | #   define  ODDBG_USR   UCSR0A | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
|  | #if defined UDRE | ||||||
|  | #   define  ODDBG_UDRE  UDRE | ||||||
|  | #else | ||||||
|  | #   define  ODDBG_UDRE  UDRE0 | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
|  | #if defined UDR | ||||||
|  | #   define  ODDBG_UDR   UDR | ||||||
|  | #elif defined UDR0 | ||||||
|  | #   define  ODDBG_UDR   UDR0 | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
|  | static inline void  odDebugInit(void) | ||||||
|  | { | ||||||
|  |     ODDBG_UCR |= (1<<ODDBG_TXEN); | ||||||
|  |     ODDBG_UBRR = F_CPU / (19200 * 16L) - 1; | ||||||
|  | } | ||||||
|  | #else | ||||||
|  | #   define odDebugInit() | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
|  | /* ------------------------------------------------------------------------- */ | ||||||
|  | 
 | ||||||
|  | #endif /* __oddebug_h_included__ */ | ||||||
							
								
								
									
										384
									
								
								keyboards/planck/thk/bootloader/usbdrv/usbconfig-prototype.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										384
									
								
								keyboards/planck/thk/bootloader/usbdrv/usbconfig-prototype.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,384 @@ | |||||||
|  | /* Name: usbconfig.h
 | ||||||
|  |  * Project: V-USB, virtual USB port for Atmel's(r) AVR(r) microcontrollers | ||||||
|  |  * Author: Christian Starkjohann | ||||||
|  |  * Creation Date: 2005-04-01 | ||||||
|  |  * Tabsize: 4 | ||||||
|  |  * Copyright: (c) 2005 by OBJECTIVE DEVELOPMENT Software GmbH | ||||||
|  |  * License: GNU GPL v2 (see License.txt), GNU GPL v3 or proprietary (CommercialLicense.txt) | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | #ifndef __usbconfig_h_included__ | ||||||
|  | #define __usbconfig_h_included__ | ||||||
|  | 
 | ||||||
|  | /*
 | ||||||
|  | General Description: | ||||||
|  | This file is an example configuration (with inline documentation) for the USB | ||||||
|  | driver. It configures V-USB for USB D+ connected to Port D bit 2 (which is | ||||||
|  | also hardware interrupt 0 on many devices) and USB D- to Port D bit 4. You may | ||||||
|  | wire the lines to any other port, as long as D+ is also wired to INT0 (or any | ||||||
|  | other hardware interrupt, as long as it is the highest level interrupt, see | ||||||
|  | section at the end of this file). | ||||||
|  | + To create your own usbconfig.h file, copy this file to your project's | ||||||
|  | + firmware source directory) and rename it to "usbconfig.h". | ||||||
|  | + Then edit it accordingly. | ||||||
|  | */ | ||||||
|  | 
 | ||||||
|  | /* ---------------------------- Hardware Config ---------------------------- */ | ||||||
|  | 
 | ||||||
|  | #define USB_CFG_IOPORTNAME      D | ||||||
|  | /* This is the port where the USB bus is connected. When you configure it to
 | ||||||
|  |  * "B", the registers PORTB, PINB and DDRB will be used. | ||||||
|  |  */ | ||||||
|  | #define USB_CFG_DMINUS_BIT      4 | ||||||
|  | /* This is the bit number in USB_CFG_IOPORT where the USB D- line is connected.
 | ||||||
|  |  * This may be any bit in the port. | ||||||
|  |  */ | ||||||
|  | #define USB_CFG_DPLUS_BIT       2 | ||||||
|  | /* This is the bit number in USB_CFG_IOPORT where the USB D+ line is connected.
 | ||||||
|  |  * This may be any bit in the port. Please note that D+ must also be connected | ||||||
|  |  * to interrupt pin INT0! [You can also use other interrupts, see section | ||||||
|  |  * "Optional MCU Description" below, or you can connect D- to the interrupt, as | ||||||
|  |  * it is required if you use the USB_COUNT_SOF feature. If you use D- for the | ||||||
|  |  * interrupt, the USB interrupt will also be triggered at Start-Of-Frame | ||||||
|  |  * markers every millisecond.] | ||||||
|  |  */ | ||||||
|  | #define USB_CFG_CLOCK_KHZ       (F_CPU/1000) | ||||||
|  | /* Clock rate of the AVR in kHz. Legal values are 12000, 12800, 15000, 16000,
 | ||||||
|  |  * 16500, 18000 and 20000. The 12.8 MHz and 16.5 MHz versions of the code | ||||||
|  |  * require no crystal, they tolerate +/- 1% deviation from the nominal | ||||||
|  |  * frequency. All other rates require a precision of 2000 ppm and thus a | ||||||
|  |  * crystal! | ||||||
|  |  * Since F_CPU should be defined to your actual clock rate anyway, you should | ||||||
|  |  * not need to modify this setting. | ||||||
|  |  */ | ||||||
|  | #define USB_CFG_CHECK_CRC       0 | ||||||
|  | /* Define this to 1 if you want that the driver checks integrity of incoming
 | ||||||
|  |  * data packets (CRC checks). CRC checks cost quite a bit of code size and are | ||||||
|  |  * currently only available for 18 MHz crystal clock. You must choose | ||||||
|  |  * USB_CFG_CLOCK_KHZ = 18000 if you enable this option. | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | /* ----------------------- Optional Hardware Config ------------------------ */ | ||||||
|  | 
 | ||||||
|  | /* #define USB_CFG_PULLUP_IOPORTNAME   D */ | ||||||
|  | /* If you connect the 1.5k pullup resistor from D- to a port pin instead of
 | ||||||
|  |  * V+, you can connect and disconnect the device from firmware by calling | ||||||
|  |  * the macros usbDeviceConnect() and usbDeviceDisconnect() (see usbdrv.h). | ||||||
|  |  * This constant defines the port on which the pullup resistor is connected. | ||||||
|  |  */ | ||||||
|  | /* #define USB_CFG_PULLUP_BIT          4 */ | ||||||
|  | /* This constant defines the bit number in USB_CFG_PULLUP_IOPORT (defined
 | ||||||
|  |  * above) where the 1.5k pullup resistor is connected. See description | ||||||
|  |  * above for details. | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | /* --------------------------- Functional Range ---------------------------- */ | ||||||
|  | 
 | ||||||
|  | #define USB_CFG_HAVE_INTRIN_ENDPOINT    0 | ||||||
|  | /* Define this to 1 if you want to compile a version with two endpoints: The
 | ||||||
|  |  * default control endpoint 0 and an interrupt-in endpoint (any other endpoint | ||||||
|  |  * number). | ||||||
|  |  */ | ||||||
|  | #define USB_CFG_HAVE_INTRIN_ENDPOINT3   0 | ||||||
|  | /* Define this to 1 if you want to compile a version with three endpoints: The
 | ||||||
|  |  * default control endpoint 0, an interrupt-in endpoint 3 (or the number | ||||||
|  |  * configured below) and a catch-all default interrupt-in endpoint as above. | ||||||
|  |  * You must also define USB_CFG_HAVE_INTRIN_ENDPOINT to 1 for this feature. | ||||||
|  |  */ | ||||||
|  | #define USB_CFG_EP3_NUMBER              3 | ||||||
|  | /* If the so-called endpoint 3 is used, it can now be configured to any other
 | ||||||
|  |  * endpoint number (except 0) with this macro. Default if undefined is 3. | ||||||
|  |  */ | ||||||
|  | /* #define USB_INITIAL_DATATOKEN           USBPID_DATA1 */ | ||||||
|  | /* The above macro defines the startup condition for data toggling on the
 | ||||||
|  |  * interrupt/bulk endpoints 1 and 3. Defaults to USBPID_DATA1. | ||||||
|  |  * Since the token is toggled BEFORE sending any data, the first packet is | ||||||
|  |  * sent with the oposite value of this configuration! | ||||||
|  |  */ | ||||||
|  | #define USB_CFG_IMPLEMENT_HALT          0 | ||||||
|  | /* Define this to 1 if you also want to implement the ENDPOINT_HALT feature
 | ||||||
|  |  * for endpoint 1 (interrupt endpoint). Although you may not need this feature, | ||||||
|  |  * it is required by the standard. We have made it a config option because it | ||||||
|  |  * bloats the code considerably. | ||||||
|  |  */ | ||||||
|  | #define USB_CFG_SUPPRESS_INTR_CODE      0 | ||||||
|  | /* Define this to 1 if you want to declare interrupt-in endpoints, but don't
 | ||||||
|  |  * want to send any data over them. If this macro is defined to 1, functions | ||||||
|  |  * usbSetInterrupt() and usbSetInterrupt3() are omitted. This is useful if | ||||||
|  |  * you need the interrupt-in endpoints in order to comply to an interface | ||||||
|  |  * (e.g. HID), but never want to send any data. This option saves a couple | ||||||
|  |  * of bytes in flash memory and the transmit buffers in RAM. | ||||||
|  |  */ | ||||||
|  | #define USB_CFG_INTR_POLL_INTERVAL      10 | ||||||
|  | /* If you compile a version with endpoint 1 (interrupt-in), this is the poll
 | ||||||
|  |  * interval. The value is in milliseconds and must not be less than 10 ms for | ||||||
|  |  * low speed devices. | ||||||
|  |  */ | ||||||
|  | #define USB_CFG_IS_SELF_POWERED         0 | ||||||
|  | /* Define this to 1 if the device has its own power supply. Set it to 0 if the
 | ||||||
|  |  * device is powered from the USB bus. | ||||||
|  |  */ | ||||||
|  | #define USB_CFG_MAX_BUS_POWER           100 | ||||||
|  | /* Set this variable to the maximum USB bus power consumption of your device.
 | ||||||
|  |  * The value is in milliamperes. [It will be divided by two since USB | ||||||
|  |  * communicates power requirements in units of 2 mA.] | ||||||
|  |  */ | ||||||
|  | #define USB_CFG_IMPLEMENT_FN_WRITE      0 | ||||||
|  | /* Set this to 1 if you want usbFunctionWrite() to be called for control-out
 | ||||||
|  |  * transfers. Set it to 0 if you don't need it and want to save a couple of | ||||||
|  |  * bytes. | ||||||
|  |  */ | ||||||
|  | #define USB_CFG_IMPLEMENT_FN_READ       0 | ||||||
|  | /* Set this to 1 if you need to send control replies which are generated
 | ||||||
|  |  * "on the fly" when usbFunctionRead() is called. If you only want to send | ||||||
|  |  * data from a static buffer, set it to 0 and return the data from | ||||||
|  |  * usbFunctionSetup(). This saves a couple of bytes. | ||||||
|  |  */ | ||||||
|  | #define USB_CFG_IMPLEMENT_FN_WRITEOUT   0 | ||||||
|  | /* Define this to 1 if you want to use interrupt-out (or bulk out) endpoints.
 | ||||||
|  |  * You must implement the function usbFunctionWriteOut() which receives all | ||||||
|  |  * interrupt/bulk data sent to any endpoint other than 0. The endpoint number | ||||||
|  |  * can be found in 'usbRxToken'. | ||||||
|  |  */ | ||||||
|  | #define USB_CFG_HAVE_FLOWCONTROL        0 | ||||||
|  | /* Define this to 1 if you want flowcontrol over USB data. See the definition
 | ||||||
|  |  * of the macros usbDisableAllRequests() and usbEnableAllRequests() in | ||||||
|  |  * usbdrv.h. | ||||||
|  |  */ | ||||||
|  | #define USB_CFG_DRIVER_FLASH_PAGE       0 | ||||||
|  | /* If the device has more than 64 kBytes of flash, define this to the 64 k page
 | ||||||
|  |  * where the driver's constants (descriptors) are located. Or in other words: | ||||||
|  |  * Define this to 1 for boot loaders on the ATMega128. | ||||||
|  |  */ | ||||||
|  | #define USB_CFG_LONG_TRANSFERS          0 | ||||||
|  | /* Define this to 1 if you want to send/receive blocks of more than 254 bytes
 | ||||||
|  |  * in a single control-in or control-out transfer. Note that the capability | ||||||
|  |  * for long transfers increases the driver size. | ||||||
|  |  */ | ||||||
|  | /* #define USB_RX_USER_HOOK(data, len)     if(usbRxToken == (uchar)USBPID_SETUP) blinkLED(); */ | ||||||
|  | /* This macro is a hook if you want to do unconventional things. If it is
 | ||||||
|  |  * defined, it's inserted at the beginning of received message processing. | ||||||
|  |  * If you eat the received message and don't want default processing to | ||||||
|  |  * proceed, do a return after doing your things. One possible application | ||||||
|  |  * (besides debugging) is to flash a status LED on each packet. | ||||||
|  |  */ | ||||||
|  | /* #define USB_RESET_HOOK(resetStarts)     if(!resetStarts){hadUsbReset();} */ | ||||||
|  | /* This macro is a hook if you need to know when an USB RESET occurs. It has
 | ||||||
|  |  * one parameter which distinguishes between the start of RESET state and its | ||||||
|  |  * end. | ||||||
|  |  */ | ||||||
|  | /* #define USB_SET_ADDRESS_HOOK()              hadAddressAssigned(); */ | ||||||
|  | /* This macro (if defined) is executed when a USB SET_ADDRESS request was
 | ||||||
|  |  * received. | ||||||
|  |  */ | ||||||
|  | #define USB_COUNT_SOF                   0 | ||||||
|  | /* define this macro to 1 if you need the global variable "usbSofCount" which
 | ||||||
|  |  * counts SOF packets. This feature requires that the hardware interrupt is | ||||||
|  |  * connected to D- instead of D+. | ||||||
|  |  */ | ||||||
|  | /* #ifdef __ASSEMBLER__
 | ||||||
|  |  * macro myAssemblerMacro | ||||||
|  |  *     in      YL, TCNT0 | ||||||
|  |  *     sts     timer0Snapshot, YL | ||||||
|  |  *     endm | ||||||
|  |  * #endif | ||||||
|  |  * #define USB_SOF_HOOK                    myAssemblerMacro | ||||||
|  |  * This macro (if defined) is executed in the assembler module when a | ||||||
|  |  * Start Of Frame condition is detected. It is recommended to define it to | ||||||
|  |  * the name of an assembler macro which is defined here as well so that more | ||||||
|  |  * than one assembler instruction can be used. The macro may use the register | ||||||
|  |  * YL and modify SREG. If it lasts longer than a couple of cycles, USB messages | ||||||
|  |  * immediately after an SOF pulse may be lost and must be retried by the host. | ||||||
|  |  * What can you do with this hook? Since the SOF signal occurs exactly every | ||||||
|  |  * 1 ms (unless the host is in sleep mode), you can use it to tune OSCCAL in | ||||||
|  |  * designs running on the internal RC oscillator. | ||||||
|  |  * Please note that Start Of Frame detection works only if D- is wired to the | ||||||
|  |  * interrupt, not D+. THIS IS DIFFERENT THAN MOST EXAMPLES! | ||||||
|  |  */ | ||||||
|  | #define USB_CFG_CHECK_DATA_TOGGLING     0 | ||||||
|  | /* define this macro to 1 if you want to filter out duplicate data packets
 | ||||||
|  |  * sent by the host. Duplicates occur only as a consequence of communication | ||||||
|  |  * errors, when the host does not receive an ACK. Please note that you need to | ||||||
|  |  * implement the filtering yourself in usbFunctionWriteOut() and | ||||||
|  |  * usbFunctionWrite(). Use the global usbCurrentDataToken and a static variable | ||||||
|  |  * for each control- and out-endpoint to check for duplicate packets. | ||||||
|  |  */ | ||||||
|  | #define USB_CFG_HAVE_MEASURE_FRAME_LENGTH   0 | ||||||
|  | /* define this macro to 1 if you want the function usbMeasureFrameLength()
 | ||||||
|  |  * compiled in. This function can be used to calibrate the AVR's RC oscillator. | ||||||
|  |  */ | ||||||
|  | #define USB_USE_FAST_CRC                0 | ||||||
|  | /* The assembler module has two implementations for the CRC algorithm. One is
 | ||||||
|  |  * faster, the other is smaller. This CRC routine is only used for transmitted | ||||||
|  |  * messages where timing is not critical. The faster routine needs 31 cycles | ||||||
|  |  * per byte while the smaller one needs 61 to 69 cycles. The faster routine | ||||||
|  |  * may be worth the 32 bytes bigger code size if you transmit lots of data and | ||||||
|  |  * run the AVR close to its limit. | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | /* -------------------------- Device Description --------------------------- */ | ||||||
|  | 
 | ||||||
|  | #define  USB_CFG_VENDOR_ID       0xc0, 0x16 /* = 0x16c0 = 5824 = voti.nl */ | ||||||
|  | /* USB vendor ID for the device, low byte first. If you have registered your
 | ||||||
|  |  * own Vendor ID, define it here. Otherwise you may use one of obdev's free | ||||||
|  |  * shared VID/PID pairs. Be sure to read USB-IDs-for-free.txt for rules! | ||||||
|  |  * *** IMPORTANT NOTE *** | ||||||
|  |  * This template uses obdev's shared VID/PID pair for Vendor Class devices | ||||||
|  |  * with libusb: 0x16c0/0x5dc.  Use this VID/PID pair ONLY if you understand | ||||||
|  |  * the implications! | ||||||
|  |  */ | ||||||
|  | #define  USB_CFG_DEVICE_ID       0xdc, 0x05 /* = 0x05dc = 1500 */ | ||||||
|  | /* This is the ID of the product, low byte first. It is interpreted in the
 | ||||||
|  |  * scope of the vendor ID. If you have registered your own VID with usb.org | ||||||
|  |  * or if you have licensed a PID from somebody else, define it here. Otherwise | ||||||
|  |  * you may use one of obdev's free shared VID/PID pairs. See the file | ||||||
|  |  * USB-IDs-for-free.txt for details! | ||||||
|  |  * *** IMPORTANT NOTE *** | ||||||
|  |  * This template uses obdev's shared VID/PID pair for Vendor Class devices | ||||||
|  |  * with libusb: 0x16c0/0x5dc.  Use this VID/PID pair ONLY if you understand | ||||||
|  |  * the implications! | ||||||
|  |  */ | ||||||
|  | #define USB_CFG_DEVICE_VERSION  0x00, 0x01 | ||||||
|  | /* Version number of the device: Minor number first, then major number.
 | ||||||
|  |  */ | ||||||
|  | #define USB_CFG_VENDOR_NAME     'o', 'b', 'd', 'e', 'v', '.', 'a', 't' | ||||||
|  | #define USB_CFG_VENDOR_NAME_LEN 8 | ||||||
|  | /* These two values define the vendor name returned by the USB device. The name
 | ||||||
|  |  * must be given as a list of characters under single quotes. The characters | ||||||
|  |  * are interpreted as Unicode (UTF-16) entities. | ||||||
|  |  * If you don't want a vendor name string, undefine these macros. | ||||||
|  |  * ALWAYS define a vendor name containing your Internet domain name if you use | ||||||
|  |  * obdev's free shared VID/PID pair. See the file USB-IDs-for-free.txt for | ||||||
|  |  * details. | ||||||
|  |  */ | ||||||
|  | #define USB_CFG_DEVICE_NAME     'T', 'e', 'm', 'p', 'l', 'a', 't', 'e' | ||||||
|  | #define USB_CFG_DEVICE_NAME_LEN 8 | ||||||
|  | /* Same as above for the device name. If you don't want a device name, undefine
 | ||||||
|  |  * the macros. See the file USB-IDs-for-free.txt before you assign a name if | ||||||
|  |  * you use a shared VID/PID. | ||||||
|  |  */ | ||||||
|  | /*#define USB_CFG_SERIAL_NUMBER   'N', 'o', 'n', 'e' */ | ||||||
|  | /*#define USB_CFG_SERIAL_NUMBER_LEN   0 */ | ||||||
|  | /* Same as above for the serial number. If you don't want a serial number,
 | ||||||
|  |  * undefine the macros. | ||||||
|  |  * It may be useful to provide the serial number through other means than at | ||||||
|  |  * compile time. See the section about descriptor properties below for how | ||||||
|  |  * to fine tune control over USB descriptors such as the string descriptor | ||||||
|  |  * for the serial number. | ||||||
|  |  */ | ||||||
|  | #define USB_CFG_DEVICE_CLASS        0xff    /* set to 0 if deferred to interface */ | ||||||
|  | #define USB_CFG_DEVICE_SUBCLASS     0 | ||||||
|  | /* See USB specification if you want to conform to an existing device class.
 | ||||||
|  |  * Class 0xff is "vendor specific". | ||||||
|  |  */ | ||||||
|  | #define USB_CFG_INTERFACE_CLASS     0   /* define class here if not at device level */ | ||||||
|  | #define USB_CFG_INTERFACE_SUBCLASS  0 | ||||||
|  | #define USB_CFG_INTERFACE_PROTOCOL  0 | ||||||
|  | /* See USB specification if you want to conform to an existing device class or
 | ||||||
|  |  * protocol. The following classes must be set at interface level: | ||||||
|  |  * HID class is 3, no subclass and protocol required (but may be useful!) | ||||||
|  |  * CDC class is 2, use subclass 2 and protocol 1 for ACM | ||||||
|  |  */ | ||||||
|  | /* #define USB_CFG_HID_REPORT_DESCRIPTOR_LENGTH    42 */ | ||||||
|  | /* Define this to the length of the HID report descriptor, if you implement
 | ||||||
|  |  * an HID device. Otherwise don't define it or define it to 0. | ||||||
|  |  * If you use this define, you must add a PROGMEM character array named | ||||||
|  |  * "usbHidReportDescriptor" to your code which contains the report descriptor. | ||||||
|  |  * Don't forget to keep the array and this define in sync! | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | /* #define USB_PUBLIC static */ | ||||||
|  | /* Use the define above if you #include usbdrv.c instead of linking against it.
 | ||||||
|  |  * This technique saves a couple of bytes in flash memory. | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | /* ------------------- Fine Control over USB Descriptors ------------------- */ | ||||||
|  | /* If you don't want to use the driver's default USB descriptors, you can
 | ||||||
|  |  * provide our own. These can be provided as (1) fixed length static data in | ||||||
|  |  * flash memory, (2) fixed length static data in RAM or (3) dynamically at | ||||||
|  |  * runtime in the function usbFunctionDescriptor(). See usbdrv.h for more | ||||||
|  |  * information about this function. | ||||||
|  |  * Descriptor handling is configured through the descriptor's properties. If | ||||||
|  |  * no properties are defined or if they are 0, the default descriptor is used. | ||||||
|  |  * Possible properties are: | ||||||
|  |  *   + USB_PROP_IS_DYNAMIC: The data for the descriptor should be fetched | ||||||
|  |  *     at runtime via usbFunctionDescriptor(). If the usbMsgPtr mechanism is | ||||||
|  |  *     used, the data is in FLASH by default. Add property USB_PROP_IS_RAM if | ||||||
|  |  *     you want RAM pointers. | ||||||
|  |  *   + USB_PROP_IS_RAM: The data returned by usbFunctionDescriptor() or found | ||||||
|  |  *     in static memory is in RAM, not in flash memory. | ||||||
|  |  *   + USB_PROP_LENGTH(len): If the data is in static memory (RAM or flash), | ||||||
|  |  *     the driver must know the descriptor's length. The descriptor itself is | ||||||
|  |  *     found at the address of a well known identifier (see below). | ||||||
|  |  * List of static descriptor names (must be declared PROGMEM if in flash): | ||||||
|  |  *   char usbDescriptorDevice[]; | ||||||
|  |  *   char usbDescriptorConfiguration[]; | ||||||
|  |  *   char usbDescriptorHidReport[]; | ||||||
|  |  *   char usbDescriptorString0[]; | ||||||
|  |  *   int usbDescriptorStringVendor[]; | ||||||
|  |  *   int usbDescriptorStringDevice[]; | ||||||
|  |  *   int usbDescriptorStringSerialNumber[]; | ||||||
|  |  * Other descriptors can't be provided statically, they must be provided | ||||||
|  |  * dynamically at runtime. | ||||||
|  |  * | ||||||
|  |  * Descriptor properties are or-ed or added together, e.g.: | ||||||
|  |  * #define USB_CFG_DESCR_PROPS_DEVICE   (USB_PROP_IS_RAM | USB_PROP_LENGTH(18)) | ||||||
|  |  * | ||||||
|  |  * The following descriptors are defined: | ||||||
|  |  *   USB_CFG_DESCR_PROPS_DEVICE | ||||||
|  |  *   USB_CFG_DESCR_PROPS_CONFIGURATION | ||||||
|  |  *   USB_CFG_DESCR_PROPS_STRINGS | ||||||
|  |  *   USB_CFG_DESCR_PROPS_STRING_0 | ||||||
|  |  *   USB_CFG_DESCR_PROPS_STRING_VENDOR | ||||||
|  |  *   USB_CFG_DESCR_PROPS_STRING_PRODUCT | ||||||
|  |  *   USB_CFG_DESCR_PROPS_STRING_SERIAL_NUMBER | ||||||
|  |  *   USB_CFG_DESCR_PROPS_HID | ||||||
|  |  *   USB_CFG_DESCR_PROPS_HID_REPORT | ||||||
|  |  *   USB_CFG_DESCR_PROPS_UNKNOWN (for all descriptors not handled by the driver) | ||||||
|  |  * | ||||||
|  |  * Note about string descriptors: String descriptors are not just strings, they | ||||||
|  |  * are Unicode strings prefixed with a 2 byte header. Example: | ||||||
|  |  * int  serialNumberDescriptor[] = { | ||||||
|  |  *     USB_STRING_DESCRIPTOR_HEADER(6), | ||||||
|  |  *     'S', 'e', 'r', 'i', 'a', 'l' | ||||||
|  |  * }; | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | #define USB_CFG_DESCR_PROPS_DEVICE                  0 | ||||||
|  | #define USB_CFG_DESCR_PROPS_CONFIGURATION           0 | ||||||
|  | #define USB_CFG_DESCR_PROPS_STRINGS                 0 | ||||||
|  | #define USB_CFG_DESCR_PROPS_STRING_0                0 | ||||||
|  | #define USB_CFG_DESCR_PROPS_STRING_VENDOR           0 | ||||||
|  | #define USB_CFG_DESCR_PROPS_STRING_PRODUCT          0 | ||||||
|  | #define USB_CFG_DESCR_PROPS_STRING_SERIAL_NUMBER    0 | ||||||
|  | #define USB_CFG_DESCR_PROPS_HID                     0 | ||||||
|  | #define USB_CFG_DESCR_PROPS_HID_REPORT              0 | ||||||
|  | #define USB_CFG_DESCR_PROPS_UNKNOWN                 0 | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | #define usbMsgPtr_t unsigned short | ||||||
|  | /* If usbMsgPtr_t is not defined, it defaults to 'uchar *'. We define it to
 | ||||||
|  |  * a scalar type here because gcc generates slightly shorter code for scalar | ||||||
|  |  * arithmetics than for pointer arithmetics. Remove this define for backward | ||||||
|  |  * type compatibility or define it to an 8 bit type if you use data in RAM only | ||||||
|  |  * and all RAM is below 256 bytes (tiny memory model in IAR CC). | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | /* ----------------------- Optional MCU Description ------------------------ */ | ||||||
|  | 
 | ||||||
|  | /* The following configurations have working defaults in usbdrv.h. You
 | ||||||
|  |  * usually don't need to set them explicitly. Only if you want to run | ||||||
|  |  * the driver on a device which is not yet supported or with a compiler | ||||||
|  |  * which is not fully supported (such as IAR C) or if you use a differnt | ||||||
|  |  * interrupt than INT0, you may have to define some of these. | ||||||
|  |  */ | ||||||
|  | /* #define USB_INTR_CFG            MCUCR */ | ||||||
|  | /* #define USB_INTR_CFG_SET        ((1 << ISC00) | (1 << ISC01)) */ | ||||||
|  | /* #define USB_INTR_CFG_CLR        0 */ | ||||||
|  | /* #define USB_INTR_ENABLE         GIMSK */ | ||||||
|  | /* #define USB_INTR_ENABLE_BIT     INT0 */ | ||||||
|  | /* #define USB_INTR_PENDING        GIFR */ | ||||||
|  | /* #define USB_INTR_PENDING_BIT    INTF0 */ | ||||||
|  | /* #define USB_INTR_VECTOR         INT0_vect */ | ||||||
|  | 
 | ||||||
|  | #endif /* __usbconfig_h_included__ */ | ||||||
							
								
								
									
										628
									
								
								keyboards/planck/thk/bootloader/usbdrv/usbdrv.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										628
									
								
								keyboards/planck/thk/bootloader/usbdrv/usbdrv.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,628 @@ | |||||||
|  | /* Name: usbdrv.c
 | ||||||
|  |  * Project: V-USB, virtual USB port for Atmel's(r) AVR(r) microcontrollers | ||||||
|  |  * Author: Christian Starkjohann | ||||||
|  |  * Creation Date: 2004-12-29 | ||||||
|  |  * Tabsize: 4 | ||||||
|  |  * Copyright: (c) 2005 by OBJECTIVE DEVELOPMENT Software GmbH | ||||||
|  |  * License: GNU GPL v2 (see License.txt), GNU GPL v3 or proprietary (CommercialLicense.txt) | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | #include "usbdrv.h" | ||||||
|  | #include "oddebug.h" | ||||||
|  | 
 | ||||||
|  | /*
 | ||||||
|  | General Description: | ||||||
|  | This module implements the C-part of the USB driver. See usbdrv.h for a | ||||||
|  | documentation of the entire driver. | ||||||
|  | */ | ||||||
|  | 
 | ||||||
|  | /* ------------------------------------------------------------------------- */ | ||||||
|  | 
 | ||||||
|  | /* raw USB registers / interface to assembler code: */ | ||||||
|  | uchar usbRxBuf[2*USB_BUFSIZE];  /* raw RX buffer: PID, 8 bytes data, 2 bytes CRC */ | ||||||
|  | uchar       usbInputBufOffset;  /* offset in usbRxBuf used for low level receiving */ | ||||||
|  | uchar       usbDeviceAddr;      /* assigned during enumeration, defaults to 0 */ | ||||||
|  | uchar       usbNewDeviceAddr;   /* device ID which should be set after status phase */ | ||||||
|  | uchar       usbConfiguration;   /* currently selected configuration. Administered by driver, but not used */ | ||||||
|  | volatile schar usbRxLen;        /* = 0; number of bytes in usbRxBuf; 0 means free, -1 for flow control */ | ||||||
|  | uchar       usbCurrentTok;      /* last token received or endpoint number for last OUT token if != 0 */ | ||||||
|  | uchar       usbRxToken;         /* token for data we received; or endpont number for last OUT */ | ||||||
|  | volatile uchar usbTxLen = USBPID_NAK;   /* number of bytes to transmit with next IN token or handshake token */ | ||||||
|  | uchar       usbTxBuf[USB_BUFSIZE];/* data to transmit with next IN, free if usbTxLen contains handshake token */ | ||||||
|  | #if USB_COUNT_SOF | ||||||
|  | volatile uchar  usbSofCount;    /* incremented by assembler module every SOF */ | ||||||
|  | #endif | ||||||
|  | #if USB_CFG_HAVE_INTRIN_ENDPOINT && !USB_CFG_SUPPRESS_INTR_CODE | ||||||
|  | usbTxStatus_t  usbTxStatus1; | ||||||
|  | #   if USB_CFG_HAVE_INTRIN_ENDPOINT3 | ||||||
|  | usbTxStatus_t  usbTxStatus3; | ||||||
|  | #   endif | ||||||
|  | #endif | ||||||
|  | #if USB_CFG_CHECK_DATA_TOGGLING | ||||||
|  | uchar       usbCurrentDataToken;/* when we check data toggling to ignore duplicate packets */ | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
|  | /* USB status registers / not shared with asm code */ | ||||||
|  | usbMsgPtr_t         usbMsgPtr;      /* data to transmit next -- ROM or RAM address */ | ||||||
|  | static usbMsgLen_t  usbMsgLen = USB_NO_MSG; /* remaining number of bytes */ | ||||||
|  | static uchar        usbMsgFlags;    /* flag values see below */ | ||||||
|  | 
 | ||||||
|  | #define USB_FLG_MSGPTR_IS_ROM   (1<<6) | ||||||
|  | #define USB_FLG_USE_USER_RW     (1<<7) | ||||||
|  | 
 | ||||||
|  | /*
 | ||||||
|  | optimizing hints: | ||||||
|  | - do not post/pre inc/dec integer values in operations | ||||||
|  | - assign value of USB_READ_FLASH() to register variables and don't use side effects in arg | ||||||
|  | - use narrow scope for variables which should be in X/Y/Z register | ||||||
|  | - assign char sized expressions to variables to force 8 bit arithmetics | ||||||
|  | */ | ||||||
|  | 
 | ||||||
|  | /* -------------------------- String Descriptors --------------------------- */ | ||||||
|  | 
 | ||||||
|  | #if USB_CFG_DESCR_PROPS_STRINGS == 0 | ||||||
|  | 
 | ||||||
|  | #if USB_CFG_DESCR_PROPS_STRING_0 == 0 | ||||||
|  | #undef USB_CFG_DESCR_PROPS_STRING_0 | ||||||
|  | #define USB_CFG_DESCR_PROPS_STRING_0    sizeof(usbDescriptorString0) | ||||||
|  | PROGMEM const char usbDescriptorString0[] = { /* language descriptor */ | ||||||
|  |     4,          /* sizeof(usbDescriptorString0): length of descriptor in bytes */ | ||||||
|  |     3,          /* descriptor type */ | ||||||
|  |     0x09, 0x04, /* language index (0x0409 = US-English) */ | ||||||
|  | }; | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
|  | #if USB_CFG_DESCR_PROPS_STRING_VENDOR == 0 && USB_CFG_VENDOR_NAME_LEN | ||||||
|  | #undef USB_CFG_DESCR_PROPS_STRING_VENDOR | ||||||
|  | #define USB_CFG_DESCR_PROPS_STRING_VENDOR   sizeof(usbDescriptorStringVendor) | ||||||
|  | PROGMEM const int  usbDescriptorStringVendor[] = { | ||||||
|  |     USB_STRING_DESCRIPTOR_HEADER(USB_CFG_VENDOR_NAME_LEN), | ||||||
|  |     USB_CFG_VENDOR_NAME | ||||||
|  | }; | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
|  | #if USB_CFG_DESCR_PROPS_STRING_PRODUCT == 0 && USB_CFG_DEVICE_NAME_LEN | ||||||
|  | #undef USB_CFG_DESCR_PROPS_STRING_PRODUCT | ||||||
|  | #define USB_CFG_DESCR_PROPS_STRING_PRODUCT   sizeof(usbDescriptorStringDevice) | ||||||
|  | PROGMEM const int  usbDescriptorStringDevice[] = { | ||||||
|  |     USB_STRING_DESCRIPTOR_HEADER(USB_CFG_DEVICE_NAME_LEN), | ||||||
|  |     USB_CFG_DEVICE_NAME | ||||||
|  | }; | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
|  | #if USB_CFG_DESCR_PROPS_STRING_SERIAL_NUMBER == 0 && USB_CFG_SERIAL_NUMBER_LEN | ||||||
|  | #undef USB_CFG_DESCR_PROPS_STRING_SERIAL_NUMBER | ||||||
|  | #define USB_CFG_DESCR_PROPS_STRING_SERIAL_NUMBER    sizeof(usbDescriptorStringSerialNumber) | ||||||
|  | PROGMEM const int usbDescriptorStringSerialNumber[] = { | ||||||
|  |     USB_STRING_DESCRIPTOR_HEADER(USB_CFG_SERIAL_NUMBER_LEN), | ||||||
|  |     USB_CFG_SERIAL_NUMBER | ||||||
|  | }; | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
|  | #endif  /* USB_CFG_DESCR_PROPS_STRINGS == 0 */ | ||||||
|  | 
 | ||||||
|  | /* --------------------------- Device Descriptor --------------------------- */ | ||||||
|  | 
 | ||||||
|  | #if USB_CFG_DESCR_PROPS_DEVICE == 0 | ||||||
|  | #undef USB_CFG_DESCR_PROPS_DEVICE | ||||||
|  | #define USB_CFG_DESCR_PROPS_DEVICE  sizeof(usbDescriptorDevice) | ||||||
|  | PROGMEM const char usbDescriptorDevice[] = {    /* USB device descriptor */ | ||||||
|  |     18,         /* sizeof(usbDescriptorDevice): length of descriptor in bytes */ | ||||||
|  |     USBDESCR_DEVICE,        /* descriptor type */ | ||||||
|  |     0x10, 0x01,             /* USB version supported */ | ||||||
|  |     USB_CFG_DEVICE_CLASS, | ||||||
|  |     USB_CFG_DEVICE_SUBCLASS, | ||||||
|  |     0,                      /* protocol */ | ||||||
|  |     8,                      /* max packet size */ | ||||||
|  |     /* the following two casts affect the first byte of the constant only, but
 | ||||||
|  |      * that's sufficient to avoid a warning with the default values. | ||||||
|  |      */ | ||||||
|  |     (char)USB_CFG_VENDOR_ID,/* 2 bytes */ | ||||||
|  |     (char)USB_CFG_DEVICE_ID,/* 2 bytes */ | ||||||
|  |     USB_CFG_DEVICE_VERSION, /* 2 bytes */ | ||||||
|  |     USB_CFG_DESCR_PROPS_STRING_VENDOR != 0 ? 1 : 0,         /* manufacturer string index */ | ||||||
|  |     USB_CFG_DESCR_PROPS_STRING_PRODUCT != 0 ? 2 : 0,        /* product string index */ | ||||||
|  |     USB_CFG_DESCR_PROPS_STRING_SERIAL_NUMBER != 0 ? 3 : 0,  /* serial number string index */ | ||||||
|  |     1,          /* number of configurations */ | ||||||
|  | }; | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
|  | /* ----------------------- Configuration Descriptor ------------------------ */ | ||||||
|  | 
 | ||||||
|  | #if USB_CFG_DESCR_PROPS_HID_REPORT != 0 && USB_CFG_DESCR_PROPS_HID == 0 | ||||||
|  | #undef USB_CFG_DESCR_PROPS_HID | ||||||
|  | #define USB_CFG_DESCR_PROPS_HID     9   /* length of HID descriptor in config descriptor below */ | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
|  | #if USB_CFG_DESCR_PROPS_CONFIGURATION == 0 | ||||||
|  | #undef USB_CFG_DESCR_PROPS_CONFIGURATION | ||||||
|  | #define USB_CFG_DESCR_PROPS_CONFIGURATION   sizeof(usbDescriptorConfiguration) | ||||||
|  | PROGMEM const char usbDescriptorConfiguration[] = {    /* USB configuration descriptor */ | ||||||
|  |     9,          /* sizeof(usbDescriptorConfiguration): length of descriptor in bytes */ | ||||||
|  |     USBDESCR_CONFIG,    /* descriptor type */ | ||||||
|  |     18 + 7 * USB_CFG_HAVE_INTRIN_ENDPOINT + 7 * USB_CFG_HAVE_INTRIN_ENDPOINT3 + | ||||||
|  |                 (USB_CFG_DESCR_PROPS_HID & 0xff), 0, | ||||||
|  |                 /* total length of data returned (including inlined descriptors) */ | ||||||
|  |     1,          /* number of interfaces in this configuration */ | ||||||
|  |     1,          /* index of this configuration */ | ||||||
|  |     0,          /* configuration name string index */ | ||||||
|  | #if USB_CFG_IS_SELF_POWERED | ||||||
|  |     (1 << 7) | USBATTR_SELFPOWER,       /* attributes */ | ||||||
|  | #else | ||||||
|  |     (1 << 7),                           /* attributes */ | ||||||
|  | #endif | ||||||
|  |     USB_CFG_MAX_BUS_POWER/2,            /* max USB current in 2mA units */ | ||||||
|  | /* interface descriptor follows inline: */ | ||||||
|  |     9,          /* sizeof(usbDescrInterface): length of descriptor in bytes */ | ||||||
|  |     USBDESCR_INTERFACE, /* descriptor type */ | ||||||
|  |     0,          /* index of this interface */ | ||||||
|  |     0,          /* alternate setting for this interface */ | ||||||
|  |     USB_CFG_HAVE_INTRIN_ENDPOINT + USB_CFG_HAVE_INTRIN_ENDPOINT3, /* endpoints excl 0: number of endpoint descriptors to follow */ | ||||||
|  |     USB_CFG_INTERFACE_CLASS, | ||||||
|  |     USB_CFG_INTERFACE_SUBCLASS, | ||||||
|  |     USB_CFG_INTERFACE_PROTOCOL, | ||||||
|  |     0,          /* string index for interface */ | ||||||
|  | #if (USB_CFG_DESCR_PROPS_HID & 0xff)    /* HID descriptor */ | ||||||
|  |     9,          /* sizeof(usbDescrHID): length of descriptor in bytes */ | ||||||
|  |     USBDESCR_HID,   /* descriptor type: HID */ | ||||||
|  |     0x01, 0x01, /* BCD representation of HID version */ | ||||||
|  |     0x00,       /* target country code */ | ||||||
|  |     0x01,       /* number of HID Report (or other HID class) Descriptor infos to follow */ | ||||||
|  |     0x22,       /* descriptor type: report */ | ||||||
|  |     USB_CFG_HID_REPORT_DESCRIPTOR_LENGTH, 0,  /* total length of report descriptor */ | ||||||
|  | #endif | ||||||
|  | #if USB_CFG_HAVE_INTRIN_ENDPOINT    /* endpoint descriptor for endpoint 1 */ | ||||||
|  |     7,          /* sizeof(usbDescrEndpoint) */ | ||||||
|  |     USBDESCR_ENDPOINT,  /* descriptor type = endpoint */ | ||||||
|  |     (char)0x81, /* IN endpoint number 1 */ | ||||||
|  |     0x03,       /* attrib: Interrupt endpoint */ | ||||||
|  |     8, 0,       /* maximum packet size */ | ||||||
|  |     USB_CFG_INTR_POLL_INTERVAL, /* in ms */ | ||||||
|  | #endif | ||||||
|  | #if USB_CFG_HAVE_INTRIN_ENDPOINT3   /* endpoint descriptor for endpoint 3 */ | ||||||
|  |     7,          /* sizeof(usbDescrEndpoint) */ | ||||||
|  |     USBDESCR_ENDPOINT,  /* descriptor type = endpoint */ | ||||||
|  |     (char)(0x80 | USB_CFG_EP3_NUMBER), /* IN endpoint number 3 */ | ||||||
|  |     0x03,       /* attrib: Interrupt endpoint */ | ||||||
|  |     8, 0,       /* maximum packet size */ | ||||||
|  |     USB_CFG_INTR_POLL_INTERVAL, /* in ms */ | ||||||
|  | #endif | ||||||
|  | }; | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
|  | /* ------------------------------------------------------------------------- */ | ||||||
|  | 
 | ||||||
|  | static inline void  usbResetDataToggling(void) | ||||||
|  | { | ||||||
|  | #if USB_CFG_HAVE_INTRIN_ENDPOINT && !USB_CFG_SUPPRESS_INTR_CODE | ||||||
|  |     USB_SET_DATATOKEN1(USB_INITIAL_DATATOKEN);  /* reset data toggling for interrupt endpoint */ | ||||||
|  | #   if USB_CFG_HAVE_INTRIN_ENDPOINT3 | ||||||
|  |     USB_SET_DATATOKEN3(USB_INITIAL_DATATOKEN);  /* reset data toggling for interrupt endpoint */ | ||||||
|  | #   endif | ||||||
|  | #endif | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static inline void  usbResetStall(void) | ||||||
|  | { | ||||||
|  | #if USB_CFG_IMPLEMENT_HALT && USB_CFG_HAVE_INTRIN_ENDPOINT | ||||||
|  |         usbTxLen1 = USBPID_NAK; | ||||||
|  | #if USB_CFG_HAVE_INTRIN_ENDPOINT3 | ||||||
|  |         usbTxLen3 = USBPID_NAK; | ||||||
|  | #endif | ||||||
|  | #endif | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /* ------------------------------------------------------------------------- */ | ||||||
|  | 
 | ||||||
|  | #if !USB_CFG_SUPPRESS_INTR_CODE | ||||||
|  | #if USB_CFG_HAVE_INTRIN_ENDPOINT | ||||||
|  | static void usbGenericSetInterrupt(uchar *data, uchar len, usbTxStatus_t *txStatus) | ||||||
|  | { | ||||||
|  | uchar   *p; | ||||||
|  | char    i; | ||||||
|  | 
 | ||||||
|  | #if USB_CFG_IMPLEMENT_HALT | ||||||
|  |     if(usbTxLen1 == USBPID_STALL) | ||||||
|  |         return; | ||||||
|  | #endif | ||||||
|  |     if(txStatus->len & 0x10){   /* packet buffer was empty */ | ||||||
|  |         txStatus->buffer[0] ^= USBPID_DATA0 ^ USBPID_DATA1; /* toggle token */ | ||||||
|  |     }else{ | ||||||
|  |         txStatus->len = USBPID_NAK; /* avoid sending outdated (overwritten) interrupt data */ | ||||||
|  |     } | ||||||
|  |     p = txStatus->buffer + 1; | ||||||
|  |     i = len; | ||||||
|  |     do{                         /* if len == 0, we still copy 1 byte, but that's no problem */ | ||||||
|  |         *p++ = *data++; | ||||||
|  |     }while(--i > 0);            /* loop control at the end is 2 bytes shorter than at beginning */ | ||||||
|  |     usbCrc16Append(&txStatus->buffer[1], len); | ||||||
|  |     txStatus->len = len + 4;    /* len must be given including sync byte */ | ||||||
|  |     DBG2(0x21 + (((int)txStatus >> 3) & 3), txStatus->buffer, len + 3); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | USB_PUBLIC void usbSetInterrupt(uchar *data, uchar len) | ||||||
|  | { | ||||||
|  |     usbGenericSetInterrupt(data, len, &usbTxStatus1); | ||||||
|  | } | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
|  | #if USB_CFG_HAVE_INTRIN_ENDPOINT3 | ||||||
|  | USB_PUBLIC void usbSetInterrupt3(uchar *data, uchar len) | ||||||
|  | { | ||||||
|  |     usbGenericSetInterrupt(data, len, &usbTxStatus3); | ||||||
|  | } | ||||||
|  | #endif | ||||||
|  | #endif /* USB_CFG_SUPPRESS_INTR_CODE */ | ||||||
|  | 
 | ||||||
|  | /* ------------------ utilities for code following below ------------------- */ | ||||||
|  | 
 | ||||||
|  | /* Use defines for the switch statement so that we can choose between an
 | ||||||
|  |  * if()else if() and a switch/case based implementation. switch() is more | ||||||
|  |  * efficient for a LARGE set of sequential choices, if() is better in all other | ||||||
|  |  * cases. | ||||||
|  |  */ | ||||||
|  | #if USB_CFG_USE_SWITCH_STATEMENT | ||||||
|  | #   define SWITCH_START(cmd)       switch(cmd){{ | ||||||
|  | #   define SWITCH_CASE(value)      }break; case (value):{ | ||||||
|  | #   define SWITCH_CASE2(v1,v2)     }break; case (v1): case(v2):{ | ||||||
|  | #   define SWITCH_CASE3(v1,v2,v3)  }break; case (v1): case(v2): case(v3):{ | ||||||
|  | #   define SWITCH_DEFAULT          }break; default:{ | ||||||
|  | #   define SWITCH_END              }} | ||||||
|  | #else | ||||||
|  | #   define SWITCH_START(cmd)       {uchar _cmd = cmd; if(0){ | ||||||
|  | #   define SWITCH_CASE(value)      }else if(_cmd == (value)){ | ||||||
|  | #   define SWITCH_CASE2(v1,v2)     }else if(_cmd == (v1) || _cmd == (v2)){ | ||||||
|  | #   define SWITCH_CASE3(v1,v2,v3)  }else if(_cmd == (v1) || _cmd == (v2) || (_cmd == v3)){ | ||||||
|  | #   define SWITCH_DEFAULT          }else{ | ||||||
|  | #   define SWITCH_END              }} | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
|  | #ifndef USB_RX_USER_HOOK | ||||||
|  | #define USB_RX_USER_HOOK(data, len) | ||||||
|  | #endif | ||||||
|  | #ifndef USB_SET_ADDRESS_HOOK | ||||||
|  | #define USB_SET_ADDRESS_HOOK() | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
|  | /* ------------------------------------------------------------------------- */ | ||||||
|  | 
 | ||||||
|  | /* We use if() instead of #if in the macro below because #if can't be used
 | ||||||
|  |  * in macros and the compiler optimizes constant conditions anyway. | ||||||
|  |  * This may cause problems with undefined symbols if compiled without | ||||||
|  |  * optimizing! | ||||||
|  |  */ | ||||||
|  | #define GET_DESCRIPTOR(cfgProp, staticName)         \ | ||||||
|  |     if(cfgProp){                                    \ | ||||||
|  |         if((cfgProp) & USB_PROP_IS_RAM)             \ | ||||||
|  |             flags = 0;                              \ | ||||||
|  |         if((cfgProp) & USB_PROP_IS_DYNAMIC){        \ | ||||||
|  |             len = usbFunctionDescriptor(rq);        \ | ||||||
|  |         }else{                                      \ | ||||||
|  |             len = USB_PROP_LENGTH(cfgProp);         \ | ||||||
|  |             usbMsgPtr = (usbMsgPtr_t)(staticName);  \ | ||||||
|  |         }                                           \ | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  | /* usbDriverDescriptor() is similar to usbFunctionDescriptor(), but used
 | ||||||
|  |  * internally for all types of descriptors. | ||||||
|  |  */ | ||||||
|  | static inline usbMsgLen_t usbDriverDescriptor(usbRequest_t *rq) | ||||||
|  | { | ||||||
|  | usbMsgLen_t len = 0; | ||||||
|  | uchar       flags = USB_FLG_MSGPTR_IS_ROM; | ||||||
|  | 
 | ||||||
|  |     SWITCH_START(rq->wValue.bytes[1]) | ||||||
|  |     SWITCH_CASE(USBDESCR_DEVICE)    /* 1 */ | ||||||
|  |         GET_DESCRIPTOR(USB_CFG_DESCR_PROPS_DEVICE, usbDescriptorDevice) | ||||||
|  |     SWITCH_CASE(USBDESCR_CONFIG)    /* 2 */ | ||||||
|  |         GET_DESCRIPTOR(USB_CFG_DESCR_PROPS_CONFIGURATION, usbDescriptorConfiguration) | ||||||
|  |     SWITCH_CASE(USBDESCR_STRING)    /* 3 */ | ||||||
|  | #if USB_CFG_DESCR_PROPS_STRINGS & USB_PROP_IS_DYNAMIC | ||||||
|  |         if(USB_CFG_DESCR_PROPS_STRINGS & USB_PROP_IS_RAM) | ||||||
|  |             flags = 0; | ||||||
|  |         len = usbFunctionDescriptor(rq); | ||||||
|  | #else   /* USB_CFG_DESCR_PROPS_STRINGS & USB_PROP_IS_DYNAMIC */ | ||||||
|  |         SWITCH_START(rq->wValue.bytes[0]) | ||||||
|  |         SWITCH_CASE(0) | ||||||
|  |             GET_DESCRIPTOR(USB_CFG_DESCR_PROPS_STRING_0, usbDescriptorString0) | ||||||
|  |         SWITCH_CASE(1) | ||||||
|  |             GET_DESCRIPTOR(USB_CFG_DESCR_PROPS_STRING_VENDOR, usbDescriptorStringVendor) | ||||||
|  |         SWITCH_CASE(2) | ||||||
|  |             GET_DESCRIPTOR(USB_CFG_DESCR_PROPS_STRING_PRODUCT, usbDescriptorStringDevice) | ||||||
|  |         SWITCH_CASE(3) | ||||||
|  |             GET_DESCRIPTOR(USB_CFG_DESCR_PROPS_STRING_SERIAL_NUMBER, usbDescriptorStringSerialNumber) | ||||||
|  |         SWITCH_DEFAULT | ||||||
|  |             if(USB_CFG_DESCR_PROPS_UNKNOWN & USB_PROP_IS_DYNAMIC){ | ||||||
|  |                 len = usbFunctionDescriptor(rq); | ||||||
|  |             } | ||||||
|  |         SWITCH_END | ||||||
|  | #endif  /* USB_CFG_DESCR_PROPS_STRINGS & USB_PROP_IS_DYNAMIC */ | ||||||
|  | #if USB_CFG_DESCR_PROPS_HID_REPORT  /* only support HID descriptors if enabled */ | ||||||
|  |     SWITCH_CASE(USBDESCR_HID)       /* 0x21 */ | ||||||
|  |         GET_DESCRIPTOR(USB_CFG_DESCR_PROPS_HID, usbDescriptorConfiguration + 18) | ||||||
|  |     SWITCH_CASE(USBDESCR_HID_REPORT)/* 0x22 */ | ||||||
|  |         GET_DESCRIPTOR(USB_CFG_DESCR_PROPS_HID_REPORT, usbDescriptorHidReport) | ||||||
|  | #endif | ||||||
|  |     SWITCH_DEFAULT | ||||||
|  |         if(USB_CFG_DESCR_PROPS_UNKNOWN & USB_PROP_IS_DYNAMIC){ | ||||||
|  |             len = usbFunctionDescriptor(rq); | ||||||
|  |         } | ||||||
|  |     SWITCH_END | ||||||
|  |     usbMsgFlags = flags; | ||||||
|  |     return len; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /* ------------------------------------------------------------------------- */ | ||||||
|  | 
 | ||||||
|  | /* usbDriverSetup() is similar to usbFunctionSetup(), but it's used for
 | ||||||
|  |  * standard requests instead of class and custom requests. | ||||||
|  |  */ | ||||||
|  | static inline usbMsgLen_t usbDriverSetup(usbRequest_t *rq) | ||||||
|  | { | ||||||
|  | usbMsgLen_t len = 0; | ||||||
|  | uchar   *dataPtr = usbTxBuf + 9;    /* there are 2 bytes free space at the end of the buffer */ | ||||||
|  | uchar   value = rq->wValue.bytes[0]; | ||||||
|  | #if USB_CFG_IMPLEMENT_HALT | ||||||
|  | uchar   index = rq->wIndex.bytes[0]; | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
|  |     dataPtr[0] = 0; /* default reply common to USBRQ_GET_STATUS and USBRQ_GET_INTERFACE */ | ||||||
|  |     SWITCH_START(rq->bRequest) | ||||||
|  |     SWITCH_CASE(USBRQ_GET_STATUS)           /* 0 */ | ||||||
|  |         uchar recipient = rq->bmRequestType & USBRQ_RCPT_MASK;  /* assign arith ops to variables to enforce byte size */ | ||||||
|  |         if(USB_CFG_IS_SELF_POWERED && recipient == USBRQ_RCPT_DEVICE) | ||||||
|  |             dataPtr[0] =  USB_CFG_IS_SELF_POWERED; | ||||||
|  | #if USB_CFG_IMPLEMENT_HALT | ||||||
|  |         if(recipient == USBRQ_RCPT_ENDPOINT && index == 0x81)   /* request status for endpoint 1 */ | ||||||
|  |             dataPtr[0] = usbTxLen1 == USBPID_STALL; | ||||||
|  | #endif | ||||||
|  |         dataPtr[1] = 0; | ||||||
|  |         len = 2; | ||||||
|  | #if USB_CFG_IMPLEMENT_HALT | ||||||
|  |     SWITCH_CASE2(USBRQ_CLEAR_FEATURE, USBRQ_SET_FEATURE)    /* 1, 3 */ | ||||||
|  |         if(value == 0 && index == 0x81){    /* feature 0 == HALT for endpoint == 1 */ | ||||||
|  |             usbTxLen1 = rq->bRequest == USBRQ_CLEAR_FEATURE ? USBPID_NAK : USBPID_STALL; | ||||||
|  |             usbResetDataToggling(); | ||||||
|  |         } | ||||||
|  | #endif | ||||||
|  |     SWITCH_CASE(USBRQ_SET_ADDRESS)          /* 5 */ | ||||||
|  |         usbNewDeviceAddr = value; | ||||||
|  |         USB_SET_ADDRESS_HOOK(); | ||||||
|  |     SWITCH_CASE(USBRQ_GET_DESCRIPTOR)       /* 6 */ | ||||||
|  |         len = usbDriverDescriptor(rq); | ||||||
|  |         goto skipMsgPtrAssignment; | ||||||
|  |     SWITCH_CASE(USBRQ_GET_CONFIGURATION)    /* 8 */ | ||||||
|  |         dataPtr = &usbConfiguration;  /* send current configuration value */ | ||||||
|  |         len = 1; | ||||||
|  |     SWITCH_CASE(USBRQ_SET_CONFIGURATION)    /* 9 */ | ||||||
|  |         usbConfiguration = value; | ||||||
|  |         usbResetStall(); | ||||||
|  |     SWITCH_CASE(USBRQ_GET_INTERFACE)        /* 10 */ | ||||||
|  |         len = 1; | ||||||
|  | #if USB_CFG_HAVE_INTRIN_ENDPOINT && !USB_CFG_SUPPRESS_INTR_CODE | ||||||
|  |     SWITCH_CASE(USBRQ_SET_INTERFACE)        /* 11 */ | ||||||
|  |         usbResetDataToggling(); | ||||||
|  |         usbResetStall(); | ||||||
|  | #endif | ||||||
|  |     SWITCH_DEFAULT                          /* 7=SET_DESCRIPTOR, 12=SYNC_FRAME */ | ||||||
|  |         /* Should we add an optional hook here? */ | ||||||
|  |     SWITCH_END | ||||||
|  |     usbMsgPtr = (usbMsgPtr_t)dataPtr; | ||||||
|  | skipMsgPtrAssignment: | ||||||
|  |     return len; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /* ------------------------------------------------------------------------- */ | ||||||
|  | 
 | ||||||
|  | /* usbProcessRx() is called for every message received by the interrupt
 | ||||||
|  |  * routine. It distinguishes between SETUP and DATA packets and processes | ||||||
|  |  * them accordingly. | ||||||
|  |  */ | ||||||
|  | static inline void usbProcessRx(uchar *data, uchar len) | ||||||
|  | { | ||||||
|  | usbRequest_t    *rq = (void *)data; | ||||||
|  | 
 | ||||||
|  | /* usbRxToken can be:
 | ||||||
|  |  * 0x2d 00101101 (USBPID_SETUP for setup data) | ||||||
|  |  * 0xe1 11100001 (USBPID_OUT: data phase of setup transfer) | ||||||
|  |  * 0...0x0f for OUT on endpoint X | ||||||
|  |  */ | ||||||
|  |     DBG2(0x10 + (usbRxToken & 0xf), data, len + 2); /* SETUP=1d, SETUP-DATA=11, OUTx=1x */ | ||||||
|  |     USB_RX_USER_HOOK(data, len) | ||||||
|  | #if USB_CFG_IMPLEMENT_FN_WRITEOUT | ||||||
|  |     if(usbRxToken < 0x10){  /* OUT to endpoint != 0: endpoint number in usbRxToken */ | ||||||
|  |         usbFunctionWriteOut(data, len); | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  | #endif | ||||||
|  |     if(usbRxToken == (uchar)USBPID_SETUP){ | ||||||
|  |         if(len != 8)    /* Setup size must be always 8 bytes. Ignore otherwise. */ | ||||||
|  |             return; | ||||||
|  |         usbMsgLen_t replyLen; | ||||||
|  |         usbTxBuf[0] = USBPID_DATA0;         /* initialize data toggling */ | ||||||
|  |         usbTxLen = USBPID_NAK;              /* abort pending transmit */ | ||||||
|  |         usbMsgFlags = 0; | ||||||
|  |         uchar type = rq->bmRequestType & USBRQ_TYPE_MASK; | ||||||
|  |         if(type != USBRQ_TYPE_STANDARD){    /* standard requests are handled by driver */ | ||||||
|  |             replyLen = usbFunctionSetup(data); | ||||||
|  |         }else{ | ||||||
|  |             replyLen = usbDriverSetup(rq); | ||||||
|  |         } | ||||||
|  | #if USB_CFG_IMPLEMENT_FN_READ || USB_CFG_IMPLEMENT_FN_WRITE | ||||||
|  |         if(replyLen == USB_NO_MSG){         /* use user-supplied read/write function */ | ||||||
|  |             /* do some conditioning on replyLen, but on IN transfers only */ | ||||||
|  |             if((rq->bmRequestType & USBRQ_DIR_MASK) != USBRQ_DIR_HOST_TO_DEVICE){ | ||||||
|  |                 if(sizeof(replyLen) < sizeof(rq->wLength.word)){ /* help compiler with optimizing */ | ||||||
|  |                     replyLen = rq->wLength.bytes[0]; | ||||||
|  |                 }else{ | ||||||
|  |                     replyLen = rq->wLength.word; | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |             usbMsgFlags = USB_FLG_USE_USER_RW; | ||||||
|  |         }else   /* The 'else' prevents that we limit a replyLen of USB_NO_MSG to the maximum transfer len. */ | ||||||
|  | #endif | ||||||
|  |         if(sizeof(replyLen) < sizeof(rq->wLength.word)){ /* help compiler with optimizing */ | ||||||
|  |             if(!rq->wLength.bytes[1] && replyLen > rq->wLength.bytes[0])    /* limit length to max */ | ||||||
|  |                 replyLen = rq->wLength.bytes[0]; | ||||||
|  |         }else{ | ||||||
|  |             if(replyLen > rq->wLength.word)     /* limit length to max */ | ||||||
|  |                 replyLen = rq->wLength.word; | ||||||
|  |         } | ||||||
|  |         usbMsgLen = replyLen; | ||||||
|  |     }else{  /* usbRxToken must be USBPID_OUT, which means data phase of setup (control-out) */ | ||||||
|  | #if USB_CFG_IMPLEMENT_FN_WRITE | ||||||
|  |         if(usbMsgFlags & USB_FLG_USE_USER_RW){ | ||||||
|  |             uchar rval = usbFunctionWrite(data, len); | ||||||
|  |             if(rval == 0xff){   /* an error occurred */ | ||||||
|  |                 usbTxLen = USBPID_STALL; | ||||||
|  |             }else if(rval != 0){    /* This was the final package */ | ||||||
|  |                 usbMsgLen = 0;  /* answer with a zero-sized data packet */ | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  | #endif | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /* ------------------------------------------------------------------------- */ | ||||||
|  | 
 | ||||||
|  | /* This function is similar to usbFunctionRead(), but it's also called for
 | ||||||
|  |  * data handled automatically by the driver (e.g. descriptor reads). | ||||||
|  |  */ | ||||||
|  | static uchar usbDeviceRead(uchar *data, uchar len) | ||||||
|  | { | ||||||
|  |     if(len > 0){    /* don't bother app with 0 sized reads */ | ||||||
|  | #if USB_CFG_IMPLEMENT_FN_READ | ||||||
|  |         if(usbMsgFlags & USB_FLG_USE_USER_RW){ | ||||||
|  |             len = usbFunctionRead(data, len); | ||||||
|  |         }else | ||||||
|  | #endif | ||||||
|  |         { | ||||||
|  |             uchar i = len; | ||||||
|  |             usbMsgPtr_t r = usbMsgPtr; | ||||||
|  |             if(usbMsgFlags & USB_FLG_MSGPTR_IS_ROM){    /* ROM data */ | ||||||
|  |                 do{ | ||||||
|  |                     uchar c = USB_READ_FLASH(r);    /* assign to char size variable to enforce byte ops */ | ||||||
|  |                     *data++ = c; | ||||||
|  |                     r++; | ||||||
|  |                 }while(--i); | ||||||
|  |             }else{  /* RAM data */ | ||||||
|  |                 do{ | ||||||
|  |                     *data++ = *((uchar *)r); | ||||||
|  |                     r++; | ||||||
|  |                 }while(--i); | ||||||
|  |             } | ||||||
|  |             usbMsgPtr = r; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     return len; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /* ------------------------------------------------------------------------- */ | ||||||
|  | 
 | ||||||
|  | /* usbBuildTxBlock() is called when we have data to transmit and the
 | ||||||
|  |  * interrupt routine's transmit buffer is empty. | ||||||
|  |  */ | ||||||
|  | static inline void usbBuildTxBlock(void) | ||||||
|  | { | ||||||
|  | usbMsgLen_t wantLen; | ||||||
|  | uchar       len; | ||||||
|  | 
 | ||||||
|  |     wantLen = usbMsgLen; | ||||||
|  |     if(wantLen > 8) | ||||||
|  |         wantLen = 8; | ||||||
|  |     usbMsgLen -= wantLen; | ||||||
|  |     usbTxBuf[0] ^= USBPID_DATA0 ^ USBPID_DATA1; /* DATA toggling */ | ||||||
|  |     len = usbDeviceRead(usbTxBuf + 1, wantLen); | ||||||
|  |     if(len <= 8){           /* valid data packet */ | ||||||
|  |         usbCrc16Append(&usbTxBuf[1], len); | ||||||
|  |         len += 4;           /* length including sync byte */ | ||||||
|  |         if(len < 12)        /* a partial package identifies end of message */ | ||||||
|  |             usbMsgLen = USB_NO_MSG; | ||||||
|  |     }else{ | ||||||
|  |         len = USBPID_STALL;   /* stall the endpoint */ | ||||||
|  |         usbMsgLen = USB_NO_MSG; | ||||||
|  |     } | ||||||
|  |     usbTxLen = len; | ||||||
|  |     DBG2(0x20, usbTxBuf, len-1); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /* ------------------------------------------------------------------------- */ | ||||||
|  | 
 | ||||||
|  | static inline void usbHandleResetHook(uchar notResetState) | ||||||
|  | { | ||||||
|  | #ifdef USB_RESET_HOOK | ||||||
|  | static uchar    wasReset; | ||||||
|  | uchar           isReset = !notResetState; | ||||||
|  | 
 | ||||||
|  |     if(wasReset != isReset){ | ||||||
|  |         USB_RESET_HOOK(isReset); | ||||||
|  |         wasReset = isReset; | ||||||
|  |     } | ||||||
|  | #else | ||||||
|  |     notResetState = notResetState;  // avoid compiler warning
 | ||||||
|  | #endif | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /* ------------------------------------------------------------------------- */ | ||||||
|  | 
 | ||||||
|  | USB_PUBLIC void usbPoll(void) | ||||||
|  | { | ||||||
|  | schar   len; | ||||||
|  | uchar   i; | ||||||
|  | 
 | ||||||
|  |     len = usbRxLen - 3; | ||||||
|  |     if(len >= 0){ | ||||||
|  | /* We could check CRC16 here -- but ACK has already been sent anyway. If you
 | ||||||
|  |  * need data integrity checks with this driver, check the CRC in your app | ||||||
|  |  * code and report errors back to the host. Since the ACK was already sent, | ||||||
|  |  * retries must be handled on application level. | ||||||
|  |  * unsigned crc = usbCrc16(buffer + 1, usbRxLen - 3); | ||||||
|  |  */ | ||||||
|  |         usbProcessRx(usbRxBuf + USB_BUFSIZE + 1 - usbInputBufOffset, len); | ||||||
|  | #if USB_CFG_HAVE_FLOWCONTROL | ||||||
|  |         if(usbRxLen > 0)    /* only mark as available if not inactivated */ | ||||||
|  |             usbRxLen = 0; | ||||||
|  | #else | ||||||
|  |         usbRxLen = 0;       /* mark rx buffer as available */ | ||||||
|  | #endif | ||||||
|  |     } | ||||||
|  |     if(usbTxLen & 0x10){    /* transmit system idle */ | ||||||
|  |         if(usbMsgLen != USB_NO_MSG){    /* transmit data pending? */ | ||||||
|  |             usbBuildTxBlock(); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     for(i = 20; i > 0; i--){ | ||||||
|  |         uchar usbLineStatus = USBIN & USBMASK; | ||||||
|  |         if(usbLineStatus != 0)  /* SE0 has ended */ | ||||||
|  |             goto isNotReset; | ||||||
|  |     } | ||||||
|  |     /* RESET condition, called multiple times during reset */ | ||||||
|  |     usbNewDeviceAddr = 0; | ||||||
|  |     usbDeviceAddr = 0; | ||||||
|  |     usbResetStall(); | ||||||
|  |     DBG1(0xff, 0, 0); | ||||||
|  | isNotReset: | ||||||
|  |     usbHandleResetHook(i); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /* ------------------------------------------------------------------------- */ | ||||||
|  | 
 | ||||||
|  | USB_PUBLIC void usbInit(void) | ||||||
|  | { | ||||||
|  | #if USB_INTR_CFG_SET != 0 | ||||||
|  |     USB_INTR_CFG |= USB_INTR_CFG_SET; | ||||||
|  | #endif | ||||||
|  | #if USB_INTR_CFG_CLR != 0 | ||||||
|  |     USB_INTR_CFG &= ~(USB_INTR_CFG_CLR); | ||||||
|  | #endif | ||||||
|  |     USB_INTR_ENABLE |= (1 << USB_INTR_ENABLE_BIT); | ||||||
|  |     usbResetDataToggling(); | ||||||
|  | #if USB_CFG_HAVE_INTRIN_ENDPOINT && !USB_CFG_SUPPRESS_INTR_CODE | ||||||
|  |     usbTxLen1 = USBPID_NAK; | ||||||
|  | #if USB_CFG_HAVE_INTRIN_ENDPOINT3 | ||||||
|  |     usbTxLen3 = USBPID_NAK; | ||||||
|  | #endif | ||||||
|  | #endif | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /* ------------------------------------------------------------------------- */ | ||||||
							
								
								
									
										746
									
								
								keyboards/planck/thk/bootloader/usbdrv/usbdrv.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										746
									
								
								keyboards/planck/thk/bootloader/usbdrv/usbdrv.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,746 @@ | |||||||
|  | /* Name: usbdrv.h
 | ||||||
|  |  * Project: V-USB, virtual USB port for Atmel's(r) AVR(r) microcontrollers | ||||||
|  |  * Author: Christian Starkjohann | ||||||
|  |  * Creation Date: 2004-12-29 | ||||||
|  |  * Tabsize: 4 | ||||||
|  |  * Copyright: (c) 2005 by OBJECTIVE DEVELOPMENT Software GmbH | ||||||
|  |  * License: GNU GPL v2 (see License.txt), GNU GPL v3 or proprietary (CommercialLicense.txt) | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | #ifndef __usbdrv_h_included__ | ||||||
|  | #define __usbdrv_h_included__ | ||||||
|  | #include "usbconfig.h" | ||||||
|  | #include "usbportability.h" | ||||||
|  | 
 | ||||||
|  | /*
 | ||||||
|  | Hardware Prerequisites: | ||||||
|  | ======================= | ||||||
|  | USB lines D+ and D- MUST be wired to the same I/O port. We recommend that D+ | ||||||
|  | triggers the interrupt (best achieved by using INT0 for D+), but it is also | ||||||
|  | possible to trigger the interrupt from D-. If D- is used, interrupts are also | ||||||
|  | triggered by SOF packets. D- requires a pull-up of 1.5k to +3.5V (and the | ||||||
|  | device must be powered at 3.5V) to identify as low-speed USB device. A | ||||||
|  | pull-down or pull-up of 1M SHOULD be connected from D+ to +3.5V to prevent | ||||||
|  | interference when no USB master is connected. If you use Zener diodes to limit | ||||||
|  | the voltage on D+ and D-, you MUST use a pull-down resistor, not a pull-up. | ||||||
|  | We use D+ as interrupt source and not D- because it does not trigger on | ||||||
|  | keep-alive and RESET states. If you want to count keep-alive events with | ||||||
|  | USB_COUNT_SOF, you MUST use D- as an interrupt source. | ||||||
|  | 
 | ||||||
|  | As a compile time option, the 1.5k pull-up resistor on D- can be made | ||||||
|  | switchable to allow the device to disconnect at will. See the definition of | ||||||
|  | usbDeviceConnect() and usbDeviceDisconnect() further down in this file. | ||||||
|  | 
 | ||||||
|  | Please adapt the values in usbconfig.h according to your hardware! | ||||||
|  | 
 | ||||||
|  | The device MUST be clocked at exactly 12 MHz, 15 MHz, 16 MHz or 20 MHz | ||||||
|  | or at 12.8 MHz resp. 16.5 MHz +/- 1%. See usbconfig-prototype.h for details. | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | Limitations: | ||||||
|  | ============ | ||||||
|  | Robustness with respect to communication errors: | ||||||
|  | The driver assumes error-free communication. It DOES check for errors in | ||||||
|  | the PID, but does NOT check bit stuffing errors, SE0 in middle of a byte, | ||||||
|  | token CRC (5 bit) and data CRC (16 bit). CRC checks can not be performed due | ||||||
|  | to timing constraints: We must start sending a reply within 7 bit times. | ||||||
|  | Bit stuffing and misplaced SE0 would have to be checked in real-time, but CPU | ||||||
|  | performance does not permit that. The driver does not check Data0/Data1 | ||||||
|  | toggling, but application software can implement the check. | ||||||
|  | 
 | ||||||
|  | Input characteristics: | ||||||
|  | Since no differential receiver circuit is used, electrical interference | ||||||
|  | robustness may suffer. The driver samples only one of the data lines with | ||||||
|  | an ordinary I/O pin's input characteristics. However, since this is only a | ||||||
|  | low speed USB implementation and the specification allows for 8 times the | ||||||
|  | bit rate over the same hardware, we should be on the safe side. Even the spec | ||||||
|  | requires detection of asymmetric states at high bit rate for SE0 detection. | ||||||
|  | 
 | ||||||
|  | Number of endpoints: | ||||||
|  | The driver supports the following endpoints: | ||||||
|  | 
 | ||||||
|  | - Endpoint 0, the default control endpoint. | ||||||
|  | - Any number of interrupt- or bulk-out endpoints. The data is sent to | ||||||
|  |   usbFunctionWriteOut() and USB_CFG_IMPLEMENT_FN_WRITEOUT must be defined | ||||||
|  |   to 1 to activate this feature. The endpoint number can be found in the | ||||||
|  |   global variable 'usbRxToken'. | ||||||
|  | - One default interrupt- or bulk-in endpoint. This endpoint is used for | ||||||
|  |   interrupt- or bulk-in transfers which are not handled by any other endpoint. | ||||||
|  |   You must define USB_CFG_HAVE_INTRIN_ENDPOINT in order to activate this | ||||||
|  |   feature and call usbSetInterrupt() to send interrupt/bulk data. | ||||||
|  | - One additional interrupt- or bulk-in endpoint. This was endpoint 3 in | ||||||
|  |   previous versions of this driver but can now be configured to any endpoint | ||||||
|  |   number. You must define USB_CFG_HAVE_INTRIN_ENDPOINT3 in order to activate | ||||||
|  |   this feature and call usbSetInterrupt3() to send interrupt/bulk data. The | ||||||
|  |   endpoint number can be set with USB_CFG_EP3_NUMBER. | ||||||
|  | 
 | ||||||
|  | Please note that the USB standard forbids bulk endpoints for low speed devices! | ||||||
|  | Most operating systems allow them anyway, but the AVR will spend 90% of the CPU | ||||||
|  | time in the USB interrupt polling for bulk data. | ||||||
|  | 
 | ||||||
|  | Maximum data payload: | ||||||
|  | Data payload of control in and out transfers may be up to 254 bytes. In order | ||||||
|  | to accept payload data of out transfers, you need to implement | ||||||
|  | 'usbFunctionWrite()'. | ||||||
|  | 
 | ||||||
|  | USB Suspend Mode supply current: | ||||||
|  | The USB standard limits power consumption to 500uA when the bus is in suspend | ||||||
|  | mode. This is not a problem for self-powered devices since they don't need | ||||||
|  | bus power anyway. Bus-powered devices can achieve this only by putting the | ||||||
|  | CPU in sleep mode. The driver does not implement suspend handling by itself. | ||||||
|  | However, the application may implement activity monitoring and wakeup from | ||||||
|  | sleep. The host sends regular SE0 states on the bus to keep it active. These | ||||||
|  | SE0 states can be detected by using D- as the interrupt source. Define | ||||||
|  | USB_COUNT_SOF to 1 and use the global variable usbSofCount to check for bus | ||||||
|  | activity. | ||||||
|  | 
 | ||||||
|  | Operation without an USB master: | ||||||
|  | The driver behaves neutral without connection to an USB master if D- reads | ||||||
|  | as 1. To avoid spurious interrupts, we recommend a high impedance (e.g. 1M) | ||||||
|  | pull-down or pull-up resistor on D+ (interrupt). If Zener diodes are used, | ||||||
|  | use a pull-down. If D- becomes statically 0, the driver may block in the | ||||||
|  | interrupt routine. | ||||||
|  | 
 | ||||||
|  | Interrupt latency: | ||||||
|  | The application must ensure that the USB interrupt is not disabled for more | ||||||
|  | than 25 cycles (this is for 12 MHz, faster clocks allow longer latency). | ||||||
|  | This implies that all interrupt routines must either have the "ISR_NOBLOCK" | ||||||
|  | attribute set (see "avr/interrupt.h") or be written in assembler with "sei" | ||||||
|  | as the first instruction. | ||||||
|  | 
 | ||||||
|  | Maximum interrupt duration / CPU cycle consumption: | ||||||
|  | The driver handles all USB communication during the interrupt service | ||||||
|  | routine. The routine will not return before an entire USB message is received | ||||||
|  | and the reply is sent. This may be up to ca. 1200 cycles @ 12 MHz (= 100us) if | ||||||
|  | the host conforms to the standard. The driver will consume CPU cycles for all | ||||||
|  | USB messages, even if they address another (low-speed) device on the same bus. | ||||||
|  | 
 | ||||||
|  | */ | ||||||
|  | 
 | ||||||
|  | /* ------------------------------------------------------------------------- */ | ||||||
|  | /* --------------------------- Module Interface ---------------------------- */ | ||||||
|  | /* ------------------------------------------------------------------------- */ | ||||||
|  | 
 | ||||||
|  | #define USBDRV_VERSION  20121206 | ||||||
|  | /* This define uniquely identifies a driver version. It is a decimal number
 | ||||||
|  |  * constructed from the driver's release date in the form YYYYMMDD. If the | ||||||
|  |  * driver's behavior or interface changes, you can use this constant to | ||||||
|  |  * distinguish versions. If it is not defined, the driver's release date is | ||||||
|  |  * older than 2006-01-25. | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | #ifndef USB_PUBLIC | ||||||
|  | #define USB_PUBLIC | ||||||
|  | #endif | ||||||
|  | /* USB_PUBLIC is used as declaration attribute for all functions exported by
 | ||||||
|  |  * the USB driver. The default is no attribute (see above). You may define it | ||||||
|  |  * to static either in usbconfig.h or from the command line if you include | ||||||
|  |  * usbdrv.c instead of linking against it. Including the C module of the driver | ||||||
|  |  * directly in your code saves a couple of bytes in flash memory. | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | #ifndef __ASSEMBLER__ | ||||||
|  | #ifndef uchar | ||||||
|  | #define uchar   unsigned char | ||||||
|  | #endif | ||||||
|  | #ifndef schar | ||||||
|  | #define schar   signed char | ||||||
|  | #endif | ||||||
|  | /* shortcuts for well defined 8 bit integer types */ | ||||||
|  | 
 | ||||||
|  | #if USB_CFG_LONG_TRANSFERS  /* if more than 254 bytes transfer size required */ | ||||||
|  | #   define usbMsgLen_t unsigned | ||||||
|  | #else | ||||||
|  | #   define usbMsgLen_t uchar | ||||||
|  | #endif | ||||||
|  | /* usbMsgLen_t is the data type used for transfer lengths. By default, it is
 | ||||||
|  |  * defined to uchar, allowing a maximum of 254 bytes (255 is reserved for | ||||||
|  |  * USB_NO_MSG below). If the usbconfig.h defines USB_CFG_LONG_TRANSFERS to 1, | ||||||
|  |  * a 16 bit data type is used, allowing up to 16384 bytes (the rest is used | ||||||
|  |  * for flags in the descriptor configuration). | ||||||
|  |  */ | ||||||
|  | #define USB_NO_MSG  ((usbMsgLen_t)-1)   /* constant meaning "no message" */ | ||||||
|  | 
 | ||||||
|  | #ifndef usbMsgPtr_t | ||||||
|  | #define usbMsgPtr_t uchar * | ||||||
|  | #endif | ||||||
|  | /* Making usbMsgPtr_t a define allows the user of this library to define it to
 | ||||||
|  |  * an 8 bit type on tiny devices. This reduces code size, especially if the | ||||||
|  |  * compiler supports a tiny memory model. | ||||||
|  |  * The type can be a pointer or scalar type, casts are made where necessary. | ||||||
|  |  * Although it's paradoxical, Gcc 4 generates slightly better code for scalar | ||||||
|  |  * types than for pointers. | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | struct usbRequest;  /* forward declaration */ | ||||||
|  | 
 | ||||||
|  | USB_PUBLIC void usbInit(void); | ||||||
|  | /* This function must be called before interrupts are enabled and the main
 | ||||||
|  |  * loop is entered. We exepct that the PORT and DDR bits for D+ and D- have | ||||||
|  |  * not been changed from their default status (which is 0). If you have changed | ||||||
|  |  * them, set both back to 0 (configure them as input with no internal pull-up). | ||||||
|  |  */ | ||||||
|  | USB_PUBLIC void usbPoll(void); | ||||||
|  | /* This function must be called at regular intervals from the main loop.
 | ||||||
|  |  * Maximum delay between calls is somewhat less than 50ms (USB timeout for | ||||||
|  |  * accepting a Setup message). Otherwise the device will not be recognized. | ||||||
|  |  * Please note that debug outputs through the UART take ~ 0.5ms per byte | ||||||
|  |  * at 19200 bps. | ||||||
|  |  */ | ||||||
|  | extern usbMsgPtr_t usbMsgPtr; | ||||||
|  | /* This variable may be used to pass transmit data to the driver from the
 | ||||||
|  |  * implementation of usbFunctionWrite(). It is also used internally by the | ||||||
|  |  * driver for standard control requests. | ||||||
|  |  */ | ||||||
|  | USB_PUBLIC usbMsgLen_t usbFunctionSetup(uchar data[8]); | ||||||
|  | /* This function is called when the driver receives a SETUP transaction from
 | ||||||
|  |  * the host which is not answered by the driver itself (in practice: class and | ||||||
|  |  * vendor requests). All control transfers start with a SETUP transaction where | ||||||
|  |  * the host communicates the parameters of the following (optional) data | ||||||
|  |  * transfer. The SETUP data is available in the 'data' parameter which can | ||||||
|  |  * (and should) be casted to 'usbRequest_t *' for a more user-friendly access | ||||||
|  |  * to parameters. | ||||||
|  |  * | ||||||
|  |  * If the SETUP indicates a control-in transfer, you should provide the | ||||||
|  |  * requested data to the driver. There are two ways to transfer this data: | ||||||
|  |  * (1) Set the global pointer 'usbMsgPtr' to the base of the static RAM data | ||||||
|  |  * block and return the length of the data in 'usbFunctionSetup()'. The driver | ||||||
|  |  * will handle the rest. Or (2) return USB_NO_MSG in 'usbFunctionSetup()'. The | ||||||
|  |  * driver will then call 'usbFunctionRead()' when data is needed. See the | ||||||
|  |  * documentation for usbFunctionRead() for details. | ||||||
|  |  * | ||||||
|  |  * If the SETUP indicates a control-out transfer, the only way to receive the | ||||||
|  |  * data from the host is through the 'usbFunctionWrite()' call. If you | ||||||
|  |  * implement this function, you must return USB_NO_MSG in 'usbFunctionSetup()' | ||||||
|  |  * to indicate that 'usbFunctionWrite()' should be used. See the documentation | ||||||
|  |  * of this function for more information. If you just want to ignore the data | ||||||
|  |  * sent by the host, return 0 in 'usbFunctionSetup()'. | ||||||
|  |  * | ||||||
|  |  * Note that calls to the functions usbFunctionRead() and usbFunctionWrite() | ||||||
|  |  * are only done if enabled by the configuration in usbconfig.h. | ||||||
|  |  */ | ||||||
|  | USB_PUBLIC usbMsgLen_t usbFunctionDescriptor(struct usbRequest *rq); | ||||||
|  | /* You need to implement this function ONLY if you provide USB descriptors at
 | ||||||
|  |  * runtime (which is an expert feature). It is very similar to | ||||||
|  |  * usbFunctionSetup() above, but it is called only to request USB descriptor | ||||||
|  |  * data. See the documentation of usbFunctionSetup() above for more info. | ||||||
|  |  */ | ||||||
|  | #if USB_CFG_HAVE_INTRIN_ENDPOINT | ||||||
|  | USB_PUBLIC void usbSetInterrupt(uchar *data, uchar len); | ||||||
|  | /* This function sets the message which will be sent during the next interrupt
 | ||||||
|  |  * IN transfer. The message is copied to an internal buffer and must not exceed | ||||||
|  |  * a length of 8 bytes. The message may be 0 bytes long just to indicate the | ||||||
|  |  * interrupt status to the host. | ||||||
|  |  * If you need to transfer more bytes, use a control read after the interrupt. | ||||||
|  |  */ | ||||||
|  | #define usbInterruptIsReady()   (usbTxLen1 & 0x10) | ||||||
|  | /* This macro indicates whether the last interrupt message has already been
 | ||||||
|  |  * sent. If you set a new interrupt message before the old was sent, the | ||||||
|  |  * message already buffered will be lost. | ||||||
|  |  */ | ||||||
|  | #if USB_CFG_HAVE_INTRIN_ENDPOINT3 | ||||||
|  | USB_PUBLIC void usbSetInterrupt3(uchar *data, uchar len); | ||||||
|  | #define usbInterruptIsReady3()   (usbTxLen3 & 0x10) | ||||||
|  | /* Same as above for endpoint 3 */ | ||||||
|  | #endif | ||||||
|  | #endif /* USB_CFG_HAVE_INTRIN_ENDPOINT */ | ||||||
|  | #if USB_CFG_HID_REPORT_DESCRIPTOR_LENGTH    /* simplified interface for backward compatibility */ | ||||||
|  | #define usbHidReportDescriptor  usbDescriptorHidReport | ||||||
|  | /* should be declared as: PROGMEM char usbHidReportDescriptor[]; */ | ||||||
|  | /* If you implement an HID device, you need to provide a report descriptor.
 | ||||||
|  |  * The HID report descriptor syntax is a bit complex. If you understand how | ||||||
|  |  * report descriptors are constructed, we recommend that you use the HID | ||||||
|  |  * Descriptor Tool from usb.org, see http://www.usb.org/developers/hidpage/.
 | ||||||
|  |  * Otherwise you should probably start with a working example. | ||||||
|  |  */ | ||||||
|  | #endif  /* USB_CFG_HID_REPORT_DESCRIPTOR_LENGTH */ | ||||||
|  | #if USB_CFG_IMPLEMENT_FN_WRITE | ||||||
|  | USB_PUBLIC uchar usbFunctionWrite(uchar *data, uchar len); | ||||||
|  | /* This function is called by the driver to provide a control transfer's
 | ||||||
|  |  * payload data (control-out). It is called in chunks of up to 8 bytes. The | ||||||
|  |  * total count provided in the current control transfer can be obtained from | ||||||
|  |  * the 'length' property in the setup data. If an error occurred during | ||||||
|  |  * processing, return 0xff (== -1). The driver will answer the entire transfer | ||||||
|  |  * with a STALL token in this case. If you have received the entire payload | ||||||
|  |  * successfully, return 1. If you expect more data, return 0. If you don't | ||||||
|  |  * know whether the host will send more data (you should know, the total is | ||||||
|  |  * provided in the usbFunctionSetup() call!), return 1. | ||||||
|  |  * NOTE: If you return 0xff for STALL, 'usbFunctionWrite()' may still be called | ||||||
|  |  * for the remaining data. You must continue to return 0xff for STALL in these | ||||||
|  |  * calls. | ||||||
|  |  * In order to get usbFunctionWrite() called, define USB_CFG_IMPLEMENT_FN_WRITE | ||||||
|  |  * to 1 in usbconfig.h and return 0xff in usbFunctionSetup().. | ||||||
|  |  */ | ||||||
|  | #endif /* USB_CFG_IMPLEMENT_FN_WRITE */ | ||||||
|  | #if USB_CFG_IMPLEMENT_FN_READ | ||||||
|  | USB_PUBLIC uchar usbFunctionRead(uchar *data, uchar len); | ||||||
|  | /* This function is called by the driver to ask the application for a control
 | ||||||
|  |  * transfer's payload data (control-in). It is called in chunks of up to 8 | ||||||
|  |  * bytes each. You should copy the data to the location given by 'data' and | ||||||
|  |  * return the actual number of bytes copied. If you return less than requested, | ||||||
|  |  * the control-in transfer is terminated. If you return 0xff, the driver aborts | ||||||
|  |  * the transfer with a STALL token. | ||||||
|  |  * In order to get usbFunctionRead() called, define USB_CFG_IMPLEMENT_FN_READ | ||||||
|  |  * to 1 in usbconfig.h and return 0xff in usbFunctionSetup().. | ||||||
|  |  */ | ||||||
|  | #endif /* USB_CFG_IMPLEMENT_FN_READ */ | ||||||
|  | 
 | ||||||
|  | extern uchar usbRxToken;    /* may be used in usbFunctionWriteOut() below */ | ||||||
|  | #if USB_CFG_IMPLEMENT_FN_WRITEOUT | ||||||
|  | USB_PUBLIC void usbFunctionWriteOut(uchar *data, uchar len); | ||||||
|  | /* This function is called by the driver when data is received on an interrupt-
 | ||||||
|  |  * or bulk-out endpoint. The endpoint number can be found in the global | ||||||
|  |  * variable usbRxToken. You must define USB_CFG_IMPLEMENT_FN_WRITEOUT to 1 in | ||||||
|  |  * usbconfig.h to get this function called. | ||||||
|  |  */ | ||||||
|  | #endif /* USB_CFG_IMPLEMENT_FN_WRITEOUT */ | ||||||
|  | #ifdef USB_CFG_PULLUP_IOPORTNAME | ||||||
|  | #define usbDeviceConnect()      ((USB_PULLUP_DDR |= (1<<USB_CFG_PULLUP_BIT)), \ | ||||||
|  |                                   (USB_PULLUP_OUT |= (1<<USB_CFG_PULLUP_BIT))) | ||||||
|  | #define usbDeviceDisconnect()   ((USB_PULLUP_DDR &= ~(1<<USB_CFG_PULLUP_BIT)), \ | ||||||
|  |                                   (USB_PULLUP_OUT &= ~(1<<USB_CFG_PULLUP_BIT))) | ||||||
|  | #else /* USB_CFG_PULLUP_IOPORTNAME */ | ||||||
|  | #define usbDeviceConnect()      (USBDDR &= ~(1<<USBMINUS)) | ||||||
|  | #define usbDeviceDisconnect()   (USBDDR |= (1<<USBMINUS)) | ||||||
|  | #endif /* USB_CFG_PULLUP_IOPORTNAME */ | ||||||
|  | /* The macros usbDeviceConnect() and usbDeviceDisconnect() (intended to look
 | ||||||
|  |  * like a function) connect resp. disconnect the device from the host's USB. | ||||||
|  |  * If the constants USB_CFG_PULLUP_IOPORT and USB_CFG_PULLUP_BIT are defined | ||||||
|  |  * in usbconfig.h, a disconnect consists of removing the pull-up resisitor | ||||||
|  |  * from D-, otherwise the disconnect is done by brute-force pulling D- to GND. | ||||||
|  |  * This does not conform to the spec, but it works. | ||||||
|  |  * Please note that the USB interrupt must be disabled while the device is | ||||||
|  |  * in disconnected state, or the interrupt handler will hang! You can either | ||||||
|  |  * turn off the USB interrupt selectively with | ||||||
|  |  *     USB_INTR_ENABLE &= ~(1 << USB_INTR_ENABLE_BIT) | ||||||
|  |  * or use cli() to disable interrupts globally. | ||||||
|  |  */ | ||||||
|  | extern unsigned usbCrc16(unsigned data, uchar len); | ||||||
|  | #define usbCrc16(data, len) usbCrc16((unsigned)(data), len) | ||||||
|  | /* This function calculates the binary complement of the data CRC used in
 | ||||||
|  |  * USB data packets. The value is used to build raw transmit packets. | ||||||
|  |  * You may want to use this function for data checksums or to verify received | ||||||
|  |  * data. We enforce 16 bit calling conventions for compatibility with IAR's | ||||||
|  |  * tiny memory model. | ||||||
|  |  */ | ||||||
|  | extern unsigned usbCrc16Append(unsigned data, uchar len); | ||||||
|  | #define usbCrc16Append(data, len)    usbCrc16Append((unsigned)(data), len) | ||||||
|  | /* This function is equivalent to usbCrc16() above, except that it appends
 | ||||||
|  |  * the 2 bytes CRC (lowbyte first) in the 'data' buffer after reading 'len' | ||||||
|  |  * bytes. | ||||||
|  |  */ | ||||||
|  | #if USB_CFG_HAVE_MEASURE_FRAME_LENGTH | ||||||
|  | extern unsigned usbMeasureFrameLength(void); | ||||||
|  | /* This function MUST be called IMMEDIATELY AFTER USB reset and measures 1/7 of
 | ||||||
|  |  * the number of CPU cycles during one USB frame minus one low speed bit | ||||||
|  |  * length. In other words: return value = 1499 * (F_CPU / 10.5 MHz) | ||||||
|  |  * Since this is a busy wait, you MUST disable all interrupts with cli() before | ||||||
|  |  * calling this function. | ||||||
|  |  * This can be used to calibrate the AVR's RC oscillator. | ||||||
|  |  */ | ||||||
|  | #endif | ||||||
|  | extern uchar    usbConfiguration; | ||||||
|  | /* This value contains the current configuration set by the host. The driver
 | ||||||
|  |  * allows setting and querying of this variable with the USB SET_CONFIGURATION | ||||||
|  |  * and GET_CONFIGURATION requests, but does not use it otherwise. | ||||||
|  |  * You may want to reflect the "configured" status with a LED on the device or | ||||||
|  |  * switch on high power parts of the circuit only if the device is configured. | ||||||
|  |  */ | ||||||
|  | #if USB_COUNT_SOF | ||||||
|  | extern volatile uchar   usbSofCount; | ||||||
|  | /* This variable is incremented on every SOF packet. It is only available if
 | ||||||
|  |  * the macro USB_COUNT_SOF is defined to a value != 0. | ||||||
|  |  */ | ||||||
|  | #endif | ||||||
|  | #if USB_CFG_CHECK_DATA_TOGGLING | ||||||
|  | extern uchar    usbCurrentDataToken; | ||||||
|  | /* This variable can be checked in usbFunctionWrite() and usbFunctionWriteOut()
 | ||||||
|  |  * to ignore duplicate packets. | ||||||
|  |  */ | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
|  | #define USB_STRING_DESCRIPTOR_HEADER(stringLength) ((2*(stringLength)+2) | (3<<8)) | ||||||
|  | /* This macro builds a descriptor header for a string descriptor given the
 | ||||||
|  |  * string's length. See usbdrv.c for an example how to use it. | ||||||
|  |  */ | ||||||
|  | #if USB_CFG_HAVE_FLOWCONTROL | ||||||
|  | extern volatile schar   usbRxLen; | ||||||
|  | #define usbDisableAllRequests()     usbRxLen = -1 | ||||||
|  | /* Must be called from usbFunctionWrite(). This macro disables all data input
 | ||||||
|  |  * from the USB interface. Requests from the host are answered with a NAK | ||||||
|  |  * while they are disabled. | ||||||
|  |  */ | ||||||
|  | #define usbEnableAllRequests()      usbRxLen = 0 | ||||||
|  | /* May only be called if requests are disabled. This macro enables input from
 | ||||||
|  |  * the USB interface after it has been disabled with usbDisableAllRequests(). | ||||||
|  |  */ | ||||||
|  | #define usbAllRequestsAreDisabled() (usbRxLen < 0) | ||||||
|  | /* Use this macro to find out whether requests are disabled. It may be needed
 | ||||||
|  |  * to ensure that usbEnableAllRequests() is never called when requests are | ||||||
|  |  * enabled. | ||||||
|  |  */ | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
|  | #define USB_SET_DATATOKEN1(token)   usbTxBuf1[0] = token | ||||||
|  | #define USB_SET_DATATOKEN3(token)   usbTxBuf3[0] = token | ||||||
|  | /* These two macros can be used by application software to reset data toggling
 | ||||||
|  |  * for interrupt-in endpoints 1 and 3. Since the token is toggled BEFORE | ||||||
|  |  * sending data, you must set the opposite value of the token which should come | ||||||
|  |  * first. | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | #endif  /* __ASSEMBLER__ */ | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | /* ------------------------------------------------------------------------- */ | ||||||
|  | /* ----------------- Definitions for Descriptor Properties ----------------- */ | ||||||
|  | /* ------------------------------------------------------------------------- */ | ||||||
|  | /* This is advanced stuff. See usbconfig-prototype.h for more information
 | ||||||
|  |  * about the various methods to define USB descriptors. If you do nothing, | ||||||
|  |  * the default descriptors will be used. | ||||||
|  |  */ | ||||||
|  | #define USB_PROP_IS_DYNAMIC     (1u << 14) | ||||||
|  | /* If this property is set for a descriptor, usbFunctionDescriptor() will be
 | ||||||
|  |  * used to obtain the particular descriptor. Data directly returned via | ||||||
|  |  * usbMsgPtr are FLASH data by default, combine (OR) with USB_PROP_IS_RAM to | ||||||
|  |  * return RAM data. | ||||||
|  |  */ | ||||||
|  | #define USB_PROP_IS_RAM         (1u << 15) | ||||||
|  | /* If this property is set for a descriptor, the data is read from RAM
 | ||||||
|  |  * memory instead of Flash. The property is used for all methods to provide | ||||||
|  |  * external descriptors. | ||||||
|  |  */ | ||||||
|  | #define USB_PROP_LENGTH(len)    ((len) & 0x3fff) | ||||||
|  | /* If a static external descriptor is used, this is the total length of the
 | ||||||
|  |  * descriptor in bytes. | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | /* all descriptors which may have properties: */ | ||||||
|  | #ifndef USB_CFG_DESCR_PROPS_DEVICE | ||||||
|  | #define USB_CFG_DESCR_PROPS_DEVICE                  0 | ||||||
|  | #endif | ||||||
|  | #ifndef USB_CFG_DESCR_PROPS_CONFIGURATION | ||||||
|  | #define USB_CFG_DESCR_PROPS_CONFIGURATION           0 | ||||||
|  | #endif | ||||||
|  | #ifndef USB_CFG_DESCR_PROPS_STRINGS | ||||||
|  | #define USB_CFG_DESCR_PROPS_STRINGS                 0 | ||||||
|  | #endif | ||||||
|  | #ifndef USB_CFG_DESCR_PROPS_STRING_0 | ||||||
|  | #define USB_CFG_DESCR_PROPS_STRING_0                0 | ||||||
|  | #endif | ||||||
|  | #ifndef USB_CFG_DESCR_PROPS_STRING_VENDOR | ||||||
|  | #define USB_CFG_DESCR_PROPS_STRING_VENDOR           0 | ||||||
|  | #endif | ||||||
|  | #ifndef USB_CFG_DESCR_PROPS_STRING_PRODUCT | ||||||
|  | #define USB_CFG_DESCR_PROPS_STRING_PRODUCT          0 | ||||||
|  | #endif | ||||||
|  | #ifndef USB_CFG_DESCR_PROPS_STRING_SERIAL_NUMBER | ||||||
|  | #define USB_CFG_DESCR_PROPS_STRING_SERIAL_NUMBER    0 | ||||||
|  | #endif | ||||||
|  | #ifndef USB_CFG_DESCR_PROPS_HID | ||||||
|  | #define USB_CFG_DESCR_PROPS_HID                     0 | ||||||
|  | #endif | ||||||
|  | #if !(USB_CFG_DESCR_PROPS_HID_REPORT) | ||||||
|  | #   undef USB_CFG_DESCR_PROPS_HID_REPORT | ||||||
|  | #   if USB_CFG_HID_REPORT_DESCRIPTOR_LENGTH /* do some backward compatibility tricks */ | ||||||
|  | #       define USB_CFG_DESCR_PROPS_HID_REPORT       USB_CFG_HID_REPORT_DESCRIPTOR_LENGTH | ||||||
|  | #   else | ||||||
|  | #       define USB_CFG_DESCR_PROPS_HID_REPORT       0 | ||||||
|  | #   endif | ||||||
|  | #endif | ||||||
|  | #ifndef USB_CFG_DESCR_PROPS_UNKNOWN | ||||||
|  | #define USB_CFG_DESCR_PROPS_UNKNOWN                 0 | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
|  | /* ------------------ forward declaration of descriptors ------------------- */ | ||||||
|  | /* If you use external static descriptors, they must be stored in global
 | ||||||
|  |  * arrays as declared below: | ||||||
|  |  */ | ||||||
|  | #ifndef __ASSEMBLER__ | ||||||
|  | extern | ||||||
|  | #if !(USB_CFG_DESCR_PROPS_DEVICE & USB_PROP_IS_RAM) | ||||||
|  | PROGMEM const | ||||||
|  | #endif | ||||||
|  | char usbDescriptorDevice[]; | ||||||
|  | 
 | ||||||
|  | extern | ||||||
|  | #if !(USB_CFG_DESCR_PROPS_CONFIGURATION & USB_PROP_IS_RAM) | ||||||
|  | PROGMEM const | ||||||
|  | #endif | ||||||
|  | char usbDescriptorConfiguration[]; | ||||||
|  | 
 | ||||||
|  | extern | ||||||
|  | #if !(USB_CFG_DESCR_PROPS_HID_REPORT & USB_PROP_IS_RAM) | ||||||
|  | PROGMEM const | ||||||
|  | #endif | ||||||
|  | char usbDescriptorHidReport[]; | ||||||
|  | 
 | ||||||
|  | extern | ||||||
|  | #if !(USB_CFG_DESCR_PROPS_STRING_0 & USB_PROP_IS_RAM) | ||||||
|  | PROGMEM const | ||||||
|  | #endif | ||||||
|  | char usbDescriptorString0[]; | ||||||
|  | 
 | ||||||
|  | extern | ||||||
|  | #if !(USB_CFG_DESCR_PROPS_STRING_VENDOR & USB_PROP_IS_RAM) | ||||||
|  | PROGMEM const | ||||||
|  | #endif | ||||||
|  | int usbDescriptorStringVendor[]; | ||||||
|  | 
 | ||||||
|  | extern | ||||||
|  | #if !(USB_CFG_DESCR_PROPS_STRING_PRODUCT & USB_PROP_IS_RAM) | ||||||
|  | PROGMEM const | ||||||
|  | #endif | ||||||
|  | int usbDescriptorStringDevice[]; | ||||||
|  | 
 | ||||||
|  | extern | ||||||
|  | #if !(USB_CFG_DESCR_PROPS_STRING_SERIAL_NUMBER & USB_PROP_IS_RAM) | ||||||
|  | PROGMEM const | ||||||
|  | #endif | ||||||
|  | int usbDescriptorStringSerialNumber[]; | ||||||
|  | 
 | ||||||
|  | #endif /* __ASSEMBLER__ */ | ||||||
|  | 
 | ||||||
|  | /* ------------------------------------------------------------------------- */ | ||||||
|  | /* ------------------------ General Purpose Macros ------------------------- */ | ||||||
|  | /* ------------------------------------------------------------------------- */ | ||||||
|  | 
 | ||||||
|  | #define USB_CONCAT(a, b)            a ## b | ||||||
|  | #define USB_CONCAT_EXPANDED(a, b)   USB_CONCAT(a, b) | ||||||
|  | 
 | ||||||
|  | #define USB_OUTPORT(name)           USB_CONCAT(PORT, name) | ||||||
|  | #define USB_INPORT(name)            USB_CONCAT(PIN, name) | ||||||
|  | #define USB_DDRPORT(name)           USB_CONCAT(DDR, name) | ||||||
|  | /* The double-define trick above lets us concatenate strings which are
 | ||||||
|  |  * defined by macros. | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | /* ------------------------------------------------------------------------- */ | ||||||
|  | /* ------------------------- Constant definitions -------------------------- */ | ||||||
|  | /* ------------------------------------------------------------------------- */ | ||||||
|  | 
 | ||||||
|  | #if !defined __ASSEMBLER__ && (!defined USB_CFG_VENDOR_ID || !defined USB_CFG_DEVICE_ID) | ||||||
|  | #warning "You should define USB_CFG_VENDOR_ID and USB_CFG_DEVICE_ID in usbconfig.h" | ||||||
|  | /* If the user has not defined IDs, we default to obdev's free IDs.
 | ||||||
|  |  * See USB-IDs-for-free.txt for details. | ||||||
|  |  */ | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
|  | /* make sure we have a VID and PID defined, byte order is lowbyte, highbyte */ | ||||||
|  | #ifndef USB_CFG_VENDOR_ID | ||||||
|  | #   define  USB_CFG_VENDOR_ID   0xc0, 0x16  /* = 0x16c0 = 5824 = voti.nl */ | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
|  | #ifndef USB_CFG_DEVICE_ID | ||||||
|  | #   if USB_CFG_HID_REPORT_DESCRIPTOR_LENGTH | ||||||
|  | #       define USB_CFG_DEVICE_ID    0xdf, 0x05  /* = 0x5df = 1503, shared PID for HIDs */ | ||||||
|  | #   elif USB_CFG_INTERFACE_CLASS == 2 | ||||||
|  | #       define USB_CFG_DEVICE_ID    0xe1, 0x05  /* = 0x5e1 = 1505, shared PID for CDC Modems */ | ||||||
|  | #   else | ||||||
|  | #       define USB_CFG_DEVICE_ID    0xdc, 0x05  /* = 0x5dc = 1500, obdev's free PID */ | ||||||
|  | #   endif | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
|  | /* Derive Output, Input and DataDirection ports from port names */ | ||||||
|  | #ifndef USB_CFG_IOPORTNAME | ||||||
|  | #error "You must define USB_CFG_IOPORTNAME in usbconfig.h, see usbconfig-prototype.h" | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
|  | #define USBOUT          USB_OUTPORT(USB_CFG_IOPORTNAME) | ||||||
|  | #define USB_PULLUP_OUT  USB_OUTPORT(USB_CFG_PULLUP_IOPORTNAME) | ||||||
|  | #define USBIN           USB_INPORT(USB_CFG_IOPORTNAME) | ||||||
|  | #define USBDDR          USB_DDRPORT(USB_CFG_IOPORTNAME) | ||||||
|  | #define USB_PULLUP_DDR  USB_DDRPORT(USB_CFG_PULLUP_IOPORTNAME) | ||||||
|  | 
 | ||||||
|  | #define USBMINUS    USB_CFG_DMINUS_BIT | ||||||
|  | #define USBPLUS     USB_CFG_DPLUS_BIT | ||||||
|  | #define USBIDLE     (1<<USB_CFG_DMINUS_BIT) /* value representing J state */ | ||||||
|  | #define USBMASK     ((1<<USB_CFG_DPLUS_BIT) | (1<<USB_CFG_DMINUS_BIT))  /* mask for USB I/O bits */ | ||||||
|  | 
 | ||||||
|  | /* defines for backward compatibility with older driver versions: */ | ||||||
|  | #define USB_CFG_IOPORT          USB_OUTPORT(USB_CFG_IOPORTNAME) | ||||||
|  | #ifdef USB_CFG_PULLUP_IOPORTNAME | ||||||
|  | #define USB_CFG_PULLUP_IOPORT   USB_OUTPORT(USB_CFG_PULLUP_IOPORTNAME) | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
|  | #ifndef USB_CFG_EP3_NUMBER  /* if not defined in usbconfig.h */ | ||||||
|  | #define USB_CFG_EP3_NUMBER  3 | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
|  | #ifndef USB_CFG_HAVE_INTRIN_ENDPOINT3 | ||||||
|  | #define USB_CFG_HAVE_INTRIN_ENDPOINT3   0 | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
|  | #define USB_BUFSIZE     11  /* PID, 8 bytes data, 2 bytes CRC */ | ||||||
|  | 
 | ||||||
|  | /* ----- Try to find registers and bits responsible for ext interrupt 0 ----- */ | ||||||
|  | 
 | ||||||
|  | #ifndef USB_INTR_CFG    /* allow user to override our default */ | ||||||
|  | #   if defined  EICRA | ||||||
|  | #       define USB_INTR_CFG EICRA | ||||||
|  | #   else | ||||||
|  | #       define USB_INTR_CFG MCUCR | ||||||
|  | #   endif | ||||||
|  | #endif | ||||||
|  | #ifndef USB_INTR_CFG_SET    /* allow user to override our default */ | ||||||
|  | #   if defined(USB_COUNT_SOF) || defined(USB_SOF_HOOK) | ||||||
|  | #       define USB_INTR_CFG_SET (1 << ISC01)                    /* cfg for falling edge */ | ||||||
|  |         /* If any SOF logic is used, the interrupt must be wired to D- where
 | ||||||
|  |          * we better trigger on falling edge | ||||||
|  |          */ | ||||||
|  | #   else | ||||||
|  | #       define USB_INTR_CFG_SET ((1 << ISC00) | (1 << ISC01))   /* cfg for rising edge */ | ||||||
|  | #   endif | ||||||
|  | #endif | ||||||
|  | #ifndef USB_INTR_CFG_CLR    /* allow user to override our default */ | ||||||
|  | #   define USB_INTR_CFG_CLR 0    /* no bits to clear */ | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
|  | #ifndef USB_INTR_ENABLE     /* allow user to override our default */ | ||||||
|  | #   if defined GIMSK | ||||||
|  | #       define USB_INTR_ENABLE  GIMSK | ||||||
|  | #   elif defined EIMSK | ||||||
|  | #       define USB_INTR_ENABLE  EIMSK | ||||||
|  | #   else | ||||||
|  | #       define USB_INTR_ENABLE  GICR | ||||||
|  | #   endif | ||||||
|  | #endif | ||||||
|  | #ifndef USB_INTR_ENABLE_BIT /* allow user to override our default */ | ||||||
|  | #   define USB_INTR_ENABLE_BIT  INT0 | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
|  | #ifndef USB_INTR_PENDING    /* allow user to override our default */ | ||||||
|  | #   if defined  EIFR | ||||||
|  | #       define USB_INTR_PENDING EIFR | ||||||
|  | #   else | ||||||
|  | #       define USB_INTR_PENDING GIFR | ||||||
|  | #   endif | ||||||
|  | #endif | ||||||
|  | #ifndef USB_INTR_PENDING_BIT    /* allow user to override our default */ | ||||||
|  | #   define USB_INTR_PENDING_BIT INTF0 | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
|  | /*
 | ||||||
|  | The defines above don't work for the following chips | ||||||
|  | at90c8534: no ISC0?, no PORTB, can't find a data sheet | ||||||
|  | at86rf401: no PORTB, no MCUCR etc, low clock rate | ||||||
|  | atmega103: no ISC0? (maybe omission in header, can't find data sheet) | ||||||
|  | atmega603: not defined in avr-libc | ||||||
|  | at43usb320, at43usb355, at76c711: have USB anyway | ||||||
|  | at94k: is different... | ||||||
|  | 
 | ||||||
|  | at90s1200, attiny11, attiny12, attiny15, attiny28: these have no RAM | ||||||
|  | */ | ||||||
|  | 
 | ||||||
|  | /* ------------------------------------------------------------------------- */ | ||||||
|  | /* ----------------- USB Specification Constants and Types ----------------- */ | ||||||
|  | /* ------------------------------------------------------------------------- */ | ||||||
|  | 
 | ||||||
|  | /* USB Token values */ | ||||||
|  | #define USBPID_SETUP    0x2d | ||||||
|  | #define USBPID_OUT      0xe1 | ||||||
|  | #define USBPID_IN       0x69 | ||||||
|  | #define USBPID_DATA0    0xc3 | ||||||
|  | #define USBPID_DATA1    0x4b | ||||||
|  | 
 | ||||||
|  | #define USBPID_ACK      0xd2 | ||||||
|  | #define USBPID_NAK      0x5a | ||||||
|  | #define USBPID_STALL    0x1e | ||||||
|  | 
 | ||||||
|  | #ifndef USB_INITIAL_DATATOKEN | ||||||
|  | #define USB_INITIAL_DATATOKEN   USBPID_DATA1 | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
|  | #ifndef __ASSEMBLER__ | ||||||
|  | 
 | ||||||
|  | typedef struct usbTxStatus{ | ||||||
|  |     volatile uchar   len; | ||||||
|  |     uchar   buffer[USB_BUFSIZE]; | ||||||
|  | }usbTxStatus_t; | ||||||
|  | 
 | ||||||
|  | extern usbTxStatus_t   usbTxStatus1, usbTxStatus3; | ||||||
|  | #define usbTxLen1   usbTxStatus1.len | ||||||
|  | #define usbTxBuf1   usbTxStatus1.buffer | ||||||
|  | #define usbTxLen3   usbTxStatus3.len | ||||||
|  | #define usbTxBuf3   usbTxStatus3.buffer | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | typedef union usbWord{ | ||||||
|  |     unsigned    word; | ||||||
|  |     uchar       bytes[2]; | ||||||
|  | }usbWord_t; | ||||||
|  | 
 | ||||||
|  | typedef struct usbRequest{ | ||||||
|  |     uchar       bmRequestType; | ||||||
|  |     uchar       bRequest; | ||||||
|  |     usbWord_t   wValue; | ||||||
|  |     usbWord_t   wIndex; | ||||||
|  |     usbWord_t   wLength; | ||||||
|  | }usbRequest_t; | ||||||
|  | /* This structure matches the 8 byte setup request */ | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
|  | /* bmRequestType field in USB setup:
 | ||||||
|  |  * d t t r r r r r, where | ||||||
|  |  * d ..... direction: 0=host->device, 1=device->host | ||||||
|  |  * t ..... type: 0=standard, 1=class, 2=vendor, 3=reserved | ||||||
|  |  * r ..... recipient: 0=device, 1=interface, 2=endpoint, 3=other | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | /* USB setup recipient values */ | ||||||
|  | #define USBRQ_RCPT_MASK         0x1f | ||||||
|  | #define USBRQ_RCPT_DEVICE       0 | ||||||
|  | #define USBRQ_RCPT_INTERFACE    1 | ||||||
|  | #define USBRQ_RCPT_ENDPOINT     2 | ||||||
|  | 
 | ||||||
|  | /* USB request type values */ | ||||||
|  | #define USBRQ_TYPE_MASK         0x60 | ||||||
|  | #define USBRQ_TYPE_STANDARD     (0<<5) | ||||||
|  | #define USBRQ_TYPE_CLASS        (1<<5) | ||||||
|  | #define USBRQ_TYPE_VENDOR       (2<<5) | ||||||
|  | 
 | ||||||
|  | /* USB direction values: */ | ||||||
|  | #define USBRQ_DIR_MASK              0x80 | ||||||
|  | #define USBRQ_DIR_HOST_TO_DEVICE    (0<<7) | ||||||
|  | #define USBRQ_DIR_DEVICE_TO_HOST    (1<<7) | ||||||
|  | 
 | ||||||
|  | /* USB Standard Requests */ | ||||||
|  | #define USBRQ_GET_STATUS        0 | ||||||
|  | #define USBRQ_CLEAR_FEATURE     1 | ||||||
|  | #define USBRQ_SET_FEATURE       3 | ||||||
|  | #define USBRQ_SET_ADDRESS       5 | ||||||
|  | #define USBRQ_GET_DESCRIPTOR    6 | ||||||
|  | #define USBRQ_SET_DESCRIPTOR    7 | ||||||
|  | #define USBRQ_GET_CONFIGURATION 8 | ||||||
|  | #define USBRQ_SET_CONFIGURATION 9 | ||||||
|  | #define USBRQ_GET_INTERFACE     10 | ||||||
|  | #define USBRQ_SET_INTERFACE     11 | ||||||
|  | #define USBRQ_SYNCH_FRAME       12 | ||||||
|  | 
 | ||||||
|  | /* USB descriptor constants */ | ||||||
|  | #define USBDESCR_DEVICE         1 | ||||||
|  | #define USBDESCR_CONFIG         2 | ||||||
|  | #define USBDESCR_STRING         3 | ||||||
|  | #define USBDESCR_INTERFACE      4 | ||||||
|  | #define USBDESCR_ENDPOINT       5 | ||||||
|  | #define USBDESCR_HID            0x21 | ||||||
|  | #define USBDESCR_HID_REPORT     0x22 | ||||||
|  | #define USBDESCR_HID_PHYS       0x23 | ||||||
|  | 
 | ||||||
|  | //#define USBATTR_BUSPOWER        0x80  // USB 1.1 does not define this value any more
 | ||||||
|  | #define USBATTR_BUSPOWER        0 | ||||||
|  | #define USBATTR_SELFPOWER       0x40 | ||||||
|  | #define USBATTR_REMOTEWAKE      0x20 | ||||||
|  | 
 | ||||||
|  | /* USB HID Requests */ | ||||||
|  | #define USBRQ_HID_GET_REPORT    0x01 | ||||||
|  | #define USBRQ_HID_GET_IDLE      0x02 | ||||||
|  | #define USBRQ_HID_GET_PROTOCOL  0x03 | ||||||
|  | #define USBRQ_HID_SET_REPORT    0x09 | ||||||
|  | #define USBRQ_HID_SET_IDLE      0x0a | ||||||
|  | #define USBRQ_HID_SET_PROTOCOL  0x0b | ||||||
|  | 
 | ||||||
|  | /* ------------------------------------------------------------------------- */ | ||||||
|  | 
 | ||||||
|  | #endif /* __usbdrv_h_included__ */ | ||||||
							
								
								
									
										392
									
								
								keyboards/planck/thk/bootloader/usbdrv/usbdrvasm.S
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										392
									
								
								keyboards/planck/thk/bootloader/usbdrv/usbdrvasm.S
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,392 @@ | |||||||
|  | /* Name: usbdrvasm.S | ||||||
|  |  * Project: V-USB, virtual USB port for Atmel's(r) AVR(r) microcontrollers | ||||||
|  |  * Author: Christian Starkjohann | ||||||
|  |  * Creation Date: 2007-06-13 | ||||||
|  |  * Tabsize: 4 | ||||||
|  |  * Copyright: (c) 2007 by OBJECTIVE DEVELOPMENT Software GmbH | ||||||
|  |  * License: GNU GPL v2 (see License.txt), GNU GPL v3 or proprietary (CommercialLicense.txt) | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | /* | ||||||
|  | General Description: | ||||||
|  | This module is the assembler part of the USB driver. This file contains | ||||||
|  | general code (preprocessor acrobatics and CRC computation) and then includes | ||||||
|  | the file appropriate for the given clock rate. | ||||||
|  | */ | ||||||
|  | 
 | ||||||
|  | #define __SFR_OFFSET 0      /* used by avr-libc's register definitions */ | ||||||
|  | #include "usbportability.h" | ||||||
|  | #include "usbdrv.h"         /* for common defs */ | ||||||
|  | 
 | ||||||
|  | /* register names */ | ||||||
|  | #define x1      r16 | ||||||
|  | #define x2      r17 | ||||||
|  | #define shift   r18 | ||||||
|  | #define cnt     r19 | ||||||
|  | #define x3      r20 | ||||||
|  | #define x4      r21 | ||||||
|  | #define x5		r22 | ||||||
|  | #define bitcnt  x5 | ||||||
|  | #define phase   x4 | ||||||
|  | #define leap    x4 | ||||||
|  | 
 | ||||||
|  | /* Some assembler dependent definitions and declarations: */ | ||||||
|  | 
 | ||||||
|  | #ifdef __IAR_SYSTEMS_ASM__ | ||||||
|  |     extern  usbRxBuf, usbDeviceAddr, usbNewDeviceAddr, usbInputBufOffset | ||||||
|  |     extern  usbCurrentTok, usbRxLen, usbRxToken, usbTxLen | ||||||
|  |     extern  usbTxBuf, usbTxStatus1, usbTxStatus3 | ||||||
|  | #   if USB_COUNT_SOF | ||||||
|  |         extern usbSofCount | ||||||
|  | #   endif | ||||||
|  |     public  usbCrc16 | ||||||
|  |     public  usbCrc16Append | ||||||
|  | 
 | ||||||
|  |     COMMON  INTVEC | ||||||
|  | #   ifndef USB_INTR_VECTOR | ||||||
|  |         ORG     INT0_vect | ||||||
|  | #   else /* USB_INTR_VECTOR */ | ||||||
|  |         ORG     USB_INTR_VECTOR | ||||||
|  | #       undef   USB_INTR_VECTOR | ||||||
|  | #   endif /* USB_INTR_VECTOR */ | ||||||
|  | #   define  USB_INTR_VECTOR usbInterruptHandler | ||||||
|  |     rjmp    USB_INTR_VECTOR | ||||||
|  |     RSEG    CODE | ||||||
|  | 
 | ||||||
|  | #else /* __IAR_SYSTEMS_ASM__ */ | ||||||
|  | 
 | ||||||
|  | #   ifndef USB_INTR_VECTOR /* default to hardware interrupt INT0 */ | ||||||
|  | #       ifdef INT0_vect | ||||||
|  | #           define USB_INTR_VECTOR  INT0_vect       // this is the "new" define for the vector | ||||||
|  | #       else | ||||||
|  | #           define USB_INTR_VECTOR  SIG_INTERRUPT0  // this is the "old" vector | ||||||
|  | #       endif | ||||||
|  | #   endif | ||||||
|  |     .text | ||||||
|  |     .global USB_INTR_VECTOR
 | ||||||
|  |     .type   USB_INTR_VECTOR, @function
 | ||||||
|  |     .global usbCrc16
 | ||||||
|  |     .global usbCrc16Append
 | ||||||
|  | #endif /* __IAR_SYSTEMS_ASM__ */ | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | #if USB_INTR_PENDING < 0x40 /* This is an I/O address, use in and out */ | ||||||
|  | #   define  USB_LOAD_PENDING(reg)   in reg, USB_INTR_PENDING | ||||||
|  | #   define  USB_STORE_PENDING(reg)  out USB_INTR_PENDING, reg | ||||||
|  | #else   /* It's a memory address, use lds and sts */ | ||||||
|  | #   define  USB_LOAD_PENDING(reg)   lds reg, USB_INTR_PENDING | ||||||
|  | #   define  USB_STORE_PENDING(reg)  sts USB_INTR_PENDING, reg | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
|  | #define usbTxLen1   usbTxStatus1 | ||||||
|  | #define usbTxBuf1   (usbTxStatus1 + 1) | ||||||
|  | #define usbTxLen3   usbTxStatus3 | ||||||
|  | #define usbTxBuf3   (usbTxStatus3 + 1) | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | ;----------------------------------------------------------------------------
 | ||||||
|  | ; Utility functions
 | ||||||
|  | ;----------------------------------------------------------------------------
 | ||||||
|  | 
 | ||||||
|  | #ifdef __IAR_SYSTEMS_ASM__ | ||||||
|  | /* Register assignments for usbCrc16 on IAR cc */ | ||||||
|  | /* Calling conventions on IAR: | ||||||
|  |  * First parameter passed in r16/r17, second in r18/r19 and so on. | ||||||
|  |  * Callee must preserve r4-r15, r24-r29 (r28/r29 is frame pointer) | ||||||
|  |  * Result is passed in r16/r17 | ||||||
|  |  * In case of the "tiny" memory model, pointers are only 8 bit with no | ||||||
|  |  * padding. We therefore pass argument 1 as "16 bit unsigned". | ||||||
|  |  */ | ||||||
|  | RTMODEL "__rt_version", "3" | ||||||
|  | /* The line above will generate an error if cc calling conventions change. | ||||||
|  |  * The value "3" above is valid for IAR 4.10B/W32 | ||||||
|  |  */ | ||||||
|  | #   define argLen   r18 /* argument 2 */ | ||||||
|  | #   define argPtrL  r16 /* argument 1 */ | ||||||
|  | #   define argPtrH  r17 /* argument 1 */ | ||||||
|  | 
 | ||||||
|  | #   define resCrcL  r16 /* result */ | ||||||
|  | #   define resCrcH  r17 /* result */ | ||||||
|  | 
 | ||||||
|  | #   define ptrL     ZL | ||||||
|  | #   define ptrH     ZH | ||||||
|  | #   define ptr      Z | ||||||
|  | #   define byte     r22 | ||||||
|  | #   define bitCnt   r19 | ||||||
|  | #   define polyL    r20 | ||||||
|  | #   define polyH    r21 | ||||||
|  | #   define scratch  r23 | ||||||
|  | 
 | ||||||
|  | #else  /* __IAR_SYSTEMS_ASM__ */  | ||||||
|  | /* Register assignments for usbCrc16 on gcc */ | ||||||
|  | /* Calling conventions on gcc: | ||||||
|  |  * First parameter passed in r24/r25, second in r22/23 and so on. | ||||||
|  |  * Callee must preserve r1-r17, r28/r29 | ||||||
|  |  * Result is passed in r24/r25 | ||||||
|  |  */ | ||||||
|  | #   define argLen   r22 /* argument 2 */ | ||||||
|  | #   define argPtrL  r24 /* argument 1 */ | ||||||
|  | #   define argPtrH  r25 /* argument 1 */ | ||||||
|  | 
 | ||||||
|  | #   define resCrcL  r24 /* result */ | ||||||
|  | #   define resCrcH  r25 /* result */ | ||||||
|  | 
 | ||||||
|  | #   define ptrL     XL | ||||||
|  | #   define ptrH     XH | ||||||
|  | #   define ptr      x | ||||||
|  | #   define byte     r18 | ||||||
|  | #   define bitCnt   r19 | ||||||
|  | #   define polyL    r20 | ||||||
|  | #   define polyH    r21 | ||||||
|  | #   define scratch  r23 | ||||||
|  | 
 | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
|  | #if USB_USE_FAST_CRC | ||||||
|  | 
 | ||||||
|  | ; This implementation is faster, but has bigger code size
 | ||||||
|  | ; Thanks to Slawomir Fras (BoskiDialer) for this code!
 | ||||||
|  | ; It implements the following C pseudo-code:
 | ||||||
|  | ; unsigned table(unsigned char x)
 | ||||||
|  | ; {
 | ||||||
|  | ; unsigned    value;
 | ||||||
|  | ; 
 | ||||||
|  | ;     value = (unsigned)x << 6;
 | ||||||
|  | ;     value ^= (unsigned)x << 7;
 | ||||||
|  | ;     if(parity(x))
 | ||||||
|  | ;         value ^= 0xc001;
 | ||||||
|  | ;     return value;
 | ||||||
|  | ; }
 | ||||||
|  | ; unsigned usbCrc16(unsigned char *argPtr, unsigned char argLen)
 | ||||||
|  | ; {
 | ||||||
|  | ; unsigned crc = 0xffff;
 | ||||||
|  | ; 
 | ||||||
|  | ;     while(argLen--)
 | ||||||
|  | ;         crc = table(lo8(crc) ^ *argPtr++) ^ hi8(crc);
 | ||||||
|  | ;     return ~crc;
 | ||||||
|  | ; }
 | ||||||
|  | 
 | ||||||
|  | ; extern unsigned usbCrc16(unsigned char *argPtr, unsigned char argLen);
 | ||||||
|  | ;   argPtr  r24+25 / r16+r17
 | ||||||
|  | ;   argLen  r22 / r18
 | ||||||
|  | ; temp variables:
 | ||||||
|  | ;   byte    r18 / r22
 | ||||||
|  | ;   scratch r23
 | ||||||
|  | ;   resCrc  r24+r25 / r16+r17
 | ||||||
|  | ;   ptr     X / Z
 | ||||||
|  | usbCrc16: | ||||||
|  |     mov     ptrL, argPtrL | ||||||
|  |     mov     ptrH, argPtrH | ||||||
|  |     ldi     resCrcL, 0xFF | ||||||
|  |     ldi     resCrcH, 0xFF | ||||||
|  |     rjmp    usbCrc16LoopTest | ||||||
|  | usbCrc16ByteLoop: | ||||||
|  |     ld      byte, ptr+ | ||||||
|  |     eor     resCrcL, byte   ; resCrcL is now 'x' in table()
 | ||||||
|  |     mov     byte, resCrcL   ; compute parity of 'x'
 | ||||||
|  |     swap    byte | ||||||
|  |     eor     byte, resCrcL | ||||||
|  |     mov     scratch, byte | ||||||
|  |     lsr     byte | ||||||
|  |     lsr     byte | ||||||
|  |     eor     byte, scratch | ||||||
|  |     inc     byte | ||||||
|  |     lsr     byte | ||||||
|  |     andi    byte, 1         ; byte is now parity(x)
 | ||||||
|  |     mov     scratch, resCrcL | ||||||
|  |     mov     resCrcL, resCrcH | ||||||
|  |     eor     resCrcL, byte   ; low byte of if(parity(x)) value ^= 0xc001;
 | ||||||
|  |     neg     byte | ||||||
|  |     andi    byte, 0xc0 | ||||||
|  |     mov     resCrcH, byte   ; high byte of if(parity(x)) value ^= 0xc001;
 | ||||||
|  |     clr     byte | ||||||
|  |     lsr     scratch | ||||||
|  |     ror     byte | ||||||
|  |     eor     resCrcH, scratch | ||||||
|  |     eor     resCrcL, byte | ||||||
|  |     lsr     scratch | ||||||
|  |     ror     byte | ||||||
|  |     eor     resCrcH, scratch | ||||||
|  |     eor     resCrcL, byte | ||||||
|  | usbCrc16LoopTest: | ||||||
|  |     subi    argLen, 1 | ||||||
|  |     brsh    usbCrc16ByteLoop | ||||||
|  |     com     resCrcL | ||||||
|  |     com     resCrcH | ||||||
|  |     ret | ||||||
|  | 
 | ||||||
|  | #else   /* USB_USE_FAST_CRC */ | ||||||
|  | 
 | ||||||
|  | ; This implementation is slower, but has less code size
 | ||||||
|  | ;
 | ||||||
|  | ; extern unsigned usbCrc16(unsigned char *argPtr, unsigned char argLen);
 | ||||||
|  | ;   argPtr  r24+25 / r16+r17
 | ||||||
|  | ;   argLen  r22 / r18
 | ||||||
|  | ; temp variables:
 | ||||||
|  | ;   byte    r18 / r22
 | ||||||
|  | ;   bitCnt  r19
 | ||||||
|  | ;   poly    r20+r21
 | ||||||
|  | ;   scratch r23
 | ||||||
|  | ;   resCrc  r24+r25 / r16+r17
 | ||||||
|  | ;   ptr     X / Z
 | ||||||
|  | usbCrc16: | ||||||
|  |     mov     ptrL, argPtrL | ||||||
|  |     mov     ptrH, argPtrH | ||||||
|  |     ldi     resCrcL, 0 | ||||||
|  |     ldi     resCrcH, 0 | ||||||
|  |     ldi     polyL, lo8(0xa001) | ||||||
|  |     ldi     polyH, hi8(0xa001) | ||||||
|  |     com     argLen      ; argLen = -argLen - 1: modified loop to ensure that carry is set
 | ||||||
|  |     ldi     bitCnt, 0   ; loop counter with starnd condition = end condition
 | ||||||
|  |     rjmp    usbCrcLoopEntry | ||||||
|  | usbCrcByteLoop: | ||||||
|  |     ld      byte, ptr+ | ||||||
|  |     eor     resCrcL, byte | ||||||
|  | usbCrcBitLoop: | ||||||
|  |     ror     resCrcH     ; carry is always set here (see brcs jumps to here)
 | ||||||
|  |     ror     resCrcL | ||||||
|  |     brcs    usbCrcNoXor | ||||||
|  |     eor     resCrcL, polyL | ||||||
|  |     eor     resCrcH, polyH | ||||||
|  | usbCrcNoXor: | ||||||
|  |     subi    bitCnt, 224 ; (8 * 224) % 256 = 0; this loop iterates 8 times
 | ||||||
|  |     brcs    usbCrcBitLoop | ||||||
|  | usbCrcLoopEntry: | ||||||
|  |     subi    argLen, -1 | ||||||
|  |     brcs    usbCrcByteLoop | ||||||
|  | usbCrcReady: | ||||||
|  |     ret | ||||||
|  | ; Thanks to Reimar Doeffinger for optimizing this CRC routine!
 | ||||||
|  | 
 | ||||||
|  | #endif /* USB_USE_FAST_CRC */ | ||||||
|  | 
 | ||||||
|  | ; extern unsigned usbCrc16Append(unsigned char *data, unsigned char len);
 | ||||||
|  | usbCrc16Append: | ||||||
|  |     rcall   usbCrc16 | ||||||
|  |     st      ptr+, resCrcL | ||||||
|  |     st      ptr+, resCrcH | ||||||
|  |     ret | ||||||
|  | 
 | ||||||
|  | #undef argLen | ||||||
|  | #undef argPtrL | ||||||
|  | #undef argPtrH | ||||||
|  | #undef resCrcL | ||||||
|  | #undef resCrcH | ||||||
|  | #undef ptrL | ||||||
|  | #undef ptrH | ||||||
|  | #undef ptr | ||||||
|  | #undef byte | ||||||
|  | #undef bitCnt | ||||||
|  | #undef polyL | ||||||
|  | #undef polyH | ||||||
|  | #undef scratch | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | #if USB_CFG_HAVE_MEASURE_FRAME_LENGTH | ||||||
|  | #ifdef __IAR_SYSTEMS_ASM__ | ||||||
|  | /* Register assignments for usbMeasureFrameLength on IAR cc */ | ||||||
|  | /* Calling conventions on IAR: | ||||||
|  |  * First parameter passed in r16/r17, second in r18/r19 and so on. | ||||||
|  |  * Callee must preserve r4-r15, r24-r29 (r28/r29 is frame pointer) | ||||||
|  |  * Result is passed in r16/r17 | ||||||
|  |  * In case of the "tiny" memory model, pointers are only 8 bit with no | ||||||
|  |  * padding. We therefore pass argument 1 as "16 bit unsigned". | ||||||
|  |  */ | ||||||
|  | #   define resL     r16 | ||||||
|  | #   define resH     r17 | ||||||
|  | #   define cnt16L   r30 | ||||||
|  | #   define cnt16H   r31 | ||||||
|  | #   define cntH     r18 | ||||||
|  | 
 | ||||||
|  | #else  /* __IAR_SYSTEMS_ASM__ */  | ||||||
|  | /* Register assignments for usbMeasureFrameLength on gcc */ | ||||||
|  | /* Calling conventions on gcc: | ||||||
|  |  * First parameter passed in r24/r25, second in r22/23 and so on. | ||||||
|  |  * Callee must preserve r1-r17, r28/r29 | ||||||
|  |  * Result is passed in r24/r25 | ||||||
|  |  */ | ||||||
|  | #   define resL     r24 | ||||||
|  | #   define resH     r25 | ||||||
|  | #   define cnt16L   r24 | ||||||
|  | #   define cnt16H   r25 | ||||||
|  | #   define cntH     r26 | ||||||
|  | #endif | ||||||
|  | #   define cnt16    cnt16L | ||||||
|  | 
 | ||||||
|  | ; extern unsigned usbMeasurePacketLength(void);
 | ||||||
|  | ; returns time between two idle strobes in multiples of 7 CPU clocks
 | ||||||
|  | .global usbMeasureFrameLength
 | ||||||
|  | usbMeasureFrameLength: | ||||||
|  |     ldi     cntH, 6         ; wait ~ 10 ms for D- == 0
 | ||||||
|  |     clr     cnt16L | ||||||
|  |     clr     cnt16H | ||||||
|  | usbMFTime16: | ||||||
|  |     dec     cntH | ||||||
|  |     breq    usbMFTimeout | ||||||
|  | usbMFWaitStrobe:            ; first wait for D- == 0 (idle strobe)
 | ||||||
|  |     sbiw    cnt16, 1        ;[0] [6]
 | ||||||
|  |     breq    usbMFTime16     ;[2]
 | ||||||
|  |     sbic    USBIN, USBMINUS ;[3]
 | ||||||
|  |     rjmp    usbMFWaitStrobe ;[4]
 | ||||||
|  | usbMFWaitIdle:              ; then wait until idle again
 | ||||||
|  |     sbis    USBIN, USBMINUS ;1 wait for D- == 1
 | ||||||
|  |     rjmp    usbMFWaitIdle   ;2
 | ||||||
|  |     ldi     cnt16L, 1       ;1 represents cycles so far
 | ||||||
|  |     clr     cnt16H          ;1
 | ||||||
|  | usbMFWaitLoop: | ||||||
|  |     in      cntH, USBIN     ;[0] [7]
 | ||||||
|  |     adiw    cnt16, 1        ;[1]
 | ||||||
|  |     breq    usbMFTimeout    ;[3]
 | ||||||
|  |     andi    cntH, USBMASK   ;[4]
 | ||||||
|  |     brne    usbMFWaitLoop   ;[5]
 | ||||||
|  | usbMFTimeout: | ||||||
|  | #if resL != cnt16L | ||||||
|  |     mov     resL, cnt16L | ||||||
|  |     mov     resH, cnt16H | ||||||
|  | #endif | ||||||
|  |     ret | ||||||
|  | 
 | ||||||
|  | #undef resL | ||||||
|  | #undef resH | ||||||
|  | #undef cnt16 | ||||||
|  | #undef cnt16L | ||||||
|  | #undef cnt16H | ||||||
|  | #undef cntH | ||||||
|  | 
 | ||||||
|  | #endif  /* USB_CFG_HAVE_MEASURE_FRAME_LENGTH */ | ||||||
|  | 
 | ||||||
|  | ;----------------------------------------------------------------------------
 | ||||||
|  | ; Now include the clock rate specific code
 | ||||||
|  | ;----------------------------------------------------------------------------
 | ||||||
|  | 
 | ||||||
|  | #ifndef USB_CFG_CLOCK_KHZ | ||||||
|  | #   ifdef F_CPU | ||||||
|  | #       define USB_CFG_CLOCK_KHZ (F_CPU/1000) | ||||||
|  | #   else | ||||||
|  | #       error "USB_CFG_CLOCK_KHZ not defined in usbconfig.h and no F_CPU set!" | ||||||
|  | #   endif | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
|  | #if USB_CFG_CHECK_CRC   /* separate dispatcher for CRC type modules */ | ||||||
|  | #   if USB_CFG_CLOCK_KHZ == 18000 | ||||||
|  | #       include "usbdrvasm18-crc.inc" | ||||||
|  | #   else | ||||||
|  | #       error "USB_CFG_CLOCK_KHZ is not one of the supported crc-rates!" | ||||||
|  | #   endif | ||||||
|  | #else   /* USB_CFG_CHECK_CRC */ | ||||||
|  | #   if USB_CFG_CLOCK_KHZ == 12000 | ||||||
|  | #       include "usbdrvasm12.inc" | ||||||
|  | #   elif USB_CFG_CLOCK_KHZ == 12800 | ||||||
|  | #       include "usbdrvasm128.inc" | ||||||
|  | #   elif USB_CFG_CLOCK_KHZ == 15000 | ||||||
|  | #       include "usbdrvasm15.inc" | ||||||
|  | #   elif USB_CFG_CLOCK_KHZ == 16000 | ||||||
|  | #       include "usbdrvasm16.inc" | ||||||
|  | #   elif USB_CFG_CLOCK_KHZ == 16500 | ||||||
|  | #       include "usbdrvasm165.inc" | ||||||
|  | #   elif USB_CFG_CLOCK_KHZ == 20000 | ||||||
|  | #       include "usbdrvasm20.inc" | ||||||
|  | #   else | ||||||
|  | #       error "USB_CFG_CLOCK_KHZ is not one of the supported non-crc-rates!" | ||||||
|  | #   endif | ||||||
|  | #endif /* USB_CFG_CHECK_CRC */ | ||||||
							
								
								
									
										20
									
								
								keyboards/planck/thk/bootloader/usbdrv/usbdrvasm.asm
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								keyboards/planck/thk/bootloader/usbdrv/usbdrvasm.asm
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,20 @@ | |||||||
|  | /* Name: usbdrvasm.asm | ||||||
|  |  * Project: V-USB, virtual USB port for Atmel's(r) AVR(r) microcontrollers | ||||||
|  |  * Author: Christian Starkjohann | ||||||
|  |  * Creation Date: 2006-03-01 | ||||||
|  |  * Tabsize: 4 | ||||||
|  |  * Copyright: (c) 2006 by OBJECTIVE DEVELOPMENT Software GmbH | ||||||
|  |  * License: GNU GPL v2 (see License.txt), GNU GPL v3 or proprietary (CommercialLicense.txt) | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | /* | ||||||
|  | General Description: | ||||||
|  | The IAR compiler/assembler system prefers assembler files with file extension | ||||||
|  | ".asm". We simply provide this file as an alias for usbdrvasm.S. | ||||||
|  | 
 | ||||||
|  | Thanks to Oleg Semyonov for his help with the IAR tools port! | ||||||
|  | */ | ||||||
|  | 
 | ||||||
|  | #include "usbdrvasm.S" | ||||||
|  | 
 | ||||||
|  | end | ||||||
							
								
								
									
										392
									
								
								keyboards/planck/thk/bootloader/usbdrv/usbdrvasm12.inc
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										392
									
								
								keyboards/planck/thk/bootloader/usbdrv/usbdrvasm12.inc
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,392 @@ | |||||||
|  | /* Name: usbdrvasm12.inc | ||||||
|  |  * Project: V-USB, virtual USB port for Atmel's(r) AVR(r) microcontrollers | ||||||
|  |  * Author: Christian Starkjohann | ||||||
|  |  * Creation Date: 2004-12-29 | ||||||
|  |  * Tabsize: 4 | ||||||
|  |  * Copyright: (c) 2007 by OBJECTIVE DEVELOPMENT Software GmbH | ||||||
|  |  * License: GNU GPL v2 (see License.txt), GNU GPL v3 or proprietary (CommercialLicense.txt) | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | /* Do not link this file! Link usbdrvasm.S instead, which includes the | ||||||
|  |  * appropriate implementation! | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | /* | ||||||
|  | General Description: | ||||||
|  | This file is the 12 MHz version of the asssembler part of the USB driver. It | ||||||
|  | requires a 12 MHz crystal (not a ceramic resonator and not a calibrated RC | ||||||
|  | oscillator). | ||||||
|  | 
 | ||||||
|  | See usbdrv.h for a description of the entire driver. | ||||||
|  | 
 | ||||||
|  | Since almost all of this code is timing critical, don't change unless you | ||||||
|  | really know what you are doing! Many parts require not only a maximum number | ||||||
|  | of CPU cycles, but even an exact number of cycles! | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | Timing constraints according to spec (in bit times): | ||||||
|  | timing subject                                      min max    CPUcycles | ||||||
|  | --------------------------------------------------------------------------- | ||||||
|  | EOP of OUT/SETUP to sync pattern of DATA0 (both rx) 2   16     16-128 | ||||||
|  | EOP of IN to sync pattern of DATA0 (rx, then tx)    2   7.5    16-60 | ||||||
|  | DATAx (rx) to ACK/NAK/STALL (tx)                    2   7.5    16-60 | ||||||
|  | */ | ||||||
|  | 
 | ||||||
|  | ;Software-receiver engine. Strict timing! Don't change unless you can preserve timing! | ||||||
|  | ;interrupt response time: 4 cycles + insn running = 7 max if interrupts always enabled | ||||||
|  | ;max allowable interrupt latency: 34 cycles -> max 25 cycles interrupt disable | ||||||
|  | ;max stack usage: [ret(2), YL, SREG, YH, shift, x1, x2, x3, cnt, x4] = 11 bytes | ||||||
|  | ;Numbers in brackets are maximum cycles since SOF. | ||||||
|  | USB_INTR_VECTOR: | ||||||
|  | ;order of registers pushed: YL, SREG [sofError], YH, shift, x1, x2, x3, cnt | ||||||
|  |     push    YL              ;2 [35] push only what is necessary to sync with edge ASAP | ||||||
|  |     in      YL, SREG        ;1 [37] | ||||||
|  |     push    YL              ;2 [39] | ||||||
|  | ;---------------------------------------------------------------------------- | ||||||
|  | ; Synchronize with sync pattern: | ||||||
|  | ;---------------------------------------------------------------------------- | ||||||
|  | ;sync byte (D-) pattern LSb to MSb: 01010100 [1 = idle = J, 0 = K] | ||||||
|  | ;sync up with J to K edge during sync pattern -- use fastest possible loops | ||||||
|  | ;The first part waits at most 1 bit long since we must be in sync pattern. | ||||||
|  | ;YL is guarenteed to be < 0x80 because I flag is clear. When we jump to | ||||||
|  | ;waitForJ, ensure that this prerequisite is met. | ||||||
|  | waitForJ: | ||||||
|  |     inc     YL | ||||||
|  |     sbis    USBIN, USBMINUS | ||||||
|  |     brne    waitForJ        ; just make sure we have ANY timeout | ||||||
|  | waitForK: | ||||||
|  | ;The following code results in a sampling window of 1/4 bit which meets the spec. | ||||||
|  |     sbis    USBIN, USBMINUS | ||||||
|  |     rjmp    foundK | ||||||
|  |     sbis    USBIN, USBMINUS | ||||||
|  |     rjmp    foundK | ||||||
|  |     sbis    USBIN, USBMINUS | ||||||
|  |     rjmp    foundK | ||||||
|  |     sbis    USBIN, USBMINUS | ||||||
|  |     rjmp    foundK | ||||||
|  |     sbis    USBIN, USBMINUS | ||||||
|  |     rjmp    foundK | ||||||
|  | #if USB_COUNT_SOF
 | ||||||
|  |     lds     YL, usbSofCount | ||||||
|  |     inc     YL | ||||||
|  |     sts     usbSofCount, YL | ||||||
|  | #endif  /* USB_COUNT_SOF */
 | ||||||
|  | #ifdef USB_SOF_HOOK
 | ||||||
|  |     USB_SOF_HOOK | ||||||
|  | #endif
 | ||||||
|  |     rjmp    sofError | ||||||
|  | foundK: | ||||||
|  | ;{3, 5} after falling D- edge, average delay: 4 cycles [we want 4 for center sampling] | ||||||
|  | ;we have 1 bit time for setup purposes, then sample again. Numbers in brackets | ||||||
|  | ;are cycles from center of first sync (double K) bit after the instruction | ||||||
|  |     push    YH                  ;2 [2] | ||||||
|  |     lds     YL, usbInputBufOffset;2 [4] | ||||||
|  |     clr     YH                  ;1 [5] | ||||||
|  |     subi    YL, lo8(-(usbRxBuf));1 [6] | ||||||
|  |     sbci    YH, hi8(-(usbRxBuf));1 [7] | ||||||
|  | 
 | ||||||
|  |     sbis    USBIN, USBMINUS ;1 [8] we want two bits K [sample 1 cycle too early] | ||||||
|  |     rjmp    haveTwoBitsK    ;2 [10] | ||||||
|  |     pop     YH              ;2 [11] undo the push from before | ||||||
|  |     rjmp    waitForK        ;2 [13] this was not the end of sync, retry | ||||||
|  | haveTwoBitsK: | ||||||
|  | ;---------------------------------------------------------------------------- | ||||||
|  | ; push more registers and initialize values while we sample the first bits: | ||||||
|  | ;---------------------------------------------------------------------------- | ||||||
|  |     push    shift           ;2 [16] | ||||||
|  |     push    x1              ;2 [12] | ||||||
|  |     push    x2              ;2 [14] | ||||||
|  | 
 | ||||||
|  |     in      x1, USBIN       ;1 [17] <-- sample bit 0 | ||||||
|  |     ldi     shift, 0xff     ;1 [18] | ||||||
|  |     bst     x1, USBMINUS    ;1 [19] | ||||||
|  |     bld     shift, 0        ;1 [20] | ||||||
|  |     push    x3              ;2 [22] | ||||||
|  |     push    cnt             ;2 [24] | ||||||
|  |      | ||||||
|  |     in      x2, USBIN       ;1 [25] <-- sample bit 1 | ||||||
|  |     ser     x3              ;1 [26] [inserted init instruction] | ||||||
|  |     eor     x1, x2          ;1 [27] | ||||||
|  |     bst     x1, USBMINUS    ;1 [28] | ||||||
|  |     bld     shift, 1        ;1 [29] | ||||||
|  |     ldi     cnt, USB_BUFSIZE;1 [30] [inserted init instruction] | ||||||
|  |     rjmp    rxbit2          ;2 [32] | ||||||
|  | 
 | ||||||
|  | ;---------------------------------------------------------------------------- | ||||||
|  | ; Receiver loop (numbers in brackets are cycles within byte after instr) | ||||||
|  | ;---------------------------------------------------------------------------- | ||||||
|  | 
 | ||||||
|  | unstuff0:               ;1 (branch taken) | ||||||
|  |     andi    x3, ~0x01   ;1 [15] | ||||||
|  |     mov     x1, x2      ;1 [16] x2 contains last sampled (stuffed) bit | ||||||
|  |     in      x2, USBIN   ;1 [17] <-- sample bit 1 again | ||||||
|  |     ori     shift, 0x01 ;1 [18] | ||||||
|  |     rjmp    didUnstuff0 ;2 [20] | ||||||
|  | 
 | ||||||
|  | unstuff1:               ;1 (branch taken) | ||||||
|  |     mov     x2, x1      ;1 [21] x1 contains last sampled (stuffed) bit | ||||||
|  |     andi    x3, ~0x02   ;1 [22] | ||||||
|  |     ori     shift, 0x02 ;1 [23] | ||||||
|  |     nop                 ;1 [24] | ||||||
|  |     in      x1, USBIN   ;1 [25] <-- sample bit 2 again | ||||||
|  |     rjmp    didUnstuff1 ;2 [27] | ||||||
|  | 
 | ||||||
|  | unstuff2:               ;1 (branch taken) | ||||||
|  |     andi    x3, ~0x04   ;1 [29] | ||||||
|  |     ori     shift, 0x04 ;1 [30] | ||||||
|  |     mov     x1, x2      ;1 [31] x2 contains last sampled (stuffed) bit | ||||||
|  |     nop                 ;1 [32] | ||||||
|  |     in      x2, USBIN   ;1 [33] <-- sample bit 3 | ||||||
|  |     rjmp    didUnstuff2 ;2 [35] | ||||||
|  | 
 | ||||||
|  | unstuff3:               ;1 (branch taken) | ||||||
|  |     in      x2, USBIN   ;1 [34] <-- sample stuffed bit 3 [one cycle too late] | ||||||
|  |     andi    x3, ~0x08   ;1 [35] | ||||||
|  |     ori     shift, 0x08 ;1 [36] | ||||||
|  |     rjmp    didUnstuff3 ;2 [38] | ||||||
|  | 
 | ||||||
|  | unstuff4:               ;1 (branch taken) | ||||||
|  |     andi    x3, ~0x10   ;1 [40] | ||||||
|  |     in      x1, USBIN   ;1 [41] <-- sample stuffed bit 4 | ||||||
|  |     ori     shift, 0x10 ;1 [42] | ||||||
|  |     rjmp    didUnstuff4 ;2 [44] | ||||||
|  | 
 | ||||||
|  | unstuff5:               ;1 (branch taken) | ||||||
|  |     andi    x3, ~0x20   ;1 [48] | ||||||
|  |     in      x2, USBIN   ;1 [49] <-- sample stuffed bit 5 | ||||||
|  |     ori     shift, 0x20 ;1 [50] | ||||||
|  |     rjmp    didUnstuff5 ;2 [52] | ||||||
|  | 
 | ||||||
|  | unstuff6:               ;1 (branch taken) | ||||||
|  |     andi    x3, ~0x40   ;1 [56] | ||||||
|  |     in      x1, USBIN   ;1 [57] <-- sample stuffed bit 6 | ||||||
|  |     ori     shift, 0x40 ;1 [58] | ||||||
|  |     rjmp    didUnstuff6 ;2 [60] | ||||||
|  | 
 | ||||||
|  | ; extra jobs done during bit interval: | ||||||
|  | ; bit 0:    store, clear [SE0 is unreliable here due to bit dribbling in hubs] | ||||||
|  | ; bit 1:    se0 check | ||||||
|  | ; bit 2:    overflow check | ||||||
|  | ; bit 3:    recovery from delay [bit 0 tasks took too long] | ||||||
|  | ; bit 4:    none | ||||||
|  | ; bit 5:    none | ||||||
|  | ; bit 6:    none | ||||||
|  | ; bit 7:    jump, eor | ||||||
|  | rxLoop: | ||||||
|  |     eor     x3, shift   ;1 [0] reconstruct: x3 is 0 at bit locations we changed, 1 at others | ||||||
|  |     in      x1, USBIN   ;1 [1] <-- sample bit 0 | ||||||
|  |     st      y+, x3      ;2 [3] store data | ||||||
|  |     ser     x3          ;1 [4] | ||||||
|  |     nop                 ;1 [5] | ||||||
|  |     eor     x2, x1      ;1 [6] | ||||||
|  |     bst     x2, USBMINUS;1 [7] | ||||||
|  |     bld     shift, 0    ;1 [8] | ||||||
|  |     in      x2, USBIN   ;1 [9] <-- sample bit 1 (or possibly bit 0 stuffed) | ||||||
|  |     andi    x2, USBMASK ;1 [10] | ||||||
|  |     breq    se0         ;1 [11] SE0 check for bit 1 | ||||||
|  |     andi    shift, 0xf9 ;1 [12] | ||||||
|  | didUnstuff0: | ||||||
|  |     breq    unstuff0    ;1 [13] | ||||||
|  |     eor     x1, x2      ;1 [14] | ||||||
|  |     bst     x1, USBMINUS;1 [15] | ||||||
|  |     bld     shift, 1    ;1 [16] | ||||||
|  | rxbit2: | ||||||
|  |     in      x1, USBIN   ;1 [17] <-- sample bit 2 (or possibly bit 1 stuffed) | ||||||
|  |     andi    shift, 0xf3 ;1 [18] | ||||||
|  |     breq    unstuff1    ;1 [19] do remaining work for bit 1 | ||||||
|  | didUnstuff1: | ||||||
|  |     subi    cnt, 1      ;1 [20] | ||||||
|  |     brcs    overflow    ;1 [21] loop control | ||||||
|  |     eor     x2, x1      ;1 [22] | ||||||
|  |     bst     x2, USBMINUS;1 [23] | ||||||
|  |     bld     shift, 2    ;1 [24] | ||||||
|  |     in      x2, USBIN   ;1 [25] <-- sample bit 3 (or possibly bit 2 stuffed) | ||||||
|  |     andi    shift, 0xe7 ;1 [26] | ||||||
|  |     breq    unstuff2    ;1 [27] | ||||||
|  | didUnstuff2: | ||||||
|  |     eor     x1, x2      ;1 [28] | ||||||
|  |     bst     x1, USBMINUS;1 [29] | ||||||
|  |     bld     shift, 3    ;1 [30] | ||||||
|  | didUnstuff3: | ||||||
|  |     andi    shift, 0xcf ;1 [31] | ||||||
|  |     breq    unstuff3    ;1 [32] | ||||||
|  |     in      x1, USBIN   ;1 [33] <-- sample bit 4 | ||||||
|  |     eor     x2, x1      ;1 [34] | ||||||
|  |     bst     x2, USBMINUS;1 [35] | ||||||
|  |     bld     shift, 4    ;1 [36] | ||||||
|  | didUnstuff4: | ||||||
|  |     andi    shift, 0x9f ;1 [37] | ||||||
|  |     breq    unstuff4    ;1 [38] | ||||||
|  |     nop2                ;2 [40] | ||||||
|  |     in      x2, USBIN   ;1 [41] <-- sample bit 5 | ||||||
|  |     eor     x1, x2      ;1 [42] | ||||||
|  |     bst     x1, USBMINUS;1 [43] | ||||||
|  |     bld     shift, 5    ;1 [44] | ||||||
|  | didUnstuff5: | ||||||
|  |     andi    shift, 0x3f ;1 [45] | ||||||
|  |     breq    unstuff5    ;1 [46] | ||||||
|  |     nop2                ;2 [48] | ||||||
|  |     in      x1, USBIN   ;1 [49] <-- sample bit 6 | ||||||
|  |     eor     x2, x1      ;1 [50] | ||||||
|  |     bst     x2, USBMINUS;1 [51] | ||||||
|  |     bld     shift, 6    ;1 [52] | ||||||
|  | didUnstuff6: | ||||||
|  |     cpi     shift, 0x02 ;1 [53] | ||||||
|  |     brlo    unstuff6    ;1 [54] | ||||||
|  |     nop2                ;2 [56] | ||||||
|  |     in      x2, USBIN   ;1 [57] <-- sample bit 7 | ||||||
|  |     eor     x1, x2      ;1 [58] | ||||||
|  |     bst     x1, USBMINUS;1 [59] | ||||||
|  |     bld     shift, 7    ;1 [60] | ||||||
|  | didUnstuff7: | ||||||
|  |     cpi     shift, 0x04 ;1 [61] | ||||||
|  |     brsh    rxLoop      ;2 [63] loop control | ||||||
|  | unstuff7: | ||||||
|  |     andi    x3, ~0x80   ;1 [63] | ||||||
|  |     ori     shift, 0x80 ;1 [64] | ||||||
|  |     in      x2, USBIN   ;1 [65] <-- sample stuffed bit 7 | ||||||
|  |     nop                 ;1 [66] | ||||||
|  |     rjmp    didUnstuff7 ;2 [68] | ||||||
|  | 
 | ||||||
|  | macro POP_STANDARD ; 12 cycles | ||||||
|  |     pop     cnt | ||||||
|  |     pop     x3 | ||||||
|  |     pop     x2 | ||||||
|  |     pop     x1 | ||||||
|  |     pop     shift | ||||||
|  |     pop     YH | ||||||
|  |     endm | ||||||
|  | macro POP_RETI     ; 5 cycles | ||||||
|  |     pop     YL | ||||||
|  |     out     SREG, YL | ||||||
|  |     pop     YL | ||||||
|  |     endm | ||||||
|  | 
 | ||||||
|  | #include "asmcommon.inc"
 | ||||||
|  | 
 | ||||||
|  | ;---------------------------------------------------------------------------- | ||||||
|  | ; Transmitting data | ||||||
|  | ;---------------------------------------------------------------------------- | ||||||
|  | 
 | ||||||
|  | txByteLoop: | ||||||
|  | txBitloop: | ||||||
|  | stuffN1Delay:                   ;     [03] | ||||||
|  |     ror     shift               ;[-5] [11] [59] | ||||||
|  |     brcc    doExorN1            ;[-4]      [60] | ||||||
|  |     subi    x4, 1               ;[-3] | ||||||
|  |     brne    commonN1            ;[-2] | ||||||
|  |     lsl     shift               ;[-1] compensate ror after rjmp stuffDelay | ||||||
|  |     nop                         ;[00] stuffing consists of just waiting 8 cycles | ||||||
|  |     rjmp    stuffN1Delay        ;[01] after ror, C bit is reliably clear | ||||||
|  | 
 | ||||||
|  | sendNakAndReti:                 ;0 [-19] 19 cycles until SOP | ||||||
|  |     ldi     x3, USBPID_NAK      ;1 [-18] | ||||||
|  |     rjmp    usbSendX3           ;2 [-16] | ||||||
|  | sendAckAndReti:                 ;0 [-19] 19 cycles until SOP | ||||||
|  |     ldi     x3, USBPID_ACK      ;1 [-18] | ||||||
|  |     rjmp    usbSendX3           ;2 [-16] | ||||||
|  | sendCntAndReti:                 ;0 [-17] 17 cycles until SOP | ||||||
|  |     mov     x3, cnt             ;1 [-16] | ||||||
|  | usbSendX3:                      ;0 [-16] | ||||||
|  |     ldi     YL, 20              ;1 [-15] 'x3' is R20 | ||||||
|  |     ldi     YH, 0               ;1 [-14] | ||||||
|  |     ldi     cnt, 2              ;1 [-13] | ||||||
|  | ;   rjmp    usbSendAndReti      fallthrough | ||||||
|  | 
 | ||||||
|  | ; USB spec says: | ||||||
|  | ; idle = J | ||||||
|  | ; J = (D+ = 0), (D- = 1) or USBOUT = 0x01 | ||||||
|  | ; K = (D+ = 1), (D- = 0) or USBOUT = 0x02 | ||||||
|  | ; Spec allows 7.5 bit times from EOP to SOP for replies (= 60 cycles) | ||||||
|  | 
 | ||||||
|  | ;usbSend: | ||||||
|  | ;pointer to data in 'Y' | ||||||
|  | ;number of bytes in 'cnt' -- including sync byte | ||||||
|  | ;uses: x1...x2, x4, shift, cnt, Y [x1 = mirror USBOUT, x2 = USBMASK, x4 = bitstuff cnt] | ||||||
|  | ;Numbers in brackets are time since first bit of sync pattern is sent (start of instruction) | ||||||
|  | usbSendAndReti: | ||||||
|  |     in      x2, USBDDR          ;[-12] 12 cycles until SOP | ||||||
|  |     ori     x2, USBMASK         ;[-11] | ||||||
|  |     sbi     USBOUT, USBMINUS    ;[-10] prepare idle state; D+ and D- must have been 0 (no pullups) | ||||||
|  |     out     USBDDR, x2          ;[-8] <--- acquire bus | ||||||
|  |     in      x1, USBOUT          ;[-7] port mirror for tx loop | ||||||
|  |     ldi     shift, 0x40         ;[-6] sync byte is first byte sent (we enter loop after ror) | ||||||
|  |     ldi     x2, USBMASK         ;[-5] | ||||||
|  |     push    x4                  ;[-4] | ||||||
|  | doExorN1: | ||||||
|  |     eor     x1, x2              ;[-2] [06] [62] | ||||||
|  |     ldi     x4, 6               ;[-1] [07] [63] | ||||||
|  | commonN1: | ||||||
|  | stuffN2Delay: | ||||||
|  |     out     USBOUT, x1          ;[00] [08] [64] <--- set bit | ||||||
|  |     ror     shift               ;[01] | ||||||
|  |     brcc    doExorN2            ;[02] | ||||||
|  |     subi    x4, 1               ;[03] | ||||||
|  |     brne    commonN2            ;[04] | ||||||
|  |     lsl     shift               ;[05] compensate ror after rjmp stuffDelay | ||||||
|  |     rjmp    stuffN2Delay        ;[06] after ror, C bit is reliably clear | ||||||
|  | doExorN2: | ||||||
|  |     eor     x1, x2              ;[04] [12] | ||||||
|  |     ldi     x4, 6               ;[05] [13] | ||||||
|  | commonN2: | ||||||
|  |     nop                         ;[06] [14] | ||||||
|  |     subi    cnt, 171            ;[07] [15] trick: (3 * 171) & 0xff = 1 | ||||||
|  |     out     USBOUT, x1          ;[08] [16] <--- set bit | ||||||
|  |     brcs    txBitloop           ;[09]      [25] [41] | ||||||
|  | 
 | ||||||
|  | stuff6Delay: | ||||||
|  |     ror     shift               ;[42] [50] | ||||||
|  |     brcc    doExor6             ;[43] | ||||||
|  |     subi    x4, 1               ;[44] | ||||||
|  |     brne    common6             ;[45] | ||||||
|  |     lsl     shift               ;[46] compensate ror after rjmp stuffDelay | ||||||
|  |     nop                         ;[47] stuffing consists of just waiting 8 cycles | ||||||
|  |     rjmp    stuff6Delay         ;[48] after ror, C bit is reliably clear | ||||||
|  | doExor6: | ||||||
|  |     eor     x1, x2              ;[45] [53] | ||||||
|  |     ldi     x4, 6               ;[46] | ||||||
|  | common6: | ||||||
|  | stuff7Delay: | ||||||
|  |     ror     shift               ;[47] [55] | ||||||
|  |     out     USBOUT, x1          ;[48] <--- set bit | ||||||
|  |     brcc    doExor7             ;[49] | ||||||
|  |     subi    x4, 1               ;[50] | ||||||
|  |     brne    common7             ;[51] | ||||||
|  |     lsl     shift               ;[52] compensate ror after rjmp stuffDelay | ||||||
|  |     rjmp    stuff7Delay         ;[53] after ror, C bit is reliably clear | ||||||
|  | doExor7: | ||||||
|  |     eor     x1, x2              ;[51] [59] | ||||||
|  |     ldi     x4, 6               ;[52] | ||||||
|  | common7: | ||||||
|  |     ld      shift, y+           ;[53] | ||||||
|  |     tst     cnt                 ;[55] | ||||||
|  |     out     USBOUT, x1          ;[56] <--- set bit | ||||||
|  |     brne    txByteLoop          ;[57] | ||||||
|  | 
 | ||||||
|  | ;make SE0: | ||||||
|  |     cbr     x1, USBMASK         ;[58] prepare SE0 [spec says EOP may be 15 to 18 cycles] | ||||||
|  |     lds     x2, usbNewDeviceAddr;[59] | ||||||
|  |     lsl     x2                  ;[61] we compare with left shifted address | ||||||
|  |     subi    YL, 2 + 20          ;[62] Only assign address on data packets, not ACK/NAK in x3 | ||||||
|  |     sbci    YH, 0               ;[63] | ||||||
|  |     out     USBOUT, x1          ;[00] <-- out SE0 -- from now 2 bits = 16 cycles until bus idle | ||||||
|  | ;2006-03-06: moved transfer of new address to usbDeviceAddr from C-Code to asm: | ||||||
|  | ;set address only after data packet was sent, not after handshake | ||||||
|  |     breq    skipAddrAssign      ;[01] | ||||||
|  |     sts     usbDeviceAddr, x2   ; if not skipped: SE0 is one cycle longer | ||||||
|  | skipAddrAssign: | ||||||
|  | ;end of usbDeviceAddress transfer | ||||||
|  |     ldi     x2, 1<<USB_INTR_PENDING_BIT;[03] int0 occurred during TX -- clear pending flag | ||||||
|  |     USB_STORE_PENDING(x2)       ;[04] | ||||||
|  |     ori     x1, USBIDLE         ;[05] | ||||||
|  |     in      x2, USBDDR          ;[06] | ||||||
|  |     cbr     x2, USBMASK         ;[07] set both pins to input | ||||||
|  |     mov     x3, x1              ;[08] | ||||||
|  |     cbr     x3, USBMASK         ;[09] configure no pullup on both pins | ||||||
|  |     pop     x4                  ;[10] | ||||||
|  |     nop2                        ;[12] | ||||||
|  |     nop2                        ;[14] | ||||||
|  |     out     USBOUT, x1          ;[16] <-- out J (idle) -- end of SE0 (EOP signal) | ||||||
|  |     out     USBDDR, x2          ;[17] <-- release bus now | ||||||
|  |     out     USBOUT, x3          ;[18] <-- ensure no pull-up resistors are active | ||||||
|  |     rjmp    doReturn | ||||||
							
								
								
									
										749
									
								
								keyboards/planck/thk/bootloader/usbdrv/usbdrvasm128.inc
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										749
									
								
								keyboards/planck/thk/bootloader/usbdrv/usbdrvasm128.inc
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,749 @@ | |||||||
|  | /* Name: usbdrvasm128.inc | ||||||
|  |  * Project: V-USB, virtual USB port for Atmel's(r) AVR(r) microcontrollers | ||||||
|  |  * Author: Christian Starkjohann | ||||||
|  |  * Creation Date: 2008-10-11 | ||||||
|  |  * Tabsize: 4 | ||||||
|  |  * Copyright: (c) 2008 by OBJECTIVE DEVELOPMENT Software GmbH | ||||||
|  |  * License: GNU GPL v2 (see License.txt), GNU GPL v3 or proprietary (CommercialLicense.txt) | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | /* Do not link this file! Link usbdrvasm.S instead, which includes the | ||||||
|  |  * appropriate implementation! | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | /* | ||||||
|  | General Description: | ||||||
|  | This file is the 12.8 MHz version of the USB driver. It is intended for use | ||||||
|  | with the internal RC oscillator. Although 12.8 MHz is outside the guaranteed | ||||||
|  | calibration range of the oscillator, almost all AVRs can reach this frequency. | ||||||
|  | This version contains a phase locked loop in the receiver routine to cope with | ||||||
|  | slight clock rate deviations of up to +/- 1%. | ||||||
|  | 
 | ||||||
|  | See usbdrv.h for a description of the entire driver. | ||||||
|  | 
 | ||||||
|  | LIMITATIONS | ||||||
|  | =========== | ||||||
|  | Although it may seem very handy to save the crystal and use the internal | ||||||
|  | RC oscillator of the CPU, this method (and this module) has some serious | ||||||
|  | limitations: | ||||||
|  | (1) The guaranteed calibration range of the oscillator is only 8.1 MHz. | ||||||
|  | They typical range is 14.5 MHz and most AVRs can actually reach this rate. | ||||||
|  | (2) Writing EEPROM and Flash may be unreliable (short data lifetime) since | ||||||
|  | the write procedure is timed from the RC oscillator. | ||||||
|  | (3) End Of Packet detection (SE0) should be in bit 1, bit it is only checked | ||||||
|  | if bits 0 and 1 both read as 0 on D- and D+ read as 0 in the middle. This may | ||||||
|  | cause problems with old hubs which delay SE0 by up to one cycle. | ||||||
|  | (4) Code size is much larger than that of the other modules. | ||||||
|  | 
 | ||||||
|  | Since almost all of this code is timing critical, don't change unless you | ||||||
|  | really know what you are doing! Many parts require not only a maximum number | ||||||
|  | of CPU cycles, but even an exact number of cycles! | ||||||
|  | 
 | ||||||
|  | Implementation notes: | ||||||
|  | ====================== | ||||||
|  | min frequency: 67 cycles for 8 bit -> 12.5625 MHz | ||||||
|  | max frequency: 69.286 cycles for 8 bit -> 12.99 MHz | ||||||
|  | nominal frequency: 12.77 MHz ( = sqrt(min * max)) | ||||||
|  | 
 | ||||||
|  | sampling positions: (next even number in range [+/- 0.5]) | ||||||
|  | cycle index range: 0 ... 66 | ||||||
|  | bits: | ||||||
|  | .5, 8.875, 17.25, 25.625, 34, 42.375, 50.75, 59.125 | ||||||
|  | [0/1], [9], [17], [25/+26], [34], [+42/43], [51], [59] | ||||||
|  | 
 | ||||||
|  | bit number:     0   1   2   3   4   5   6   7 | ||||||
|  | spare cycles    1   2   1   2   1   1   1   0 | ||||||
|  | 
 | ||||||
|  | operations to perform:      duration cycle | ||||||
|  |                             ---------------- | ||||||
|  |     eor     fix, shift          1 -> 00 | ||||||
|  |     andi    phase, USBMASK      1 -> 08 | ||||||
|  |     breq    se0                 1 -> 16 (moved to 11) | ||||||
|  |     st      y+, data            2 -> 24, 25 | ||||||
|  |     mov     data, fix           1 -> 33 | ||||||
|  |     ser     data                1 -> 41 | ||||||
|  |     subi    cnt, 1              1 -> 49 | ||||||
|  |     brcs    overflow            1 -> 50 | ||||||
|  | 
 | ||||||
|  | layout of samples and operations: | ||||||
|  | [##] = sample bit
 | ||||||
|  | <##> = sample phase
 | ||||||
|  | *##* = operation
 | ||||||
|  | 
 | ||||||
|  | 0:  *00* [01]  02   03   04  <05>  06   07 | ||||||
|  | 1:  *08* [09]  10   11   12  <13>  14   15  *16* | ||||||
|  | 2:  [17]  18   19   20  <21>  22   23 | ||||||
|  | 3:  *24* *25* [26]  27   28   29  <30>  31   32 | ||||||
|  | 4:  *33* [34]  35   36   37  <38>  39   40 | ||||||
|  | 5:  *41* [42]  43   44   45  <46>  47   48 | ||||||
|  | 6:  *49* *50* [51]  52   53   54  <55>  56   57   58 | ||||||
|  | 7:  [59]  60   61   62  <63>  64   65   66 | ||||||
|  | *****************************************************************************/ | ||||||
|  | 
 | ||||||
|  | /* we prefer positive expressions (do if condition) instead of negative | ||||||
|  |  * (skip if condition), therefore use defines for skip instructions: | ||||||
|  |  */ | ||||||
|  | #define ifioclr sbis
 | ||||||
|  | #define ifioset sbic
 | ||||||
|  | #define ifrclr  sbrs
 | ||||||
|  | #define ifrset  sbrc
 | ||||||
|  | 
 | ||||||
|  | /* The registers "fix" and "data" swap their meaning during the loop. Use | ||||||
|  |  * defines to keep their name constant. | ||||||
|  |  */ | ||||||
|  | #define fix     x2
 | ||||||
|  | #define data    x1
 | ||||||
|  | #undef phase        /* phase has a default definition to x4 */
 | ||||||
|  | #define phase   x3
 | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | USB_INTR_VECTOR: | ||||||
|  | ;order of registers pushed: YL, SREG [sofError], YH, shift, x1, x2, x3, cnt, r0 | ||||||
|  |     push    YL              ;2 push only what is necessary to sync with edge ASAP | ||||||
|  |     in      YL, SREG        ;1 | ||||||
|  |     push    YL              ;2 | ||||||
|  | ;---------------------------------------------------------------------------- | ||||||
|  | ; Synchronize with sync pattern: | ||||||
|  | ;---------------------------------------------------------------------------- | ||||||
|  | ;sync byte (D-) pattern LSb to MSb: 01010100 [1 = idle = J, 0 = K] | ||||||
|  | ;sync up with J to K edge during sync pattern -- use fastest possible loops | ||||||
|  | ;The first part waits at most 1 bit long since we must be in sync pattern. | ||||||
|  | ;YL is guarenteed to be < 0x80 because I flag is clear. When we jump to | ||||||
|  | ;waitForJ, ensure that this prerequisite is met. | ||||||
|  | waitForJ: | ||||||
|  |     inc     YL | ||||||
|  |     sbis    USBIN, USBMINUS | ||||||
|  |     brne    waitForJ        ; just make sure we have ANY timeout | ||||||
|  | waitForK: | ||||||
|  | ;The following code results in a sampling window of 1/4 bit which meets the spec. | ||||||
|  |     sbis    USBIN, USBMINUS | ||||||
|  |     rjmp    foundK | ||||||
|  |     sbis    USBIN, USBMINUS | ||||||
|  |     rjmp    foundK | ||||||
|  |     sbis    USBIN, USBMINUS | ||||||
|  |     rjmp    foundK | ||||||
|  |     sbis    USBIN, USBMINUS | ||||||
|  |     rjmp    foundK | ||||||
|  |     sbis    USBIN, USBMINUS ;[0] | ||||||
|  |     rjmp    foundK          ;[1] | ||||||
|  | #if USB_COUNT_SOF
 | ||||||
|  |     lds     YL, usbSofCount | ||||||
|  |     inc     YL | ||||||
|  |     sts     usbSofCount, YL | ||||||
|  | #endif  /* USB_COUNT_SOF */
 | ||||||
|  | #ifdef USB_SOF_HOOK
 | ||||||
|  |     USB_SOF_HOOK | ||||||
|  | #endif
 | ||||||
|  |     rjmp    sofError | ||||||
|  | 
 | ||||||
|  | foundK: | ||||||
|  | ;{3, 5} after falling D- edge, average delay: 4 cycles [we want 4 for center sampling] | ||||||
|  | ;we have 1 bit time for setup purposes, then sample again. Numbers in brackets | ||||||
|  | ;are cycles from center of first sync (double K) bit after the instruction | ||||||
|  |     push    YH                  ;[2] | ||||||
|  |     lds     YL, usbInputBufOffset;[4] | ||||||
|  |     clr     YH                  ;[6] | ||||||
|  |     subi    YL, lo8(-(usbRxBuf));[7] | ||||||
|  |     sbci    YH, hi8(-(usbRxBuf));[8] | ||||||
|  | 
 | ||||||
|  |     sbis    USBIN, USBMINUS     ;[9] we want two bits K [we want to sample at 8 + 4 - 1.5 = 10.5] | ||||||
|  |     rjmp    haveTwoBitsK        ;[10] | ||||||
|  |     pop     YH                  ;[11] undo the push from before | ||||||
|  |     rjmp    waitForK            ;[13] this was not the end of sync, retry | ||||||
|  | haveTwoBitsK: | ||||||
|  | ;---------------------------------------------------------------------------- | ||||||
|  | ; push more registers and initialize values while we sample the first bits: | ||||||
|  | ;---------------------------------------------------------------------------- | ||||||
|  | #define fix     x2
 | ||||||
|  | #define data    x1
 | ||||||
|  | 
 | ||||||
|  |     push    shift               ;[12] | ||||||
|  |     push    x1                  ;[14] | ||||||
|  |     push    x2                  ;[16] | ||||||
|  |     ldi     shift, 0x80         ;[18] prevent bit-unstuffing but init low bits to 0 | ||||||
|  |     ifioset USBIN, USBMINUS     ;[19] [01] <--- bit 0 [10.5 + 8 = 18.5] | ||||||
|  |     ori     shift, 1<<0         ;[02] | ||||||
|  |     push    x3                  ;[03] | ||||||
|  |     push    cnt                 ;[05] | ||||||
|  |     push    r0                  ;[07] | ||||||
|  |     ifioset USBIN, USBMINUS     ;[09] <--- bit 1 | ||||||
|  |     ori     shift, 1<<1         ;[10] | ||||||
|  |     ser     fix                 ;[11] | ||||||
|  |     ldi     cnt, USB_BUFSIZE    ;[12] | ||||||
|  |     mov     data, shift         ;[13] | ||||||
|  |     lsl     shift               ;[14] | ||||||
|  |     nop2                        ;[15] | ||||||
|  |     ifioset USBIN, USBMINUS     ;[17] <--- bit 2 | ||||||
|  |     ori     data, 3<<2          ;[18] store in bit 2 AND bit 3 | ||||||
|  |     eor     shift, data         ;[19] do nrzi decoding | ||||||
|  |     andi    data, 1<<3          ;[20] | ||||||
|  |     in      phase, USBIN        ;[21] <- phase | ||||||
|  |     brne    jumpToEntryAfterSet ;[22] if USBMINS at bit 3 was 1 | ||||||
|  |     nop                         ;[23] | ||||||
|  |     rjmp    entryAfterClr       ;[24] | ||||||
|  | jumpToEntryAfterSet: | ||||||
|  |     rjmp    entryAfterSet       ;[24] | ||||||
|  | 
 | ||||||
|  | ;---------------------------------------------------------------------------- | ||||||
|  | ; Receiver loop (numbers in brackets are cycles within byte after instr) | ||||||
|  | ;---------------------------------------------------------------------------- | ||||||
|  | #undef  fix
 | ||||||
|  | #define  fix    x1
 | ||||||
|  | #undef  data
 | ||||||
|  | #define data    x2
 | ||||||
|  | 
 | ||||||
|  | bit7IsSet: | ||||||
|  |     ifrclr  phase, USBMINUS     ;[62] check phase only if D- changed | ||||||
|  |     lpm                         ;[63] | ||||||
|  |     in      phase, USBIN        ;[64] <- phase (one cycle too late) | ||||||
|  |     ori     shift, 1 << 7       ;[65] | ||||||
|  |     nop                         ;[66] | ||||||
|  | ;;;;rjmp    bit0AfterSet        ; -> [00] == [67] moved block up to save jump | ||||||
|  | bit0AfterSet: | ||||||
|  |     eor     fix, shift          ;[00] | ||||||
|  | #undef  fix
 | ||||||
|  | #define fix     x2
 | ||||||
|  | #undef  data
 | ||||||
|  | #define data    x1  /* we now have result in data, fix is reset to 0xff */
 | ||||||
|  |     ifioclr USBIN, USBMINUS     ;[01] <--- sample 0 | ||||||
|  |     rjmp    bit0IsClr           ;[02] | ||||||
|  |     andi    shift, ~(7 << 0)    ;[03] | ||||||
|  |     breq    unstuff0s           ;[04] | ||||||
|  |     in      phase, USBIN        ;[05] <- phase | ||||||
|  |     rjmp    bit1AfterSet        ;[06] | ||||||
|  | unstuff0s: | ||||||
|  |     in      phase, USBIN        ;[06] <- phase (one cycle too late) | ||||||
|  |     andi    fix, ~(1 << 0)      ;[07] | ||||||
|  |     ifioclr USBIN, USBMINUS     ;[00] | ||||||
|  |     ifioset USBIN, USBPLUS      ;[01] | ||||||
|  |     rjmp    bit0IsClr           ;[02] executed if first expr false or second true | ||||||
|  | se0AndStore:                    ; executed only if both bits 0 | ||||||
|  |     st      y+, x1              ;[15/17] cycles after start of byte | ||||||
|  |     rjmp    se0                 ;[17/19] | ||||||
|  | 
 | ||||||
|  | bit0IsClr: | ||||||
|  |     ifrset  phase, USBMINUS     ;[04] check phase only if D- changed | ||||||
|  |     lpm                         ;[05] | ||||||
|  |     in      phase, USBIN        ;[06] <- phase (one cycle too late) | ||||||
|  |     ori     shift, 1 << 0       ;[07] | ||||||
|  | bit1AfterClr: | ||||||
|  |     andi    phase, USBMASK      ;[08] | ||||||
|  |     ifioset USBIN, USBMINUS     ;[09] <--- sample 1 | ||||||
|  |     rjmp    bit1IsSet           ;[10] | ||||||
|  |     breq    se0AndStore         ;[11] if D- was 0 in bits 0 AND 1 and D+ was 0 in between, we have SE0 | ||||||
|  |     andi    shift, ~(7 << 1)    ;[12] | ||||||
|  |     in      phase, USBIN        ;[13] <- phase | ||||||
|  |     breq    unstuff1c           ;[14] | ||||||
|  |     rjmp    bit2AfterClr        ;[15] | ||||||
|  | unstuff1c: | ||||||
|  |     andi    fix, ~(1 << 1)      ;[16] | ||||||
|  |     nop2                        ;[08] | ||||||
|  |     nop2                        ;[10] | ||||||
|  | bit1IsSet: | ||||||
|  |     ifrclr  phase, USBMINUS     ;[12] check phase only if D- changed | ||||||
|  |     lpm                         ;[13] | ||||||
|  |     in      phase, USBIN        ;[14] <- phase (one cycle too late) | ||||||
|  |     ori     shift, 1 << 1       ;[15] | ||||||
|  |     nop                         ;[16] | ||||||
|  | bit2AfterSet: | ||||||
|  |     ifioclr USBIN, USBMINUS     ;[17] <--- sample 2 | ||||||
|  |     rjmp    bit2IsClr           ;[18] | ||||||
|  |     andi    shift, ~(7 << 2)    ;[19] | ||||||
|  |     breq    unstuff2s           ;[20] | ||||||
|  |     in      phase, USBIN        ;[21] <- phase | ||||||
|  |     rjmp    bit3AfterSet        ;[22] | ||||||
|  | unstuff2s: | ||||||
|  |     in      phase, USBIN        ;[22] <- phase (one cycle too late) | ||||||
|  |     andi    fix, ~(1 << 2)      ;[23] | ||||||
|  |     nop2                        ;[16] | ||||||
|  |     nop2                        ;[18] | ||||||
|  | bit2IsClr: | ||||||
|  |     ifrset  phase, USBMINUS     ;[20] check phase only if D- changed | ||||||
|  |     lpm                         ;[21] | ||||||
|  |     in      phase, USBIN        ;[22] <- phase (one cycle too late) | ||||||
|  |     ori     shift, 1 << 2       ;[23] | ||||||
|  | bit3AfterClr: | ||||||
|  |     st      y+, data            ;[24] | ||||||
|  | entryAfterClr: | ||||||
|  |     ifioset USBIN, USBMINUS     ;[26] <--- sample 3 | ||||||
|  |     rjmp    bit3IsSet           ;[27] | ||||||
|  |     andi    shift, ~(7 << 3)    ;[28] | ||||||
|  |     breq    unstuff3c           ;[29] | ||||||
|  |     in      phase, USBIN        ;[30] <- phase | ||||||
|  |     rjmp    bit4AfterClr        ;[31] | ||||||
|  | unstuff3c: | ||||||
|  |     in      phase, USBIN        ;[31] <- phase (one cycle too late) | ||||||
|  |     andi    fix, ~(1 << 3)      ;[32] | ||||||
|  |     nop2                        ;[25] | ||||||
|  |     nop2                        ;[27] | ||||||
|  | bit3IsSet: | ||||||
|  |     ifrclr  phase, USBMINUS     ;[29] check phase only if D- changed | ||||||
|  |     lpm                         ;[30] | ||||||
|  |     in      phase, USBIN        ;[31] <- phase (one cycle too late) | ||||||
|  |     ori     shift, 1 << 3       ;[32] | ||||||
|  | bit4AfterSet: | ||||||
|  |     mov     data, fix           ;[33] undo this move by swapping defines | ||||||
|  | #undef  fix
 | ||||||
|  | #define fix     x1
 | ||||||
|  | #undef  data
 | ||||||
|  | #define data    x2
 | ||||||
|  |     ifioclr USBIN, USBMINUS     ;[34] <--- sample 4 | ||||||
|  |     rjmp    bit4IsClr           ;[35] | ||||||
|  |     andi    shift, ~(7 << 4)    ;[36] | ||||||
|  |     breq    unstuff4s           ;[37] | ||||||
|  |     in      phase, USBIN        ;[38] <- phase | ||||||
|  |     rjmp    bit5AfterSet        ;[39] | ||||||
|  | unstuff4s: | ||||||
|  |     in      phase, USBIN        ;[39] <- phase (one cycle too late) | ||||||
|  |     andi    fix, ~(1 << 4)      ;[40] | ||||||
|  |     nop2                        ;[33] | ||||||
|  |     nop2                        ;[35] | ||||||
|  | bit4IsClr: | ||||||
|  |     ifrset  phase, USBMINUS     ;[37] check phase only if D- changed | ||||||
|  |     lpm                         ;[38] | ||||||
|  |     in      phase, USBIN        ;[39] <- phase (one cycle too late) | ||||||
|  |     ori     shift, 1 << 4       ;[40] | ||||||
|  | bit5AfterClr: | ||||||
|  |     ser     data                ;[41] | ||||||
|  |     ifioset USBIN, USBMINUS     ;[42] <--- sample 5 | ||||||
|  |     rjmp    bit5IsSet           ;[43] | ||||||
|  |     andi    shift, ~(7 << 5)    ;[44] | ||||||
|  |     breq    unstuff5c           ;[45] | ||||||
|  |     in      phase, USBIN        ;[46] <- phase | ||||||
|  |     rjmp    bit6AfterClr        ;[47] | ||||||
|  | unstuff5c: | ||||||
|  |     in      phase, USBIN        ;[47] <- phase (one cycle too late) | ||||||
|  |     andi    fix, ~(1 << 5)      ;[48] | ||||||
|  |     nop2                        ;[41] | ||||||
|  |     nop2                        ;[43] | ||||||
|  | bit5IsSet: | ||||||
|  |     ifrclr  phase, USBMINUS     ;[45] check phase only if D- changed | ||||||
|  |     lpm                         ;[46] | ||||||
|  |     in      phase, USBIN        ;[47] <- phase (one cycle too late) | ||||||
|  |     ori     shift, 1 << 5       ;[48] | ||||||
|  | bit6AfterSet: | ||||||
|  |     subi    cnt, 1              ;[49] | ||||||
|  |     brcs    jumpToOverflow      ;[50] | ||||||
|  |     ifioclr USBIN, USBMINUS     ;[51] <--- sample 6 | ||||||
|  |     rjmp    bit6IsClr           ;[52] | ||||||
|  |     andi    shift, ~(3 << 6)    ;[53] | ||||||
|  |     cpi     shift, 2            ;[54] | ||||||
|  |     in      phase, USBIN        ;[55] <- phase | ||||||
|  |     brlt    unstuff6s           ;[56] | ||||||
|  |     rjmp    bit7AfterSet        ;[57] | ||||||
|  | 
 | ||||||
|  | jumpToOverflow: | ||||||
|  |     rjmp    overflow | ||||||
|  | 
 | ||||||
|  | unstuff6s: | ||||||
|  |     andi    fix, ~(1 << 6)      ;[50] | ||||||
|  |     lpm                         ;[51] | ||||||
|  | bit6IsClr: | ||||||
|  |     ifrset  phase, USBMINUS     ;[54] check phase only if D- changed | ||||||
|  |     lpm                         ;[55] | ||||||
|  |     in      phase, USBIN        ;[56] <- phase (one cycle too late) | ||||||
|  |     ori     shift, 1 << 6       ;[57] | ||||||
|  |     nop                         ;[58] | ||||||
|  | bit7AfterClr: | ||||||
|  |     ifioset USBIN, USBMINUS     ;[59] <--- sample 7 | ||||||
|  |     rjmp    bit7IsSet           ;[60] | ||||||
|  |     andi    shift, ~(1 << 7)    ;[61] | ||||||
|  |     cpi     shift, 4            ;[62] | ||||||
|  |     in      phase, USBIN        ;[63] <- phase | ||||||
|  |     brlt    unstuff7c           ;[64] | ||||||
|  |     rjmp    bit0AfterClr        ;[65] -> [00] == [67] | ||||||
|  | unstuff7c: | ||||||
|  |     andi    fix, ~(1 << 7)      ;[58] | ||||||
|  |     nop                         ;[59] | ||||||
|  |     rjmp    bit7IsSet           ;[60] | ||||||
|  | 
 | ||||||
|  | bit7IsClr: | ||||||
|  |     ifrset  phase, USBMINUS     ;[62] check phase only if D- changed | ||||||
|  |     lpm                         ;[63] | ||||||
|  |     in      phase, USBIN        ;[64] <- phase (one cycle too late) | ||||||
|  |     ori     shift, 1 << 7       ;[65] | ||||||
|  |     nop                         ;[66] | ||||||
|  | ;;;;rjmp    bit0AfterClr        ; -> [00] == [67] moved block up to save jump | ||||||
|  | bit0AfterClr: | ||||||
|  |     eor     fix, shift          ;[00] | ||||||
|  | #undef  fix
 | ||||||
|  | #define fix     x2
 | ||||||
|  | #undef  data
 | ||||||
|  | #define data    x1  /* we now have result in data, fix is reset to 0xff */
 | ||||||
|  |     ifioset USBIN, USBMINUS     ;[01] <--- sample 0 | ||||||
|  |     rjmp    bit0IsSet           ;[02] | ||||||
|  |     andi    shift, ~(7 << 0)    ;[03] | ||||||
|  |     breq    unstuff0c           ;[04] | ||||||
|  |     in      phase, USBIN        ;[05] <- phase | ||||||
|  |     rjmp    bit1AfterClr        ;[06] | ||||||
|  | unstuff0c: | ||||||
|  |     in      phase, USBIN        ;[06] <- phase (one cycle too late) | ||||||
|  |     andi    fix, ~(1 << 0)      ;[07] | ||||||
|  |     ifioclr USBIN, USBMINUS     ;[00] | ||||||
|  |     ifioset USBIN, USBPLUS      ;[01] | ||||||
|  |     rjmp    bit0IsSet           ;[02] executed if first expr false or second true | ||||||
|  |     rjmp    se0AndStore         ;[03] executed only if both bits 0 | ||||||
|  | bit0IsSet: | ||||||
|  |     ifrclr  phase, USBMINUS     ;[04] check phase only if D- changed | ||||||
|  |     lpm                         ;[05] | ||||||
|  |     in      phase, USBIN        ;[06] <- phase (one cycle too late) | ||||||
|  |     ori     shift, 1 << 0       ;[07] | ||||||
|  | bit1AfterSet: | ||||||
|  |     andi    shift, ~(7 << 1)    ;[08] compensated by "ori shift, 1<<1" if bit1IsClr | ||||||
|  |     ifioclr USBIN, USBMINUS     ;[09] <--- sample 1 | ||||||
|  |     rjmp    bit1IsClr           ;[10] | ||||||
|  |     breq    unstuff1s           ;[11] | ||||||
|  |     nop2                        ;[12] do not check for SE0 if bit 0 was 1 | ||||||
|  |     in      phase, USBIN        ;[14] <- phase (one cycle too late) | ||||||
|  |     rjmp    bit2AfterSet        ;[15] | ||||||
|  | unstuff1s: | ||||||
|  |     in      phase, USBIN        ;[13] <- phase | ||||||
|  |     andi    fix, ~(1 << 1)      ;[14] | ||||||
|  |     lpm                         ;[07] | ||||||
|  |     nop2                        ;[10] | ||||||
|  | bit1IsClr: | ||||||
|  |     ifrset  phase, USBMINUS     ;[12] check phase only if D- changed | ||||||
|  |     lpm                         ;[13] | ||||||
|  |     in      phase, USBIN        ;[14] <- phase (one cycle too late) | ||||||
|  |     ori     shift, 1 << 1       ;[15] | ||||||
|  |     nop                         ;[16] | ||||||
|  | bit2AfterClr: | ||||||
|  |     ifioset USBIN, USBMINUS     ;[17] <--- sample 2 | ||||||
|  |     rjmp    bit2IsSet           ;[18] | ||||||
|  |     andi    shift, ~(7 << 2)    ;[19] | ||||||
|  |     breq    unstuff2c           ;[20] | ||||||
|  |     in      phase, USBIN        ;[21] <- phase | ||||||
|  |     rjmp    bit3AfterClr        ;[22] | ||||||
|  | unstuff2c: | ||||||
|  |     in      phase, USBIN        ;[22] <- phase (one cycle too late) | ||||||
|  |     andi    fix, ~(1 << 2)      ;[23] | ||||||
|  |     nop2                        ;[16] | ||||||
|  |     nop2                        ;[18] | ||||||
|  | bit2IsSet: | ||||||
|  |     ifrclr  phase, USBMINUS     ;[20] check phase only if D- changed | ||||||
|  |     lpm                         ;[21] | ||||||
|  |     in      phase, USBIN        ;[22] <- phase (one cycle too late) | ||||||
|  |     ori     shift, 1 << 2       ;[23] | ||||||
|  | bit3AfterSet: | ||||||
|  |     st      y+, data            ;[24] | ||||||
|  | entryAfterSet: | ||||||
|  |     ifioclr USBIN, USBMINUS     ;[26] <--- sample 3 | ||||||
|  |     rjmp    bit3IsClr           ;[27] | ||||||
|  |     andi    shift, ~(7 << 3)    ;[28] | ||||||
|  |     breq    unstuff3s           ;[29] | ||||||
|  |     in      phase, USBIN        ;[30] <- phase | ||||||
|  |     rjmp    bit4AfterSet        ;[31] | ||||||
|  | unstuff3s: | ||||||
|  |     in      phase, USBIN        ;[31] <- phase (one cycle too late) | ||||||
|  |     andi    fix, ~(1 << 3)      ;[32] | ||||||
|  |     nop2                        ;[25] | ||||||
|  |     nop2                        ;[27] | ||||||
|  | bit3IsClr: | ||||||
|  |     ifrset  phase, USBMINUS     ;[29] check phase only if D- changed | ||||||
|  |     lpm                         ;[30] | ||||||
|  |     in      phase, USBIN        ;[31] <- phase (one cycle too late) | ||||||
|  |     ori     shift, 1 << 3       ;[32] | ||||||
|  | bit4AfterClr: | ||||||
|  |     mov     data, fix           ;[33] undo this move by swapping defines | ||||||
|  | #undef  fix
 | ||||||
|  | #define fix     x1
 | ||||||
|  | #undef  data
 | ||||||
|  | #define data    x2
 | ||||||
|  |     ifioset USBIN, USBMINUS     ;[34] <--- sample 4 | ||||||
|  |     rjmp    bit4IsSet           ;[35] | ||||||
|  |     andi    shift, ~(7 << 4)    ;[36] | ||||||
|  |     breq    unstuff4c           ;[37] | ||||||
|  |     in      phase, USBIN        ;[38] <- phase | ||||||
|  |     rjmp    bit5AfterClr        ;[39] | ||||||
|  | unstuff4c: | ||||||
|  |     in      phase, USBIN        ;[39] <- phase (one cycle too late) | ||||||
|  |     andi    fix, ~(1 << 4)      ;[40] | ||||||
|  |     nop2                        ;[33] | ||||||
|  |     nop2                        ;[35] | ||||||
|  | bit4IsSet: | ||||||
|  |     ifrclr  phase, USBMINUS     ;[37] check phase only if D- changed | ||||||
|  |     lpm                         ;[38] | ||||||
|  |     in      phase, USBIN        ;[39] <- phase (one cycle too late) | ||||||
|  |     ori     shift, 1 << 4       ;[40] | ||||||
|  | bit5AfterSet: | ||||||
|  |     ser     data                ;[41] | ||||||
|  |     ifioclr USBIN, USBMINUS     ;[42] <--- sample 5 | ||||||
|  |     rjmp    bit5IsClr           ;[43] | ||||||
|  |     andi    shift, ~(7 << 5)    ;[44] | ||||||
|  |     breq    unstuff5s           ;[45] | ||||||
|  |     in      phase, USBIN        ;[46] <- phase | ||||||
|  |     rjmp    bit6AfterSet        ;[47] | ||||||
|  | unstuff5s: | ||||||
|  |     in      phase, USBIN        ;[47] <- phase (one cycle too late) | ||||||
|  |     andi    fix, ~(1 << 5)      ;[48] | ||||||
|  |     nop2                        ;[41] | ||||||
|  |     nop2                        ;[43] | ||||||
|  | bit5IsClr: | ||||||
|  |     ifrset  phase, USBMINUS     ;[45] check phase only if D- changed | ||||||
|  |     lpm                         ;[46] | ||||||
|  |     in      phase, USBIN        ;[47] <- phase (one cycle too late) | ||||||
|  |     ori     shift, 1 << 5       ;[48] | ||||||
|  | bit6AfterClr: | ||||||
|  |     subi    cnt, 1              ;[49] | ||||||
|  |     brcs    overflow            ;[50] | ||||||
|  |     ifioset USBIN, USBMINUS     ;[51] <--- sample 6 | ||||||
|  |     rjmp    bit6IsSet           ;[52] | ||||||
|  |     andi    shift, ~(3 << 6)    ;[53] | ||||||
|  |     cpi     shift, 2            ;[54] | ||||||
|  |     in      phase, USBIN        ;[55] <- phase | ||||||
|  |     brlt    unstuff6c           ;[56] | ||||||
|  |     rjmp    bit7AfterClr        ;[57] | ||||||
|  | unstuff6c: | ||||||
|  |     andi    fix, ~(1 << 6)      ;[50] | ||||||
|  |     lpm                         ;[51] | ||||||
|  | bit6IsSet: | ||||||
|  |     ifrclr  phase, USBMINUS     ;[54] check phase only if D- changed | ||||||
|  |     lpm                         ;[55] | ||||||
|  |     in      phase, USBIN        ;[56] <- phase (one cycle too late) | ||||||
|  |     ori     shift, 1 << 6       ;[57] | ||||||
|  | bit7AfterSet: | ||||||
|  |     ifioclr USBIN, USBMINUS     ;[59] <--- sample 7 | ||||||
|  |     rjmp    bit7IsClr           ;[60] | ||||||
|  |     andi    shift, ~(1 << 7)    ;[61] | ||||||
|  |     cpi     shift, 4            ;[62] | ||||||
|  |     in      phase, USBIN        ;[63] <- phase | ||||||
|  |     brlt    unstuff7s           ;[64] | ||||||
|  |     rjmp    bit0AfterSet        ;[65] -> [00] == [67] | ||||||
|  | unstuff7s: | ||||||
|  |     andi    fix, ~(1 << 7)      ;[58] | ||||||
|  |     nop                         ;[59] | ||||||
|  |     rjmp    bit7IsClr           ;[60] | ||||||
|  | 
 | ||||||
|  | macro POP_STANDARD ; 14 cycles | ||||||
|  |     pop     r0 | ||||||
|  |     pop     cnt | ||||||
|  |     pop     x3 | ||||||
|  |     pop     x2 | ||||||
|  |     pop     x1 | ||||||
|  |     pop     shift | ||||||
|  |     pop     YH | ||||||
|  |     endm | ||||||
|  | macro POP_RETI     ; 5 cycles | ||||||
|  |     pop     YL | ||||||
|  |     out     SREG, YL | ||||||
|  |     pop     YL | ||||||
|  |     endm | ||||||
|  | 
 | ||||||
|  | #include "asmcommon.inc"
 | ||||||
|  | 
 | ||||||
|  | ;---------------------------------------------------------------------------- | ||||||
|  | ; Transmitting data | ||||||
|  | ;---------------------------------------------------------------------------- | ||||||
|  | 
 | ||||||
|  | txByteLoop: | ||||||
|  | txBitloop: | ||||||
|  | stuffN1Delay:                   ;     [03] | ||||||
|  |     ror     shift               ;[-5] [11] [63] | ||||||
|  |     brcc    doExorN1            ;[-4]      [64] | ||||||
|  |     subi    x3, 1               ;[-3] | ||||||
|  |     brne    commonN1            ;[-2] | ||||||
|  |     lsl     shift               ;[-1] compensate ror after rjmp stuffDelay | ||||||
|  |     nop                         ;[00] stuffing consists of just waiting 8 cycles | ||||||
|  |     rjmp    stuffN1Delay        ;[01] after ror, C bit is reliably clear | ||||||
|  | 
 | ||||||
|  | sendNakAndReti: | ||||||
|  |     ldi     cnt, USBPID_NAK ;[-19] | ||||||
|  |     rjmp    sendCntAndReti  ;[-18] | ||||||
|  | sendAckAndReti: | ||||||
|  |     ldi     cnt, USBPID_ACK ;[-17] | ||||||
|  | sendCntAndReti: | ||||||
|  |     mov     r0, cnt         ;[-16] | ||||||
|  |     ldi     YL, 0           ;[-15] R0 address is 0 | ||||||
|  |     ldi     YH, 0           ;[-14] | ||||||
|  |     ldi     cnt, 2          ;[-13] | ||||||
|  | ;   rjmp    usbSendAndReti      fallthrough | ||||||
|  | 
 | ||||||
|  | ; USB spec says: | ||||||
|  | ; idle = J | ||||||
|  | ; J = (D+ = 0), (D- = 1) or USBOUT = 0x01 | ||||||
|  | ; K = (D+ = 1), (D- = 0) or USBOUT = 0x02 | ||||||
|  | ; Spec allows 7.5 bit times from EOP to SOP for replies (= 60 cycles) | ||||||
|  | 
 | ||||||
|  | ;usbSend: | ||||||
|  | ;pointer to data in 'Y' | ||||||
|  | ;number of bytes in 'cnt' -- including sync byte | ||||||
|  | ;uses: x1...x3, shift, cnt, Y [x1 = mirror USBOUT, x2 = USBMASK, x3 = bitstuff cnt] | ||||||
|  | ;Numbers in brackets are time since first bit of sync pattern is sent (start of instruction) | ||||||
|  | usbSendAndReti: | ||||||
|  |     in      x2, USBDDR          ;[-10] 10 cycles until SOP | ||||||
|  |     ori     x2, USBMASK         ;[-9] | ||||||
|  |     sbi     USBOUT, USBMINUS    ;[-8] prepare idle state; D+ and D- must have been 0 (no pullups) | ||||||
|  |     out     USBDDR, x2          ;[-6] <--- acquire bus | ||||||
|  |     in      x1, USBOUT          ;[-5] port mirror for tx loop | ||||||
|  |     ldi     shift, 0x40         ;[-4] sync byte is first byte sent (we enter loop after ror) | ||||||
|  |     ldi     x2, USBMASK         ;[-3] | ||||||
|  | doExorN1: | ||||||
|  |     eor     x1, x2              ;[-2] [06] [62] | ||||||
|  |     ldi     x3, 6               ;[-1] [07] [63] | ||||||
|  | commonN1: | ||||||
|  | stuffN2Delay: | ||||||
|  |     out     USBOUT, x1          ;[00] [08] [64] <--- set bit | ||||||
|  |     ror     shift               ;[01] | ||||||
|  |     brcc    doExorN2            ;[02] | ||||||
|  |     subi    x3, 1               ;[03] | ||||||
|  |     brne    commonN2            ;[04] | ||||||
|  |     lsl     shift               ;[05] compensate ror after rjmp stuffDelay | ||||||
|  |     rjmp    stuffN2Delay        ;[06] after ror, C bit is reliably clear | ||||||
|  | doExorN2: | ||||||
|  |     eor     x1, x2              ;[04] [12] | ||||||
|  |     ldi     x3, 6               ;[05] [13] | ||||||
|  | commonN2: | ||||||
|  |     nop2                        ;[06] [14] | ||||||
|  |     subi    cnt, 171            ;[08] [16] trick: (3 * 171) & 0xff = 1 | ||||||
|  |     out     USBOUT, x1          ;[09] [17] <--- set bit | ||||||
|  |     brcs    txBitloop           ;[10]      [27] [44] | ||||||
|  | 
 | ||||||
|  | stuff6Delay: | ||||||
|  |     ror     shift               ;[45] [53] | ||||||
|  |     brcc    doExor6             ;[46] | ||||||
|  |     subi    x3, 1               ;[47] | ||||||
|  |     brne    common6             ;[48] | ||||||
|  |     lsl     shift               ;[49] compensate ror after rjmp stuffDelay | ||||||
|  |     nop                         ;[50] stuffing consists of just waiting 8 cycles | ||||||
|  |     rjmp    stuff6Delay         ;[51] after ror, C bit is reliably clear | ||||||
|  | doExor6: | ||||||
|  |     eor     x1, x2              ;[48] [56] | ||||||
|  |     ldi     x3, 6               ;[49] | ||||||
|  | common6: | ||||||
|  | stuff7Delay: | ||||||
|  |     ror     shift               ;[50] [58] | ||||||
|  |     out     USBOUT, x1          ;[51] <--- set bit | ||||||
|  |     brcc    doExor7             ;[52] | ||||||
|  |     subi    x3, 1               ;[53] | ||||||
|  |     brne    common7             ;[54] | ||||||
|  |     lsl     shift               ;[55] compensate ror after rjmp stuffDelay | ||||||
|  |     rjmp    stuff7Delay         ;[56] after ror, C bit is reliably clear | ||||||
|  | doExor7: | ||||||
|  |     eor     x1, x2              ;[54] [62] | ||||||
|  |     ldi     x3, 6               ;[55] | ||||||
|  | common7: | ||||||
|  |     ld      shift, y+           ;[56] | ||||||
|  |     nop                         ;[58] | ||||||
|  |     tst     cnt                 ;[59] | ||||||
|  |     out     USBOUT, x1          ;[60] [00]<--- set bit | ||||||
|  |     brne    txByteLoop          ;[61] [01] | ||||||
|  | ;make SE0: | ||||||
|  |     cbr     x1, USBMASK         ;[02] prepare SE0 [spec says EOP may be 15 to 18 cycles] | ||||||
|  |     lds     x2, usbNewDeviceAddr;[03] | ||||||
|  |     lsl     x2                  ;[05] we compare with left shifted address | ||||||
|  |     subi    YL, 2 + 0           ;[06] Only assign address on data packets, not ACK/NAK in r0 | ||||||
|  |     sbci    YH, 0               ;[07] | ||||||
|  |     out     USBOUT, x1          ;[00] <-- out SE0 -- from now 2 bits = 16 cycles until bus idle | ||||||
|  | ;2006-03-06: moved transfer of new address to usbDeviceAddr from C-Code to asm: | ||||||
|  | ;set address only after data packet was sent, not after handshake | ||||||
|  |     breq    skipAddrAssign      ;[01] | ||||||
|  |     sts     usbDeviceAddr, x2   ; if not skipped: SE0 is one cycle longer | ||||||
|  | skipAddrAssign: | ||||||
|  | ;end of usbDeviceAddress transfer | ||||||
|  |     ldi     x2, 1<<USB_INTR_PENDING_BIT;[03] int0 occurred during TX -- clear pending flag | ||||||
|  |     USB_STORE_PENDING(x2)       ;[04] | ||||||
|  |     ori     x1, USBIDLE         ;[05] | ||||||
|  |     in      x2, USBDDR          ;[06] | ||||||
|  |     cbr     x2, USBMASK         ;[07] set both pins to input | ||||||
|  |     mov     x3, x1              ;[08] | ||||||
|  |     cbr     x3, USBMASK         ;[09] configure no pullup on both pins | ||||||
|  |     lpm                         ;[10] | ||||||
|  |     lpm                         ;[13] | ||||||
|  |     out     USBOUT, x1          ;[16] <-- out J (idle) -- end of SE0 (EOP signal) | ||||||
|  |     out     USBDDR, x2          ;[17] <-- release bus now | ||||||
|  |     out     USBOUT, x3          ;[18] <-- ensure no pull-up resistors are active | ||||||
|  |     rjmp    doReturn | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | /***************************************************************************** | ||||||
|  | The following PHP script generates a code skeleton for the receiver routine: | ||||||
|  | 
 | ||||||
|  | <?php | ||||||
|  | 
 | ||||||
|  | function printCmdBuffer($thisBit) | ||||||
|  | { | ||||||
|  | global $cycle; | ||||||
|  | 
 | ||||||
|  |     $nextBit = ($thisBit + 1) % 8; | ||||||
|  |     $s = ob_get_contents(); | ||||||
|  |     ob_end_clean(); | ||||||
|  |     $s = str_replace("#", $thisBit, $s); | ||||||
|  |     $s = str_replace("@", $nextBit, $s); | ||||||
|  |     $lines = explode("\n", $s); | ||||||
|  |     for($i = 0; $i < count($lines); $i++){ | ||||||
|  |         $s = $lines[$i]; | ||||||
|  |         if(ereg("\\[([0-9-][0-9])\\]", $s, $regs)){ | ||||||
|  |             $c = $cycle + (int)$regs[1]; | ||||||
|  |             $s = ereg_replace("\\[[0-9-][0-9]\\]", sprintf("[%02d]", $c), $s); | ||||||
|  |         } | ||||||
|  |         if(strlen($s) > 0) | ||||||
|  |             echo "$s\n"; | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | function printBit($isAfterSet, $bitNum) | ||||||
|  | { | ||||||
|  |     ob_start(); | ||||||
|  |     if($isAfterSet){ | ||||||
|  | ?>
 | ||||||
|  |     ifioclr USBIN, USBMINUS     ;[00] <--- sample | ||||||
|  |     rjmp    bit#IsClr           ;[01]
 | ||||||
|  |     andi    shift, ~(7 << #)    ;[02]
 | ||||||
|  |     breq    unstuff#s           ;[03]
 | ||||||
|  |     in      phase, USBIN        ;[04] <- phase | ||||||
|  |     rjmp    bit@AfterSet        ;[05] | ||||||
|  | unstuff#s:
 | ||||||
|  |     in      phase, USBIN        ;[05] <- phase (one cycle too late) | ||||||
|  |     andi    fix, ~(1 << #)      ;[06]
 | ||||||
|  |     nop2                        ;[-1] | ||||||
|  |     nop2                        ;[01] | ||||||
|  | bit#IsClr:
 | ||||||
|  |     ifrset  phase, USBMINUS     ;[03] check phase only if D- changed | ||||||
|  |     lpm                         ;[04] | ||||||
|  |     in      phase, USBIN        ;[05] <- phase (one cycle too late) | ||||||
|  |     ori     shift, 1 << #       ;[06]
 | ||||||
|  | <?php | ||||||
|  |     }else{ | ||||||
|  | ?>
 | ||||||
|  |     ifioset USBIN, USBMINUS     ;[00] <--- sample | ||||||
|  |     rjmp    bit#IsSet           ;[01]
 | ||||||
|  |     andi    shift, ~(7 << #)    ;[02]
 | ||||||
|  |     breq    unstuff#c           ;[03]
 | ||||||
|  |     in      phase, USBIN        ;[04] <- phase | ||||||
|  |     rjmp    bit@AfterClr        ;[05] | ||||||
|  | unstuff#c:
 | ||||||
|  |     in      phase, USBIN        ;[05] <- phase (one cycle too late) | ||||||
|  |     andi    fix, ~(1 << #)      ;[06]
 | ||||||
|  |     nop2                        ;[-1] | ||||||
|  |     nop2                        ;[01] | ||||||
|  | bit#IsSet:
 | ||||||
|  |     ifrclr  phase, USBMINUS     ;[03] check phase only if D- changed | ||||||
|  |     lpm                         ;[04] | ||||||
|  |     in      phase, USBIN        ;[05] <- phase (one cycle too late) | ||||||
|  |     ori     shift, 1 << #       ;[06]
 | ||||||
|  | <?php | ||||||
|  |     } | ||||||
|  |     printCmdBuffer($bitNum); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | $bitStartCycles = array(1, 9, 17, 26, 34, 42, 51, 59); | ||||||
|  | for($i = 0; $i < 16; $i++){ | ||||||
|  |     $bit = $i % 8; | ||||||
|  |     $emitClrCode = ($i + (int)($i / 8)) % 2; | ||||||
|  |     $cycle = $bitStartCycles[$bit]; | ||||||
|  |     if($emitClrCode){ | ||||||
|  |         printf("bit%dAfterClr:\n", $bit); | ||||||
|  |     }else{ | ||||||
|  |         printf("bit%dAfterSet:\n", $bit); | ||||||
|  |     } | ||||||
|  |     ob_start(); | ||||||
|  |     echo "    *****                       ;[-1]\n"; | ||||||
|  |     printCmdBuffer($bit); | ||||||
|  |     printBit(!$emitClrCode, $bit); | ||||||
|  |     if($i == 7) | ||||||
|  |         echo "\n"; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | ?>
 | ||||||
|  | *****************************************************************************/ | ||||||
							
								
								
									
										422
									
								
								keyboards/planck/thk/bootloader/usbdrv/usbdrvasm15.inc
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										422
									
								
								keyboards/planck/thk/bootloader/usbdrv/usbdrvasm15.inc
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,422 @@ | |||||||
|  | /* Name: usbdrvasm15.inc | ||||||
|  |  * Project: V-USB, virtual USB port for Atmel's(r) AVR(r) microcontrollers | ||||||
|  |  * Author: contributed by V. Bosch | ||||||
|  |  * Creation Date: 2007-08-06 | ||||||
|  |  * Tabsize: 4 | ||||||
|  |  * Copyright: (c) 2007 by OBJECTIVE DEVELOPMENT Software GmbH | ||||||
|  |  * License: GNU GPL v2 (see License.txt), GNU GPL v3 or proprietary (CommercialLicense.txt) | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | /* Do not link this file! Link usbdrvasm.S instead, which includes the | ||||||
|  |  * appropriate implementation! | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | /* | ||||||
|  | General Description: | ||||||
|  | This file is the 15 MHz version of the asssembler part of the USB driver. It | ||||||
|  | requires a 15 MHz crystal (not a ceramic resonator and not a calibrated RC | ||||||
|  | oscillator). | ||||||
|  | 
 | ||||||
|  | See usbdrv.h for a description of the entire driver. | ||||||
|  | 
 | ||||||
|  | Since almost all of this code is timing critical, don't change unless you | ||||||
|  | really know what you are doing! Many parts require not only a maximum number | ||||||
|  | of CPU cycles, but even an exact number of cycles! | ||||||
|  | */ | ||||||
|  | 
 | ||||||
|  | ;max stack usage: [ret(2), YL, SREG, YH, bitcnt, shift, x1, x2, x3, x4, cnt] = 12 bytes | ||||||
|  | ;nominal frequency: 15 MHz -> 10.0 cycles per bit, 80.0 cycles per byte | ||||||
|  | ; Numbers in brackets are clocks counted from center of last sync bit | ||||||
|  | ; when instruction starts | ||||||
|  | 
 | ||||||
|  | ;---------------------------------------------------------------------------- | ||||||
|  | ; order of registers pushed:  | ||||||
|  | ;	YL, SREG [sofError] YH, shift, x1, x2, x3, bitcnt, cnt, x4 | ||||||
|  | ;---------------------------------------------------------------------------- | ||||||
|  | USB_INTR_VECTOR:               | ||||||
|  |     push    YL                   ;2 	push only what is necessary to sync with edge ASAP | ||||||
|  |     in      YL, SREG             ;1  | ||||||
|  |     push    YL                   ;2  | ||||||
|  | ;---------------------------------------------------------------------------- | ||||||
|  | ; Synchronize with sync pattern: | ||||||
|  | ; | ||||||
|  | ;   sync byte (D-) pattern LSb to MSb: 01010100 [1 = idle = J, 0 = K] | ||||||
|  | ;   sync up with J to K edge during sync pattern -- use fastest possible loops | ||||||
|  | ;The first part waits at most 1 bit long since we must be in sync pattern. | ||||||
|  | ;YL is guarenteed to be < 0x80 because I flag is clear. When we jump to | ||||||
|  | ;waitForJ, ensure that this prerequisite is met. | ||||||
|  | waitForJ: | ||||||
|  |     inc     YL | ||||||
|  |     sbis    USBIN, USBMINUS | ||||||
|  |     brne    waitForJ        ; just make sure we have ANY timeout | ||||||
|  | ;------------------------------------------------------------------------------- | ||||||
|  | ; The following code results in a sampling window of < 1/4 bit  | ||||||
|  | ;	which meets the spec. | ||||||
|  | ;------------------------------------------------------------------------------- | ||||||
|  | waitForK:			 ;-  | ||||||
|  |     sbis    USBIN, USBMINUS      ;1 [00] <-- sample | ||||||
|  |     rjmp    foundK               ;2 [01] | ||||||
|  |     sbis    USBIN, USBMINUS	 ;	 <-- sample | ||||||
|  |     rjmp    foundK | ||||||
|  |     sbis    USBIN, USBMINUS	 ;	 <-- sample | ||||||
|  |     rjmp    foundK | ||||||
|  |     sbis    USBIN, USBMINUS	 ;	 <-- sample | ||||||
|  |     rjmp    foundK | ||||||
|  |     sbis    USBIN, USBMINUS	 ;	 <-- sample | ||||||
|  |     rjmp    foundK | ||||||
|  |     sbis    USBIN, USBMINUS	 ;	 <-- sample | ||||||
|  |     rjmp    foundK | ||||||
|  | #if USB_COUNT_SOF
 | ||||||
|  |     lds     YL, usbSofCount | ||||||
|  |     inc     YL | ||||||
|  |     sts     usbSofCount, YL | ||||||
|  | #endif  /* USB_COUNT_SOF */
 | ||||||
|  | #ifdef USB_SOF_HOOK
 | ||||||
|  |     USB_SOF_HOOK | ||||||
|  | #endif
 | ||||||
|  |     rjmp    sofError | ||||||
|  | ;------------------------------------------------------------------------------ | ||||||
|  | ; {3, 5} after falling D- edge, average delay: 4 cycles [we want 5 for  | ||||||
|  | ;	center sampling]  | ||||||
|  | ; 	we have 1 bit time for setup purposes, then sample again.  | ||||||
|  | ;	Numbers in brackets are cycles from center of first sync (double K)  | ||||||
|  | ;	bit after the instruction | ||||||
|  | ;------------------------------------------------------------------------------ | ||||||
|  | foundK:                          ;- [02] | ||||||
|  |     lds     YL, usbInputBufOffset;2 [03+04]	tx loop | ||||||
|  |     push    YH                   ;2 [05+06] | ||||||
|  |     clr     YH                   ;1 [07] | ||||||
|  |     subi    YL, lo8(-(usbRxBuf)) ;1 [08] 	[rx loop init] | ||||||
|  |     sbci    YH, hi8(-(usbRxBuf)) ;1 [09] 	[rx loop init] | ||||||
|  |     push    shift                ;2 [10+11] | ||||||
|  |     ser	    shift		 ;1 [12] | ||||||
|  |     sbis    USBIN, USBMINUS      ;1 [-1] [13] <--sample:we want two bits K (sample 1 cycle too early) | ||||||
|  |     rjmp    haveTwoBitsK         ;2 [00] [14] | ||||||
|  |     pop     shift                ;2 	 [15+16] undo the push from before | ||||||
|  |     pop     YH 			 ;2 	 [17+18] undo the push from before | ||||||
|  |     rjmp    waitForK             ;2 	 [19+20] this was not the end of sync, retry | ||||||
|  | ; The entire loop from waitForK until rjmp waitForK above must not exceed two | ||||||
|  | ; bit times (= 20 cycles). | ||||||
|  | 
 | ||||||
|  | ;---------------------------------------------------------------------------- | ||||||
|  | ; push more registers and initialize values while we sample the first bits: | ||||||
|  | ;---------------------------------------------------------------------------- | ||||||
|  | haveTwoBitsK:			;- [01] | ||||||
|  |     push    x1              	;2 [02+03] | ||||||
|  |     push    x2              	;2 [04+05] | ||||||
|  |     push    x3              	;2 [06+07] | ||||||
|  |     push    bitcnt              ;2 [08+09]	 | ||||||
|  |     in      x1, USBIN       	;1 [00] [10] <-- sample bit 0 | ||||||
|  |     bst     x1, USBMINUS    	;1 [01] | ||||||
|  |     bld     shift, 0        	;1 [02] | ||||||
|  |     push    cnt             	;2 [03+04] | ||||||
|  |     ldi     cnt, USB_BUFSIZE	;1 [05]  | ||||||
|  |     push    x4              	;2 [06+07] tx loop | ||||||
|  |     rjmp    rxLoop          	;2 [08] | ||||||
|  | ;---------------------------------------------------------------------------- | ||||||
|  | ; Receiver loop (numbers in brackets are cycles within byte after instr) | ||||||
|  | ;---------------------------------------------------------------------------- | ||||||
|  | unstuff0:               	;- [07] (branch taken) | ||||||
|  |     andi    x3, ~0x01   	;1 [08] | ||||||
|  |     mov     x1, x2      	;1 [09] x2 contains last sampled (stuffed) bit | ||||||
|  |     in      x2, USBIN   	;1 [00] [10] <-- sample bit 1 again | ||||||
|  |     andi    x2, USBMASK 	;1 [01] | ||||||
|  |     breq    se0Hop         	;1 [02] SE0 check for bit 1  | ||||||
|  |     ori     shift, 0x01 	;1 [03] 0b00000001 | ||||||
|  |     nop				;1 [04] | ||||||
|  |     rjmp    didUnstuff0 	;2 [05] | ||||||
|  | ;----------------------------------------------------- | ||||||
|  | unstuff1:               	;- [05] (branch taken) | ||||||
|  |     mov     x2, x1      	;1 [06] x1 contains last sampled (stuffed) bit | ||||||
|  |     andi    x3, ~0x02   	;1 [07] | ||||||
|  |     ori     shift, 0x02 	;1 [08] 0b00000010 | ||||||
|  |     nop                 	;1 [09] | ||||||
|  |     in      x1, USBIN   	;1 [00] [10] <-- sample bit 2 again | ||||||
|  |     andi    x1, USBMASK 	;1 [01] | ||||||
|  |     breq    se0Hop         	;1 [02] SE0 check for bit 2  | ||||||
|  |     rjmp    didUnstuff1 	;2 [03] | ||||||
|  | ;----------------------------------------------------- | ||||||
|  | unstuff2:               	;- [05] (branch taken) | ||||||
|  |     andi    x3, ~0x04   	;1 [06] | ||||||
|  |     ori     shift, 0x04 	;1 [07] 0b00000100 | ||||||
|  |     mov     x1, x2      	;1 [08] x2 contains last sampled (stuffed) bit | ||||||
|  |     nop                 	;1 [09] | ||||||
|  |     in      x2, USBIN   	;1 [00] [10] <-- sample bit 3 | ||||||
|  |     andi    x2, USBMASK 	;1 [01] | ||||||
|  |     breq    se0Hop         	;1 [02] SE0 check for bit 3  | ||||||
|  |     rjmp    didUnstuff2 	;2 [03] | ||||||
|  | ;----------------------------------------------------- | ||||||
|  | unstuff3:               	;- [00] [10]  (branch taken) | ||||||
|  |     in      x2, USBIN   	;1 [01] [11] <-- sample stuffed bit 3 one cycle too late | ||||||
|  |     andi    x2, USBMASK 	;1 [02] | ||||||
|  |     breq    se0Hop         	;1 [03] SE0 check for stuffed bit 3  | ||||||
|  |     andi    x3, ~0x08   	;1 [04] | ||||||
|  |     ori     shift, 0x08 	;1 [05] 0b00001000 | ||||||
|  |     rjmp    didUnstuff3 	;2 [06] | ||||||
|  | ;---------------------------------------------------------------------------- | ||||||
|  | ; extra jobs done during bit interval: | ||||||
|  | ; | ||||||
|  | ; bit 0:    store, clear [SE0 is unreliable here due to bit dribbling in hubs],  | ||||||
|  | ; 		overflow check, jump to the head of rxLoop | ||||||
|  | ; bit 1:    SE0 check | ||||||
|  | ; bit 2:    SE0 check, recovery from delay [bit 0 tasks took too long] | ||||||
|  | ; bit 3:    SE0 check, recovery from delay [bit 0 tasks took too long] | ||||||
|  | ; bit 4:    SE0 check, none | ||||||
|  | ; bit 5:    SE0 check, none | ||||||
|  | ; bit 6:    SE0 check, none | ||||||
|  | ; bit 7:    SE0 check, reconstruct: x3 is 0 at bit locations we changed, 1 at others | ||||||
|  | ;---------------------------------------------------------------------------- | ||||||
|  | rxLoop:				;- [09] | ||||||
|  |     in      x2, USBIN   	;1 [00] [10] <-- sample bit 1 (or possibly bit 0 stuffed) | ||||||
|  |     andi    x2, USBMASK 	;1 [01] | ||||||
|  |     brne    SkipSe0Hop		;1 [02] | ||||||
|  | se0Hop:				;- [02] | ||||||
|  |     rjmp    se0         	;2 [03] SE0 check for bit 1  | ||||||
|  | SkipSe0Hop:			;- [03] | ||||||
|  |     ser     x3          	;1 [04] | ||||||
|  |     andi    shift, 0xf9 	;1 [05] 0b11111001 | ||||||
|  |     breq    unstuff0    	;1 [06] | ||||||
|  | didUnstuff0:			;- [06] | ||||||
|  |     eor     x1, x2      	;1 [07] | ||||||
|  |     bst     x1, USBMINUS	;1 [08] | ||||||
|  |     bld     shift, 1    	;1 [09]  | ||||||
|  |     in      x1, USBIN   	;1 [00] [10] <-- sample bit 2 (or possibly bit 1 stuffed) | ||||||
|  |     andi    x1, USBMASK 	;1 [01] | ||||||
|  |     breq    se0Hop         	;1 [02] SE0 check for bit 2  | ||||||
|  |     andi    shift, 0xf3 	;1 [03] 0b11110011 | ||||||
|  |     breq    unstuff1    	;1 [04] do remaining work for bit 1 | ||||||
|  | didUnstuff1:			;- [04] | ||||||
|  |     eor     x2, x1      	;1 [05] | ||||||
|  |     bst     x2, USBMINUS	;1 [06] | ||||||
|  |     bld     shift, 2    	;1 [07] | ||||||
|  |     nop2			;2 [08+09] | ||||||
|  |     in      x2, USBIN   	;1 [00] [10] <-- sample bit 3 (or possibly bit 2 stuffed) | ||||||
|  |     andi    x2, USBMASK 	;1 [01] | ||||||
|  |     breq    se0Hop         	;1 [02] SE0 check for bit 3  | ||||||
|  |     andi    shift, 0xe7 	;1 [03] 0b11100111 | ||||||
|  |     breq    unstuff2    	;1 [04] | ||||||
|  | didUnstuff2:			;- [04] | ||||||
|  |     eor     x1, x2      	;1 [05] | ||||||
|  |     bst     x1, USBMINUS	;1 [06] | ||||||
|  |     bld     shift, 3    	;1 [07] | ||||||
|  | didUnstuff3:			;- [07] | ||||||
|  |     andi    shift, 0xcf 	;1 [08] 0b11001111 | ||||||
|  |     breq    unstuff3    	;1 [09] | ||||||
|  |     in      x1, USBIN   	;1 [00] [10] <-- sample bit 4 | ||||||
|  |     andi    x1, USBMASK 	;1 [01] | ||||||
|  |     breq    se0Hop         	;1 [02] SE0 check for bit 4 | ||||||
|  |     eor     x2, x1      	;1 [03] | ||||||
|  |     bst     x2, USBMINUS	;1 [04] | ||||||
|  |     bld     shift, 4    	;1 [05] | ||||||
|  | didUnstuff4:			;- [05] | ||||||
|  |     andi    shift, 0x9f 	;1 [06] 0b10011111 | ||||||
|  |     breq    unstuff4    	;1 [07] | ||||||
|  |     nop2			;2 [08+09] | ||||||
|  |     in      x2, USBIN   	;1 [00] [10] <-- sample bit 5 | ||||||
|  |     andi    x2, USBMASK 	;1 [01] | ||||||
|  |     breq    se0         	;1 [02] SE0 check for bit 5 | ||||||
|  |     eor     x1, x2      	;1 [03] | ||||||
|  |     bst     x1, USBMINUS	;1 [04] | ||||||
|  |     bld     shift, 5    	;1 [05] | ||||||
|  | didUnstuff5:			;- [05] | ||||||
|  |     andi    shift, 0x3f 	;1 [06] 0b00111111 | ||||||
|  |     breq    unstuff5    	;1 [07] | ||||||
|  |     nop2			;2 [08+09] | ||||||
|  |     in      x1, USBIN   	;1 [00] [10] <-- sample bit 6 | ||||||
|  |     andi    x1, USBMASK 	;1 [01] | ||||||
|  |     breq    se0         	;1 [02] SE0 check for bit 6 | ||||||
|  |     eor     x2, x1      	;1 [03] | ||||||
|  |     bst     x2, USBMINUS	;1 [04] | ||||||
|  |     bld     shift, 6   	 	;1 [05] | ||||||
|  | didUnstuff6:			;- [05] | ||||||
|  |     cpi     shift, 0x02 	;1 [06] 0b00000010 | ||||||
|  |     brlo    unstuff6    	;1 [07] | ||||||
|  |     nop2			;2 [08+09] | ||||||
|  |     in      x2, USBIN   	;1 [00] [10] <-- sample bit 7 | ||||||
|  |     andi    x2, USBMASK 	;1 [01] | ||||||
|  |     breq    se0         	;1 [02] SE0 check for bit 7 | ||||||
|  |     eor     x1, x2      	;1 [03] | ||||||
|  |     bst     x1, USBMINUS	;1 [04] | ||||||
|  |     bld     shift, 7    	;1 [05] | ||||||
|  | didUnstuff7:			;- [05]  | ||||||
|  |     cpi     shift, 0x04 	;1 [06] 0b00000100 | ||||||
|  |     brlo    unstuff7		;1 [07] | ||||||
|  |     eor     x3, shift   	;1 [08] reconstruct: x3 is 0 at bit locations we changed, 1 at others | ||||||
|  |     nop				;1 [09] | ||||||
|  |     in      x1, USBIN   	;1 [00]	[10] <-- sample bit 0 | ||||||
|  |     st      y+, x3      	;2 [01+02] store data | ||||||
|  |     eor     x2, x1      	;1 [03] | ||||||
|  |     bst     x2, USBMINUS	;1 [04] | ||||||
|  |     bld     shift, 0    	;1 [05] | ||||||
|  |     subi    cnt, 1		;1 [06] | ||||||
|  |     brcs    overflow	;1 [07] | ||||||
|  |     rjmp    rxLoop		;2 [08] | ||||||
|  | ;----------------------------------------------------- | ||||||
|  | unstuff4:               	;- [08]  | ||||||
|  |     andi    x3, ~0x10   	;1 [09] | ||||||
|  |     in      x1, USBIN   	;1 [00] [10] <-- sample stuffed bit 4 | ||||||
|  |     andi    x1, USBMASK 	;1 [01] | ||||||
|  |     breq    se0         	;1 [02] SE0 check for stuffed bit 4 | ||||||
|  |     ori     shift, 0x10 	;1 [03] | ||||||
|  |     rjmp    didUnstuff4 	;2 [04] | ||||||
|  | ;----------------------------------------------------- | ||||||
|  | unstuff5:               	;- [08]  | ||||||
|  |     ori     shift, 0x20 	;1 [09] | ||||||
|  |     in      x2, USBIN   	;1 [00] [10] <-- sample stuffed bit 5 | ||||||
|  |     andi    x2, USBMASK 	;1 [01] | ||||||
|  |     breq    se0         	;1 [02] SE0 check for stuffed bit 5 | ||||||
|  |     andi    x3, ~0x20   	;1 [03] | ||||||
|  |     rjmp    didUnstuff5		;2 [04] | ||||||
|  | ;----------------------------------------------------- | ||||||
|  | unstuff6:               	;- [08]  | ||||||
|  |     andi    x3, ~0x40   	;1 [09] | ||||||
|  |     in      x1, USBIN   	;1 [00] [10] <-- sample stuffed bit 6 | ||||||
|  |     andi    x1, USBMASK 	;1 [01] | ||||||
|  |     breq    se0         	;1 [02] SE0 check for stuffed bit 6 | ||||||
|  |     ori     shift, 0x40 	;1 [03] | ||||||
|  |     rjmp    didUnstuff6 	;2 [04] | ||||||
|  | ;----------------------------------------------------- | ||||||
|  | unstuff7:			;- [08] | ||||||
|  |     andi    x3, ~0x80   	;1 [09] | ||||||
|  |     in      x2, USBIN   	;1 [00] [10] <-- sample stuffed bit 7 | ||||||
|  |     andi    x2, USBMASK 	;1 [01] | ||||||
|  |     breq    se0         	;1 [02] SE0 check for stuffed bit 7 | ||||||
|  |     ori     shift, 0x80 	;1 [03] | ||||||
|  |     rjmp    didUnstuff7 	;2 [04] | ||||||
|  |      | ||||||
|  | macro POP_STANDARD ; 16 cycles | ||||||
|  |     pop     x4     | ||||||
|  |     pop     cnt | ||||||
|  |     pop     bitcnt | ||||||
|  |     pop     x3 | ||||||
|  |     pop     x2 | ||||||
|  |     pop     x1 | ||||||
|  |     pop     shift | ||||||
|  |     pop     YH | ||||||
|  |     endm | ||||||
|  | macro POP_RETI     ; 5 cycles | ||||||
|  |     pop     YL | ||||||
|  |     out     SREG, YL | ||||||
|  |     pop     YL | ||||||
|  |     endm | ||||||
|  | 
 | ||||||
|  | #include "asmcommon.inc"
 | ||||||
|  | 
 | ||||||
|  | ;--------------------------------------------------------------------------- | ||||||
|  | ; USB spec says: | ||||||
|  | ; idle = J | ||||||
|  | ; J = (D+ = 0), (D- = 1) | ||||||
|  | ; K = (D+ = 1), (D- = 0) | ||||||
|  | ; Spec allows 7.5 bit times from EOP to SOP for replies | ||||||
|  | ;--------------------------------------------------------------------------- | ||||||
|  | bitstuffN:		    	;- [04] | ||||||
|  |     eor     x1, x4          	;1 [05] | ||||||
|  |     clr	    x2			;1 [06] | ||||||
|  |     nop				;1 [07] | ||||||
|  |     rjmp    didStuffN       	;1 [08] | ||||||
|  | ;---------------------------------------------------------------------------     | ||||||
|  | bitstuff6:		    	;- [04] | ||||||
|  |     eor     x1, x4          	;1 [05] | ||||||
|  |     clr	    x2			;1 [06] | ||||||
|  |     rjmp    didStuff6       	;1 [07] | ||||||
|  | ;--------------------------------------------------------------------------- | ||||||
|  | bitstuff7:		    	;- [02] | ||||||
|  |     eor     x1, x4          	;1 [03] | ||||||
|  |     clr	    x2			;1 [06] | ||||||
|  |     nop			    	;1 [05] | ||||||
|  |     rjmp    didStuff7       	;1 [06] | ||||||
|  | ;--------------------------------------------------------------------------- | ||||||
|  | sendNakAndReti:			;- [-19] | ||||||
|  |     ldi     x3, USBPID_NAK  	;1 [-18] | ||||||
|  |     rjmp    sendX3AndReti   	;1 [-17] | ||||||
|  | ;--------------------------------------------------------------------------- | ||||||
|  | sendAckAndReti:			;- [-17] | ||||||
|  |     ldi     cnt, USBPID_ACK 	;1 [-16] | ||||||
|  | sendCntAndReti:			;- [-16] | ||||||
|  |     mov     x3, cnt         	;1 [-15] | ||||||
|  | sendX3AndReti:			;- [-15] | ||||||
|  |     ldi     YL, 20          	;1 [-14] x3==r20 address is 20 | ||||||
|  |     ldi     YH, 0           	;1 [-13] | ||||||
|  |     ldi     cnt, 2          	;1 [-12] | ||||||
|  | ;   rjmp    usbSendAndReti      fallthrough | ||||||
|  | ;--------------------------------------------------------------------------- | ||||||
|  | ;usbSend: | ||||||
|  | ;pointer to data in 'Y' | ||||||
|  | ;number of bytes in 'cnt' -- including sync byte [range 2 ... 12] | ||||||
|  | ;uses: x1...x4, btcnt, shift, cnt, Y | ||||||
|  | ;Numbers in brackets are time since first bit of sync pattern is sent | ||||||
|  | ;We need not to match the transfer rate exactly because the spec demands  | ||||||
|  | ;only 1.5% precision anyway. | ||||||
|  | usbSendAndReti:             	;- [-13] 13 cycles until SOP | ||||||
|  |     in      x2, USBDDR      	;1 [-12] | ||||||
|  |     ori     x2, USBMASK     	;1 [-11] | ||||||
|  |     sbi     USBOUT, USBMINUS	;2 [-09-10] prepare idle state; D+ and D- must have been 0 (no pullups) | ||||||
|  |     in      x1, USBOUT      	;1 [-08] port mirror for tx loop | ||||||
|  |     out     USBDDR, x2      	;1 [-07] <- acquire bus | ||||||
|  | 	; need not init x2 (bitstuff history) because sync starts with 0  | ||||||
|  |     ldi     x4, USBMASK     	;1 [-06] 	exor mask | ||||||
|  |     ldi     shift, 0x80     	;1 [-05] 	sync byte is first byte sent | ||||||
|  |     ldi     bitcnt, 6    	;1 [-04]  | ||||||
|  | txBitLoop:		    	;- [-04] [06] | ||||||
|  |     sbrs    shift, 0        	;1 [-03] [07] | ||||||
|  |     eor     x1, x4          	;1 [-02] [08]  | ||||||
|  |     ror     shift           	;1 [-01] [09]   | ||||||
|  | didStuffN:		    	;-       [09] | ||||||
|  |     out     USBOUT, x1      	;1 [00]  [10] <-- out N | ||||||
|  |     ror     x2              	;1 [01] | ||||||
|  |     cpi     x2, 0xfc        	;1 [02] | ||||||
|  |     brcc    bitstuffN       	;1 [03] | ||||||
|  |     dec     bitcnt          	;1 [04] | ||||||
|  |     brne    txBitLoop       	;1 [05] | ||||||
|  |     sbrs    shift, 0        	;1 [06] | ||||||
|  |     eor     x1, x4          	;1 [07] | ||||||
|  |     ror     shift           	;1 [08] | ||||||
|  | didStuff6:			;- [08] | ||||||
|  |     nop				;1 [09] | ||||||
|  |     out     USBOUT, x1      	;1 [00] [10] <-- out 6 | ||||||
|  |     ror     x2              	;1 [01]  | ||||||
|  |     cpi     x2, 0xfc        	;1 [02] | ||||||
|  |     brcc    bitstuff6       	;1 [03] | ||||||
|  |     sbrs    shift, 0        	;1 [04] | ||||||
|  |     eor     x1, x4          	;1 [05] | ||||||
|  |     ror     shift           	;1 [06] | ||||||
|  |     ror     x2              	;1 [07] | ||||||
|  | didStuff7:			;- [07] | ||||||
|  |     ldi     bitcnt, 6    	;1 [08] | ||||||
|  |     cpi     x2, 0xfc        	;1 [09] | ||||||
|  |     out     USBOUT, x1      	;1 [00] [10] <-- out 7 | ||||||
|  |     brcc    bitstuff7       	;1 [01] | ||||||
|  |     ld      shift, y+       	;2 [02+03] | ||||||
|  |     dec     cnt             	;1 [04] | ||||||
|  |     brne    txBitLoop      	;1 [05] | ||||||
|  | makeSE0: | ||||||
|  |     cbr     x1, USBMASK     	;1 [06] 	prepare SE0 [spec says EOP may be 19 to 23 cycles] | ||||||
|  |     lds     x2, usbNewDeviceAddr;2 [07+08] | ||||||
|  |     lsl     x2                  ;1 [09] we compare with left shifted address | ||||||
|  | ;2006-03-06: moved transfer of new address to usbDeviceAddr from C-Code to asm: | ||||||
|  | ;set address only after data packet was sent, not after handshake | ||||||
|  |     out     USBOUT, x1      	;1 [00] [10] <-- out SE0-- from now 2 bits==20 cycl. until bus idle | ||||||
|  |     subi    YL, 20 + 2          ;1 [01] Only assign address on data packets, not ACK/NAK in x3 | ||||||
|  |     sbci    YH, 0           	;1 [02] | ||||||
|  |     breq    skipAddrAssign  	;1 [03] | ||||||
|  |     sts     usbDeviceAddr, x2	;2 [04+05] if not skipped: SE0 is one cycle longer | ||||||
|  | ;---------------------------------------------------------------------------- | ||||||
|  | ;end of usbDeviceAddress transfer | ||||||
|  | skipAddrAssign:				;- [03/04] | ||||||
|  |     ldi     x2, 1<<USB_INTR_PENDING_BIT	;1 [05] int0 occurred during TX -- clear pending flag | ||||||
|  |     USB_STORE_PENDING(x2)           ;1 [06] | ||||||
|  |     ori     x1, USBIDLE     		;1 [07] | ||||||
|  |     in      x2, USBDDR      		;1 [08] | ||||||
|  |     cbr     x2, USBMASK     		;1 [09] set both pins to input | ||||||
|  |     mov     x3, x1          		;1 [10] | ||||||
|  |     cbr     x3, USBMASK     		;1 [11] configure no pullup on both pins | ||||||
|  |     ldi     x4, 3           		;1 [12] | ||||||
|  | se0Delay:				;- [12] [15]  | ||||||
|  |     dec     x4              		;1 [13] [16]  | ||||||
|  |     brne    se0Delay        		;1 [14] [17]  | ||||||
|  |     nop2				;2      [18+19] | ||||||
|  |     out     USBOUT, x1      		;1      [20] <--out J (idle) -- end of SE0 (EOP sig.) | ||||||
|  |     out     USBDDR, x2      		;1      [21] <--release bus now | ||||||
|  |     out     USBOUT, x3      		;1      [22] <--ensure no pull-up resistors are active | ||||||
|  |     rjmp    doReturn			;1	[23] | ||||||
|  | ;--------------------------------------------------------------------------- | ||||||
							
								
								
									
										345
									
								
								keyboards/planck/thk/bootloader/usbdrv/usbdrvasm16.inc
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										345
									
								
								keyboards/planck/thk/bootloader/usbdrv/usbdrvasm16.inc
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,345 @@ | |||||||
|  | /* Name: usbdrvasm16.inc | ||||||
|  |  * Project: V-USB, virtual USB port for Atmel's(r) AVR(r) microcontrollers | ||||||
|  |  * Author: Christian Starkjohann | ||||||
|  |  * Creation Date: 2007-06-15 | ||||||
|  |  * Tabsize: 4 | ||||||
|  |  * Copyright: (c) 2007 by OBJECTIVE DEVELOPMENT Software GmbH | ||||||
|  |  * License: GNU GPL v2 (see License.txt), GNU GPL v3 or proprietary (CommercialLicense.txt) | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | /* Do not link this file! Link usbdrvasm.S instead, which includes the | ||||||
|  |  * appropriate implementation! | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | /* | ||||||
|  | General Description: | ||||||
|  | This file is the 16 MHz version of the asssembler part of the USB driver. It | ||||||
|  | requires a 16 MHz crystal (not a ceramic resonator and not a calibrated RC | ||||||
|  | oscillator). | ||||||
|  | 
 | ||||||
|  | See usbdrv.h for a description of the entire driver. | ||||||
|  | 
 | ||||||
|  | Since almost all of this code is timing critical, don't change unless you | ||||||
|  | really know what you are doing! Many parts require not only a maximum number | ||||||
|  | of CPU cycles, but even an exact number of cycles! | ||||||
|  | */ | ||||||
|  | 
 | ||||||
|  | ;max stack usage: [ret(2), YL, SREG, YH, bitcnt, shift, x1, x2, x3, x4, cnt] = 12 bytes | ||||||
|  | ;nominal frequency: 16 MHz -> 10.6666666 cycles per bit, 85.333333333 cycles per byte | ||||||
|  | ; Numbers in brackets are clocks counted from center of last sync bit | ||||||
|  | ; when instruction starts | ||||||
|  | 
 | ||||||
|  | USB_INTR_VECTOR: | ||||||
|  | ;order of registers pushed: YL, SREG YH, [sofError], bitcnt, shift, x1, x2, x3, x4, cnt | ||||||
|  |     push    YL                  ;[-25] push only what is necessary to sync with edge ASAP | ||||||
|  |     in      YL, SREG            ;[-23] | ||||||
|  |     push    YL                  ;[-22] | ||||||
|  |     push    YH                  ;[-20] | ||||||
|  | ;---------------------------------------------------------------------------- | ||||||
|  | ; Synchronize with sync pattern: | ||||||
|  | ;---------------------------------------------------------------------------- | ||||||
|  | ;sync byte (D-) pattern LSb to MSb: 01010100 [1 = idle = J, 0 = K] | ||||||
|  | ;sync up with J to K edge during sync pattern -- use fastest possible loops | ||||||
|  | ;The first part waits at most 1 bit long since we must be in sync pattern. | ||||||
|  | ;YL is guarenteed to be < 0x80 because I flag is clear. When we jump to | ||||||
|  | ;waitForJ, ensure that this prerequisite is met. | ||||||
|  | waitForJ: | ||||||
|  |     inc     YL | ||||||
|  |     sbis    USBIN, USBMINUS | ||||||
|  |     brne    waitForJ        ; just make sure we have ANY timeout | ||||||
|  | waitForK: | ||||||
|  | ;The following code results in a sampling window of < 1/4 bit which meets the spec. | ||||||
|  |     sbis    USBIN, USBMINUS     ;[-15] | ||||||
|  |     rjmp    foundK              ;[-14] | ||||||
|  |     sbis    USBIN, USBMINUS | ||||||
|  |     rjmp    foundK | ||||||
|  |     sbis    USBIN, USBMINUS | ||||||
|  |     rjmp    foundK | ||||||
|  |     sbis    USBIN, USBMINUS | ||||||
|  |     rjmp    foundK | ||||||
|  |     sbis    USBIN, USBMINUS | ||||||
|  |     rjmp    foundK | ||||||
|  |     sbis    USBIN, USBMINUS | ||||||
|  |     rjmp    foundK | ||||||
|  | #if USB_COUNT_SOF
 | ||||||
|  |     lds     YL, usbSofCount | ||||||
|  |     inc     YL | ||||||
|  |     sts     usbSofCount, YL | ||||||
|  | #endif  /* USB_COUNT_SOF */
 | ||||||
|  | #ifdef USB_SOF_HOOK
 | ||||||
|  |     USB_SOF_HOOK | ||||||
|  | #endif
 | ||||||
|  |     rjmp    sofError | ||||||
|  | foundK:                         ;[-12] | ||||||
|  | ;{3, 5} after falling D- edge, average delay: 4 cycles [we want 5 for center sampling] | ||||||
|  | ;we have 1 bit time for setup purposes, then sample again. Numbers in brackets | ||||||
|  | ;are cycles from center of first sync (double K) bit after the instruction | ||||||
|  |     push    bitcnt              ;[-12] | ||||||
|  | ;   [---]                       ;[-11] | ||||||
|  |     lds     YL, usbInputBufOffset;[-10] | ||||||
|  | ;   [---]                       ;[-9] | ||||||
|  |     clr     YH                  ;[-8] | ||||||
|  |     subi    YL, lo8(-(usbRxBuf));[-7] [rx loop init] | ||||||
|  |     sbci    YH, hi8(-(usbRxBuf));[-6] [rx loop init] | ||||||
|  |     push    shift               ;[-5] | ||||||
|  | ;   [---]                       ;[-4] | ||||||
|  |     ldi     bitcnt, 0x55        ;[-3] [rx loop init] | ||||||
|  |     sbis    USBIN, USBMINUS     ;[-2] we want two bits K (sample 2 cycles too early) | ||||||
|  |     rjmp    haveTwoBitsK        ;[-1] | ||||||
|  |     pop     shift               ;[0] undo the push from before | ||||||
|  |     pop     bitcnt              ;[2] undo the push from before | ||||||
|  |     rjmp    waitForK            ;[4] this was not the end of sync, retry | ||||||
|  | ; The entire loop from waitForK until rjmp waitForK above must not exceed two | ||||||
|  | ; bit times (= 21 cycles). | ||||||
|  | 
 | ||||||
|  | ;---------------------------------------------------------------------------- | ||||||
|  | ; push more registers and initialize values while we sample the first bits: | ||||||
|  | ;---------------------------------------------------------------------------- | ||||||
|  | haveTwoBitsK: | ||||||
|  |     push    x1              ;[1] | ||||||
|  |     push    x2              ;[3] | ||||||
|  |     push    x3              ;[5] | ||||||
|  |     ldi     shift, 0        ;[7] | ||||||
|  |     ldi     x3, 1<<4        ;[8] [rx loop init] first sample is inverse bit, compensate that | ||||||
|  |     push    x4              ;[9] == leap | ||||||
|  | 
 | ||||||
|  |     in      x1, USBIN       ;[11] <-- sample bit 0 | ||||||
|  |     andi    x1, USBMASK     ;[12] | ||||||
|  |     bst     x1, USBMINUS    ;[13] | ||||||
|  |     bld     shift, 7        ;[14] | ||||||
|  |     push    cnt             ;[15] | ||||||
|  |     ldi     leap, 0         ;[17] [rx loop init] | ||||||
|  |     ldi     cnt, USB_BUFSIZE;[18] [rx loop init] | ||||||
|  |     rjmp    rxbit1          ;[19] arrives at [21] | ||||||
|  | 
 | ||||||
|  | ;---------------------------------------------------------------------------- | ||||||
|  | ; Receiver loop (numbers in brackets are cycles within byte after instr) | ||||||
|  | ;---------------------------------------------------------------------------- | ||||||
|  | 
 | ||||||
|  | ; duration of unstuffing code should be 10.66666667 cycles. We adjust "leap" | ||||||
|  | ; accordingly to approximate this value in the long run. | ||||||
|  | 
 | ||||||
|  | unstuff6: | ||||||
|  |     andi    x2, USBMASK ;[03] | ||||||
|  |     ori     x3, 1<<6    ;[04] will not be shifted any more | ||||||
|  |     andi    shift, ~0x80;[05] | ||||||
|  |     mov     x1, x2      ;[06] sampled bit 7 is actually re-sampled bit 6 | ||||||
|  |     subi    leap, -1    ;[07] total duration = 11 bits -> subtract 1/3 | ||||||
|  |     rjmp    didUnstuff6 ;[08] | ||||||
|  | 
 | ||||||
|  | unstuff7: | ||||||
|  |     ori     x3, 1<<7    ;[09] will not be shifted any more | ||||||
|  |     in      x2, USBIN   ;[00] [10]  re-sample bit 7 | ||||||
|  |     andi    x2, USBMASK ;[01] | ||||||
|  |     andi    shift, ~0x80;[02] | ||||||
|  |     subi    leap, 2     ;[03] total duration = 10 bits -> add 1/3 | ||||||
|  |     rjmp    didUnstuff7 ;[04] | ||||||
|  | 
 | ||||||
|  | unstuffEven: | ||||||
|  |     ori     x3, 1<<6    ;[09] will be shifted right 6 times for bit 0 | ||||||
|  |     in      x1, USBIN   ;[00] [10] | ||||||
|  |     andi    shift, ~0x80;[01] | ||||||
|  |     andi    x1, USBMASK ;[02] | ||||||
|  |     breq    se0         ;[03] | ||||||
|  |     subi    leap, -1    ;[04] total duration = 11 bits -> subtract 1/3 | ||||||
|  |     nop2                ;[05] | ||||||
|  |     rjmp    didUnstuffE ;[06] | ||||||
|  | 
 | ||||||
|  | unstuffOdd: | ||||||
|  |     ori     x3, 1<<5    ;[09] will be shifted right 4 times for bit 1 | ||||||
|  |     in      x2, USBIN   ;[00] [10] | ||||||
|  |     andi    shift, ~0x80;[01] | ||||||
|  |     andi    x2, USBMASK ;[02] | ||||||
|  |     breq    se0         ;[03] | ||||||
|  |     subi    leap, -1    ;[04] total duration = 11 bits -> subtract 1/3 | ||||||
|  |     nop2                ;[05] | ||||||
|  |     rjmp    didUnstuffO ;[06] | ||||||
|  | 
 | ||||||
|  | rxByteLoop: | ||||||
|  |     andi    x1, USBMASK ;[03] | ||||||
|  |     eor     x2, x1      ;[04] | ||||||
|  |     subi    leap, 1     ;[05] | ||||||
|  |     brpl    skipLeap    ;[06] | ||||||
|  |     subi    leap, -3    ;1 one leap cycle every 3rd byte -> 85 + 1/3 cycles per byte | ||||||
|  |     nop                 ;1 | ||||||
|  | skipLeap: | ||||||
|  |     subi    x2, 1       ;[08] | ||||||
|  |     ror     shift       ;[09] | ||||||
|  | didUnstuff6: | ||||||
|  |     cpi     shift, 0xfc ;[10] | ||||||
|  |     in      x2, USBIN   ;[00] [11] <-- sample bit 7 | ||||||
|  |     brcc    unstuff6    ;[01] | ||||||
|  |     andi    x2, USBMASK ;[02] | ||||||
|  |     eor     x1, x2      ;[03] | ||||||
|  |     subi    x1, 1       ;[04] | ||||||
|  |     ror     shift       ;[05] | ||||||
|  | didUnstuff7: | ||||||
|  |     cpi     shift, 0xfc ;[06] | ||||||
|  |     brcc    unstuff7    ;[07] | ||||||
|  |     eor     x3, shift   ;[08] reconstruct: x3 is 1 at bit locations we changed, 0 at others | ||||||
|  |     st      y+, x3      ;[09] store data | ||||||
|  | rxBitLoop: | ||||||
|  |     in      x1, USBIN   ;[00] [11] <-- sample bit 0/2/4 | ||||||
|  |     andi    x1, USBMASK ;[01] | ||||||
|  |     eor     x2, x1      ;[02] | ||||||
|  |     andi    x3, 0x3f    ;[03] topmost two bits reserved for 6 and 7 | ||||||
|  |     subi    x2, 1       ;[04] | ||||||
|  |     ror     shift       ;[05] | ||||||
|  |     cpi     shift, 0xfc ;[06] | ||||||
|  |     brcc    unstuffEven ;[07] | ||||||
|  | didUnstuffE: | ||||||
|  |     lsr     x3          ;[08] | ||||||
|  |     lsr     x3          ;[09] | ||||||
|  | rxbit1: | ||||||
|  |     in      x2, USBIN   ;[00] [10] <-- sample bit 1/3/5 | ||||||
|  |     andi    x2, USBMASK ;[01] | ||||||
|  |     breq    se0         ;[02] | ||||||
|  |     eor     x1, x2      ;[03] | ||||||
|  |     subi    x1, 1       ;[04] | ||||||
|  |     ror     shift       ;[05] | ||||||
|  |     cpi     shift, 0xfc ;[06] | ||||||
|  |     brcc    unstuffOdd  ;[07] | ||||||
|  | didUnstuffO: | ||||||
|  |     subi    bitcnt, 0xab;[08] == addi 0x55, 0x55 = 0x100/3 | ||||||
|  |     brcs    rxBitLoop   ;[09] | ||||||
|  | 
 | ||||||
|  |     subi    cnt, 1      ;[10] | ||||||
|  |     in      x1, USBIN   ;[00] [11] <-- sample bit 6 | ||||||
|  |     brcc    rxByteLoop  ;[01] | ||||||
|  |     rjmp    overflow | ||||||
|  | 
 | ||||||
|  | macro POP_STANDARD ; 14 cycles | ||||||
|  |     pop     cnt | ||||||
|  |     pop     x4 | ||||||
|  |     pop     x3 | ||||||
|  |     pop     x2 | ||||||
|  |     pop     x1 | ||||||
|  |     pop     shift | ||||||
|  |     pop     bitcnt | ||||||
|  |     endm | ||||||
|  | macro POP_RETI     ; 7 cycles | ||||||
|  |     pop     YH | ||||||
|  |     pop     YL | ||||||
|  |     out     SREG, YL | ||||||
|  |     pop     YL | ||||||
|  |     endm | ||||||
|  | 
 | ||||||
|  | #include "asmcommon.inc"
 | ||||||
|  | 
 | ||||||
|  | ; USB spec says: | ||||||
|  | ; idle = J | ||||||
|  | ; J = (D+ = 0), (D- = 1) | ||||||
|  | ; K = (D+ = 1), (D- = 0) | ||||||
|  | ; Spec allows 7.5 bit times from EOP to SOP for replies | ||||||
|  | 
 | ||||||
|  | bitstuffN: | ||||||
|  |     eor     x1, x4          ;[5] | ||||||
|  |     ldi     x2, 0           ;[6] | ||||||
|  |     nop2                    ;[7] | ||||||
|  |     nop                     ;[9] | ||||||
|  |     out     USBOUT, x1      ;[10] <-- out | ||||||
|  |     rjmp    didStuffN       ;[0] | ||||||
|  |      | ||||||
|  | bitstuff6: | ||||||
|  |     eor     x1, x4          ;[5] | ||||||
|  |     ldi     x2, 0           ;[6] Carry is zero due to brcc | ||||||
|  |     rol     shift           ;[7] compensate for ror shift at branch destination | ||||||
|  |     rjmp    didStuff6       ;[8] | ||||||
|  | 
 | ||||||
|  | bitstuff7: | ||||||
|  |     ldi     x2, 0           ;[2] Carry is zero due to brcc | ||||||
|  |     rjmp    didStuff7       ;[3] | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | sendNakAndReti: | ||||||
|  |     ldi     x3, USBPID_NAK  ;[-18] | ||||||
|  |     rjmp    sendX3AndReti   ;[-17] | ||||||
|  | sendAckAndReti: | ||||||
|  |     ldi     cnt, USBPID_ACK ;[-17] | ||||||
|  | sendCntAndReti: | ||||||
|  |     mov     x3, cnt         ;[-16] | ||||||
|  | sendX3AndReti: | ||||||
|  |     ldi     YL, 20          ;[-15] x3==r20 address is 20 | ||||||
|  |     ldi     YH, 0           ;[-14] | ||||||
|  |     ldi     cnt, 2          ;[-13] | ||||||
|  | ;   rjmp    usbSendAndReti      fallthrough | ||||||
|  | 
 | ||||||
|  | ;usbSend: | ||||||
|  | ;pointer to data in 'Y' | ||||||
|  | ;number of bytes in 'cnt' -- including sync byte [range 2 ... 12] | ||||||
|  | ;uses: x1...x4, btcnt, shift, cnt, Y | ||||||
|  | ;Numbers in brackets are time since first bit of sync pattern is sent | ||||||
|  | ;We don't match the transfer rate exactly (don't insert leap cycles every third | ||||||
|  | ;byte) because the spec demands only 1.5% precision anyway. | ||||||
|  | usbSendAndReti:             ; 12 cycles until SOP | ||||||
|  |     in      x2, USBDDR      ;[-12] | ||||||
|  |     ori     x2, USBMASK     ;[-11] | ||||||
|  |     sbi     USBOUT, USBMINUS;[-10] prepare idle state; D+ and D- must have been 0 (no pullups) | ||||||
|  |     in      x1, USBOUT      ;[-8] port mirror for tx loop | ||||||
|  |     out     USBDDR, x2      ;[-7] <- acquire bus | ||||||
|  | ; need not init x2 (bitstuff history) because sync starts with 0 | ||||||
|  |     ldi     x4, USBMASK     ;[-6] exor mask | ||||||
|  |     ldi     shift, 0x80     ;[-5] sync byte is first byte sent | ||||||
|  | txByteLoop: | ||||||
|  |     ldi     bitcnt, 0x35    ;[-4] [6] binary 0011 0101 | ||||||
|  | txBitLoop: | ||||||
|  |     sbrs    shift, 0        ;[-3] [7] | ||||||
|  |     eor     x1, x4          ;[-2] [8] | ||||||
|  |     out     USBOUT, x1      ;[-1] [9] <-- out N | ||||||
|  |     ror     shift           ;[0] [10] | ||||||
|  |     ror     x2              ;[1] | ||||||
|  | didStuffN: | ||||||
|  |     cpi     x2, 0xfc        ;[2] | ||||||
|  |     brcc    bitstuffN       ;[3] | ||||||
|  |     lsr     bitcnt          ;[4] | ||||||
|  |     brcc    txBitLoop       ;[5] | ||||||
|  |     brne    txBitLoop       ;[6] | ||||||
|  | 
 | ||||||
|  |     sbrs    shift, 0        ;[7] | ||||||
|  |     eor     x1, x4          ;[8] | ||||||
|  | didStuff6: | ||||||
|  |     out     USBOUT, x1      ;[-1] [9] <-- out 6 | ||||||
|  |     ror     shift           ;[0] [10] | ||||||
|  |     ror     x2              ;[1] | ||||||
|  |     cpi     x2, 0xfc        ;[2] | ||||||
|  |     brcc    bitstuff6       ;[3] | ||||||
|  |     ror     shift           ;[4] | ||||||
|  | didStuff7: | ||||||
|  |     ror     x2              ;[5] | ||||||
|  |     sbrs    x2, 7           ;[6] | ||||||
|  |     eor     x1, x4          ;[7] | ||||||
|  |     nop                     ;[8] | ||||||
|  |     cpi     x2, 0xfc        ;[9] | ||||||
|  |     out     USBOUT, x1      ;[-1][10] <-- out 7 | ||||||
|  |     brcc    bitstuff7       ;[0] [11] | ||||||
|  |     ld      shift, y+       ;[1] | ||||||
|  |     dec     cnt             ;[3] | ||||||
|  |     brne    txByteLoop      ;[4] | ||||||
|  | ;make SE0: | ||||||
|  |     cbr     x1, USBMASK     ;[5] prepare SE0 [spec says EOP may be 21 to 25 cycles] | ||||||
|  |     lds     x2, usbNewDeviceAddr;[6] | ||||||
|  |     lsl     x2              ;[8] we compare with left shifted address | ||||||
|  |     subi    YL, 20 + 2      ;[9] Only assign address on data packets, not ACK/NAK in x3 | ||||||
|  |     sbci    YH, 0           ;[10] | ||||||
|  |     out     USBOUT, x1      ;[11] <-- out SE0 -- from now 2 bits = 22 cycles until bus idle | ||||||
|  | ;2006-03-06: moved transfer of new address to usbDeviceAddr from C-Code to asm: | ||||||
|  | ;set address only after data packet was sent, not after handshake | ||||||
|  |     breq    skipAddrAssign  ;[0] | ||||||
|  |     sts     usbDeviceAddr, x2; if not skipped: SE0 is one cycle longer | ||||||
|  | skipAddrAssign: | ||||||
|  | ;end of usbDeviceAddress transfer | ||||||
|  |     ldi     x2, 1<<USB_INTR_PENDING_BIT;[2] int0 occurred during TX -- clear pending flag | ||||||
|  |     USB_STORE_PENDING(x2)   ;[3] | ||||||
|  |     ori     x1, USBIDLE     ;[4] | ||||||
|  |     in      x2, USBDDR      ;[5] | ||||||
|  |     cbr     x2, USBMASK     ;[6] set both pins to input | ||||||
|  |     mov     x3, x1          ;[7] | ||||||
|  |     cbr     x3, USBMASK     ;[8] configure no pullup on both pins | ||||||
|  |     ldi     x4, 4           ;[9] | ||||||
|  | se0Delay: | ||||||
|  |     dec     x4              ;[10] [13] [16] [19] | ||||||
|  |     brne    se0Delay        ;[11] [14] [17] [20] | ||||||
|  |     out     USBOUT, x1      ;[21] <-- out J (idle) -- end of SE0 (EOP signal) | ||||||
|  |     out     USBDDR, x2      ;[22] <-- release bus now | ||||||
|  |     out     USBOUT, x3      ;[23] <-- ensure no pull-up resistors are active | ||||||
|  |     rjmp    doReturn | ||||||
							
								
								
									
										452
									
								
								keyboards/planck/thk/bootloader/usbdrv/usbdrvasm165.inc
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										452
									
								
								keyboards/planck/thk/bootloader/usbdrv/usbdrvasm165.inc
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,452 @@ | |||||||
|  | /* Name: usbdrvasm165.inc | ||||||
|  |  * Project: V-USB, virtual USB port for Atmel's(r) AVR(r) microcontrollers | ||||||
|  |  * Author: Christian Starkjohann | ||||||
|  |  * Creation Date: 2007-04-22 | ||||||
|  |  * Tabsize: 4 | ||||||
|  |  * Copyright: (c) 2007 by OBJECTIVE DEVELOPMENT Software GmbH | ||||||
|  |  * License: GNU GPL v2 (see License.txt), GNU GPL v3 or proprietary (CommercialLicense.txt) | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | /* Do not link this file! Link usbdrvasm.S instead, which includes the | ||||||
|  |  * appropriate implementation! | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | /* | ||||||
|  | General Description: | ||||||
|  | This file is the 16.5 MHz version of the USB driver. It is intended for the | ||||||
|  | ATTiny45 and similar controllers running on 16.5 MHz internal RC oscillator. | ||||||
|  | This version contains a phase locked loop in the receiver routine to cope with | ||||||
|  | slight clock rate deviations of up to +/- 1%. | ||||||
|  | 
 | ||||||
|  | See usbdrv.h for a description of the entire driver. | ||||||
|  | 
 | ||||||
|  | Since almost all of this code is timing critical, don't change unless you | ||||||
|  | really know what you are doing! Many parts require not only a maximum number | ||||||
|  | of CPU cycles, but even an exact number of cycles! | ||||||
|  | */ | ||||||
|  | 
 | ||||||
|  | ;Software-receiver engine. Strict timing! Don't change unless you can preserve timing! | ||||||
|  | ;interrupt response time: 4 cycles + insn running = 7 max if interrupts always enabled | ||||||
|  | ;max allowable interrupt latency: 59 cycles -> max 52 cycles interrupt disable | ||||||
|  | ;max stack usage: [ret(2), r0, SREG, YL, YH, shift, x1, x2, x3, x4, cnt] = 12 bytes | ||||||
|  | ;nominal frequency: 16.5 MHz -> 11 cycles per bit | ||||||
|  | ; 16.3125 MHz < F_CPU < 16.6875 MHz (+/- 1.1%) | ||||||
|  | ; Numbers in brackets are clocks counted from center of last sync bit | ||||||
|  | ; when instruction starts | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | USB_INTR_VECTOR: | ||||||
|  | ;order of registers pushed: YL, SREG [sofError], r0, YH, shift, x1, x2, x3, x4, cnt | ||||||
|  |     push    YL                  ;[-23] push only what is necessary to sync with edge ASAP | ||||||
|  |     in      YL, SREG            ;[-21] | ||||||
|  |     push    YL                  ;[-20] | ||||||
|  | ;---------------------------------------------------------------------------- | ||||||
|  | ; Synchronize with sync pattern: | ||||||
|  | ;---------------------------------------------------------------------------- | ||||||
|  | ;sync byte (D-) pattern LSb to MSb: 01010100 [1 = idle = J, 0 = K] | ||||||
|  | ;sync up with J to K edge during sync pattern -- use fastest possible loops | ||||||
|  | ;The first part waits at most 1 bit long since we must be in sync pattern. | ||||||
|  | ;YL is guarenteed to be < 0x80 because I flag is clear. When we jump to | ||||||
|  | ;waitForJ, ensure that this prerequisite is met. | ||||||
|  | waitForJ: | ||||||
|  |     inc     YL | ||||||
|  |     sbis    USBIN, USBMINUS | ||||||
|  |     brne    waitForJ        ; just make sure we have ANY timeout | ||||||
|  | waitForK: | ||||||
|  | ;The following code results in a sampling window of < 1/4 bit which meets the spec. | ||||||
|  |     sbis    USBIN, USBMINUS     ;[-15] | ||||||
|  |     rjmp    foundK              ;[-14] | ||||||
|  |     sbis    USBIN, USBMINUS | ||||||
|  |     rjmp    foundK | ||||||
|  |     sbis    USBIN, USBMINUS | ||||||
|  |     rjmp    foundK | ||||||
|  |     sbis    USBIN, USBMINUS | ||||||
|  |     rjmp    foundK | ||||||
|  |     sbis    USBIN, USBMINUS | ||||||
|  |     rjmp    foundK | ||||||
|  |     sbis    USBIN, USBMINUS | ||||||
|  |     rjmp    foundK | ||||||
|  | #if USB_COUNT_SOF
 | ||||||
|  |     lds     YL, usbSofCount | ||||||
|  |     inc     YL | ||||||
|  |     sts     usbSofCount, YL | ||||||
|  | #endif  /* USB_COUNT_SOF */
 | ||||||
|  | #ifdef USB_SOF_HOOK
 | ||||||
|  |     USB_SOF_HOOK | ||||||
|  | #endif
 | ||||||
|  |     rjmp    sofError | ||||||
|  | foundK:                         ;[-12] | ||||||
|  | ;{3, 5} after falling D- edge, average delay: 4 cycles [we want 5 for center sampling] | ||||||
|  | ;we have 1 bit time for setup purposes, then sample again. Numbers in brackets | ||||||
|  | ;are cycles from center of first sync (double K) bit after the instruction | ||||||
|  |     push    r0                  ;[-12] | ||||||
|  | ;   [---]                       ;[-11] | ||||||
|  |     push    YH                  ;[-10] | ||||||
|  | ;   [---]                       ;[-9] | ||||||
|  |     lds     YL, usbInputBufOffset;[-8] | ||||||
|  | ;   [---]                       ;[-7] | ||||||
|  |     clr     YH                  ;[-6] | ||||||
|  |     subi    YL, lo8(-(usbRxBuf));[-5] [rx loop init] | ||||||
|  |     sbci    YH, hi8(-(usbRxBuf));[-4] [rx loop init] | ||||||
|  |     mov     r0, x2              ;[-3] [rx loop init] | ||||||
|  |     sbis    USBIN, USBMINUS     ;[-2] we want two bits K (sample 2 cycles too early) | ||||||
|  |     rjmp    haveTwoBitsK        ;[-1] | ||||||
|  |     pop     YH                  ;[0] undo the pushes from before | ||||||
|  |     pop     r0                  ;[2] | ||||||
|  |     rjmp    waitForK            ;[4] this was not the end of sync, retry | ||||||
|  | ; The entire loop from waitForK until rjmp waitForK above must not exceed two | ||||||
|  | ; bit times (= 22 cycles). | ||||||
|  | 
 | ||||||
|  | ;---------------------------------------------------------------------------- | ||||||
|  | ; push more registers and initialize values while we sample the first bits: | ||||||
|  | ;---------------------------------------------------------------------------- | ||||||
|  | haveTwoBitsK:               ;[1] | ||||||
|  |     push    shift           ;[1] | ||||||
|  |     push    x1              ;[3] | ||||||
|  |     push    x2              ;[5] | ||||||
|  |     push    x3              ;[7] | ||||||
|  |     ldi     shift, 0xff     ;[9] [rx loop init] | ||||||
|  |     ori     x3, 0xff        ;[10] [rx loop init] == ser x3, clear zero flag | ||||||
|  | 
 | ||||||
|  |     in      x1, USBIN       ;[11] <-- sample bit 0 | ||||||
|  |     bst     x1, USBMINUS    ;[12] | ||||||
|  |     bld     shift, 0        ;[13] | ||||||
|  |     push    x4              ;[14] == phase | ||||||
|  | ;   [---]                   ;[15] | ||||||
|  |     push    cnt             ;[16] | ||||||
|  | ;   [---]                   ;[17] | ||||||
|  |     ldi     phase, 0        ;[18] [rx loop init] | ||||||
|  |     ldi     cnt, USB_BUFSIZE;[19] [rx loop init] | ||||||
|  |     rjmp    rxbit1          ;[20] | ||||||
|  | ;   [---]                   ;[21] | ||||||
|  | 
 | ||||||
|  | ;---------------------------------------------------------------------------- | ||||||
|  | ; Receiver loop (numbers in brackets are cycles within byte after instr) | ||||||
|  | ;---------------------------------------------------------------------------- | ||||||
|  | /* | ||||||
|  | byte oriented operations done during loop: | ||||||
|  | bit 0: store data | ||||||
|  | bit 1: SE0 check | ||||||
|  | bit 2: overflow check | ||||||
|  | bit 3: catch up | ||||||
|  | bit 4: rjmp to achieve conditional jump range | ||||||
|  | bit 5: PLL | ||||||
|  | bit 6: catch up | ||||||
|  | bit 7: jump, fixup bitstuff | ||||||
|  | ; 87 [+ 2] cycles | ||||||
|  | ------------------------------------------------------------------ | ||||||
|  | */ | ||||||
|  | continueWithBit5: | ||||||
|  |     in      x2, USBIN       ;[055] <-- bit 5 | ||||||
|  |     eor     r0, x2          ;[056] | ||||||
|  |     or      phase, r0       ;[057] | ||||||
|  |     sbrc    phase, USBMINUS ;[058] | ||||||
|  |     lpm                     ;[059] optional nop3; modifies r0 | ||||||
|  |     in      phase, USBIN    ;[060] <-- phase | ||||||
|  |     eor     x1, x2          ;[061] | ||||||
|  |     bst     x1, USBMINUS    ;[062] | ||||||
|  |     bld     shift, 5        ;[063] | ||||||
|  |     andi    shift, 0x3f     ;[064] | ||||||
|  |     in      x1, USBIN       ;[065] <-- bit 6 | ||||||
|  |     breq    unstuff5        ;[066] *** unstuff escape | ||||||
|  |     eor     phase, x1       ;[067] | ||||||
|  |     eor     x2, x1          ;[068] | ||||||
|  |     bst     x2, USBMINUS    ;[069] | ||||||
|  |     bld     shift, 6        ;[070] | ||||||
|  | didUnstuff6:                ;[   ] | ||||||
|  |     in      r0, USBIN       ;[071] <-- phase | ||||||
|  |     cpi     shift, 0x02     ;[072] | ||||||
|  |     brlo    unstuff6        ;[073] *** unstuff escape | ||||||
|  | didUnstuff5:                ;[   ] | ||||||
|  |     nop2                    ;[074] | ||||||
|  | ;   [---]                   ;[075] | ||||||
|  |     in      x2, USBIN       ;[076] <-- bit 7 | ||||||
|  |     eor     x1, x2          ;[077] | ||||||
|  |     bst     x1, USBMINUS    ;[078] | ||||||
|  |     bld     shift, 7        ;[079] | ||||||
|  | didUnstuff7:                ;[   ] | ||||||
|  |     eor     r0, x2          ;[080] | ||||||
|  |     or      phase, r0       ;[081] | ||||||
|  |     in      r0, USBIN       ;[082] <-- phase | ||||||
|  |     cpi     shift, 0x04     ;[083] | ||||||
|  |     brsh    rxLoop          ;[084] | ||||||
|  | ;   [---]                   ;[085] | ||||||
|  | unstuff7:                   ;[   ] | ||||||
|  |     andi    x3, ~0x80       ;[085] | ||||||
|  |     ori     shift, 0x80     ;[086] | ||||||
|  |     in      x2, USBIN       ;[087] <-- sample stuffed bit 7 | ||||||
|  |     nop                     ;[088] | ||||||
|  |     rjmp    didUnstuff7     ;[089] | ||||||
|  | ;   [---]                   ;[090] | ||||||
|  |                             ;[080] | ||||||
|  | 
 | ||||||
|  | unstuff5:                   ;[067] | ||||||
|  |     eor     phase, x1       ;[068] | ||||||
|  |     andi    x3, ~0x20       ;[069] | ||||||
|  |     ori     shift, 0x20     ;[070] | ||||||
|  |     in      r0, USBIN       ;[071] <-- phase | ||||||
|  |     mov     x2, x1          ;[072] | ||||||
|  |     nop                     ;[073] | ||||||
|  |     nop2                    ;[074] | ||||||
|  | ;   [---]                   ;[075] | ||||||
|  |     in      x1, USBIN       ;[076] <-- bit 6 | ||||||
|  |     eor     r0, x1          ;[077] | ||||||
|  |     or      phase, r0       ;[078] | ||||||
|  |     eor     x2, x1          ;[079] | ||||||
|  |     bst     x2, USBMINUS    ;[080] | ||||||
|  |     bld     shift, 6        ;[081] no need to check bitstuffing, we just had one | ||||||
|  |     in      r0, USBIN       ;[082] <-- phase | ||||||
|  |     rjmp    didUnstuff5     ;[083] | ||||||
|  | ;   [---]                   ;[084] | ||||||
|  |                             ;[074] | ||||||
|  | 
 | ||||||
|  | unstuff6:                   ;[074] | ||||||
|  |     andi    x3, ~0x40       ;[075] | ||||||
|  |     in      x1, USBIN       ;[076] <-- bit 6 again | ||||||
|  |     ori     shift, 0x40     ;[077] | ||||||
|  |     nop2                    ;[078] | ||||||
|  | ;   [---]                   ;[079] | ||||||
|  |     rjmp    didUnstuff6     ;[080] | ||||||
|  | ;   [---]                   ;[081] | ||||||
|  |                             ;[071] | ||||||
|  | 
 | ||||||
|  | unstuff0:                   ;[013] | ||||||
|  |     eor     r0, x2          ;[014] | ||||||
|  |     or      phase, r0       ;[015] | ||||||
|  |     andi    x2, USBMASK     ;[016] check for SE0 | ||||||
|  |     in      r0, USBIN       ;[017] <-- phase | ||||||
|  |     breq    didUnstuff0     ;[018] direct jump to se0 would be too long | ||||||
|  |     andi    x3, ~0x01       ;[019] | ||||||
|  |     ori     shift, 0x01     ;[020] | ||||||
|  |     mov     x1, x2          ;[021] mov existing sample | ||||||
|  |     in      x2, USBIN       ;[022] <-- bit 1 again | ||||||
|  |     rjmp    didUnstuff0     ;[023] | ||||||
|  | ;   [---]                   ;[024] | ||||||
|  |                             ;[014] | ||||||
|  | 
 | ||||||
|  | unstuff1:                   ;[024] | ||||||
|  |     eor     r0, x1          ;[025] | ||||||
|  |     or      phase, r0       ;[026] | ||||||
|  |     andi    x3, ~0x02       ;[027] | ||||||
|  |     in      r0, USBIN       ;[028] <-- phase | ||||||
|  |     ori     shift, 0x02     ;[029] | ||||||
|  |     mov     x2, x1          ;[030] | ||||||
|  |     rjmp    didUnstuff1     ;[031] | ||||||
|  | ;   [---]                   ;[032] | ||||||
|  |                             ;[022] | ||||||
|  | 
 | ||||||
|  | unstuff2:                   ;[035] | ||||||
|  |     eor     r0, x2          ;[036] | ||||||
|  |     or      phase, r0       ;[037] | ||||||
|  |     andi    x3, ~0x04       ;[038] | ||||||
|  |     in      r0, USBIN       ;[039] <-- phase | ||||||
|  |     ori     shift, 0x04     ;[040] | ||||||
|  |     mov     x1, x2          ;[041] | ||||||
|  |     rjmp    didUnstuff2     ;[042] | ||||||
|  | ;   [---]                   ;[043] | ||||||
|  |                             ;[033] | ||||||
|  | 
 | ||||||
|  | unstuff3:                   ;[043] | ||||||
|  |     in      x2, USBIN       ;[044] <-- bit 3 again | ||||||
|  |     eor     r0, x2          ;[045] | ||||||
|  |     or      phase, r0       ;[046] | ||||||
|  |     andi    x3, ~0x08       ;[047] | ||||||
|  |     ori     shift, 0x08     ;[048] | ||||||
|  |     nop                     ;[049] | ||||||
|  |     in      r0, USBIN       ;[050] <-- phase | ||||||
|  |     rjmp    didUnstuff3     ;[051] | ||||||
|  | ;   [---]                   ;[052] | ||||||
|  |                             ;[042] | ||||||
|  | 
 | ||||||
|  | unstuff4:                   ;[053] | ||||||
|  |     andi    x3, ~0x10       ;[054] | ||||||
|  |     in      x1, USBIN       ;[055] <-- bit 4 again | ||||||
|  |     ori     shift, 0x10     ;[056] | ||||||
|  |     rjmp    didUnstuff4     ;[057] | ||||||
|  | ;   [---]                   ;[058] | ||||||
|  |                             ;[048] | ||||||
|  | 
 | ||||||
|  | rxLoop:                     ;[085] | ||||||
|  |     eor     x3, shift       ;[086] reconstruct: x3 is 0 at bit locations we changed, 1 at others | ||||||
|  |     in      x1, USBIN       ;[000] <-- bit 0 | ||||||
|  |     st      y+, x3          ;[001] | ||||||
|  | ;   [---]                   ;[002] | ||||||
|  |     eor     r0, x1          ;[003] | ||||||
|  |     or      phase, r0       ;[004] | ||||||
|  |     eor     x2, x1          ;[005] | ||||||
|  |     in      r0, USBIN       ;[006] <-- phase | ||||||
|  |     ser     x3              ;[007] | ||||||
|  |     bst     x2, USBMINUS    ;[008] | ||||||
|  |     bld     shift, 0        ;[009] | ||||||
|  |     andi    shift, 0xf9     ;[010] | ||||||
|  | rxbit1:                     ;[   ] | ||||||
|  |     in      x2, USBIN       ;[011] <-- bit 1 | ||||||
|  |     breq    unstuff0        ;[012] *** unstuff escape | ||||||
|  |     andi    x2, USBMASK     ;[013] SE0 check for bit 1 | ||||||
|  | didUnstuff0:                ;[   ] Z only set if we detected SE0 in bitstuff | ||||||
|  |     breq    se0             ;[014] | ||||||
|  |     eor     r0, x2          ;[015] | ||||||
|  |     or      phase, r0       ;[016] | ||||||
|  |     in      r0, USBIN       ;[017] <-- phase | ||||||
|  |     eor     x1, x2          ;[018] | ||||||
|  |     bst     x1, USBMINUS    ;[019] | ||||||
|  |     bld     shift, 1        ;[020] | ||||||
|  |     andi    shift, 0xf3     ;[021] | ||||||
|  | didUnstuff1:                ;[   ] | ||||||
|  |     in      x1, USBIN       ;[022] <-- bit 2 | ||||||
|  |     breq    unstuff1        ;[023] *** unstuff escape | ||||||
|  |     eor     r0, x1          ;[024] | ||||||
|  |     or      phase, r0       ;[025] | ||||||
|  |     subi    cnt, 1          ;[026] overflow check | ||||||
|  |     brcs    overflow        ;[027] | ||||||
|  |     in      r0, USBIN       ;[028] <-- phase | ||||||
|  |     eor     x2, x1          ;[029] | ||||||
|  |     bst     x2, USBMINUS    ;[030] | ||||||
|  |     bld     shift, 2        ;[031] | ||||||
|  |     andi    shift, 0xe7     ;[032] | ||||||
|  | didUnstuff2:                ;[   ] | ||||||
|  |     in      x2, USBIN       ;[033] <-- bit 3 | ||||||
|  |     breq    unstuff2        ;[034] *** unstuff escape | ||||||
|  |     eor     r0, x2          ;[035] | ||||||
|  |     or      phase, r0       ;[036] | ||||||
|  |     eor     x1, x2          ;[037] | ||||||
|  |     bst     x1, USBMINUS    ;[038] | ||||||
|  |     in      r0, USBIN       ;[039] <-- phase | ||||||
|  |     bld     shift, 3        ;[040] | ||||||
|  |     andi    shift, 0xcf     ;[041] | ||||||
|  | didUnstuff3:                ;[   ] | ||||||
|  |     breq    unstuff3        ;[042] *** unstuff escape | ||||||
|  |     nop                     ;[043] | ||||||
|  |     in      x1, USBIN       ;[044] <-- bit 4 | ||||||
|  |     eor     x2, x1          ;[045] | ||||||
|  |     bst     x2, USBMINUS    ;[046] | ||||||
|  |     bld     shift, 4        ;[047] | ||||||
|  | didUnstuff4:                ;[   ] | ||||||
|  |     eor     r0, x1          ;[048] | ||||||
|  |     or      phase, r0       ;[049] | ||||||
|  |     in      r0, USBIN       ;[050] <-- phase | ||||||
|  |     andi    shift, 0x9f     ;[051] | ||||||
|  |     breq    unstuff4        ;[052] *** unstuff escape | ||||||
|  |     rjmp    continueWithBit5;[053] | ||||||
|  | ;   [---]                   ;[054] | ||||||
|  | 
 | ||||||
|  | macro POP_STANDARD ; 16 cycles | ||||||
|  |     pop     cnt | ||||||
|  |     pop     x4 | ||||||
|  |     pop     x3 | ||||||
|  |     pop     x2 | ||||||
|  |     pop     x1 | ||||||
|  |     pop     shift | ||||||
|  |     pop     YH | ||||||
|  |     pop     r0 | ||||||
|  |     endm | ||||||
|  | macro POP_RETI     ; 5 cycles | ||||||
|  |     pop     YL | ||||||
|  |     out     SREG, YL | ||||||
|  |     pop     YL | ||||||
|  |     endm | ||||||
|  | 
 | ||||||
|  | #include "asmcommon.inc"
 | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | ; USB spec says: | ||||||
|  | ; idle = J | ||||||
|  | ; J = (D+ = 0), (D- = 1) | ||||||
|  | ; K = (D+ = 1), (D- = 0) | ||||||
|  | ; Spec allows 7.5 bit times from EOP to SOP for replies | ||||||
|  | 
 | ||||||
|  | bitstuff7: | ||||||
|  |     eor     x1, x4          ;[4] | ||||||
|  |     ldi     x2, 0           ;[5] | ||||||
|  |     nop2                    ;[6] C is zero (brcc) | ||||||
|  |     rjmp    didStuff7       ;[8] | ||||||
|  | 
 | ||||||
|  | bitstuffN: | ||||||
|  |     eor     x1, x4          ;[5] | ||||||
|  |     ldi     x2, 0           ;[6] | ||||||
|  |     lpm                     ;[7] 3 cycle NOP, modifies r0 | ||||||
|  |     out     USBOUT, x1      ;[10] <-- out | ||||||
|  |     rjmp    didStuffN       ;[0] | ||||||
|  | 
 | ||||||
|  | #define bitStatus   x3
 | ||||||
|  | 
 | ||||||
|  | sendNakAndReti: | ||||||
|  |     ldi     cnt, USBPID_NAK ;[-19] | ||||||
|  |     rjmp    sendCntAndReti  ;[-18] | ||||||
|  | sendAckAndReti: | ||||||
|  |     ldi     cnt, USBPID_ACK ;[-17] | ||||||
|  | sendCntAndReti: | ||||||
|  |     mov     r0, cnt         ;[-16] | ||||||
|  |     ldi     YL, 0           ;[-15] R0 address is 0 | ||||||
|  |     ldi     YH, 0           ;[-14] | ||||||
|  |     ldi     cnt, 2          ;[-13] | ||||||
|  | ;   rjmp    usbSendAndReti      fallthrough | ||||||
|  | 
 | ||||||
|  | ;usbSend: | ||||||
|  | ;pointer to data in 'Y' | ||||||
|  | ;number of bytes in 'cnt' -- including sync byte [range 2 ... 12] | ||||||
|  | ;uses: x1...x4, shift, cnt, Y | ||||||
|  | ;Numbers in brackets are time since first bit of sync pattern is sent | ||||||
|  | usbSendAndReti:             ; 12 cycles until SOP | ||||||
|  |     in      x2, USBDDR      ;[-12] | ||||||
|  |     ori     x2, USBMASK     ;[-11] | ||||||
|  |     sbi     USBOUT, USBMINUS;[-10] prepare idle state; D+ and D- must have been 0 (no pullups) | ||||||
|  |     in      x1, USBOUT      ;[-8] port mirror for tx loop | ||||||
|  |     out     USBDDR, x2      ;[-7] <- acquire bus | ||||||
|  | ; need not init x2 (bitstuff history) because sync starts with 0 | ||||||
|  |     ldi     x4, USBMASK     ;[-6] exor mask | ||||||
|  |     ldi     shift, 0x80     ;[-5] sync byte is first byte sent | ||||||
|  |     ldi     bitStatus, 0xff ;[-4] init bit loop counter, works for up to 12 bytes | ||||||
|  | byteloop: | ||||||
|  | bitloop: | ||||||
|  |     sbrs    shift, 0        ;[8] [-3] | ||||||
|  |     eor     x1, x4          ;[9] [-2] | ||||||
|  |     out     USBOUT, x1      ;[10] [-1] <-- out | ||||||
|  |     ror     shift           ;[0] | ||||||
|  |     ror     x2              ;[1] | ||||||
|  | didStuffN: | ||||||
|  |     cpi     x2, 0xfc        ;[2] | ||||||
|  |     brcc    bitstuffN       ;[3] | ||||||
|  |     nop                     ;[4] | ||||||
|  |     subi    bitStatus, 37   ;[5] 256 / 7 ~=~ 37 | ||||||
|  |     brcc    bitloop         ;[6] when we leave the loop, bitStatus has almost the initial value | ||||||
|  |     sbrs    shift, 0        ;[7] | ||||||
|  |     eor     x1, x4          ;[8] | ||||||
|  |     ror     shift           ;[9] | ||||||
|  | didStuff7: | ||||||
|  |     out     USBOUT, x1      ;[10] <-- out | ||||||
|  |     ror     x2              ;[0] | ||||||
|  |     cpi     x2, 0xfc        ;[1] | ||||||
|  |     brcc    bitstuff7       ;[2] | ||||||
|  |     ld      shift, y+       ;[3] | ||||||
|  |     dec     cnt             ;[5] | ||||||
|  |     brne    byteloop        ;[6] | ||||||
|  | ;make SE0: | ||||||
|  |     cbr     x1, USBMASK     ;[7] prepare SE0 [spec says EOP may be 21 to 25 cycles] | ||||||
|  |     lds     x2, usbNewDeviceAddr;[8] | ||||||
|  |     lsl     x2              ;[10] we compare with left shifted address | ||||||
|  |     out     USBOUT, x1      ;[11] <-- out SE0 -- from now 2 bits = 22 cycles until bus idle | ||||||
|  | ;2006-03-06: moved transfer of new address to usbDeviceAddr from C-Code to asm: | ||||||
|  | ;set address only after data packet was sent, not after handshake | ||||||
|  |     subi    YL, 2           ;[0] Only assign address on data packets, not ACK/NAK in r0 | ||||||
|  |     sbci    YH, 0           ;[1] | ||||||
|  |     breq    skipAddrAssign  ;[2] | ||||||
|  |     sts     usbDeviceAddr, x2; if not skipped: SE0 is one cycle longer | ||||||
|  | skipAddrAssign: | ||||||
|  | ;end of usbDeviceAddress transfer | ||||||
|  |     ldi     x2, 1<<USB_INTR_PENDING_BIT;[4] int0 occurred during TX -- clear pending flag | ||||||
|  |     USB_STORE_PENDING(x2)   ;[5] | ||||||
|  |     ori     x1, USBIDLE     ;[6] | ||||||
|  |     in      x2, USBDDR      ;[7] | ||||||
|  |     cbr     x2, USBMASK     ;[8] set both pins to input | ||||||
|  |     mov     x3, x1          ;[9] | ||||||
|  |     cbr     x3, USBMASK     ;[10] configure no pullup on both pins | ||||||
|  |     ldi     x4, 4           ;[11] | ||||||
|  | se0Delay: | ||||||
|  |     dec     x4              ;[12] [15] [18] [21] | ||||||
|  |     brne    se0Delay        ;[13] [16] [19] [22] | ||||||
|  |     out     USBOUT, x1      ;[23] <-- out J (idle) -- end of SE0 (EOP signal) | ||||||
|  |     out     USBDDR, x2      ;[24] <-- release bus now | ||||||
|  |     out     USBOUT, x3      ;[25] <-- ensure no pull-up resistors are active | ||||||
|  |     rjmp    doReturn | ||||||
|  | 
 | ||||||
							
								
								
									
										706
									
								
								keyboards/planck/thk/bootloader/usbdrv/usbdrvasm18-crc.inc
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										706
									
								
								keyboards/planck/thk/bootloader/usbdrv/usbdrvasm18-crc.inc
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,706 @@ | |||||||
|  | /* Name: usbdrvasm18.inc | ||||||
|  |  * Project: V-USB, virtual USB port for Atmel's(r) AVR(r) microcontrollers | ||||||
|  |  * Author: Lukas Schrittwieser (based on 20 MHz usbdrvasm20.inc by Jeroen Benschop) | ||||||
|  |  * Creation Date: 2009-01-20 | ||||||
|  |  * Tabsize: 4 | ||||||
|  |  * Copyright: (c) 2008 by Lukas Schrittwieser and OBJECTIVE DEVELOPMENT Software GmbH | ||||||
|  |  * License: GNU GPL v2 (see License.txt), GNU GPL v3 or proprietary (CommercialLicense.txt) | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | /* Do not link this file! Link usbdrvasm.S instead, which includes the | ||||||
|  |  * appropriate implementation! | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | /* | ||||||
|  | General Description: | ||||||
|  | This file is the 18 MHz version of the asssembler part of the USB driver. It | ||||||
|  | requires a 18 MHz crystal (not a ceramic resonator and not a calibrated RC | ||||||
|  | oscillator). | ||||||
|  | 
 | ||||||
|  | See usbdrv.h for a description of the entire driver. | ||||||
|  | 
 | ||||||
|  | Since almost all of this code is timing critical, don't change unless you | ||||||
|  | really know what you are doing! Many parts require not only a maximum number | ||||||
|  | of CPU cycles, but even an exact number of cycles! | ||||||
|  | */ | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | ;max stack usage: [ret(2), YL, SREG, YH, [sofError], bitcnt(x5), shift, x1, x2, x3, x4, cnt, ZL, ZH] = 14 bytes | ||||||
|  | ;nominal frequency: 18 MHz -> 12 cycles per bit | ||||||
|  | ; Numbers in brackets are clocks counted from center of last sync bit | ||||||
|  | ; when instruction starts | ||||||
|  | ;register use in receive loop to receive the data bytes: | ||||||
|  | ; shift assembles the byte currently being received | ||||||
|  | ; x1 holds the D+ and D- line state | ||||||
|  | ; x2 holds the previous line state | ||||||
|  | ; cnt holds the number of bytes left in the receive buffer | ||||||
|  | ; x3 holds the higher crc byte (see algorithm below) | ||||||
|  | ; x4 is used as temporary register for the crc algorithm | ||||||
|  | ; x5 is used for unstuffing: when unstuffing the last received bit is inverted in shift (to prevent further | ||||||
|  | ;    unstuffing calls. In the same time the corresponding bit in x5 is cleared to mark the bit as beening iverted | ||||||
|  | ; zl lower crc value and crc table index | ||||||
|  | ; zh used for crc table accesses | ||||||
|  | 
 | ||||||
|  | ;-------------------------------------------------------------------------------------------------------------- | ||||||
|  | ; CRC mods: | ||||||
|  | ;  table driven crc checker, Z points to table in prog space | ||||||
|  | ;   ZL is the lower crc byte, x3 is the higher crc byte | ||||||
|  | ;	x4 is used as temp register to store different results | ||||||
|  | ;	the initialization of the crc register is not 0xFFFF but 0xFE54. This is because during the receipt of the | ||||||
|  | ;	first data byte an virtual zero data byte is added to the crc register, this results in the correct initial | ||||||
|  | ;	value of 0xFFFF at beginning of the second data byte before the first data byte is added to the crc. | ||||||
|  | ;	The magic number 0xFE54 results form the crc table: At tabH[0x54] = 0xFF = crcH (required) and | ||||||
|  | ;	tabL[0x54] = 0x01  ->  crcL = 0x01 xor 0xFE = 0xFF | ||||||
|  | ;  bitcnt is renamed to x5 and is used for unstuffing purposes, the unstuffing works like in the 12MHz version | ||||||
|  | ;-------------------------------------------------------------------------------------------------------------- | ||||||
|  | ; CRC algorithm: | ||||||
|  | ;	The crc register is formed by x3 (higher byte) and ZL (lower byte). The algorithm uses a 'reversed' form | ||||||
|  | ;	i.e. that it takes the least significant bit first and shifts to the right. So in fact the highest order | ||||||
|  | ;	bit seen from the polynomial devision point of view is the lsb of ZL. (If this sounds strange to you i | ||||||
|  | ;	propose a research on CRC :-) ) | ||||||
|  | ;	Each data byte received is xored to ZL, the lower crc byte. This byte now builds the crc | ||||||
|  | ;	table index. Next the new high byte is loaded from the table and stored in x4 until we have space in x3 | ||||||
|  | ;	(its destination). | ||||||
|  | ;	Afterwards the lower table is loaded from the table and stored in ZL (the old index is overwritten as | ||||||
|  | ;	we don't need it anymore. In fact this is a right shift by 8 bits.) Now the old crc high value is xored | ||||||
|  | ;	to ZL, this is the second shift of the old crc value. Now x4 (the temp reg) is moved to x3 and the crc | ||||||
|  | ; 	calculation is done. | ||||||
|  | ;	Prior to the first byte the two CRC register have to be initialized to 0xFFFF (as defined in usb spec) | ||||||
|  | ;	however the crc engine also runs during the receipt of the first byte, therefore x3 and zl are initialized | ||||||
|  | ;	to a magic number which results in a crc value of 0xFFFF after the first complete byte. | ||||||
|  | ; | ||||||
|  | ;	This algorithm is split into the extra cycles of the different bits: | ||||||
|  | ;	bit7:	XOR the received byte to ZL | ||||||
|  | ;	bit5:	load the new high byte to x4 | ||||||
|  | ;	bit6:	load the lower xor byte from the table, xor zl and x3, store result in zl (=the new crc low value) | ||||||
|  | ;			move x4 (the new high byte) to x3, the crc value is ready | ||||||
|  | ; | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | macro POP_STANDARD ; 18 cycles | ||||||
|  |     pop		ZH | ||||||
|  |     pop		ZL | ||||||
|  | 	pop     cnt | ||||||
|  |     pop     x5 | ||||||
|  |     pop     x3 | ||||||
|  |     pop     x2 | ||||||
|  |     pop     x1 | ||||||
|  |     pop     shift | ||||||
|  |     pop     x4 | ||||||
|  |     endm | ||||||
|  | macro POP_RETI     ; 7 cycles | ||||||
|  |     pop     YH | ||||||
|  |     pop     YL | ||||||
|  |     out     SREG, YL | ||||||
|  |     pop     YL | ||||||
|  |     endm | ||||||
|  | 
 | ||||||
|  | macro CRC_CLEANUP_AND_CHECK | ||||||
|  | 	; the last byte has already been xored with the lower crc byte, we have to do the table lookup and xor | ||||||
|  | 	; x3 is the higher crc byte, zl the lower one | ||||||
|  | 	ldi		ZH, hi8(usbCrcTableHigh);[+1] get the new high byte from the table | ||||||
|  | 	lpm		x2, Z				;[+2][+3][+4] | ||||||
|  | 	ldi		ZH, hi8(usbCrcTableLow);[+5] get the new low xor byte from the table | ||||||
|  | 	lpm		ZL, Z				;[+6][+7][+8] | ||||||
|  | 	eor		ZL, x3				;[+7] xor the old high byte with the value from the table, x2:ZL now holds the crc value | ||||||
|  | 	cpi		ZL, 0x01			;[+8] if the crc is ok we have a fixed remainder value of 0xb001 in x2:ZL (see usb spec) | ||||||
|  | 	brne	ignorePacket		;[+9] detected a crc fault -> paket is ignored and retransmitted by the host | ||||||
|  | 	cpi		x2, 0xb0			;[+10] | ||||||
|  | 	brne	ignorePacket		;[+11] detected a crc fault -> paket is ignored and retransmitted by the host | ||||||
|  |     endm | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | USB_INTR_VECTOR: | ||||||
|  | ;order of registers pushed: YL, SREG, YH, [sofError], x4, shift, x1, x2, x3, x5, cnt, ZL, ZH | ||||||
|  |     push    YL                  ;[-28] push only what is necessary to sync with edge ASAP | ||||||
|  |     in      YL, SREG            ;[-26] | ||||||
|  |     push    YL                  ;[-25] | ||||||
|  |     push    YH                  ;[-23] | ||||||
|  | ;---------------------------------------------------------------------------- | ||||||
|  | ; Synchronize with sync pattern: | ||||||
|  | ;---------------------------------------------------------------------------- | ||||||
|  | ;sync byte (D-) pattern LSb to MSb: 01010100 [1 = idle = J, 0 = K] | ||||||
|  | ;sync up with J to K edge during sync pattern -- use fastest possible loops | ||||||
|  | ;The first part waits at most 1 bit long since we must be in sync pattern. | ||||||
|  | ;YL is guarenteed to be < 0x80 because I flag is clear. When we jump to | ||||||
|  | ;waitForJ, ensure that this prerequisite is met. | ||||||
|  | waitForJ: | ||||||
|  |     inc     YL | ||||||
|  |     sbis    USBIN, USBMINUS | ||||||
|  |     brne    waitForJ        ; just make sure we have ANY timeout | ||||||
|  | waitForK: | ||||||
|  | ;The following code results in a sampling window of < 1/4 bit which meets the spec. | ||||||
|  |     sbis    USBIN, USBMINUS     ;[-17] | ||||||
|  |     rjmp    foundK              ;[-16] | ||||||
|  |     sbis    USBIN, USBMINUS | ||||||
|  |     rjmp    foundK | ||||||
|  |     sbis    USBIN, USBMINUS | ||||||
|  |     rjmp    foundK | ||||||
|  |     sbis    USBIN, USBMINUS | ||||||
|  |     rjmp    foundK | ||||||
|  |     sbis    USBIN, USBMINUS | ||||||
|  |     rjmp    foundK | ||||||
|  |     sbis    USBIN, USBMINUS | ||||||
|  |     rjmp    foundK | ||||||
|  |     sbis    USBIN, USBMINUS | ||||||
|  |     rjmp    foundK | ||||||
|  |     sbis    USBIN, USBMINUS | ||||||
|  |     rjmp    foundK | ||||||
|  |     sbis    USBIN, USBMINUS | ||||||
|  |     rjmp    foundK | ||||||
|  | #if USB_COUNT_SOF
 | ||||||
|  |     lds     YL, usbSofCount | ||||||
|  |     inc     YL | ||||||
|  |     sts     usbSofCount, YL | ||||||
|  | #endif  /* USB_COUNT_SOF */
 | ||||||
|  | #ifdef USB_SOF_HOOK
 | ||||||
|  |     USB_SOF_HOOK | ||||||
|  | #endif
 | ||||||
|  |     rjmp    sofError | ||||||
|  | foundK:                         ;[-15] | ||||||
|  | ;{3, 5} after falling D- edge, average delay: 4 cycles | ||||||
|  | ;bit0 should be at 30  (2.5 bits) for center sampling. Currently at 4 so 26 cylces till bit 0 sample | ||||||
|  | ;use 1 bit time for setup purposes, then sample again. Numbers in brackets | ||||||
|  | ;are cycles from center of first sync (double K) bit after the instruction | ||||||
|  |     push    x4                  ;[-14] | ||||||
|  | ;   [---]                       ;[-13] | ||||||
|  |     lds     YL, usbInputBufOffset;[-12] used to toggle the two usb receive buffers | ||||||
|  | ;   [---]                       ;[-11] | ||||||
|  |     clr     YH                  ;[-10] | ||||||
|  |     subi    YL, lo8(-(usbRxBuf));[-9] [rx loop init] | ||||||
|  |     sbci    YH, hi8(-(usbRxBuf));[-8] [rx loop init] | ||||||
|  |     push    shift               ;[-7] | ||||||
|  | ;   [---]                       ;[-6] | ||||||
|  |     ldi		shift, 0x80			;[-5] the last bit is the end of byte marker for the pid receiver loop | ||||||
|  |     clc			      	      	;[-4] the carry has to be clear for receipt of pid bit 0 | ||||||
|  |     sbis    USBIN, USBMINUS     ;[-3] we want two bits K (sample 3 cycles too early) | ||||||
|  |     rjmp    haveTwoBitsK        ;[-2] | ||||||
|  |     pop     shift               ;[-1] undo the push from before | ||||||
|  |     pop     x4                  ;[1] | ||||||
|  |     rjmp    waitForK            ;[3] this was not the end of sync, retry | ||||||
|  | ; The entire loop from waitForK until rjmp waitForK above must not exceed two | ||||||
|  | ; bit times (= 24 cycles). | ||||||
|  | 
 | ||||||
|  | ;---------------------------------------------------------------------------- | ||||||
|  | ; push more registers and initialize values while we sample the first bits: | ||||||
|  | ;---------------------------------------------------------------------------- | ||||||
|  | haveTwoBitsK: | ||||||
|  |     push    x1                  ;[0] | ||||||
|  |     push    x2                  ;[2] | ||||||
|  |     push    x3                  ;[4] crc high byte | ||||||
|  |     ldi     x2, 1<<USBPLUS      ;[6] [rx loop init] current line state is K state. D+=="1", D-=="0" | ||||||
|  |     push    x5                  ;[7] | ||||||
|  |     push    cnt                 ;[9] | ||||||
|  |     ldi     cnt, USB_BUFSIZE    ;[11] | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | ;-------------------------------------------------------------------------------------------------------------- | ||||||
|  | ; receives the pid byte | ||||||
|  | ; there is no real unstuffing algorithm implemented here as a stuffing bit is impossible in the pid byte. | ||||||
|  | ; That's because the last four bits of the byte are the inverted of the first four bits. If we detect a | ||||||
|  | ; unstuffing condition something went wrong and abort | ||||||
|  | ; shift has to be initialized to 0x80 | ||||||
|  | ;-------------------------------------------------------------------------------------------------------------- | ||||||
|  | 
 | ||||||
|  | ; pid bit 0 - used for even more register saving (we need the z pointer) | ||||||
|  | 	in      x1, USBIN           ;[0] sample line state | ||||||
|  |     andi    x1, USBMASK         ;[1] filter only D+ and D- bits | ||||||
|  |     eor		x2, x1				;[2] generate inverted of actual bit | ||||||
|  | 	sbrc	x2, USBMINUS		;[3] if the bit is set we received a zero | ||||||
|  | 	sec							;[4] | ||||||
|  | 	ror		shift				;[5] we perform no unstuffing check here as this is the first bit | ||||||
|  | 	mov		x2, x1				;[6] | ||||||
|  | 	push	ZL					;[7] | ||||||
|  | 								;[8] | ||||||
|  | 	push	ZH					;[9] | ||||||
|  | 								;[10] | ||||||
|  | 	ldi		x3, 0xFE			;[11] x3 is the high order crc value | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | bitloopPid:						 | ||||||
|  | 	in      x1, USBIN           ;[0] sample line state | ||||||
|  |    	andi    x1, USBMASK         ;[1] filter only D+ and D- bits | ||||||
|  |     breq    nse0                ;[2] both lines are low so handle se0	 | ||||||
|  | 	eor		x2, x1				;[3] generate inverted of actual bit | ||||||
|  | 	sbrc	x2, USBMINUS		;[4] set the carry if we received a zero | ||||||
|  | 	sec							;[5] | ||||||
|  | 	ror		shift				;[6] | ||||||
|  | 	ldi		ZL, 0x54			;[7] ZL is the low order crc value | ||||||
|  | 	ser		x4					;[8] the is no bit stuffing check here as the pid bit can't be stuffed. if so | ||||||
|  | 								; some error occured. In this case the paket is discarded later on anyway. | ||||||
|  | 	mov		x2, x1				;[9] prepare for the next cycle | ||||||
|  | 	brcc	bitloopPid			;[10] while 0s drop out of shift we get the next bit | ||||||
|  | 	eor		x4, shift			;[11] invert all bits in shift and store result in x4 | ||||||
|  | 
 | ||||||
|  | ;-------------------------------------------------------------------------------------------------------------- | ||||||
|  | ; receives data bytes and calculates the crc | ||||||
|  | ; the last USBIN state has to be in x2 | ||||||
|  | ; this is only the first half, due to branch distanc limitations the second half of the loop is near the end | ||||||
|  | ; of this asm file | ||||||
|  | ;-------------------------------------------------------------------------------------------------------------- | ||||||
|  | 
 | ||||||
|  | rxDataStart: | ||||||
|  |     in      x1, USBIN           ;[0] sample line state (note: a se0 check is not useful due to bit dribbling) | ||||||
|  |     ser		x5					;[1] prepare the unstuff marker register | ||||||
|  |     eor		x2, x1             	;[2] generates the inverted of the actual bit | ||||||
|  |     bst		x2, USBMINUS       	;[3] copy the bit from x2 | ||||||
|  |     bld		shift, 0	        ;[4] and store it in shift | ||||||
|  |     mov		x2, shift	     	;[5] make a copy of shift for unstuffing check | ||||||
|  |     andi	x2, 0xF9	      	;[6] mask the last six bits, if we got six zeros (which are six ones in fact) | ||||||
|  |     breq	unstuff0	      	;[7] then Z is set now and we branch to the unstuffing handler | ||||||
|  | didunstuff0: | ||||||
|  | 	subi    cnt, 1         		;[8] cannot use dec because it doesn't affect the carry flag | ||||||
|  |     brcs    nOverflow    		;[9] Too many bytes received. Ignore packet							 | ||||||
|  |     st		Y+, x4				;[10] store the last received byte | ||||||
|  | 								;[11] st needs two cycles | ||||||
|  | 
 | ||||||
|  | ; bit1							 | ||||||
|  | 	in		x2, USBIN			;[0] sample line state | ||||||
|  |     andi	x1, USBMASK			;[1] check for se0 during bit 0 | ||||||
|  |     breq	nse0				;[2] | ||||||
|  |     andi	x2, USBMASK			;[3] check se0 during bit 1 | ||||||
|  |     breq	nse0				;[4] | ||||||
|  | 	eor		x1, x2				;[5] | ||||||
|  |     bst		x1, USBMINUS		;[6] | ||||||
|  |     bld 	shift, 1	 		;[7] | ||||||
|  |     mov		x1, shift			;[8] | ||||||
|  |     andi	x1, 0xF3			;[9] | ||||||
|  |     breq	unstuff1			;[10] | ||||||
|  | didunstuff1: | ||||||
|  | 	nop							;[11]	 | ||||||
|  | 
 | ||||||
|  | ; bit2 | ||||||
|  | 	in      x1, USBIN           ;[0] sample line state | ||||||
|  |     andi	x1, USBMASK			;[1] check for se0 (as there is nothing else to do here | ||||||
|  | 	breq	nOverflow	 		;[2] | ||||||
|  |     eor		x2, x1              ;[3] generates the inverted of the actual bit | ||||||
|  |     bst		x2, USBMINUS		;[4] | ||||||
|  |     bld		shift, 2			;[5] store the bit | ||||||
|  |     mov		x2, shift			;[6] | ||||||
|  |     andi	x2, 0xE7			;[7] if we have six zeros here (which means six 1 in the stream) | ||||||
|  |     breq	unstuff2			;[8] the next bit is a stuffing bit | ||||||
|  | didunstuff2: | ||||||
|  | 	nop2						;[9] | ||||||
|  | 								;[10] | ||||||
|  | 	nop							;[11]					 | ||||||
|  | 					 | ||||||
|  | ; bit3							 | ||||||
|  | 	in		x2, USBIN			;[0] sample line state | ||||||
|  |     andi	x2, USBMASK			;[1] check for se0 | ||||||
|  |     breq	nOverflow           ;[2] | ||||||
|  |     eor		x1, x2				;[3] | ||||||
|  |     bst		x1, USBMINUS		;[4] | ||||||
|  |     bld 	shift, 3	 		;[5] | ||||||
|  |     mov		x1, shift			;[6] | ||||||
|  |     andi	x1, 0xCF			;[7] | ||||||
|  |     breq	unstuff3			;[8] | ||||||
|  | didunstuff3: | ||||||
|  | 	nop							;[9] | ||||||
|  | 	rjmp 	rxDataBit4			;[10] | ||||||
|  | 								;[11]				 | ||||||
|  | 
 | ||||||
|  | ; the avr branch instructions allow an offset of +63 insturction only, so we need this | ||||||
|  | ; 'local copy' of se0 | ||||||
|  | nse0:		 | ||||||
|  | 	rjmp	se0					;[4] | ||||||
|  | 								;[5] | ||||||
|  | ; the same same as for se0 is needed for overflow and StuffErr | ||||||
|  | nOverflow: | ||||||
|  | stuffErr: | ||||||
|  | 	rjmp	overflow | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | unstuff0:						;[8] this is the branch delay of breq unstuffX | ||||||
|  | 	andi	x1, USBMASK			;[9] do an se0 check here (if the last crc byte ends with 5 one's we might end up here | ||||||
|  | 	breq	didunstuff0			;[10] event tough the message is complete -> jump back and store the byte | ||||||
|  | 	ori		shift, 0x01			;[11] invert the last received bit to prevent furhter unstuffing | ||||||
|  | 	in		x2, USBIN			;[0] we have some free cycles so we could check for bit stuffing errors | ||||||
|  | 	andi	x5, 0xFE			;[1] mark this bit as inverted (will be corrected before storing shift) | ||||||
|  | 	eor		x1, x2				;[2] x1 and x2 have to be different because the stuff bit is always a zero | ||||||
|  | 	andi	x1, USBMASK			;[3] mask the interesting bits | ||||||
|  | 	breq	stuffErr			;[4] if the stuff bit is a 1-bit something went wrong | ||||||
|  | 	mov 	x1, x2				;[5] the next bit expects the last state to be in x1 | ||||||
|  | 	rjmp 	didunstuff0			;[6] | ||||||
|  | 								;[7] jump delay of rjmp didunstuffX	 | ||||||
|  | 
 | ||||||
|  | unstuff1:						;[11] this is the jump delay of breq unstuffX | ||||||
|  | 	in		x1, USBIN			;[0] we have some free cycles so we could check for bit stuffing errors | ||||||
|  | 	ori		shift, 0x02			;[1] invert the last received bit to prevent furhter unstuffing | ||||||
|  | 	andi	x5, 0xFD			;[2] mark this bit as inverted (will be corrected before storing shift) | ||||||
|  | 	eor		x2, x1				;[3] x1 and x2 have to be different because the stuff bit is always a zero | ||||||
|  | 	andi	x2, USBMASK			;[4] mask the interesting bits | ||||||
|  | 	breq	stuffErr			;[5] if the stuff bit is a 1-bit something went wrong | ||||||
|  | 	mov 	x2, x1				;[6] the next bit expects the last state to be in x2 | ||||||
|  | 	nop2						;[7] | ||||||
|  | 								;[8] | ||||||
|  | 	rjmp 	didunstuff1			;[9] | ||||||
|  | 								;[10] jump delay of rjmp didunstuffX		 | ||||||
|  | 
 | ||||||
|  | unstuff2:						;[9] this is the jump delay of breq unstuffX | ||||||
|  | 	ori		shift, 0x04			;[10] invert the last received bit to prevent furhter unstuffing | ||||||
|  | 	andi	x5, 0xFB			;[11] mark this bit as inverted (will be corrected before storing shift) | ||||||
|  | 	in		x2, USBIN			;[0] we have some free cycles so we could check for bit stuffing errors | ||||||
|  | 	eor		x1, x2				;[1] x1 and x2 have to be different because the stuff bit is always a zero | ||||||
|  | 	andi	x1, USBMASK			;[2] mask the interesting bits | ||||||
|  | 	breq	stuffErr			;[3] if the stuff bit is a 1-bit something went wrong | ||||||
|  | 	mov 	x1, x2				;[4] the next bit expects the last state to be in x1 | ||||||
|  | 	nop2						;[5] | ||||||
|  | 								;[6] | ||||||
|  | 	rjmp 	didunstuff2			;[7] | ||||||
|  | 								;[8] jump delay of rjmp didunstuffX	 | ||||||
|  | 
 | ||||||
|  | unstuff3:						;[9] this is the jump delay of breq unstuffX | ||||||
|  | 	ori		shift, 0x08			;[10] invert the last received bit to prevent furhter unstuffing | ||||||
|  | 	andi	x5, 0xF7			;[11] mark this bit as inverted (will be corrected before storing shift) | ||||||
|  | 	in		x1, USBIN			;[0] we have some free cycles so we could check for bit stuffing errors | ||||||
|  | 	eor		x2, x1				;[1] x1 and x2 have to be different because the stuff bit is always a zero | ||||||
|  | 	andi	x2, USBMASK			;[2] mask the interesting bits | ||||||
|  | 	breq	stuffErr			;[3] if the stuff bit is a 1-bit something went wrong | ||||||
|  | 	mov 	x2, x1				;[4] the next bit expects the last state to be in x2 | ||||||
|  | 	nop2						;[5] | ||||||
|  | 								;[6] | ||||||
|  | 	rjmp 	didunstuff3			;[7] | ||||||
|  | 								;[8] jump delay of rjmp didunstuffX			 | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | ; the include has to be here due to branch distance restirctions | ||||||
|  | #define __USE_CRC__
 | ||||||
|  | #include "asmcommon.inc"
 | ||||||
|  | 
 | ||||||
|  | 	 | ||||||
|  | 
 | ||||||
|  | ; USB spec says: | ||||||
|  | ; idle = J | ||||||
|  | ; J = (D+ = 0), (D- = 1) | ||||||
|  | ; K = (D+ = 1), (D- = 0) | ||||||
|  | ; Spec allows 7.5 bit times from EOP to SOP for replies | ||||||
|  | ; 7.5 bit times is 90 cycles. ...there is plenty of time | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | sendNakAndReti: | ||||||
|  |     ldi     x3, USBPID_NAK  ;[-18] | ||||||
|  |     rjmp    sendX3AndReti   ;[-17] | ||||||
|  | sendAckAndReti: | ||||||
|  |     ldi     cnt, USBPID_ACK ;[-17] | ||||||
|  | sendCntAndReti: | ||||||
|  |     mov     x3, cnt         ;[-16] | ||||||
|  | sendX3AndReti: | ||||||
|  |     ldi     YL, 20          ;[-15] x3==r20 address is 20 | ||||||
|  |     ldi     YH, 0           ;[-14] | ||||||
|  |     ldi     cnt, 2          ;[-13] | ||||||
|  | ;   rjmp    usbSendAndReti      fallthrough | ||||||
|  | 
 | ||||||
|  | ;usbSend: | ||||||
|  | ;pointer to data in 'Y' | ||||||
|  | ;number of bytes in 'cnt' -- including sync byte [range 2 ... 12] | ||||||
|  | ;uses: x1...x4, btcnt, shift, cnt, Y | ||||||
|  | ;Numbers in brackets are time since first bit of sync pattern is sent | ||||||
|  | 
 | ||||||
|  | usbSendAndReti:             ; 12 cycles until SOP | ||||||
|  |     in      x2, USBDDR      ;[-12] | ||||||
|  |     ori     x2, USBMASK     ;[-11] | ||||||
|  |     sbi     USBOUT, USBMINUS;[-10] prepare idle state; D+ and D- must have been 0 (no pullups) | ||||||
|  |     in      x1, USBOUT      ;[-8] port mirror for tx loop | ||||||
|  |     out     USBDDR, x2      ;[-6] <- acquire bus | ||||||
|  | 	ldi		x2, 0			;[-6] init x2 (bitstuff history) because sync starts with 0 | ||||||
|  |     ldi     x4, USBMASK     ;[-5] exor mask | ||||||
|  |     ldi     shift, 0x80     ;[-4] sync byte is first byte sent | ||||||
|  | txByteLoop: | ||||||
|  |     ldi     bitcnt, 0x40    ;[-3]=[9]     binary 01000000 | ||||||
|  | txBitLoop:					; the loop sends the first 7 bits of the byte | ||||||
|  |     sbrs    shift, 0        ;[-2]=[10] if we have to send a 1 don't change the line state | ||||||
|  |     eor     x1, x4          ;[-1]=[11] | ||||||
|  |     out     USBOUT, x1      ;[0] | ||||||
|  |     ror     shift           ;[1] | ||||||
|  |     ror     x2              ;[2] transfers the last sent bit to the stuffing history | ||||||
|  | didStuffN: | ||||||
|  |     nop	                    ;[3] | ||||||
|  |     nop                     ;[4] | ||||||
|  |     cpi     x2, 0xfc        ;[5] if we sent six consecutive ones | ||||||
|  |     brcc    bitstuffN       ;[6] | ||||||
|  |     lsr     bitcnt          ;[7] | ||||||
|  |     brne    txBitLoop       ;[8] restart the loop while the 1 is still in the bitcount | ||||||
|  | 
 | ||||||
|  | ; transmit bit 7 | ||||||
|  |     sbrs    shift, 0        ;[9] | ||||||
|  |     eor     x1, x4          ;[10] | ||||||
|  | didStuff7: | ||||||
|  |     ror     shift           ;[11] | ||||||
|  | 	out     USBOUT, x1      ;[0] transfer bit 7 to the pins | ||||||
|  |     ror     x2              ;[1] move the bit into the stuffing history	 | ||||||
|  |     cpi     x2, 0xfc        ;[2] | ||||||
|  |     brcc    bitstuff7       ;[3] | ||||||
|  |     ld      shift, y+       ;[4] get next byte to transmit | ||||||
|  |     dec     cnt             ;[5] decrement byte counter | ||||||
|  |     brne    txByteLoop      ;[7] if we have more bytes start next one | ||||||
|  |     						;[8] branch delay | ||||||
|  |     						 | ||||||
|  | ;make SE0: | ||||||
|  |     cbr     x1, USBMASK     ;[8] 		prepare SE0 [spec says EOP may be 25 to 30 cycles] | ||||||
|  |     lds     x2, usbNewDeviceAddr;[9] | ||||||
|  |     lsl     x2              ;[11] 		we compare with left shifted address | ||||||
|  |     out     USBOUT, x1      ;[0] 		<-- out SE0 -- from now 2 bits = 24 cycles until bus idle | ||||||
|  |     subi    YL, 20 + 2      ;[1] 		Only assign address on data packets, not ACK/NAK in x3 | ||||||
|  |     sbci    YH, 0           ;[2] | ||||||
|  | ;2006-03-06: moved transfer of new address to usbDeviceAddr from C-Code to asm: | ||||||
|  | ;set address only after data packet was sent, not after handshake | ||||||
|  |     breq    skipAddrAssign  ;[3] | ||||||
|  |     sts     usbDeviceAddr, x2		; if not skipped: SE0 is one cycle longer | ||||||
|  | skipAddrAssign: | ||||||
|  | ;end of usbDeviceAddress transfer | ||||||
|  |     ldi     x2, 1<<USB_INTR_PENDING_BIT;[5] int0 occurred during TX -- clear pending flag | ||||||
|  |     USB_STORE_PENDING(x2)   ;[6] | ||||||
|  |     ori     x1, USBIDLE     ;[7] | ||||||
|  |     in      x2, USBDDR      ;[8] | ||||||
|  |     cbr     x2, USBMASK     ;[9] set both pins to input | ||||||
|  |     mov     x3, x1          ;[10] | ||||||
|  |     cbr     x3, USBMASK     ;[11] configure no pullup on both pins | ||||||
|  |     ldi     x4, 4           ;[12] | ||||||
|  | se0Delay: | ||||||
|  |     dec     x4              ;[13] [16] [19] [22] | ||||||
|  |     brne    se0Delay        ;[14] [17] [20] [23] | ||||||
|  |     out     USBOUT, x1      ;[24] <-- out J (idle) -- end of SE0 (EOP signal) | ||||||
|  |     out     USBDDR, x2      ;[25] <-- release bus now | ||||||
|  |     out     USBOUT, x3      ;[26] <-- ensure no pull-up resistors are active | ||||||
|  |     rjmp    doReturn | ||||||
|  | 
 | ||||||
|  | bitstuffN: | ||||||
|  |     eor     x1, x4          ;[8] generate a zero | ||||||
|  |     ldi     x2, 0           ;[9] reset the bit stuffing history | ||||||
|  |     nop2                    ;[10] | ||||||
|  |     out     USBOUT, x1      ;[0] <-- send the stuffing bit | ||||||
|  |     rjmp    didStuffN       ;[1] | ||||||
|  | 
 | ||||||
|  | bitstuff7: | ||||||
|  |     eor     x1, x4          ;[5] | ||||||
|  |     ldi     x2, 0           ;[6] reset bit stuffing history | ||||||
|  |     clc						;[7] fill a zero into the shift register | ||||||
|  |     rol     shift           ;[8] compensate for ror shift at branch destination | ||||||
|  |     rjmp    didStuff7       ;[9] | ||||||
|  |     						;[10] jump delay | ||||||
|  | 
 | ||||||
|  | ;-------------------------------------------------------------------------------------------------------------- | ||||||
|  | ; receives data bytes and calculates the crc | ||||||
|  | ; second half of the data byte receiver loop | ||||||
|  | ; most parts of the crc algorithm are here | ||||||
|  | ;-------------------------------------------------------------------------------------------------------------- | ||||||
|  | 
 | ||||||
|  | nOverflow2: | ||||||
|  | 	rjmp overflow | ||||||
|  | 
 | ||||||
|  | rxDataBit4: | ||||||
|  | 	in      x1, USBIN           ;[0] sample line state | ||||||
|  |     andi	x1, USBMASK			;[1] check for se0 | ||||||
|  |     breq	nOverflow2			;[2] | ||||||
|  |     eor		x2, x1              ;[3] | ||||||
|  |     bst		x2, USBMINUS		;[4] | ||||||
|  |     bld		shift, 4			;[5] | ||||||
|  |     mov		x2, shift			;[6] | ||||||
|  |     andi	x2, 0x9F			;[7] | ||||||
|  |     breq	unstuff4			;[8] | ||||||
|  | didunstuff4: | ||||||
|  | 	nop2						;[9][10] | ||||||
|  | 	nop							;[11] | ||||||
|  | 
 | ||||||
|  | ; bit5							 | ||||||
|  | 	in		x2, USBIN			;[0] sample line state | ||||||
|  |     ldi		ZH, hi8(usbCrcTableHigh);[1] use the table for the higher byte | ||||||
|  |     eor		x1, x2				;[2] | ||||||
|  |     bst		x1, USBMINUS		;[3] | ||||||
|  |     bld 	shift, 5	 		;[4] | ||||||
|  |     mov		x1, shift			;[5] | ||||||
|  |     andi	x1, 0x3F			;[6] | ||||||
|  |     breq	unstuff5			;[7] | ||||||
|  | didunstuff5: | ||||||
|  | 	lpm		x4, Z				;[8] load the higher crc xor-byte and store it for later use | ||||||
|  | 								;[9] lpm needs 3 cycles | ||||||
|  | 								;[10]			 | ||||||
|  | 	ldi		ZH, hi8(usbCrcTableLow);[11] load the lower crc xor byte adress | ||||||
|  | 
 | ||||||
|  | ; bit6	    					 | ||||||
|  | 	in      x1, USBIN           ;[0] sample line state | ||||||
|  |     eor		x2, x1              ;[1] | ||||||
|  |     bst		x2, USBMINUS		;[2] | ||||||
|  |     bld		shift, 6			;[3] | ||||||
|  |     mov		x2, shift			;[4] | ||||||
|  |     andi	x2, 0x7E			;[5] | ||||||
|  |     breq	unstuff6			;[6] | ||||||
|  | didunstuff6: | ||||||
|  | 	lpm		ZL, Z				;[7] load the lower xor crc byte | ||||||
|  | 								;[8] lpm needs 3 cycles | ||||||
|  | 	    						;[9] | ||||||
|  | 	eor		ZL, x3				;[10] xor the old high crc byte with the low xor-byte | ||||||
|  | 	mov		x3, x4				;[11] move the new high order crc value from temp to its destination | ||||||
|  | 			 | ||||||
|  | ; bit7							 | ||||||
|  | 	in		x2, USBIN			;[0] sample line state | ||||||
|  |     eor		x1, x2				;[1] | ||||||
|  |     bst		x1, USBMINUS		;[2] | ||||||
|  |     bld 	shift, 7	 		;[3] now shift holds the complete but inverted data byte | ||||||
|  |     mov		x1, shift			;[4] | ||||||
|  |     andi	x1, 0xFC			;[5] | ||||||
|  |     breq	unstuff7			;[6] | ||||||
|  | didunstuff7: | ||||||
|  | 	eor		x5, shift			;[7] x5 marks all bits which have not been inverted by the unstuffing subs | ||||||
|  | 	mov		x4, x5				;[8] keep a copy of the data byte it will be stored during next bit0 | ||||||
|  | 	eor		ZL, x4				;[9] feed the actual byte into the crc algorithm | ||||||
|  | 	rjmp	rxDataStart			;[10] next byte | ||||||
|  | 								;[11] during the reception of the next byte this one will be fed int the crc algorithm | ||||||
|  | 
 | ||||||
|  | unstuff4:						;[9] this is the jump delay of rjmp unstuffX | ||||||
|  | 	ori		shift, 0x10			;[10] invert the last received bit to prevent furhter unstuffing | ||||||
|  | 	andi	x5, 0xEF			;[11] mark this bit as inverted (will be corrected before storing shift) | ||||||
|  | 	in		x2, USBIN			;[0] we have some free cycles so we could check for bit stuffing errors | ||||||
|  | 	eor		x1, x2				;[1] x1 and x2 have to be different because the stuff bit is always a zero | ||||||
|  | 	andi	x1, USBMASK			;[2] mask the interesting bits | ||||||
|  | 	breq	stuffErr2			;[3] if the stuff bit is a 1-bit something went wrong | ||||||
|  | 	mov 	x1, x2				;[4] the next bit expects the last state to be in x1 | ||||||
|  | 	nop2						;[5] | ||||||
|  | 								;[6] | ||||||
|  | 	rjmp 	didunstuff4			;[7] | ||||||
|  | 								;[8] jump delay of rjmp didunstuffX	 | ||||||
|  | 
 | ||||||
|  | unstuff5:						;[8] this is the jump delay of rjmp unstuffX | ||||||
|  | 	nop							;[9] | ||||||
|  | 	ori		shift, 0x20			;[10] invert the last received bit to prevent furhter unstuffing | ||||||
|  | 	andi	x5, 0xDF			;[11] mark this bit as inverted (will be corrected before storing shift) | ||||||
|  | 	in		x1, USBIN			;[0] we have some free cycles so we could check for bit stuffing errors | ||||||
|  | 	eor		x2, x1				;[1] x1 and x2 have to be different because the stuff bit is always a zero | ||||||
|  | 	andi	x2, USBMASK			;[2] mask the interesting bits | ||||||
|  | 	breq	stuffErr2			;[3] if the stuff bit is a 1-bit something went wrong | ||||||
|  | 	mov 	x2, x1				;[4] the next bit expects the last state to be in x2 | ||||||
|  | 	nop							;[5] | ||||||
|  | 	rjmp 	didunstuff5			;[6] | ||||||
|  | 								;[7] jump delay of rjmp didunstuffX													 | ||||||
|  | 
 | ||||||
|  | unstuff6:						;[7] this is the jump delay of rjmp unstuffX | ||||||
|  | 	nop2						;[8] | ||||||
|  | 								;[9] | ||||||
|  | 	ori		shift, 0x40			;[10] invert the last received bit to prevent furhter unstuffing | ||||||
|  | 	andi	x5, 0xBF			;[11] mark this bit as inverted (will be corrected before storing shift) | ||||||
|  | 	in		x2, USBIN			;[0] we have some free cycles so we could check for bit stuffing errors | ||||||
|  | 	eor		x1, x2				;[1] x1 and x2 have to be different because the stuff bit is always a zero | ||||||
|  | 	andi	x1, USBMASK			;[2] mask the interesting bits | ||||||
|  | 	breq	stuffErr2			;[3] if the stuff bit is a 1-bit something went wrong | ||||||
|  | 	mov 	x1, x2				;[4] the next bit expects the last state to be in x1 | ||||||
|  | 	rjmp 	didunstuff6			;[5] | ||||||
|  | 								;[6] jump delay of rjmp didunstuffX	 | ||||||
|  | 
 | ||||||
|  | unstuff7:						;[7] this is the jump delay of rjmp unstuffX | ||||||
|  | 	nop							;[8] | ||||||
|  | 	nop							;[9] | ||||||
|  | 	ori		shift, 0x80			;[10] invert the last received bit to prevent furhter unstuffing | ||||||
|  | 	andi	x5, 0x7F			;[11] mark this bit as inverted (will be corrected before storing shift) | ||||||
|  | 	in		x1, USBIN			;[0] we have some free cycles so we could check for bit stuffing errors | ||||||
|  | 	eor		x2, x1				;[1] x1 and x2 have to be different because the stuff bit is always a zero | ||||||
|  | 	andi	x2, USBMASK			;[2] mask the interesting bits | ||||||
|  | 	breq	stuffErr2			;[3] if the stuff bit is a 1-bit something went wrong | ||||||
|  | 	mov 	x2, x1				;[4] the next bit expects the last state to be in x2 | ||||||
|  | 	rjmp 	didunstuff7			;[5] | ||||||
|  | 								;[6] jump delay of rjmp didunstuff7 | ||||||
|  | 
 | ||||||
|  | ; local copy of the stuffErr desitnation for the second half of the receiver loop | ||||||
|  | stuffErr2: | ||||||
|  | 	rjmp	stuffErr | ||||||
|  | 
 | ||||||
|  | ;-------------------------------------------------------------------------------------------------------------- | ||||||
|  | ; The crc table follows. It has to be aligned to enable a fast loading of the needed bytes. | ||||||
|  | ; There are two tables of 256 entries each, the low and the high byte table. | ||||||
|  | ; Table values were generated with the following C code: | ||||||
|  | /* | ||||||
|  | #include <stdio.h>
 | ||||||
|  | int main (int argc, char **argv) | ||||||
|  | { | ||||||
|  | 	int i, j; | ||||||
|  | 	for (i=0; i<512; i++){ | ||||||
|  | 		unsigned short crc = i & 0xff; | ||||||
|  | 		for(j=0; j<8; j++) crc = (crc >> 1) ^ ((crc & 1) ? 0xa001 : 0); | ||||||
|  | 		if((i & 7) == 0) printf("\n.byte "); | ||||||
|  | 		printf("0x%02x, ", (i > 0xff ? (crc >> 8) : crc) & 0xff); | ||||||
|  | 		if(i == 255) printf("\n"); | ||||||
|  | 	} | ||||||
|  | 	return 0; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // Use the following algorithm to compute CRC values:
 | ||||||
|  | ushort computeCrc(uchar *msg, uchar msgLen) | ||||||
|  | { | ||||||
|  |     uchar i; | ||||||
|  | 	ushort crc = 0xffff; | ||||||
|  | 	for(i = 0; i < msgLen; i++) | ||||||
|  | 		crc = usbCrcTable16[lo8(crc) ^ msg[i]] ^ hi8(crc); | ||||||
|  |     return crc; | ||||||
|  | } | ||||||
|  | */ | ||||||
|  | 
 | ||||||
|  | .balign 256 | ||||||
|  | usbCrcTableLow:	 | ||||||
|  | .byte 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41 | ||||||
|  | .byte 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40 | ||||||
|  | .byte 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40 | ||||||
|  | .byte 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41 | ||||||
|  | .byte 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40 | ||||||
|  | .byte 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41 | ||||||
|  | .byte 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41 | ||||||
|  | .byte 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40 | ||||||
|  | .byte 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40 | ||||||
|  | .byte 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41 | ||||||
|  | .byte 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41 | ||||||
|  | .byte 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40 | ||||||
|  | .byte 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41 | ||||||
|  | .byte 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40 | ||||||
|  | .byte 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40 | ||||||
|  | .byte 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41 | ||||||
|  | .byte 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40 | ||||||
|  | .byte 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41 | ||||||
|  | .byte 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41 | ||||||
|  | .byte 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40 | ||||||
|  | .byte 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41 | ||||||
|  | .byte 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40 | ||||||
|  | .byte 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40 | ||||||
|  | .byte 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41 | ||||||
|  | .byte 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41 | ||||||
|  | .byte 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40 | ||||||
|  | .byte 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40 | ||||||
|  | .byte 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41 | ||||||
|  | .byte 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40 | ||||||
|  | .byte 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41 | ||||||
|  | .byte 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41 | ||||||
|  | .byte 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40 | ||||||
|  | 
 | ||||||
|  | ; .balign 256 | ||||||
|  | usbCrcTableHigh: | ||||||
|  | .byte 0x00, 0xC0, 0xC1, 0x01, 0xC3, 0x03, 0x02, 0xC2 | ||||||
|  | .byte 0xC6, 0x06, 0x07, 0xC7, 0x05, 0xC5, 0xC4, 0x04 | ||||||
|  | .byte 0xCC, 0x0C, 0x0D, 0xCD, 0x0F, 0xCF, 0xCE, 0x0E | ||||||
|  | .byte 0x0A, 0xCA, 0xCB, 0x0B, 0xC9, 0x09, 0x08, 0xC8 | ||||||
|  | .byte 0xD8, 0x18, 0x19, 0xD9, 0x1B, 0xDB, 0xDA, 0x1A | ||||||
|  | .byte 0x1E, 0xDE, 0xDF, 0x1F, 0xDD, 0x1D, 0x1C, 0xDC | ||||||
|  | .byte 0x14, 0xD4, 0xD5, 0x15, 0xD7, 0x17, 0x16, 0xD6 | ||||||
|  | .byte 0xD2, 0x12, 0x13, 0xD3, 0x11, 0xD1, 0xD0, 0x10 | ||||||
|  | .byte 0xF0, 0x30, 0x31, 0xF1, 0x33, 0xF3, 0xF2, 0x32 | ||||||
|  | .byte 0x36, 0xF6, 0xF7, 0x37, 0xF5, 0x35, 0x34, 0xF4 | ||||||
|  | .byte 0x3C, 0xFC, 0xFD, 0x3D, 0xFF, 0x3F, 0x3E, 0xFE | ||||||
|  | .byte 0xFA, 0x3A, 0x3B, 0xFB, 0x39, 0xF9, 0xF8, 0x38 | ||||||
|  | .byte 0x28, 0xE8, 0xE9, 0x29, 0xEB, 0x2B, 0x2A, 0xEA | ||||||
|  | .byte 0xEE, 0x2E, 0x2F, 0xEF, 0x2D, 0xED, 0xEC, 0x2C | ||||||
|  | .byte 0xE4, 0x24, 0x25, 0xE5, 0x27, 0xE7, 0xE6, 0x26 | ||||||
|  | .byte 0x22, 0xE2, 0xE3, 0x23, 0xE1, 0x21, 0x20, 0xE0 | ||||||
|  | .byte 0xA0, 0x60, 0x61, 0xA1, 0x63, 0xA3, 0xA2, 0x62 | ||||||
|  | .byte 0x66, 0xA6, 0xA7, 0x67, 0xA5, 0x65, 0x64, 0xA4 | ||||||
|  | .byte 0x6C, 0xAC, 0xAD, 0x6D, 0xAF, 0x6F, 0x6E, 0xAE | ||||||
|  | .byte 0xAA, 0x6A, 0x6B, 0xAB, 0x69, 0xA9, 0xA8, 0x68 | ||||||
|  | .byte 0x78, 0xB8, 0xB9, 0x79, 0xBB, 0x7B, 0x7A, 0xBA | ||||||
|  | .byte 0xBE, 0x7E, 0x7F, 0xBF, 0x7D, 0xBD, 0xBC, 0x7C | ||||||
|  | .byte 0xB4, 0x74, 0x75, 0xB5, 0x77, 0xB7, 0xB6, 0x76 | ||||||
|  | .byte 0x72, 0xB2, 0xB3, 0x73, 0xB1, 0x71, 0x70, 0xB0 | ||||||
|  | .byte 0x50, 0x90, 0x91, 0x51, 0x93, 0x53, 0x52, 0x92 | ||||||
|  | .byte 0x96, 0x56, 0x57, 0x97, 0x55, 0x95, 0x94, 0x54 | ||||||
|  | .byte 0x9C, 0x5C, 0x5D, 0x9D, 0x5F, 0x9F, 0x9E, 0x5E | ||||||
|  | .byte 0x5A, 0x9A, 0x9B, 0x5B, 0x99, 0x59, 0x58, 0x98 | ||||||
|  | .byte 0x88, 0x48, 0x49, 0x89, 0x4B, 0x8B, 0x8A, 0x4A | ||||||
|  | .byte 0x4E, 0x8E, 0x8F, 0x4F, 0x8D, 0x4D, 0x4C, 0x8C | ||||||
|  | .byte 0x44, 0x84, 0x85, 0x45, 0x87, 0x47, 0x46, 0x86 | ||||||
|  | .byte 0x82, 0x42, 0x43, 0x83, 0x41, 0x81, 0x80, 0x40	 | ||||||
|  | 
 | ||||||
							
								
								
									
										359
									
								
								keyboards/planck/thk/bootloader/usbdrv/usbdrvasm20.inc
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										359
									
								
								keyboards/planck/thk/bootloader/usbdrv/usbdrvasm20.inc
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,359 @@ | |||||||
|  | /* Name: usbdrvasm20.inc | ||||||
|  |  * Project: V-USB, virtual USB port for Atmel's(r) AVR(r) microcontrollers | ||||||
|  |  * Author: Jeroen Benschop | ||||||
|  |  * Based on usbdrvasm16.inc from Christian Starkjohann | ||||||
|  |  * Creation Date: 2008-03-05 | ||||||
|  |  * Tabsize: 4 | ||||||
|  |  * Copyright: (c) 2008 by Jeroen Benschop and OBJECTIVE DEVELOPMENT Software GmbH | ||||||
|  |  * License: GNU GPL v2 (see License.txt), GNU GPL v3 or proprietary (CommercialLicense.txt) | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | /* Do not link this file! Link usbdrvasm.S instead, which includes the | ||||||
|  |  * appropriate implementation! | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | /* | ||||||
|  | General Description: | ||||||
|  | This file is the 20 MHz version of the asssembler part of the USB driver. It | ||||||
|  | requires a 20 MHz crystal (not a ceramic resonator and not a calibrated RC | ||||||
|  | oscillator). | ||||||
|  | 
 | ||||||
|  | See usbdrv.h for a description of the entire driver. | ||||||
|  | 
 | ||||||
|  | Since almost all of this code is timing critical, don't change unless you | ||||||
|  | really know what you are doing! Many parts require not only a maximum number | ||||||
|  | of CPU cycles, but even an exact number of cycles! | ||||||
|  | */ | ||||||
|  | 
 | ||||||
|  | #define leap2   x3
 | ||||||
|  | #ifdef __IAR_SYSTEMS_ASM__
 | ||||||
|  | #define nextInst    $+2
 | ||||||
|  | #else
 | ||||||
|  | #define nextInst    .+0
 | ||||||
|  | #endif
 | ||||||
|  | 
 | ||||||
|  | ;max stack usage: [ret(2), YL, SREG, YH, bitcnt, shift, x1, x2, x3, x4, cnt] = 12 bytes | ||||||
|  | ;nominal frequency: 20 MHz -> 13.333333 cycles per bit, 106.666667 cycles per byte | ||||||
|  | ; Numbers in brackets are clocks counted from center of last sync bit | ||||||
|  | ; when instruction starts | ||||||
|  | ;register use in receive loop: | ||||||
|  | ; shift assembles the byte currently being received | ||||||
|  | ; x1 holds the D+ and D- line state | ||||||
|  | ; x2 holds the previous line state | ||||||
|  | ; x4 (leap)  is used to add a leap cycle once every three bytes received | ||||||
|  | ; X3 (leap2) is used to add a leap cycle once every three stuff bits received | ||||||
|  | ; bitcnt is used to determine when a stuff bit is due | ||||||
|  | ; cnt holds the number of bytes left in the receive buffer | ||||||
|  | 
 | ||||||
|  | USB_INTR_VECTOR: | ||||||
|  | ;order of registers pushed: YL, SREG YH, [sofError], bitcnt, shift, x1, x2, x3, x4, cnt | ||||||
|  |     push    YL                  ;[-28] push only what is necessary to sync with edge ASAP | ||||||
|  |     in      YL, SREG            ;[-26] | ||||||
|  |     push    YL                  ;[-25] | ||||||
|  |     push    YH                  ;[-23] | ||||||
|  | ;---------------------------------------------------------------------------- | ||||||
|  | ; Synchronize with sync pattern: | ||||||
|  | ;---------------------------------------------------------------------------- | ||||||
|  | ;sync byte (D-) pattern LSb to MSb: 01010100 [1 = idle = J, 0 = K] | ||||||
|  | ;sync up with J to K edge during sync pattern -- use fastest possible loops | ||||||
|  | ;The first part waits at most 1 bit long since we must be in sync pattern. | ||||||
|  | ;YL is guarenteed to be < 0x80 because I flag is clear. When we jump to | ||||||
|  | ;waitForJ, ensure that this prerequisite is met. | ||||||
|  | waitForJ: | ||||||
|  |     inc     YL | ||||||
|  |     sbis    USBIN, USBMINUS | ||||||
|  |     brne    waitForJ        ; just make sure we have ANY timeout | ||||||
|  | waitForK: | ||||||
|  | ;The following code results in a sampling window of < 1/4 bit which meets the spec. | ||||||
|  |     sbis    USBIN, USBMINUS     ;[-19] | ||||||
|  |     rjmp    foundK              ;[-18] | ||||||
|  |     sbis    USBIN, USBMINUS | ||||||
|  |     rjmp    foundK | ||||||
|  |     sbis    USBIN, USBMINUS | ||||||
|  |     rjmp    foundK | ||||||
|  |     sbis    USBIN, USBMINUS | ||||||
|  |     rjmp    foundK | ||||||
|  |     sbis    USBIN, USBMINUS | ||||||
|  |     rjmp    foundK | ||||||
|  |     sbis    USBIN, USBMINUS | ||||||
|  |     rjmp    foundK | ||||||
|  |     sbis    USBIN, USBMINUS | ||||||
|  |     rjmp    foundK | ||||||
|  |     sbis    USBIN, USBMINUS | ||||||
|  |     rjmp    foundK | ||||||
|  |     sbis    USBIN, USBMINUS | ||||||
|  |     rjmp    foundK | ||||||
|  | #if USB_COUNT_SOF
 | ||||||
|  |     lds     YL, usbSofCount | ||||||
|  |     inc     YL | ||||||
|  |     sts     usbSofCount, YL | ||||||
|  | #endif  /* USB_COUNT_SOF */
 | ||||||
|  | #ifdef USB_SOF_HOOK
 | ||||||
|  |     USB_SOF_HOOK | ||||||
|  | #endif
 | ||||||
|  |     rjmp    sofError | ||||||
|  | foundK:                         ;[-16] | ||||||
|  | ;{3, 5} after falling D- edge, average delay: 4 cycles | ||||||
|  | ;bit0 should be at 34 for center sampling. Currently at 4 so 30 cylces till bit 0 sample | ||||||
|  | ;use 1 bit time for setup purposes, then sample again. Numbers in brackets | ||||||
|  | ;are cycles from center of first sync (double K) bit after the instruction | ||||||
|  |     push    bitcnt              ;[-16] | ||||||
|  | ;   [---]                       ;[-15] | ||||||
|  |     lds     YL, usbInputBufOffset;[-14] | ||||||
|  | ;   [---]                       ;[-13] | ||||||
|  |     clr     YH                  ;[-12] | ||||||
|  |     subi    YL, lo8(-(usbRxBuf));[-11] [rx loop init] | ||||||
|  |     sbci    YH, hi8(-(usbRxBuf));[-10] [rx loop init] | ||||||
|  |     push    shift               ;[-9] | ||||||
|  | ;   [---]                       ;[-8] | ||||||
|  |     ldi     shift,0x40          ;[-7] set msb to "1" so processing bit7 can be detected | ||||||
|  |     nop2                        ;[-6] | ||||||
|  | ;   [---]                       ;[-5] | ||||||
|  |     ldi     bitcnt, 5           ;[-4] [rx loop init] | ||||||
|  |     sbis    USBIN, USBMINUS     ;[-3] we want two bits K (sample 3 cycles too early) | ||||||
|  |     rjmp    haveTwoBitsK        ;[-2] | ||||||
|  |     pop     shift               ;[-1] undo the push from before | ||||||
|  |     pop     bitcnt              ;[1]  | ||||||
|  |     rjmp    waitForK            ;[3] this was not the end of sync, retry | ||||||
|  | ; The entire loop from waitForK until rjmp waitForK above must not exceed two | ||||||
|  | ; bit times (= 27 cycles). | ||||||
|  | 
 | ||||||
|  | ;---------------------------------------------------------------------------- | ||||||
|  | ; push more registers and initialize values while we sample the first bits: | ||||||
|  | ;---------------------------------------------------------------------------- | ||||||
|  | haveTwoBitsK: | ||||||
|  |     push    x1                  ;[0] | ||||||
|  |     push    x2                  ;[2] | ||||||
|  |     push    x3                  ;[4] (leap2) | ||||||
|  |     ldi     leap2, 0x55         ;[6] add leap cycle on 2nd,5th,8th,... stuff bit | ||||||
|  |     push    x4                  ;[7] == leap | ||||||
|  |     ldi     leap, 0x55          ;[9] skip leap cycle on 2nd,5th,8th,... byte received | ||||||
|  |     push    cnt                 ;[10] | ||||||
|  |     ldi     cnt, USB_BUFSIZE    ;[12] [rx loop init] | ||||||
|  |     ldi     x2, 1<<USBPLUS      ;[13] current line state is K state. D+=="1", D-=="0" | ||||||
|  | bit0:        | ||||||
|  |     in      x1, USBIN           ;[0] sample line state | ||||||
|  |     andi    x1, USBMASK         ;[1] filter only D+ and D- bits | ||||||
|  |     rjmp    handleBit           ;[2] make bit0 14 cycles long | ||||||
|  | 
 | ||||||
|  | ;---------------------------------------------------------------------------- | ||||||
|  | ; Process bit7. However, bit 6 still may need unstuffing. | ||||||
|  | ;---------------------------------------------------------------------------- | ||||||
|  | 
 | ||||||
|  | b6checkUnstuff: | ||||||
|  |     dec     bitcnt              ;[9] | ||||||
|  |     breq    unstuff6            ;[10] | ||||||
|  | bit7: | ||||||
|  |     subi    cnt, 1              ;[11] cannot use dec becaus it does not affect the carry flag | ||||||
|  |     brcs    overflow            ;[12] Too many bytes received. Ignore packet | ||||||
|  |     in      x1, USBIN           ;[0] sample line state | ||||||
|  |     andi    x1, USBMASK         ;[1] filter only D+ and D- bits | ||||||
|  |     cpse    x1, x2              ;[2] when previous line state equals current line state, handle "1" | ||||||
|  |     rjmp    b7handle0           ;[3] when line state differs, handle "0" | ||||||
|  |     sec                         ;[4] | ||||||
|  |     ror     shift               ;[5] shift "1" into the data | ||||||
|  |     st      y+, shift           ;[6] store the data into the buffer | ||||||
|  |     ldi     shift, 0x40         ;[7] reset data for receiving the next byte | ||||||
|  |     subi    leap, 0x55          ;[9] trick to introduce a leap cycle every 3 bytes | ||||||
|  |     brcc    nextInst            ;[10 or 11] it will fail after 85 bytes. However low speed can only receive 11 | ||||||
|  |     dec     bitcnt              ;[11 or 12] | ||||||
|  |     brne    bit0                ;[12 or 13] | ||||||
|  |     ldi     x1, 1               ;[13 or 14] unstuffing bit 7 | ||||||
|  |     in      bitcnt, USBIN       ;[0] sample stuff bit | ||||||
|  |     rjmp    unstuff             ;[1] | ||||||
|  | 
 | ||||||
|  | b7handle0: | ||||||
|  |     mov     x2,x1               ;[5] Set x2 to current line state | ||||||
|  |     ldi     bitcnt, 6           ;[6] | ||||||
|  |     lsr     shift               ;[7] shift "0" into the data | ||||||
|  |     st      y+, shift           ;[8] store data into the buffer | ||||||
|  |     ldi     shift, 0x40         ;[10] reset data for receiving the next byte | ||||||
|  |     subi    leap, 0x55          ;[11] trick to introduce a leap cycle every 3 bytes | ||||||
|  |     brcs    bit0                ;[12] it will fail after 85 bytes. However low speed can only receive 11 | ||||||
|  |     rjmp    bit0                ;[13] | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | ;---------------------------------------------------------------------------- | ||||||
|  | ; Handle unstuff | ||||||
|  | ; x1==0xFF indicate unstuffing bit6 | ||||||
|  | ;---------------------------------------------------------------------------- | ||||||
|  | 
 | ||||||
|  | unstuff6: | ||||||
|  |     ldi     x1,0xFF             ;[12] indicate unstuffing bit 6 | ||||||
|  |     in      bitcnt, USBIN       ;[0]  sample stuff bit | ||||||
|  |     nop                         ;[1]  fix timing | ||||||
|  | unstuff:                        ;b0-5  b6   b7 | ||||||
|  |     mov     x2,bitcnt           ;[3]  [2]  [3]  Set x2 to match line state | ||||||
|  |     subi    leap2, 0x55         ;[4]  [3]  [4]  delay loop | ||||||
|  |     brcs    nextInst            ;[5]  [4]  [5]  add one cycle every three stuff bits | ||||||
|  |     sbci    leap2,0             ;[6]  [5]  [6] | ||||||
|  |     ldi     bitcnt,6            ;[7]  [6]  [7]  reset bit stuff counter | ||||||
|  |     andi    x2, USBMASK         ;[8]  [7]  [8] only keep D+ and D- | ||||||
|  |     cpi     x1,0                ;[9]  [8]  [9] | ||||||
|  |     brmi    bit7                ;[10] [9]  [10] finished unstuffing bit6 When x1<0 | ||||||
|  |     breq    bitloop             ;[11] ---  [11] finished unstuffing bit0-5 when x1=0 | ||||||
|  |     nop                         ;---  ---  [12] | ||||||
|  |     in      x1, USBIN           ;---  ---  [0] sample line state for bit0 | ||||||
|  |     andi    x1, USBMASK         ;---  ---  [1] filter only D+ and D- bits | ||||||
|  |     rjmp    handleBit           ;---  ---  [2] make bit0 14 cycles long | ||||||
|  | 
 | ||||||
|  | ;---------------------------------------------------------------------------- | ||||||
|  | ; Receiver loop (numbers in brackets are cycles within byte after instr) | ||||||
|  | ;---------------------------------------------------------------------------- | ||||||
|  | bitloop: | ||||||
|  |     in      x1, USBIN           ;[0] sample line state | ||||||
|  |     andi    x1, USBMASK         ;[1] filter only D+ and D- bits | ||||||
|  |     breq    se0                 ;[2] both lines are low so handle se0 | ||||||
|  | handleBit: | ||||||
|  |     cpse    x1, x2              ;[3] when previous line state equals current line state, handle "1" | ||||||
|  |     rjmp    handle0             ;[4] when line state differs, handle "0" | ||||||
|  |     sec                         ;[5] | ||||||
|  |     ror     shift               ;[6] shift "1" into the data | ||||||
|  |     brcs    b6checkUnstuff      ;[7] When after shift C is set, next bit is bit7 | ||||||
|  |     nop2                        ;[8] | ||||||
|  |     dec     bitcnt              ;[10] | ||||||
|  |     brne    bitloop             ;[11] | ||||||
|  |     ldi     x1,0                ;[12] indicate unstuff for bit other than bit6 or bit7 | ||||||
|  |     in      bitcnt, USBIN       ;[0] sample stuff bit | ||||||
|  |     rjmp    unstuff             ;[1] | ||||||
|  | 
 | ||||||
|  | handle0: | ||||||
|  |     mov     x2, x1              ;[6] Set x2 to current line state | ||||||
|  |     ldi     bitcnt, 6           ;[7] reset unstuff counter.  | ||||||
|  |     lsr     shift               ;[8] shift "0" into the data | ||||||
|  |     brcs    bit7                ;[9] When after shift C is set, next bit is bit7 | ||||||
|  |     nop                         ;[10] | ||||||
|  |     rjmp    bitloop             ;[11]  | ||||||
|  |      | ||||||
|  | ;---------------------------------------------------------------------------- | ||||||
|  | ; End of receive loop. Now start handling EOP | ||||||
|  | ;---------------------------------------------------------------------------- | ||||||
|  | 
 | ||||||
|  | macro POP_STANDARD ; 14 cycles | ||||||
|  |     pop     cnt | ||||||
|  |     pop     x4 | ||||||
|  |     pop     x3 | ||||||
|  |     pop     x2 | ||||||
|  |     pop     x1 | ||||||
|  |     pop     shift | ||||||
|  |     pop     bitcnt | ||||||
|  |     endm | ||||||
|  | macro POP_RETI     ; 7 cycles | ||||||
|  |     pop     YH | ||||||
|  |     pop     YL | ||||||
|  |     out     SREG, YL | ||||||
|  |     pop     YL | ||||||
|  |     endm | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | #include "asmcommon.inc"
 | ||||||
|  | 
 | ||||||
|  | ; USB spec says: | ||||||
|  | ; idle = J | ||||||
|  | ; J = (D+ = 0), (D- = 1) | ||||||
|  | ; K = (D+ = 1), (D- = 0) | ||||||
|  | ; Spec allows 7.5 bit times from EOP to SOP for replies | ||||||
|  | ; 7.5 bit times is 100 cycles. This implementation arrives a bit later at se0 | ||||||
|  | ; then specified in the include file but there is plenty of time | ||||||
|  | 
 | ||||||
|  | bitstuffN: | ||||||
|  |     eor     x1, x4          ;[8] | ||||||
|  |     ldi     x2, 0           ;[9] | ||||||
|  |     nop2                    ;[10] | ||||||
|  |     out     USBOUT, x1      ;[12] <-- out | ||||||
|  |     rjmp    didStuffN       ;[0] | ||||||
|  |      | ||||||
|  | bitstuff7: | ||||||
|  |     eor     x1, x4          ;[6] | ||||||
|  |     ldi     x2, 0           ;[7] Carry is zero due to brcc | ||||||
|  |     rol     shift           ;[8] compensate for ror shift at branch destination | ||||||
|  |     nop2                    ;[9] | ||||||
|  |     rjmp    didStuff7       ;[11] | ||||||
|  | 
 | ||||||
|  | sendNakAndReti: | ||||||
|  |     ldi     x3, USBPID_NAK  ;[-18] | ||||||
|  |     rjmp    sendX3AndReti   ;[-17] | ||||||
|  | sendAckAndReti: | ||||||
|  |     ldi     cnt, USBPID_ACK ;[-17] | ||||||
|  | sendCntAndReti: | ||||||
|  |     mov     x3, cnt         ;[-16] | ||||||
|  | sendX3AndReti: | ||||||
|  |     ldi     YL, 20          ;[-15] x3==r20 address is 20 | ||||||
|  |     ldi     YH, 0           ;[-14] | ||||||
|  |     ldi     cnt, 2          ;[-13] | ||||||
|  | ;   rjmp    usbSendAndReti      fallthrough | ||||||
|  | 
 | ||||||
|  | ;usbSend: | ||||||
|  | ;pointer to data in 'Y' | ||||||
|  | ;number of bytes in 'cnt' -- including sync byte [range 2 ... 12] | ||||||
|  | ;uses: x1...x4, btcnt, shift, cnt, Y | ||||||
|  | ;Numbers in brackets are time since first bit of sync pattern is sent | ||||||
|  | ;We don't match the transfer rate exactly (don't insert leap cycles every third | ||||||
|  | ;byte) because the spec demands only 1.5% precision anyway. | ||||||
|  | usbSendAndReti:             ; 12 cycles until SOP | ||||||
|  |     in      x2, USBDDR      ;[-12] | ||||||
|  |     ori     x2, USBMASK     ;[-11] | ||||||
|  |     sbi     USBOUT, USBMINUS;[-10] prepare idle state; D+ and D- must have been 0 (no pullups) | ||||||
|  |     in      x1, USBOUT      ;[-8] port mirror for tx loop | ||||||
|  |     out     USBDDR, x2      ;[-7] <- acquire bus | ||||||
|  | ; need not init x2 (bitstuff history) because sync starts with 0 | ||||||
|  |     ldi     x4, USBMASK     ;[-6] exor mask | ||||||
|  |     ldi     shift, 0x80     ;[-5] sync byte is first byte sent | ||||||
|  | txByteLoop: | ||||||
|  |     ldi     bitcnt, 0x49    ;[-4]        [10] binary 01001001 | ||||||
|  | txBitLoop: | ||||||
|  |     sbrs    shift, 0        ;[-3] [10]   [11] | ||||||
|  |     eor     x1, x4          ;[-2] [11]   [12] | ||||||
|  |     out     USBOUT, x1      ;[-1] [12]   [13]   <-- out N | ||||||
|  |     ror     shift           ;[0]  [13]   [14] | ||||||
|  |     ror     x2              ;[1] | ||||||
|  | didStuffN: | ||||||
|  |     nop2                    ;[2] | ||||||
|  |     nop                     ;[4] | ||||||
|  |     cpi     x2, 0xfc        ;[5] | ||||||
|  |     brcc    bitstuffN       ;[6] | ||||||
|  |     lsr     bitcnt          ;[7] | ||||||
|  |     brcc    txBitLoop       ;[8] | ||||||
|  |     brne    txBitLoop       ;[9] | ||||||
|  | 
 | ||||||
|  |     sbrs    shift, 0        ;[10] | ||||||
|  |     eor     x1, x4          ;[11] | ||||||
|  | didStuff7: | ||||||
|  |     out     USBOUT, x1      ;[-1] [13] <-- out 7 | ||||||
|  |     ror     shift           ;[0] [14] | ||||||
|  |     ror     x2              ;[1] | ||||||
|  |     nop                     ;[2] | ||||||
|  |     cpi     x2, 0xfc        ;[3] | ||||||
|  |     brcc    bitstuff7       ;[4] | ||||||
|  |     ld      shift, y+       ;[5] | ||||||
|  |     dec     cnt             ;[7] | ||||||
|  |     brne    txByteLoop      ;[8] | ||||||
|  | ;make SE0: | ||||||
|  |     cbr     x1, USBMASK     ;[9] prepare SE0 [spec says EOP may be 25 to 30 cycles] | ||||||
|  |     lds     x2, usbNewDeviceAddr;[10] | ||||||
|  |     lsl     x2              ;[12] we compare with left shifted address | ||||||
|  |     out     USBOUT, x1      ;[13] <-- out SE0 -- from now 2 bits = 22 cycles until bus idle | ||||||
|  |     subi    YL, 20 + 2      ;[0] Only assign address on data packets, not ACK/NAK in x3 | ||||||
|  |     sbci    YH, 0           ;[1] | ||||||
|  | ;2006-03-06: moved transfer of new address to usbDeviceAddr from C-Code to asm: | ||||||
|  | ;set address only after data packet was sent, not after handshake | ||||||
|  |     breq    skipAddrAssign  ;[2] | ||||||
|  |     sts     usbDeviceAddr, x2; if not skipped: SE0 is one cycle longer | ||||||
|  | skipAddrAssign: | ||||||
|  | ;end of usbDeviceAddress transfer | ||||||
|  |     ldi     x2, 1<<USB_INTR_PENDING_BIT;[4] int0 occurred during TX -- clear pending flag | ||||||
|  |     USB_STORE_PENDING(x2)   ;[5] | ||||||
|  |     ori     x1, USBIDLE     ;[6] | ||||||
|  |     in      x2, USBDDR      ;[7] | ||||||
|  |     cbr     x2, USBMASK     ;[8] set both pins to input | ||||||
|  |     mov     x3, x1          ;[9] | ||||||
|  |     cbr     x3, USBMASK     ;[10] configure no pullup on both pins | ||||||
|  |     ldi     x4, 5           ;[11] | ||||||
|  | se0Delay: | ||||||
|  |     dec     x4              ;[12] [15] [18] [21] [24] | ||||||
|  |     brne    se0Delay        ;[13] [16] [19] [22] [25] | ||||||
|  |     out     USBOUT, x1      ;[26] <-- out J (idle) -- end of SE0 (EOP signal) | ||||||
|  |     out     USBDDR, x2      ;[27] <-- release bus now | ||||||
|  |     out     USBOUT, x3      ;[28] <-- ensure no pull-up resistors are active | ||||||
|  |     rjmp    doReturn | ||||||
							
								
								
									
										143
									
								
								keyboards/planck/thk/bootloader/usbdrv/usbportability.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										143
									
								
								keyboards/planck/thk/bootloader/usbdrv/usbportability.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,143 @@ | |||||||
|  | /* Name: usbportability.h
 | ||||||
|  |  * Project: V-USB, virtual USB port for Atmel's(r) AVR(r) microcontrollers | ||||||
|  |  * Author: Christian Starkjohann | ||||||
|  |  * Creation Date: 2008-06-17 | ||||||
|  |  * Tabsize: 4 | ||||||
|  |  * Copyright: (c) 2008 by OBJECTIVE DEVELOPMENT Software GmbH | ||||||
|  |  * License: GNU GPL v2 (see License.txt), GNU GPL v3 or proprietary (CommercialLicense.txt) | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | /*
 | ||||||
|  | General Description: | ||||||
|  | This header is intended to contain all (or at least most of) the compiler | ||||||
|  | and library dependent stuff. The C code is written for avr-gcc and avr-libc. | ||||||
|  | The API of other development environments is converted to gcc's and avr-libc's | ||||||
|  | API by means of defines. | ||||||
|  | 
 | ||||||
|  | This header also contains all system includes since they depend on the | ||||||
|  | development environment. | ||||||
|  | 
 | ||||||
|  | Thanks to Oleg Semyonov for his help with the IAR tools port! | ||||||
|  | */ | ||||||
|  | 
 | ||||||
|  | #ifndef __usbportability_h_INCLUDED__ | ||||||
|  | #define __usbportability_h_INCLUDED__ | ||||||
|  | 
 | ||||||
|  | /* We check explicitly for IAR and CodeVision. Default is avr-gcc/avr-libc. */ | ||||||
|  | 
 | ||||||
|  | /* ------------------------------------------------------------------------- */ | ||||||
|  | #if defined __IAR_SYSTEMS_ICC__ || defined __IAR_SYSTEMS_ASM__  /* check for IAR */ | ||||||
|  | /* ------------------------------------------------------------------------- */ | ||||||
|  | 
 | ||||||
|  | #ifndef ENABLE_BIT_DEFINITIONS | ||||||
|  | #   define ENABLE_BIT_DEFINITIONS	1   /* Enable bit definitions */ | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
|  | /* Include IAR headers */ | ||||||
|  | #include <ioavr.h> | ||||||
|  | #ifndef __IAR_SYSTEMS_ASM__ | ||||||
|  | #   include <inavr.h> | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
|  | #define __attribute__(arg)  /* not supported on IAR */ | ||||||
|  | 
 | ||||||
|  | #ifdef __IAR_SYSTEMS_ASM__ | ||||||
|  | #   define __ASSEMBLER__    /* IAR does not define standard macro for asm */ | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
|  | #ifdef __HAS_ELPM__ | ||||||
|  | #   define PROGMEM __farflash | ||||||
|  | #else | ||||||
|  | #   define PROGMEM __flash | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
|  | #define USB_READ_FLASH(addr)    (*(PROGMEM char *)(addr)) | ||||||
|  | 
 | ||||||
|  | /* The following definitions are not needed by the driver, but may be of some
 | ||||||
|  |  * help if you port a gcc based project to IAR. | ||||||
|  |  */ | ||||||
|  | #define cli()       __disable_interrupt() | ||||||
|  | #define sei()       __enable_interrupt() | ||||||
|  | #define wdt_reset() __watchdog_reset() | ||||||
|  | #define _BV(x)      (1 << (x)) | ||||||
|  | 
 | ||||||
|  | /* assembler compatibility macros */ | ||||||
|  | #define nop2    rjmp    $+2 /* jump to next instruction */ | ||||||
|  | #define XL      r26 | ||||||
|  | #define XH      r27 | ||||||
|  | #define YL      r28 | ||||||
|  | #define YH      r29 | ||||||
|  | #define ZL      r30 | ||||||
|  | #define ZH      r31 | ||||||
|  | #define lo8(x)  LOW(x) | ||||||
|  | #define hi8(x)  (((x)>>8) & 0xff)   /* not HIGH to allow XLINK to make a proper range check */ | ||||||
|  | 
 | ||||||
|  | /* Depending on the device you use, you may get problems with the way usbdrv.h
 | ||||||
|  |  * handles the differences between devices. Since IAR does not use #defines | ||||||
|  |  * for MCU registers, we can't check for the existence of a particular | ||||||
|  |  * register with an #ifdef. If the autodetection mechanism fails, include | ||||||
|  |  * definitions for the required USB_INTR_* macros in your usbconfig.h. See | ||||||
|  |  * usbconfig-prototype.h and usbdrv.h for details. | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | /* ------------------------------------------------------------------------- */ | ||||||
|  | #elif __CODEVISIONAVR__ /* check for CodeVision AVR */ | ||||||
|  | /* ------------------------------------------------------------------------- */ | ||||||
|  | /* This port is not working (yet) */ | ||||||
|  | 
 | ||||||
|  | /* #define F_CPU   _MCU_CLOCK_FREQUENCY_    seems to be defined automatically */ | ||||||
|  | 
 | ||||||
|  | #include <io.h> | ||||||
|  | #include <delay.h> | ||||||
|  | 
 | ||||||
|  | #define __attribute__(arg)  /* not supported on IAR */ | ||||||
|  | 
 | ||||||
|  | #define PROGMEM                 __flash | ||||||
|  | #define USB_READ_FLASH(addr)    (*(PROGMEM char *)(addr)) | ||||||
|  | 
 | ||||||
|  | #ifndef __ASSEMBLER__ | ||||||
|  | static inline void  cli(void) | ||||||
|  | { | ||||||
|  |     #asm("cli"); | ||||||
|  | } | ||||||
|  | static inline void  sei(void) | ||||||
|  | { | ||||||
|  |     #asm("sei"); | ||||||
|  | } | ||||||
|  | #endif | ||||||
|  | #define _delay_ms(t)    delay_ms(t) | ||||||
|  | #define _BV(x)          (1 << (x)) | ||||||
|  | #define USB_CFG_USE_SWITCH_STATEMENT 1  /* macro for if() cascase fails for unknown reason */ | ||||||
|  | 
 | ||||||
|  | #define macro   .macro | ||||||
|  | #define endm    .endmacro | ||||||
|  | #define nop2    rjmp    .+0 /* jump to next instruction */ | ||||||
|  | 
 | ||||||
|  | /* ------------------------------------------------------------------------- */ | ||||||
|  | #else   /* default development environment is avr-gcc/avr-libc */ | ||||||
|  | /* ------------------------------------------------------------------------- */ | ||||||
|  | 
 | ||||||
|  | #include <avr/io.h> | ||||||
|  | #ifdef __ASSEMBLER__ | ||||||
|  | #   define _VECTOR(N)   __vector_ ## N   /* io.h does not define this for asm */ | ||||||
|  | #else | ||||||
|  | #   include <avr/pgmspace.h> | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
|  | #if USB_CFG_DRIVER_FLASH_PAGE | ||||||
|  | #   define USB_READ_FLASH(addr)    pgm_read_byte_far(((long)USB_CFG_DRIVER_FLASH_PAGE << 16) | (long)(addr)) | ||||||
|  | #else | ||||||
|  | #   define USB_READ_FLASH(addr)    pgm_read_byte(addr) | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
|  | #define macro   .macro | ||||||
|  | #define endm    .endm | ||||||
|  | #define nop2    rjmp    .+0 /* jump to next instruction */ | ||||||
|  | 
 | ||||||
|  | #endif  /* development environment */ | ||||||
|  | 
 | ||||||
|  | /* for conveniecne, ensure that PRG_RDB exists */ | ||||||
|  | #ifndef PRG_RDB | ||||||
|  | #   define PRG_RDB(addr)    USB_READ_FLASH(addr) | ||||||
|  | #endif | ||||||
|  | #endif  /* __usbportability_h_INCLUDED__ */ | ||||||
| @ -42,6 +42,9 @@ static bool dip_switch[4] = {0, 0, 0, 0}; | |||||||
| __attribute__ ((weak)) | __attribute__ ((weak)) | ||||||
| void dip_update(uint8_t index, bool active) { } | void dip_update(uint8_t index, bool active) { } | ||||||
| 
 | 
 | ||||||
|  | __attribute__ ((weak)) | ||||||
|  | void dip_update_kb(uint8_t index, bool active) { } | ||||||
|  | 
 | ||||||
| __attribute__ ((weak)) | __attribute__ ((weak)) | ||||||
| void encoder_update(uint8_t index, bool clockwise) { } | void encoder_update(uint8_t index, bool clockwise) { } | ||||||
| 
 | 
 | ||||||
| @ -117,6 +120,7 @@ uint8_t matrix_scan(void) { | |||||||
|     for (uint8_t i = 0; i < 4; i++) { |     for (uint8_t i = 0; i < 4; i++) { | ||||||
|       if (last_dip_switch[i] ^ dip_switch[i]) |       if (last_dip_switch[i] ^ dip_switch[i]) | ||||||
|         dip_update(i, dip_switch[i]); |         dip_update(i, dip_switch[i]); | ||||||
|  |         dip_update_kb(i, dip_switch[i]); | ||||||
|     } |     } | ||||||
|     memcpy(last_dip_switch, dip_switch, sizeof(&dip_switch)); |     memcpy(last_dip_switch, dip_switch, sizeof(&dip_switch)); | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -16,6 +16,8 @@ | |||||||
| 
 | 
 | ||||||
| #include "thk.h" | #include "thk.h" | ||||||
| 
 | 
 | ||||||
|  | extern bool dip_switch[4]; | ||||||
|  | 
 | ||||||
| void matrix_init_kb(void) { | void matrix_init_kb(void) { | ||||||
| 
 | 
 | ||||||
|   DDRD |= (1<<5); |   DDRD |= (1<<5); | ||||||
| @ -29,6 +31,13 @@ void matrix_scan_kb(void) { | |||||||
| 
 | 
 | ||||||
| static uint8_t keys_pressed = 0; | static uint8_t keys_pressed = 0; | ||||||
| 
 | 
 | ||||||
|  | bool react_to_keys = false; | ||||||
|  | 
 | ||||||
|  | void dip_update_kb(uint8_t index, bool active) { | ||||||
|  |   if (index == 0) | ||||||
|  |     react_to_keys = active; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| bool process_record_kb(uint16_t keycode, keyrecord_t *record) { | bool process_record_kb(uint16_t keycode, keyrecord_t *record) { | ||||||
|   if (record->event.pressed) { |   if (record->event.pressed) { | ||||||
|     keys_pressed++; |     keys_pressed++; | ||||||
| @ -36,10 +45,12 @@ bool process_record_kb(uint16_t keycode, keyrecord_t *record) { | |||||||
|     keys_pressed--; |     keys_pressed--; | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   if (keys_pressed) { |   if (react_to_keys){ | ||||||
|     PORTD |= (1<<5); |     if (keys_pressed) { | ||||||
|   } else { |       PORTD |= (1<<5); | ||||||
|     PORTD &= ~(1<<5); |     } else { | ||||||
|  |       PORTD &= ~(1<<5); | ||||||
|  |     } | ||||||
|   } |   } | ||||||
|   return process_record_user(keycode, record); |   return process_record_user(keycode, record); | ||||||
| } | } | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 Jack Humbert
						Jack Humbert