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 { | ||||
|       if (clockwise) { | ||||
|         register_code(KC_MS_WH_DOWN); | ||||
|         unregister_code(KC_MS_WH_DOWN); | ||||
|         register_code(KC_MS_DOWN); | ||||
|         unregister_code(KC_MS_DOWN); | ||||
|       } else { | ||||
|         register_code(KC_MS_WH_UP); | ||||
|         unregister_code(KC_MS_WH_UP); | ||||
|         register_code(KC_MS_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)) | ||||
| void dip_update(uint8_t index, bool active) { } | ||||
| 
 | ||||
| __attribute__ ((weak)) | ||||
| void dip_update_kb(uint8_t index, bool active) { } | ||||
| 
 | ||||
| __attribute__ ((weak)) | ||||
| 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++) { | ||||
|       if (last_dip_switch[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)); | ||||
| 
 | ||||
|  | ||||
| @ -16,6 +16,8 @@ | ||||
| 
 | ||||
| #include "thk.h" | ||||
| 
 | ||||
| extern bool dip_switch[4]; | ||||
| 
 | ||||
| void matrix_init_kb(void) { | ||||
| 
 | ||||
|   DDRD |= (1<<5); | ||||
| @ -29,6 +31,13 @@ void matrix_scan_kb(void) { | ||||
| 
 | ||||
| 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) { | ||||
|   if (record->event.pressed) { | ||||
|     keys_pressed++; | ||||
| @ -36,10 +45,12 @@ bool process_record_kb(uint16_t keycode, keyrecord_t *record) { | ||||
|     keys_pressed--; | ||||
|   } | ||||
| 
 | ||||
|   if (react_to_keys){ | ||||
|     if (keys_pressed) { | ||||
|       PORTD |= (1<<5); | ||||
|     } else { | ||||
|       PORTD &= ~(1<<5); | ||||
|     } | ||||
|   } | ||||
|   return process_record_user(keycode, record); | ||||
| } | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 Jack Humbert
						Jack Humbert