X-Git-Url: http://git.linex4red.de/pub/USBasp.git/blobdiff_plain/82162c710c3c26739c07b41b20048c30cce78943..d4f00fe7d51cd6779d2264c1f2a80b4435ca7b38:/Projects/AVRISP-MKII/Descriptors.c diff --git a/Projects/AVRISP-MKII/Descriptors.c b/Projects/AVRISP-MKII/Descriptors.c index da57b7113..0a43dc902 100644 --- a/Projects/AVRISP-MKII/Descriptors.c +++ b/Projects/AVRISP-MKII/Descriptors.c @@ -37,6 +37,16 @@ #include "Descriptors.h" +#if defined(RESET_TOGGLES_LIBUSB_COMPAT) || defined(__DOXYGEN__) + static bool AVRISP_NeedCompatibilitySwitch ATTR_NO_INIT; + + /** Current AVRISP data IN endpoint address. */ + uint8_t AVRISP_CurrDataINEndpointAddress; + + /** Saved AVRISP data IN endpoint address in EEPROM. */ + uint8_t AVRISP_CurrDataINEndpointAddress_EEPROM EEMEM; +#endif + /** Device descriptor structure. This descriptor, located in FLASH memory, describes the overall * device characteristics, including the supported USB version, control endpoint size and the * number of device configurations. The descriptor is read out by the USB host when the enumeration @@ -69,7 +79,7 @@ const USB_Descriptor_Device_t PROGMEM DeviceDescriptor = * and endpoints. The descriptor is read out by the USB host during the enumeration process when selecting * a configuration so that the host may correctly communicate with the USB device. */ -const USB_Descriptor_Configuration_t PROGMEM ConfigurationDescriptor = +USB_Descriptor_Configuration_t ConfigurationDescriptor = { .Config = { @@ -106,7 +116,11 @@ const USB_Descriptor_Configuration_t PROGMEM ConfigurationDescriptor = { .Header = {.Size = sizeof(USB_Descriptor_Endpoint_t), .Type = DTYPE_Endpoint}, +#if defined(RESET_TOGGLES_LIBUSB_COMPAT) + .EndpointAddress = 0, +#else .EndpointAddress = AVRISP_DATA_IN_EPADDR, +#endif .Attributes = (EP_TYPE_BULK | ENDPOINT_ATTR_NO_SYNC | ENDPOINT_USAGE_DATA), .EndpointSize = AVRISP_DATA_EPSIZE, .PollingIntervalMS = 0x0A @@ -174,7 +188,8 @@ const USB_Descriptor_String_t PROGMEM SerialString = */ uint16_t CALLBACK_USB_GetDescriptor(const uint16_t wValue, const uint8_t wIndex, - const void** const DescriptorAddress) + const void** const DescriptorAddress, + uint8_t* DescriptorMemorySpace) { const uint8_t DescriptorType = (wValue >> 8); const uint8_t DescriptorNumber = (wValue & 0xFF); @@ -182,6 +197,8 @@ uint16_t CALLBACK_USB_GetDescriptor(const uint16_t wValue, const void* Address = NULL; uint16_t Size = NO_DESCRIPTOR; + *DescriptorMemorySpace = MEMSPACE_FLASH; + switch (DescriptorType) { case DTYPE_Device: @@ -189,6 +206,11 @@ uint16_t CALLBACK_USB_GetDescriptor(const uint16_t wValue, Size = sizeof(USB_Descriptor_Device_t); break; case DTYPE_Configuration: + *DescriptorMemorySpace = MEMSPACE_RAM; + #if defined(RESET_TOGGLES_LIBUSB_COMPAT) + ConfigurationDescriptor.AVRISP_DataInEndpoint.EndpointAddress = AVRISP_CurrDataINEndpointAddress; + #endif + Address = &ConfigurationDescriptor; Size = sizeof(USB_Descriptor_Configuration_t); break; @@ -220,3 +242,70 @@ uint16_t CALLBACK_USB_GetDescriptor(const uint16_t wValue, return Size; } +#if defined(RESET_TOGGLES_LIBUSB_COMPAT) || defined(__DOXYGEN__) +/** Checks the state of the system status register MCUSR and indicates via a flag if + * the current AVRISP driver compatibility mode needs to be reset. + * + * When the \c RESET_TOGGLES_LIBUSB_COMPAT compile time option is enabled, pulling + * the reset line of the AVR low will toggle between Jungo and libUSB compatibility + * modes. Other forms of reset (such as power on or watchdog) will not force a mode + * change. + */ +void CheckExternalReset(void) +{ + /* If an external reset occured, we need to change compatibility mode */ + AVRISP_NeedCompatibilitySwitch = (MCUSR == (1 << EXTRF)); + + MCUSR = 0; +} + +/** Updates the device descriptors so that the correct compatibility mode is used + * when the \c RESET_TOGGLES_LIBUSB_COMPAT compile time option is enabled. This + * configures the programmer for either Jungo or libUSB driver compatibility. Each + * time the AVR is reset via pulling the reset line low the compatibility mode will + * be toggled. The current mode is stored in EEPROM and preserved through power + * cycles of the AVR. + */ +void UpdateCurrentCompatibilityMode(void) +{ + /* Load the current IN endpoint address stored in EEPROM */ + AVRISP_CurrDataINEndpointAddress = eeprom_read_byte(&AVRISP_CurrDataINEndpointAddress_EEPROM); + + /* Check if we need to switch compatibility modes */ + if (AVRISP_NeedCompatibilitySwitch) + { + /* Toggle between compatibility modes */ + AVRISP_CurrDataINEndpointAddress = (AVRISP_CurrDataINEndpointAddress == AVRISP_DATA_IN_EPADDR_LIBUSB) ? + AVRISP_DATA_IN_EPADDR_JUNGO : AVRISP_DATA_IN_EPADDR_LIBUSB; + + /* Save the new mode into EEPROM */ + eeprom_update_byte(&AVRISP_CurrDataINEndpointAddress_EEPROM, AVRISP_CurrDataINEndpointAddress); + } + + LEDs_SetAllLEDs(LEDS_NO_LEDS); + + /* Validate IN endpoint address and indicate current mode via LED flashes */ + switch (AVRISP_CurrDataINEndpointAddress) + { + default: + /* Default to Jungo compatibility mode if saved EEPROM is invalid */ + AVRISP_CurrDataINEndpointAddress = AVRISP_DATA_IN_EPADDR_JUNGO; + case AVRISP_DATA_IN_EPADDR_JUNGO: + /* Two flashes for Jungo compatibility mode */ + for (uint8_t i = 0; i < 4; i++) + { + LEDs_ToggleLEDs(LEDS_ALL_LEDS); + Delay_MS(100); + } + break; + case AVRISP_DATA_IN_EPADDR_LIBUSB: + /* Five flashes for libUSB compatibility mode */ + for (uint8_t i = 0; i < 10; i++) + { + LEDs_ToggleLEDs(LEDS_ALL_LEDS); + Delay_MS(100); + } + break; + } +} +#endif