X-Git-Url: http://git.linex4red.de/pub/lufa.git/blobdiff_plain/cb779e3d7d32d7c43e0a45bb526de0a04135b0c7..063474561de084fbdd8c1ddc02fcce5b8abebe3e:/Projects/AVRISP-MKII/Descriptors.c diff --git a/Projects/AVRISP-MKII/Descriptors.c b/Projects/AVRISP-MKII/Descriptors.c index ac592fd27..0a43dc902 100644 --- a/Projects/AVRISP-MKII/Descriptors.c +++ b/Projects/AVRISP-MKII/Descriptors.c @@ -1,13 +1,13 @@ /* LUFA Library - Copyright (C) Dean Camera, 2010. + Copyright (C) Dean Camera, 2012. dean [at] fourwalledcubicle [dot] com www.lufa-lib.org */ /* - Copyright 2010 Dean Camera (dean [at] fourwalledcubicle [dot] com) + Copyright 2012 Dean Camera (dean [at] fourwalledcubicle [dot] com) Permission to use, copy, modify, distribute, and sell this software and its documentation for any purpose is hereby granted @@ -37,12 +37,22 @@ #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 * process begins. */ -USB_Descriptor_Device_t PROGMEM DeviceDescriptor = +const USB_Descriptor_Device_t PROGMEM DeviceDescriptor = { .Header = {.Size = sizeof(USB_Descriptor_Device_t), .Type = DTYPE_Device}, @@ -69,7 +79,7 @@ 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. */ -USB_Descriptor_Configuration_t PROGMEM ConfigurationDescriptor = +USB_Descriptor_Configuration_t ConfigurationDescriptor = { .Config = { @@ -81,7 +91,7 @@ USB_Descriptor_Configuration_t PROGMEM ConfigurationDescriptor = .ConfigurationNumber = 1, .ConfigurationStrIndex = NO_DESCRIPTOR, - .ConfigAttributes = USB_CONFIG_ATTR_BUSPOWERED, + .ConfigAttributes = (USB_CONFIG_ATTR_RESERVED | USB_CONFIG_ATTR_SELFPOWERED), .MaxPowerConsumption = USB_CONFIG_POWER_MA(100) }, @@ -96,8 +106,8 @@ USB_Descriptor_Configuration_t PROGMEM ConfigurationDescriptor = .TotalEndpoints = 2, .Class = USB_CSCP_VendorSpecificClass, - .SubClass = 0x00, - .Protocol = 0x00, + .SubClass = USB_CSCP_NoDeviceSubclass, + .Protocol = USB_CSCP_NoDeviceProtocol, .InterfaceStrIndex = NO_DESCRIPTOR }, @@ -106,20 +116,24 @@ USB_Descriptor_Configuration_t PROGMEM ConfigurationDescriptor = { .Header = {.Size = sizeof(USB_Descriptor_Endpoint_t), .Type = DTYPE_Endpoint}, - .EndpointAddress = (ENDPOINT_DESCRIPTOR_DIR_IN | AVRISP_DATA_IN_EPNUM), +#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 = 0x00 + .PollingIntervalMS = 0x0A }, .AVRISP_DataOutEndpoint = { .Header = {.Size = sizeof(USB_Descriptor_Endpoint_t), .Type = DTYPE_Endpoint}, - .EndpointAddress = (ENDPOINT_DESCRIPTOR_DIR_OUT | AVRISP_DATA_OUT_EPNUM), + .EndpointAddress = AVRISP_DATA_OUT_EPADDR, .Attributes = (EP_TYPE_BULK | ENDPOINT_ATTR_NO_SYNC | ENDPOINT_USAGE_DATA), .EndpointSize = AVRISP_DATA_EPSIZE, - .PollingIntervalMS = 0x00 + .PollingIntervalMS = 0x0A }, }; @@ -127,7 +141,7 @@ USB_Descriptor_Configuration_t PROGMEM ConfigurationDescriptor = * the string descriptor with index 0 (the first index). It is actually an array of 16-bit integers, which indicate * via the language ID table available at USB.org what languages the device supports for its string descriptors. */ -USB_Descriptor_String_t PROGMEM LanguageString = +const USB_Descriptor_String_t PROGMEM LanguageString = { .Header = {.Size = USB_STRING_LEN(1), .Type = DTYPE_String}, @@ -138,32 +152,32 @@ USB_Descriptor_String_t PROGMEM LanguageString = * form, and is read out upon request by the host when the appropriate string ID is requested, listed in the Device * Descriptor. */ -USB_Descriptor_String_t PROGMEM ManufacturerString = +const USB_Descriptor_String_t PROGMEM ManufacturerString = { - .Header = {.Size = USB_STRING_LEN(11), .Type = DTYPE_String}, + .Header = {.Size = USB_STRING_LEN(5), .Type = DTYPE_String}, - .UnicodeString = L"Dean Camera" + .UnicodeString = L"ATMEL" }; /** Product descriptor string. This is a Unicode string containing the product's details in human readable form, * and is read out upon request by the host when the appropriate string ID is requested, listed in the Device * Descriptor. */ -USB_Descriptor_String_t PROGMEM ProductString = +const USB_Descriptor_String_t PROGMEM ProductString = { - .Header = {.Size = USB_STRING_LEN(22), .Type = DTYPE_String}, + .Header = {.Size = USB_STRING_LEN(11), .Type = DTYPE_String}, - .UnicodeString = L"LUFA AVRISP MkII Clone" + .UnicodeString = L"AVRISP mkII" }; /** Serial number string. This is a Unicode string containing the device's unique serial number, expressed as a * series of uppercase hexadecimal digits. */ -USB_Descriptor_String_t PROGMEM SerialString = +const USB_Descriptor_String_t PROGMEM SerialString = { .Header = {.Size = USB_STRING_LEN(13), .Type = DTYPE_String}, - - .UnicodeString = L"0000A00128255" + + .UnicodeString = L"000200012345\0" // Note: Real AVRISP-MKII has the embedded NUL byte, bug in firmware? }; /** This function is called by the library when in device mode, and must be overridden (see library "USB Descriptors" @@ -174,7 +188,8 @@ 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