Merge in latest trunk.
[pub/lufa.git] / Projects / AVRISP-MKII / Descriptors.c
index 28db15f..0a43dc9 100644 (file)
@@ -1,13 +1,13 @@
 /*
              LUFA Library
-     Copyright (C) Dean Camera, 2011.
+     Copyright (C) Dean Camera, 2012.
 
   dean [at] fourwalledcubicle [dot] com
            www.lufa-lib.org
 */
 
 /*
-  Copyright 2011  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
 
 #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,7 +116,11 @@ 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      = 0x0A
@@ -116,7 +130,7 @@ USB_Descriptor_Configuration_t PROGMEM ConfigurationDescriptor =
                {
                        .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      = 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