Index: dfu.c
===================================================================
--- dfu.c	(revision 0)
+++ dfu.c	(revision 0)
@@ -0,0 +1,512 @@
+/*
+ * avrdude - A Downloader/Uploader for AVR device programmers
+ * Copyright (C) 2007 Dick Streefland, adapted for 5.4 by Limor Fried
+ *
+ * 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
+ */
+
+#include "ac_cfg.h"
+#include "dfu.h"
+
+#include "avrdude.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <limits.h>
+#include <unistd.h>
+
+#include "usbdevs.h" /* for USB_VENDOR_ATMEL */
+
+/* If we don't have LibUSB, define dummy functions that report an error. */
+
+#ifndef HAVE_LIBUSB
+
+int dfu_open(struct dfu_dev *dfu, char *port_name) {
+  fprintf(stderr, "%s: Error: No USB support in this compile of avrdude\n",
+    progname);
+  return -1;
+}
+
+int dfu_init(struct dfu_dev *dfu, unsigned short usb_pid) {
+  return -1;
+}
+
+void dfu_close(struct dfu_dev *dfu) {
+  /* nothing */
+}
+
+int dfu_getstatus(struct dfu_dev *dfu, struct dfu_status *status)
+{
+  return -1;
+}
+
+int dfu_clrstatus(struct dfu_dev *dfu) {
+  return -1;
+}
+
+int dfu_download(struct dfu_dev *dfu, void * ptr, int size) {
+  return -1;
+}
+
+int dfu_upload(struct dfu_dev *dfu, void * ptr, int size) {
+  return -1;
+}
+
+#else
+
+/* If we DO have LibUSB, we can define the real functions. */
+
+#include <usb.h>
+
+/* DFU data structures and constants.
+ */
+
+#define DFU_TIMEOUT 200 /* ms */
+
+#define DFU_DNLOAD 1
+#define DFU_UPLOAD 2
+#define DFU_GETSTATUS 3
+#define DFU_CLRSTATUS 4
+
+/* Block counter global variable. Incremented each time a DFU_DNLOAD command
+ * is sent to the device.
+ */
+
+static u_int16_t wIndex = 0;
+
+/* INTERNAL FUNCTION PROTOTYPES
+ */
+
+static char * get_usb_string(usb_dev_handle * dev_handle, int index);
+
+/* EXPORTED FUNCTION DEFINITIONS
+ */
+
+struct dfu_dev * dfu_open(char *port_spec)
+{
+  struct dfu_dev *dfu;
+  char *bus_name = NULL;
+  char *dev_name = NULL;
+  
+  /* The following USB device spec parsing code was copied from usbtiny.c. The
+   * expected format is "usb:BUS:DEV" where BUS and DEV are the bus and device
+   * names. We stash these away in the dfu_dev structure for the dfu_init() 
+   * function, where we actually open the device.
+   */
+  
+  if (strncmp(port_spec, "usb", 3) != 0) {
+    fprintf(stderr, "%s: Error: " \
+      "Invalid port specification \"%s\" for USB device\n",
+      progname, port_spec);
+    return NULL;
+  }
+  
+  if(':' == port_spec[3]) {
+      bus_name = strdup(port_spec + 3 + 1);
+      if (bus_name == NULL) {
+        perror(progname);
+        exit(1);
+      }
+
+      dev_name = strchr(bus_name, ':');
+      if(NULL != dev_name)
+        *dev_name++ = '\0';
+  }
+  
+  /* Allocate the dfu_dev structure and save the bus_name and dev_name
+   * strings for use in dfu_initialize().
+   */
+  
+  dfu = calloc(1, sizeof(struct dfu_dev));
+  
+  if (dfu == NULL)
+  {
+    perror(progname);
+    exit(1);
+  }
+  
+  dfu->bus_name = bus_name;
+  dfu->dev_name = dev_name;
+
+  /* LibUSB initialization. */
+
+  usb_init();
+  usb_find_busses();
+  usb_find_devices();
+  
+  return dfu;
+}
+
+int dfu_init(struct dfu_dev *dfu, unsigned short vid, unsigned short pid)
+{
+  struct usb_device *found = NULL;
+  struct usb_device *dev;
+  struct usb_bus *bus;
+
+  /* At last, we reach out through the USB bus to the part. There are three
+   * ways to specify the part: by USB address, by USB vendor and product id,
+   * and by part name. To specify the part by USB address, the user specifies
+   * a port parameter in the form "usb:BUS:DEV" (see dfu_open()). To specify
+   * the part by vendor and product, the user must specify a usbvid and usbpid
+   * in the configuration file. Finally, if the user specifies the part only,
+   * we use the default vendor and product id.
+   */
+  
+  if (pid == 0 && dfu->dev_name == NULL) {
+    fprintf(stderr, "%s: Error: No DFU support for part; " \
+      "specify PID in config or USB address (via -P) to override.\n",
+      progname);
+    return -1;
+  }
+  
+  /* Scan through all the devices for the part. The matching rules are:
+   *
+   *   1. If the user specified a USB bus name, it must match.
+   *   2. If the user specified a USB device name, it must match.
+   *   3. If the user didn't specify a USB device name and specified a vendor
+   *      id, the vendor id must match.
+   *   4. If the user didn't specify a USB device name and specified a product
+   *      id, the product id must match.
+   */
+  
+  for (bus = usb_busses; !found && bus != NULL; bus = bus->next) {
+    for (dev = bus->devices; !found && dev != NULL; dev = dev->next) {
+      if (dfu->bus_name != NULL && strcmp(bus->dirname, dfu->bus_name))
+         continue;
+      if (dfu->dev_name != NULL) {
+        if (strcmp(dev->filename, dfu->dev_name))
+          continue;
+      } else if (vid != dev->descriptor.idVendor)
+        continue;
+      else if (pid != 0 && pid != dev->descriptor.idProduct)
+        continue;
+      
+      found = dev;
+    }
+  }
+ 
+  if (found == NULL) {
+    /* We could try to be more informative here. For example, we could report
+     * why the match failed, and if we came across another DFU-capable part.
+     */
+    
+    fprintf(stderr, "%s: Error: No matching USB device found\n", progname);
+    return -1;
+  }
+
+  if(verbose)
+    fprintf(stderr,
+      "%s: Found VID=0x%04x PID=0x%04x at %s:%s\n",
+      progname, found->descriptor.idVendor, found->descriptor.idProduct,
+      found->bus->dirname, found->filename);
+  
+  dfu->dev_handle = usb_open(found);
+
+  if (dfu->dev_handle == NULL) {
+    fprintf(stderr, "%s: Error: USB device at %s:%s: %s\n",
+      progname, found->bus->dirname, found->filename, usb_strerror());
+    return -1;
+  }
+  
+  /* Save device, configuration, interface and endpoint descriptors. */
+  
+  memcpy(&dfu->dev_desc, &found->descriptor, sizeof(dfu->dev_desc));
+  memcpy(&dfu->conf_desc, found->config, sizeof(dfu->conf_desc));
+  dfu->conf_desc.interface = NULL;
+  
+  memcpy(&dfu->intf_desc, found->config->interface->altsetting,
+    sizeof(dfu->intf_desc));
+  dfu->intf_desc.endpoint = &dfu->endp_desc;
+  
+  memcpy(&dfu->endp_desc, found->config->interface->altsetting->endpoint,
+    sizeof(dfu->endp_desc));
+
+  /* Check if descriptor values are what we expect. */
+  
+  if (dfu->dev_desc.idVendor != vid)
+    fprintf( stderr, "%s: Warning: USB idVendor = 0x%04X (expected 0x%04X)\n",
+      progname, dfu->dev_desc.idVendor, vid);
+
+  if (pid != 0 && dfu->dev_desc.idProduct != pid)
+    fprintf( stderr, "%s: Warning: USB idProduct = 0x%04X (expected 0x%04X)\n",
+      progname, dfu->dev_desc.idProduct, pid);
+
+  if (dfu->dev_desc.bNumConfigurations != 1)
+    fprintf( stderr, "%s: Warning: USB bNumConfigurations = %d (expected 1)\n",
+      progname, (int) dfu->dev_desc.bNumConfigurations);
+
+  if (dfu->conf_desc.bNumInterfaces != 1)
+    fprintf( stderr, "%s: Warning: USB bNumInterfaces = %d (expected 1)\n",
+      progname, (int) dfu->conf_desc.bNumInterfaces);
+  
+  if (dfu->dev_desc.bDeviceClass != 0)
+    fprintf( stderr, "%s: Warning: USB bDeviceClass = %d (expected 0)\n",
+      progname, (int) dfu->dev_desc.bDeviceClass);
+  
+  if (dfu->dev_desc.bDeviceSubClass != 0)
+    fprintf( stderr, "%s: Warning: USB bDeviceSubClass = %d (expected 0)\n",
+      progname, (int) dfu->dev_desc.bDeviceSubClass);
+  
+  if (dfu->dev_desc.bDeviceProtocol != 0)
+    fprintf( stderr, "%s: Warning: USB bDeviceProtocol = %d (expected 0)\n",
+      progname, (int) dfu->dev_desc.bDeviceProtocol);
+  
+  if (dfu->intf_desc.bInterfaceClass != 0xFF)
+    fprintf( stderr, "%s: Warning: USB bInterfaceClass = %d (expected 255)\n",
+      progname, (int) dfu->intf_desc.bInterfaceClass);
+  
+  if (dfu->intf_desc.bInterfaceSubClass != 0)
+    fprintf( stderr, "%s: Warning: USB bInterfaceSubClass = %d (expected 0)\n",
+      progname, (int) dfu->intf_desc.bInterfaceSubClass);
+  
+  if (dfu->intf_desc.bInterfaceProtocol != 0)
+    fprintf( stderr, "%s: Warning: USB bInterfaceSubClass = %d (expected 0)\n",
+      progname, (int) dfu->intf_desc.bInterfaceProtocol);
+  
+  /* Get strings. */
+  
+  dfu->manf_str = get_usb_string(dfu->dev_handle,
+    dfu->dev_desc.iManufacturer);
+  
+  dfu->prod_str = get_usb_string(dfu->dev_handle,
+    dfu->dev_desc.iProduct);
+  
+  dfu->serno_str = get_usb_string(dfu->dev_handle,
+    dfu->dev_desc.iSerialNumber);
+  
+  return 0;
+}
+
+void dfu_close(struct dfu_dev *dfu)
+{
+  if (dfu->dev_handle != NULL)
+    usb_close(dfu->dev_handle);
+  if (dfu->bus_name != NULL)
+    free(dfu->bus_name);
+  if (dfu->manf_str != NULL)
+    free(dfu->manf_str);
+  if (dfu->prod_str != NULL)
+    free(dfu->prod_str);
+  if (dfu->serno_str != NULL)
+    free(dfu->serno_str);
+}
+
+int dfu_getstatus(struct dfu_dev *dfu, struct dfu_status *status)
+{
+  int result;
+  
+  result = usb_control_msg(dfu->dev_handle,
+    0x80 | USB_TYPE_CLASS | USB_RECIP_INTERFACE, DFU_GETSTATUS, 0, 0,
+    (char*) status, sizeof(struct dfu_status), DFU_TIMEOUT);
+  
+  if (result < 0) {
+    fprintf(stderr, "%s: Error: Failed to get DFU status: %s\n",
+      progname, usb_strerror());
+    return -1;
+  }
+  
+  if (result < sizeof(struct dfu_status)) {
+    fprintf(stderr, "%s: Error: Failed to get DFU status: %s\n",
+      progname, "short read");
+    return -1;
+  }
+
+  if (result > sizeof(struct dfu_status)) {
+    fprintf(stderr, "%s: Error: Oversize read (should not happen); " \
+      "exiting\n", progname);
+    exit(1);
+  }
+  
+  return 0;
+}
+
+int dfu_clrstatus(struct dfu_dev *dfu)
+{
+  int result;
+  
+  result = usb_control_msg(dfu->dev_handle,
+    USB_TYPE_CLASS | USB_RECIP_INTERFACE, DFU_CLRSTATUS, 0, 0,
+    NULL, 0, DFU_TIMEOUT);
+  
+  if (result < 0) {
+    fprintf(stderr, "%s: Error: Failed to clear DFU status: %s\n",
+      progname, usb_strerror());
+    return -1;
+  }
+  
+  return 0;
+}
+
+int dfu_dnload(struct dfu_dev *dfu, void *ptr, int size)
+{
+  int result;
+
+  result = usb_control_msg(dfu->dev_handle,
+    USB_TYPE_CLASS | USB_RECIP_INTERFACE, DFU_DNLOAD, wIndex++, 0,
+    ptr, size, DFU_TIMEOUT);
+    
+  if (result < 0) {
+    fprintf(stderr, "%s: Error: DFU_DNLOAD failed: %s\n",
+      progname, usb_strerror());
+    return -1;
+  }
+  
+  if (result < size) {
+    fprintf(stderr, "%s: Error: DFU_DNLOAD failed: %s\n",
+      progname, "short write");
+    return -1;
+  }
+
+  if (result > size) {
+    fprintf(stderr, "%s: Error: Oversize write (should not happen); " \
+      "exiting\n", progname);
+    exit(1);
+  }
+  
+  return 0;
+}
+
+int dfu_upload(struct dfu_dev *dfu, void *ptr, int size)
+{
+  int result;
+  
+  result = usb_control_msg(dfu->dev_handle,
+    0x80 | USB_TYPE_CLASS | USB_RECIP_INTERFACE, DFU_UPLOAD, wIndex++, 0,
+    ptr, size, DFU_TIMEOUT);
+
+  if (result < 0) {
+    fprintf(stderr, "%s: Error: DFU_UPLOAD failed: %s\n",
+      progname, usb_strerror());
+    return -1;
+  }
+  
+  if (result < size) {
+    fprintf(stderr, "%s: Error: DFU_UPLOAD failed: %s\n",
+      progname, "short read");
+    return -1;
+  }
+  
+  if (result > size) {
+    fprintf(stderr, "%s: Error: Oversize read (should not happen); " \
+      "exiting\n", progname);
+    exit(1);
+  }
+
+  return 0;
+}
+
+void dfu_show_info(struct dfu_dev *dfu)
+{
+  if (dfu->manf_str != NULL)
+    fprintf(stderr, "    USB Vendor          : %s (0x%04hX)\n",
+      dfu->manf_str, (unsigned short) dfu->dev_desc.idVendor);
+  else
+    fprintf(stderr, "    USB Vendor          : 0x%04hX\n",
+      (unsigned short) dfu->dev_desc.idVendor);
+
+  if (dfu->prod_str != NULL)
+    fprintf(stderr, "    USB Product         : %s (0x%04hX)\n",
+      dfu->prod_str, (unsigned short) dfu->dev_desc.idProduct);
+  else
+    fprintf(stderr, "    USB Product         : 0x%04hX\n",
+      (unsigned short) dfu->dev_desc.idProduct);
+
+  fprintf(stderr, "    USB Release         : %hu.%hu.%hu\n",
+    ((unsigned short) dfu->dev_desc.bcdDevice >> 8) & 0xFF,
+    ((unsigned short) dfu->dev_desc.bcdDevice >> 4) & 0xF,
+    ((unsigned short) dfu->dev_desc.bcdDevice >> 0) & 0xF);
+
+  if (dfu->serno_str != NULL)
+    fprintf(stderr, "    USB Serial No       : %s\n", dfu->serno_str);
+}
+
+/* INTERNAL FUNCTION DEFINITIONS
+ */
+
+char * get_usb_string(usb_dev_handle * dev_handle, int index) {
+  char buffer[256];
+  char * str;
+  int result;
+  
+  if (index == 0)
+    return NULL;
+
+  result = usb_get_string_simple(dev_handle, index, buffer, sizeof(buffer)-1);
+  
+  if (result < 0) {
+    fprintf( stderr, "%s: Warning: Failed to read USB device string %d: %s\n",
+      progname, index, usb_strerror());
+    return NULL;
+  }
+  
+  str = malloc(result+1);
+  
+  if (str == NULL) {
+    perror(progname);
+    exit(1);
+  }
+  
+  memcpy(str, buffer, result);
+  str[result] = '\0';
+  return str;
+}
+
+#endif /* defined(HAVE_LIBUSB) */
+
+/* EXPORTED FUNCTIONS THAT DO NO REQUIRE LIBUSB
+ */
+
+const char * dfu_status_str(int bStatus)
+{
+  switch (bStatus) {
+    case DFU_STATUS_OK: return "OK";
+    case DFU_STATUS_ERR_TARGET: return "ERR_TARGET";
+    case DFU_STATUS_ERR_FILE: return "ERR_FILE";
+    case DFU_STATUS_ERR_WRITE: return "ERR_WRITE";
+    case DFU_STATUS_ERR_ERASE: return "ERR_ERASE";
+    case DFU_STATUS_ERR_CHECK_ERASED: return "ERR_CHECK_ERASED";
+    case DFU_STATUS_ERR_PROG: return "ERR_PROG";
+    case DFU_STATUS_ERR_VERIFY: return "ERR_VERIFY";
+    case DFU_STATUS_ERR_ADDRESS: return "ERR_ADDRESS";
+    case DFU_STATUS_ERR_NOTDONE: return "ERR_NOTDONE";
+    case DFU_STATUS_ERR_FIRMWARE: return "ERR_FIRMWARE";
+    case DFU_STATUS_ERR_VENDOR: return "ERR_VENDOR";
+    case DFU_STATUS_ERR_USBR: return "ERR_USBR";
+    case DFU_STATUS_ERR_POR: return "ERR_POR";
+    case DFU_STATUS_ERR_UNKNOWN: return "ERR_UNKNOWN";
+    case DFU_STATUS_ERR_STALLEDPKT: return "ERR_STALLEDPKT";
+    default: return "Unknown";
+  }
+}
+
+const char * dfu_state_str(int bState)
+{
+  switch (bState) {
+    case DFU_STATE_APP_IDLE: return "APP_IDLE";
+    case DFU_STATE_APP_DETACH: return "APP_DETACH";
+    case DFU_STATE_DFU_IDLE: return "DFU_IDLE";
+    case DFU_STATE_DFU_DLOAD_SYNC: return "DFU_DLOAD_SYNC";
+    case DFU_STATE_DFU_DNBUSY: return "DFU_DNBUSY";
+    case DFU_STATE_DFU_DNLOAD_IDLE: return "DFU_DNLOAD_IDLE";
+    case DFU_STATE_DFU_MANIFEST_SYNC: return "DFU_MANIFEST_SYNC";
+    case DFU_STATE_DFU_MANIFEST: return "DFU_MANIFEST";
+    case DFU_STATE_DFU_MANIFEST_WAIT_RESET: return "DFU_MANIFEST_WAIT_RESET";
+    case DFU_STATE_DFU_UPLOAD_IDLE: return "DFU_UPLOAD_IDLE";
+    case DFU_STATE_DFU_ERROR: return "DFU_ERROR";
+    default: return "Unknown";
+  }
+}
+

Property changes on: dfu.c
___________________________________________________________________
Added: svn:executable
   + *

Index: dfu.h
===================================================================
--- dfu.h	(revision 0)
+++ dfu.h	(revision 0)
@@ -0,0 +1,129 @@
+/*
+ * avrdude - A Downloader/Uploader for AVR device programmers
+ * Copyright (C) 2007 Limor Fried
+ *
+ * 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
+ */
+
+
+#ifndef dfu_h
+#define dfu_h
+
+#include "ac_cfg.h"
+
+#ifdef HAVE_LIBUSB
+#include <usb.h>
+#endif
+
+#include <limits.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* If we have LIBUSB, define the dfu_dev struct normally. Otherwise, declare
+ * it as an empty struct so that code compiles, but we generate an error at
+ * run time.
+ */
+
+#ifdef HAVE_LIBUSB
+
+struct dfu_dev
+{
+  char *bus_name, *dev_name;
+  usb_dev_handle *dev_handle;
+  struct usb_device_descriptor dev_desc;
+  struct usb_config_descriptor conf_desc;
+  struct usb_interface_descriptor intf_desc;
+  struct usb_endpoint_descriptor endp_desc;
+  char *manf_str, *prod_str, *serno_str;
+};
+
+#else
+
+struct dfu_dev {
+  // empty
+};
+
+#endif
+
+/* We assume unsigned char is 1 byte. */
+
+#if UCHAR_MAX != 255
+#error UCHAR_MAX != 255
+#endif
+
+struct dfu_status {
+  unsigned char bStatus;
+  unsigned char bwPollTimeout[3];
+  unsigned char bState;
+  unsigned char iString;
+};
+
+// Values of bStatus field.
+
+#define DFU_STATUS_OK 0x0
+#define DFU_STATUS_ERR_TARGET 0x1
+#define DFU_STATUS_ERR_FILE 0x2
+#define DFU_STATUS_ERR_WRITE 0x3
+#define DFU_STATUS_ERR_ERASE 0x4
+#define DFU_STATUS_ERR_CHECK_ERASED 0x5
+#define DFU_STATUS_ERR_PROG 0x6
+#define DFU_STATUS_ERR_VERIFY 0x7
+#define DFU_STATUS_ERR_ADDRESS 0x8
+#define DFU_STATUS_ERR_NOTDONE 0x9
+#define DFU_STATUS_ERR_FIRMWARE 0xA
+#define DFU_STATUS_ERR_VENDOR 0xB
+#define DFU_STATUS_ERR_USBR 0xC
+#define DFU_STATUS_ERR_POR 0xD
+#define DFU_STATUS_ERR_UNKNOWN 0xE
+#define DFU_STATUS_ERR_STALLEDPKT 0xF
+
+// Values of bState field.
+
+#define DFU_STATE_APP_IDLE 0
+#define DFU_STATE_APP_DETACH 1
+#define DFU_STATE_DFU_IDLE 2
+#define DFU_STATE_DFU_DLOAD_SYNC 3
+#define DFU_STATE_DFU_DNBUSY 4
+#define DFU_STATE_DFU_DNLOAD_IDLE 5
+#define DFU_STATE_DFU_MANIFEST_SYNC 6
+#define DFU_STATE_DFU_MANIFEST 7
+#define DFU_STATE_DFU_MANIFEST_WAIT_RESET 8
+#define DFU_STATE_DFU_UPLOAD_IDLE 9
+#define DFU_STATE_DFU_ERROR 10
+
+// FUNCTIONS
+
+extern struct dfu_dev * dfu_open(char *port_spec);
+extern int dfu_init(struct dfu_dev *dfu,
+  unsigned short vid, unsigned short pid);
+extern void dfu_close(struct dfu_dev *dfu);
+
+extern int dfu_getstatus(struct dfu_dev *dfu, struct dfu_status *status);
+extern int dfu_clrstatus(struct dfu_dev *dfu);
+extern int dfu_dnload(struct dfu_dev *dfu, void *ptr, int size);
+extern int dfu_upload(struct dfu_dev *dfu, void *ptr, int size);
+
+extern void dfu_show_info(struct dfu_dev *dfu);
+
+extern const char * dfu_status_str(int bStatus);
+extern const char * dfu_state_str(int bState);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* dfu_h */

Property changes on: dfu.h
___________________________________________________________________
Added: svn:executable
   + *

Index: pgm_type.c
===================================================================
--- pgm_type.c	(revision 1118)
+++ pgm_type.c	(working copy)
@@ -34,6 +34,7 @@
 #include "avrftdi.h"
 #include "buspirate.h"
 #include "butterfly.h"
+#include "flip.h"
 #include "ft245r.h"
 #include "jtagmkI.h"
 #include "jtagmkII.h"
@@ -63,6 +64,7 @@
         {"dragon_jtag", jtagmkII_dragon_initpgm, jtagmkII_dragon_desc},
         {"dragon_pdi", jtagmkII_dragon_pdi_initpgm, jtagmkII_dragon_pdi_desc},
         {"dragon_pp", stk500v2_dragon_pp_initpgm, stk500v2_dragon_pp_desc},
+        {"flip2", flip2_initpgm, flip2_desc},
         {"ftdi_syncbb", ft245r_initpgm, ft245r_desc},
         {"jtagmki", jtagmkI_initpgm, jtagmkI_desc},
         {"jtagmkii", jtagmkII_initpgm, jtagmkII_desc},
Index: doc/avrdude.texi
===================================================================
--- doc/avrdude.texi	(revision 1118)
+++ doc/avrdude.texi	(working copy)
@@ -1386,6 +1386,7 @@
     stk500_devcode   = <num> ;                # numeric
     avr910_devcode   = <num> ;                # numeric
     signature        = <num> <num> <num> ;    # signature bytes
+    usbpid           = <num> ;                # DFU USB PID
     reset            = dedicated | io;
     retry_pulse      = reset | sck;
     pgm_enable       = <instruction format> ;
Index: flip.c
===================================================================
--- flip.c	(revision 0)
+++ flip.c	(revision 0)
@@ -0,0 +1,867 @@
+/*
+ * avrdude - A Downloader/Uploader for AVR device programmers
+ * Copyright (C) 2007 Dick Streefland, adapted for 5.4 by Limor Fried
+ *
+ * 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
+ */
+
+#include "ac_cfg.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <limits.h>
+#include <unistd.h>
+
+#if HAVE_STDINT_H
+#include <stdint.h>
+#elif HAVE_INTTYPES_H
+#include <inttypes.h>
+#endif
+
+#include "flip.h"
+#include "dfu.h"
+
+#include "avrdude.h"
+#include "avr.h"
+#include "pgm.h"
+
+#include "usbdevs.h" /* for USB_VENDOR_ATMEL */
+
+/* There are three versions of the FLIP protocol:
+ * 
+ * Version 0: C51 parts
+ * Version 1: megaAVR parts ("USB DFU Bootloader Datasheet" [doc7618])
+ * Version 2: XMEGA parts (AVR4023 [doc8457])
+ * 
+ * We currently only support Version 2, as documented in AVR4023.
+ * 
+ * Additional references:
+ *   flip_protocol.h from the Atmel Software Framework.
+ *   udi_dfu_atmel.c from XMEGA bootloaders archive.
+ */
+
+/* EXPORTED CONSTANT STRINGS */
+
+const char flip2_desc[] = "FLIPv2 USB DFU protocol (AVR4023)";
+
+/* PRIVATE DATA STRUCTURES */
+
+struct flip2
+{
+  struct dfu_dev *dfu;
+  unsigned char part_sig[3];
+  unsigned char part_rev;
+  unsigned char boot_ver;
+};
+
+#define FLIP2(pgm) ((struct flip2 *)(pgm->cookie))
+
+/* The FLIP2 protocol assigns specific meaning to certain combinations of 
+ * status and state bytes in the DFU_GETSTATUS response. These constants en-
+ * code these combinations as a 16-bit value: the high order byte is the
+ * status and the low order byte is the state of the status-state pairing.
+ */
+
+#define FLIP2_STATUS_OK 0x0000
+#define FLIP2_STATUS_STALL 0x0F0A
+#define FLIP2_STATUS_MEM_UKNOWN 0x030A
+#define FLIP2_STATUS_MEM_PROTECTED 0x0300
+#define FLIP2_STATUS_OUTOFRANGE 0x080A
+#define FLIP2_STATUS_BLANK_FAIL 0x0500
+#define FLIP2_STATUS_ERASE_ONGOING 0x0904
+
+/* FLIP2 data structures and constants. */
+
+struct flip2_cmd {
+  unsigned char group_id;
+  unsigned char cmd_id;
+  unsigned char args[4];
+};
+
+#define FLIP2_CMD_GROUP_DOWNLOAD 0x01
+#define FLIP2_CMD_GROUP_UPLOAD 0x03
+#define FLIP2_CMD_GROUP_EXEC 0x04
+#define FLIP2_CMD_GROUP_SELECT 0x06
+
+#define FLIP2_CMD_PROG_START 0x00
+#define FLIP2_CMD_READ_MEMORY 0x00
+#define FLIP2_CMD_SELECT_MEMORY 0x03
+#define FLIP2_CMD_CHIP_ERASE 0x00
+#define FLIP2_CMD_START_APP 0x03
+
+#define FLIP2_SELECT_MEMORY_UNIT 0x00
+#define FLIP2_SELECT_MEMORY_PAGE 0x01
+
+enum flip2_mem_unit {
+  FLIP2_MEM_UNIT_UNKNOWN = -1,
+  FLIP2_MEM_UNIT_FLASH = 0x00,
+  FLIP2_MEM_UNIT_EEPROM = 0x01,
+  FLIP2_MEM_UNIT_SECURITY = 0x02,
+  FLIP2_MEM_UNIT_CONFIGURATION = 0x03,
+  FLIP2_MEM_UNIT_BOOTLOADER = 0x04,
+  FLIP2_MEM_UNIT_SIGNATURE = 0x05,
+  FLIP2_MEM_UNIT_USER = 0x06,
+  FLIP2_MEM_UNIT_INT_RAM = 0x07,
+  FLIP2_MEM_UNIT_EXT_MEM_CS0 = 0x08,
+  FLIP2_MEM_UNIT_EXT_MEM_CS1 = 0x09,
+  FLIP2_MEM_UNIT_EXT_MEM_CS2 = 0x0A,
+  FLIP2_MEM_UNIT_EXT_MEM_CS3 = 0x0B,
+  FLIP2_MEM_UNIT_EXT_MEM_CS4 = 0x0C,
+  FLIP2_MEM_UNIT_EXT_MEM_CS5 = 0x0D,
+  FLIP2_MEM_UNIT_EXT_MEM_CS6 = 0x0E,
+  FLIP2_MEM_UNIT_EXT_MEM_CS7 = 0x0F,
+  FLIP2_MEM_UNIT_EXT_MEM_DF = 0x10
+};
+
+/* EXPORTED PROGRAMMER FUNCTION PROTOTYPES */
+
+static int flip2_open(PROGRAMMER *pgm, char *port_spec);
+static int flip2_initialize(PROGRAMMER* pgm, AVRPART *part);
+static void flip2_close(PROGRAMMER* pgm);
+static void flip2_enable(PROGRAMMER* pgm);
+static void flip2_disable(PROGRAMMER* pgm);
+static void flip2_display(PROGRAMMER* pgm, const char *prefix);
+static int flip2_program_enable(PROGRAMMER* pgm, AVRPART *part);
+static int flip2_chip_erase(PROGRAMMER* pgm, AVRPART *part);
+static int flip2_read_byte(PROGRAMMER* pgm, AVRPART *part, AVRMEM *mem,
+  unsigned long addr, unsigned char *value);
+static int flip2_write_byte(PROGRAMMER* pgm, AVRPART *part, AVRMEM *mem,
+  unsigned long addr, unsigned char value);
+static int flip2_page_erase(PROGRAMMER* pgm, AVRPART *part, AVRMEM *mem,
+  unsigned int base_addr);
+static int flip2_paged_load(PROGRAMMER* pgm, AVRPART *part, AVRMEM *mem,
+  unsigned int page_size, unsigned int addr, unsigned int n_bytes);
+static int flip2_paged_write(PROGRAMMER* pgm, AVRPART *part, AVRMEM *mem,
+  unsigned int page_size, unsigned int addr, unsigned int n_bytes);
+static int flip2_read_sig_bytes(PROGRAMMER* pgm, AVRPART *part, AVRMEM *mem);
+static void flip2_setup(PROGRAMMER * pgm);
+static void flip2_teardown(PROGRAMMER * pgm);
+
+/* INTERNAL PROGRAMMER FUNCTION PROTOTYPES */
+
+static void flip2_show_info(struct flip2 *flip2);
+
+static int flip2_read_memory(struct dfu_dev *dfu,
+  enum flip2_mem_unit mem_unit, uint32_t addr, void *ptr, int size);
+static int flip2_write_memory(struct dfu_dev *dfu,
+  enum flip2_mem_unit mem_unit, uint32_t addr, const void *ptr, int size);
+
+static int flip2_set_mem_unit(struct dfu_dev *dfu,
+  enum flip2_mem_unit mem_unit);
+static int flip2_set_mem_page(struct dfu_dev *dfu, unsigned short page_addr);
+static int flip2_read_max1k(struct dfu_dev *dfu,
+  unsigned short offset, void *ptr, unsigned short size);
+static int flip2_write_max1k(struct dfu_dev *dfu,
+  unsigned short offset, const void *ptr, unsigned short size);
+
+static const char * flip2_status_str(const struct dfu_status *status);
+static const char * flip2_mem_unit_str(enum flip2_mem_unit mem_unit);
+static enum flip2_mem_unit flip2_mem_unit(const char *name);
+
+/* THE INITPGM FUNCTION DEFINITIONS */
+
+void flip2_initpgm(PROGRAMMER *pgm)
+{
+  strcpy(pgm->type, "flip2");
+
+  /* Mandatory Functions */
+  pgm->initialize       = flip2_initialize;
+  pgm->enable           = flip2_enable;
+  pgm->disable          = flip2_disable;
+  pgm->display          = flip2_display;
+  pgm->program_enable   = flip2_program_enable;
+  pgm->chip_erase       = flip2_chip_erase;
+  pgm->open             = flip2_open;
+  pgm->close            = flip2_close;
+  pgm->page_erase       = flip2_page_erase;
+  pgm->paged_load       = flip2_paged_load;
+  pgm->paged_write      = flip2_paged_write;
+  pgm->read_byte        = flip2_read_byte;
+  pgm->write_byte       = flip2_write_byte;
+  pgm->read_sig_bytes   = flip2_read_sig_bytes;
+  pgm->setup            = flip2_setup;
+  pgm->teardown         = flip2_teardown;
+}
+
+/* EXPORTED PROGRAMMER FUNCTION DEFINITIONS */
+
+int flip2_open(PROGRAMMER *pgm, char *port_spec)
+{
+  FLIP2(pgm)->dfu = dfu_open(port_spec);
+  return (FLIP2(pgm)->dfu != NULL) ? 0 : -1;
+}
+
+int flip2_initialize(PROGRAMMER* pgm, AVRPART *part)
+{
+  unsigned short vid, pid;
+  int result;
+  
+  /* A note about return values. Negative return values from this function are
+   * interpreted as failure by main(), from where this function is called.
+   * However such failures are interpreted as a device signature check failure
+   * and the user is adviced to use the -F option to override this check. In
+   * our case, this is misleading, so we defer reporting an error until another
+   * function is called. Thus, we always return 0 (success) from initialize().
+   * I don't like this, but I don't want to mess with main().
+   */
+  
+  /* The dfu_init() function will try to find the target part either based on
+   * a USB address provided by the user with the -P option or by matching the
+   * VID and PID of the device. The VID may be specified in the programmer
+   * definition; if not specified, it defaults to USB_VENDOR_ATMEL (defined
+   * in usbdevs.h). The PID may be specified either in the programmer
+   * definition or the part definition; the programmer definition takes
+   * priority. The default PID value is 0, which causes dfu_init() to ignore
+   * the PID when matching a target device.
+   */
+ 
+  vid = (pgm->usbvid != 0) ? pgm->usbvid : USB_VENDOR_ATMEL;
+  pid = (pgm->usbpid != 0) ? pgm->usbpid : part->usbpid;
+  
+  result = dfu_init(FLIP2(pgm)->dfu, vid, pid);
+  
+  if (result != 0)
+    goto flip2_initialize_fail;
+  
+  result = flip2_read_memory(FLIP2(pgm)->dfu,
+    FLIP2_MEM_UNIT_SIGNATURE, 0, FLIP2(pgm)->part_sig, 4);
+
+  if (result != 0)
+    goto flip2_initialize_fail;
+  
+  result = flip2_read_memory(FLIP2(pgm)->dfu,
+    FLIP2_MEM_UNIT_BOOTLOADER, 0, &FLIP2(pgm)->boot_ver, 1);
+
+  if (result != 0)
+    goto flip2_initialize_fail;
+  
+  if (verbose)
+    flip2_show_info(FLIP2(pgm));
+  
+  return 0;
+
+flip2_initialize_fail:
+  dfu_close(FLIP2(pgm)->dfu);
+  FLIP2(pgm)->dfu = NULL;
+  return 0;
+}
+
+void flip2_close(PROGRAMMER* pgm)
+{
+  if (FLIP2(pgm)->dfu != NULL) {
+    dfu_close(FLIP2(pgm)->dfu);
+    FLIP2(pgm)->dfu = NULL;
+  }
+}
+
+void flip2_enable(PROGRAMMER* pgm)
+{
+  /* Nothing to do. */
+}
+
+void flip2_disable(PROGRAMMER* pgm)
+{
+  /* Nothing to do. */
+}
+
+void flip2_display(PROGRAMMER* pgm, const char *prefix)
+{
+  /* Nothing to do. */
+}
+
+int flip2_program_enable(PROGRAMMER* pgm, AVRPART *part)
+{
+  /* I couldn't find anything that uses this function, although it is marked
+   * as "mandatory" in pgm.c. In case anyone does use it, we'll report an
+   * error if we failed to initialize.
+   */
+  
+  return (FLIP2(pgm)->dfu != NULL) ? 0 : -1;
+}
+
+int flip2_chip_erase(PROGRAMMER* pgm, AVRPART *part)
+{
+  struct dfu_status status;
+  int cmd_result = 0;
+  int aux_result;
+  
+  struct flip2_cmd cmd = {
+    FLIP2_CMD_GROUP_EXEC, FLIP2_CMD_CHIP_ERASE, { 0xFF, 0, 0, 0 }
+  };
+  
+  for (;;) {
+    cmd_result = dfu_dnload(FLIP2(pgm)->dfu, &cmd, sizeof(cmd));
+    aux_result = dfu_getstatus(FLIP2(pgm)->dfu, &status);
+  
+    if (aux_result != 0)
+      return aux_result;
+  
+    if (status.bStatus != DFU_STATUS_OK) {
+      if (status.bStatus == ((FLIP2_STATUS_ERASE_ONGOING >> 8) & 0xFF) &&
+          status.bState == ((FLIP2_STATUS_ERASE_ONGOING >> 0) & 0xFF))
+      {
+        continue;
+      } else
+        fprintf(stderr, "%s: Error: DFU status %s\n", progname,
+          flip2_status_str(&status));
+      dfu_clrstatus(FLIP2(pgm)->dfu);
+    } else
+      break;
+  }
+  
+  return cmd_result;
+}
+
+int flip2_read_byte(PROGRAMMER* pgm, AVRPART *part, AVRMEM *mem,
+  unsigned long addr, unsigned char *value)
+{
+  enum flip2_mem_unit mem_unit;
+  
+  if (FLIP2(pgm)->dfu == NULL)
+    return -1;
+    
+  mem_unit = flip2_mem_unit(mem->desc);
+  
+  if (mem_unit == FLIP2_MEM_UNIT_UNKNOWN) {
+    fprintf(stderr, "%s: Error: " \
+      "\"%s\" memory not accessible using FLIP",
+      progname, mem->desc);
+    if (strcmp(mem->desc, "flash") == 0)
+      fprintf(stderr, " (did you mean \"application\"?)");
+    fprintf(stderr, "\n");
+    return -1;
+  }
+  
+  return flip2_read_memory(FLIP2(pgm)->dfu, mem_unit, addr, value, 1);
+}
+
+int flip2_write_byte(PROGRAMMER* pgm, AVRPART *part, AVRMEM *mem,
+  unsigned long addr, unsigned char value)
+{
+  enum flip2_mem_unit mem_unit;
+  
+  if (FLIP2(pgm)->dfu == NULL)
+    return -1;
+    
+  mem_unit = flip2_mem_unit(mem->desc);
+  
+  if (mem_unit == FLIP2_MEM_UNIT_UNKNOWN) {
+    fprintf(stderr, "%s: Error: " \
+      "\"%s\" memory not accessible using FLIP",
+      progname, mem->desc);
+    if (strcmp(mem->desc, "flash") == 0)
+      fprintf(stderr, " (did you mean \"application\"?)");
+    fprintf(stderr, "\n");
+    return -1;
+  }
+  
+  return flip2_write_memory(FLIP2(pgm)->dfu, mem_unit, addr, &value, 1);
+}
+
+int flip2_page_erase(PROGRAMMER* pgm, AVRPART *part, AVRMEM *mem,
+  unsigned int base_addr)
+{
+  return 0;
+}
+
+int flip2_paged_load(PROGRAMMER* pgm, AVRPART *part, AVRMEM *mem,
+  unsigned int page_size, unsigned int addr, unsigned int n_bytes)
+{
+  enum flip2_mem_unit mem_unit;
+  int result;
+  
+  if (FLIP2(pgm)->dfu == NULL)
+    return -1;
+    
+  mem_unit = flip2_mem_unit(mem->desc);
+  
+  if (mem_unit == FLIP2_MEM_UNIT_UNKNOWN) {
+    fprintf(stderr, "%s: Error: " \
+      "\"%s\" memory not accessible using FLIP",
+      progname, mem->desc);
+    if (strcmp(mem->desc, "flash") == 0)
+      fprintf(stderr, " (did you mean \"application\"?)");
+    fprintf(stderr, "\n");
+    return -1;
+  }
+  
+  if (n_bytes > INT_MAX) {
+    /* This should never happen, unless the int type is only 16 bits. */
+    fprintf(stderr, "%s: Error: Attempting to read more than %d bytes\n",
+      progname, INT_MAX);
+    exit(1);
+  }
+  
+  result = flip2_read_memory(FLIP2(pgm)->dfu, mem_unit, addr,
+    mem->buf + addr, n_bytes);
+
+#if 0 /* DEBUG */
+  fprintf(stderr, "%s: Debug: flip2_read_memory(%s,0x%04X,0x%04X) = %d\n",
+    progname, mem->desc, addr, n_bytes, result);
+#endif
+
+  return (result == 0) ? n_bytes : -1;
+}
+
+int flip2_paged_write(PROGRAMMER* pgm, AVRPART *part, AVRMEM *mem,
+  unsigned int page_size, unsigned int addr, unsigned int n_bytes)
+{
+  enum flip2_mem_unit mem_unit;
+  int result;
+  
+  if (FLIP2(pgm)->dfu == NULL)
+    return -1;
+    
+  mem_unit = flip2_mem_unit(mem->desc);
+  
+  if (mem_unit == FLIP2_MEM_UNIT_UNKNOWN) {
+    fprintf(stderr, "%s: Error: " \
+      "\"%s\" memory not accessible using FLIP",
+      progname, mem->desc);
+    if (strcmp(mem->desc, "flash") == 0)
+      fprintf(stderr, " (did you mean \"application\"?)");
+    fprintf(stderr, "\n");
+    return -1;
+  }
+  
+  if (n_bytes > INT_MAX) {
+    /* This should never happen, unless the int type is only 16 bits. */
+    fprintf(stderr, "%s: Error: Attempting to read more than %d bytes\n",
+      progname, INT_MAX);
+    exit(1);
+  }
+  
+  result = flip2_write_memory(FLIP2(pgm)->dfu, mem_unit, addr,
+    mem->buf + addr, n_bytes);
+  
+#if 0 /* DEBUG */
+  fprintf(stderr, "%s: Debug: flip2_write_memory(%s,0x%04X,0x%04X) = %d\n",
+    progname, mem->desc, addr, n_bytes, result);
+#endif
+  
+  return 0;
+}
+
+int flip2_read_sig_bytes(PROGRAMMER* pgm, AVRPART *part, AVRMEM *mem)
+{
+  if (FLIP2(pgm)->dfu == NULL)
+    return -1;
+    
+  if (mem->size < sizeof(FLIP2(pgm)->part_sig)) {
+    fprintf(stderr, "%s: Error: Signature read must be at least %u bytes\n",
+      progname, (unsigned int) sizeof(FLIP2(pgm)->part_sig));
+    return -1;
+  }
+  
+  memcpy(mem->buf, FLIP2(pgm)->part_sig, sizeof(FLIP2(pgm)->part_sig));
+  return 0;
+}
+
+void flip2_setup(PROGRAMMER * pgm)
+{
+  pgm->cookie = calloc(1, sizeof(struct flip2));
+  
+  if (pgm->cookie == NULL) {
+    perror(progname);
+    exit(1);
+  }
+}
+
+void flip2_teardown(PROGRAMMER * pgm)
+{
+  free(pgm->cookie);
+  pgm->cookie = NULL;
+}
+
+/* INTERNAL FUNCTION DEFINITIONS
+ */
+
+void flip2_show_info(struct flip2 *flip2)
+{
+  dfu_show_info(flip2->dfu);
+  
+  fprintf(stderr, "    Part signature      : 0x%02X%02X%02X\n",
+    (int) flip2->part_sig[0],
+    (int) flip2->part_sig[1],
+    (int) flip2->part_sig[2]);
+
+  if (flip2->part_rev < 26)
+    fprintf(stderr, "    Part revision       : %c\n", 
+      (char) (flip2->part_rev + 'A'));
+  else
+    fprintf(stderr, "    Part revision       : %c%c\n", 
+      (char) (flip2->part_rev / 26 - 1 + 'A'),
+      (char) (flip2->part_rev % 26 + 'A'));
+
+  fprintf(stderr, "    Bootloader version  : 2.%hu.%hu\n",
+    ((unsigned short) flip2->boot_ver >> 4) & 0xF,
+    ((unsigned short) flip2->boot_ver >> 0) & 0xF);
+
+  fprintf(stderr, "    USB max packet size : %hu\n",
+    (unsigned short) flip2->dfu->dev_desc.bMaxPacketSize0);
+}
+
+int flip2_read_memory(struct dfu_dev *dfu,
+  enum flip2_mem_unit mem_unit, uint32_t addr, void *ptr, int size)
+{
+  unsigned short prev_page_addr;
+  unsigned short page_addr;
+  const char * mem_name;
+  int read_size;
+  int result;
+  
+  result = flip2_set_mem_unit(dfu, mem_unit);
+  
+  if (result != 0) {
+    if ((mem_name = flip2_mem_unit_str(mem_unit)) != NULL)
+      fprintf(stderr, "%s: Error: Failed to set memory unit 0x%02X (%s)\n",
+        progname, (int) mem_unit, mem_name);
+    else
+      fprintf(stderr, "%s: Error: Failed to set memory unit 0x%02X\n",
+        progname, (int) mem_unit);
+    return -1;
+  }
+  
+  page_addr = addr >> 16;
+  result = flip2_set_mem_page(dfu, page_addr);
+
+  if (result != 0) {
+    fprintf(stderr, "%s: Error: Failed to set memory page 0x%04hX\n",
+        progname, page_addr);
+    return -1;
+  }
+  
+  while (size > 0) {
+    prev_page_addr = page_addr;
+    page_addr = addr >> 16;
+    
+    if (page_addr != prev_page_addr) {
+      result = flip2_set_mem_page(dfu, page_addr);
+      if (result != 0) {
+        fprintf(stderr, "%s: Error: Failed to set memory page 0x%04hX\n",
+            progname, page_addr);
+        return -1;
+      }
+    }
+    
+    read_size = (size > 0x400) ? 0x400 : size;
+    result = flip2_read_max1k(dfu, addr & 0xFFFF, ptr, read_size);
+    
+    if (result != 0) {
+      fprintf(stderr, "%s: Error: Failed to read 0x%04X bytes at 0x%04lX\n",
+          progname, read_size, (unsigned long) addr);
+      return -1;
+    }
+    
+    ptr += read_size;
+    addr += read_size;
+    size -= read_size;
+  }
+  
+  return 0;
+}
+
+int flip2_write_memory(struct dfu_dev *dfu,
+  enum flip2_mem_unit mem_unit, uint32_t addr, const void *ptr, int size)
+{
+  unsigned short prev_page_addr;
+  unsigned short page_addr;
+  const char * mem_name;
+  int write_size;
+  int result;
+  
+  result = flip2_set_mem_unit(dfu, mem_unit);
+  
+  if (result != 0) {
+    if ((mem_name = flip2_mem_unit_str(mem_unit)) != NULL)
+      fprintf(stderr, "%s: Error: Failed to set memory unit 0x%02X (%s)\n",
+        progname, (int) mem_unit, mem_name);
+    else
+      fprintf(stderr, "%s: Error: Failed to set memory unit 0x%02X\n",
+        progname, (int) mem_unit);
+    return -1;
+  }
+  
+  page_addr = addr >> 16;
+  result = flip2_set_mem_page(dfu, page_addr);
+
+  if (result != 0) {
+    fprintf(stderr, "%s: Error: Failed to set memory page 0x%04hX\n",
+        progname, page_addr);
+    return -1;
+  }
+  
+  while (size > 0) {
+    prev_page_addr = page_addr;
+    page_addr = addr >> 16;
+    
+    if (page_addr != prev_page_addr) {
+      result = flip2_set_mem_page(dfu, page_addr);
+      if (result != 0) {
+        fprintf(stderr, "%s: Error: Failed to set memory page 0x%04hX\n",
+            progname, page_addr);
+        return -1;
+      }
+    }
+    
+    write_size = (size > 0x800) ? 0x800 : size;
+    result = flip2_write_max1k(dfu, addr & 0xFFFF, ptr, write_size);
+    
+    if (result != 0) {
+      fprintf(stderr, "%s: Error: Failed to write 0x%04X bytes at 0x%04lX\n",
+          progname, write_size, (unsigned long) addr);
+      return -1;
+    }
+    
+    ptr += write_size;
+    addr += write_size;
+    size -= write_size;
+  }
+  
+  return 0;
+}
+
+int flip2_set_mem_unit(struct dfu_dev *dfu, enum flip2_mem_unit mem_unit)
+{
+  struct dfu_status status;
+  int cmd_result = 0;
+  int aux_result;
+  
+  struct flip2_cmd cmd = {
+    FLIP2_CMD_GROUP_SELECT, FLIP2_CMD_SELECT_MEMORY, { 0, 0, 0, 0 }
+  };
+
+  cmd.args[0] = FLIP2_SELECT_MEMORY_UNIT;
+  cmd.args[1] = mem_unit;
+
+  cmd_result = dfu_dnload(dfu, &cmd, sizeof(cmd));
+  
+  aux_result = dfu_getstatus(dfu, &status);
+
+  if (aux_result != 0)
+    return aux_result;
+
+  if (status.bStatus != DFU_STATUS_OK) {
+    if (status.bStatus == ((FLIP2_STATUS_OUTOFRANGE >> 8) & 0xFF) &&
+        status.bState == ((FLIP2_STATUS_OUTOFRANGE >> 0) & 0xFF))
+    {
+      fprintf(stderr, "%s: Error: Unknown memory unit (0x%02x)\n",
+        progname, (unsigned int) mem_unit);
+    } else
+      fprintf(stderr, "%s: Error: DFU status %s\n", progname,
+        flip2_status_str(&status));
+    dfu_clrstatus(dfu);
+  }
+  
+  return cmd_result;
+}
+
+int flip2_set_mem_page(struct dfu_dev *dfu,
+  unsigned short page_addr)
+{
+  struct dfu_status status;
+  int cmd_result = 0;
+  int aux_result;
+  
+  struct flip2_cmd cmd = {
+    FLIP2_CMD_GROUP_SELECT, FLIP2_CMD_SELECT_MEMORY, { 0, 0, 0, 0 }
+  };
+
+  cmd.args[0] = FLIP2_SELECT_MEMORY_PAGE;
+  cmd.args[1] = (page_addr >> 8) & 0xFF;
+  cmd.args[2] = (page_addr >> 0) & 0xFF;
+
+  cmd_result = dfu_dnload(dfu, &cmd, sizeof(cmd));
+  
+  aux_result = dfu_getstatus(dfu, &status);
+
+  if (aux_result != 0)
+    return aux_result;
+
+  if (status.bStatus != DFU_STATUS_OK) {
+    if (status.bStatus == ((FLIP2_STATUS_OUTOFRANGE >> 8) & 0xFF) &&
+        status.bState == ((FLIP2_STATUS_OUTOFRANGE >> 0) & 0xFF))
+    {
+      fprintf(stderr, "%s: Error: Page address out of range (0x%04hx)\n",
+        progname, page_addr);
+    } else
+      fprintf(stderr, "%s: Error: DFU status %s\n", progname,
+        flip2_status_str(&status));
+    dfu_clrstatus(dfu);
+  }
+
+  return cmd_result;
+}
+
+int flip2_read_max1k(struct dfu_dev *dfu,
+  unsigned short offset, void *ptr, unsigned short size)
+{
+  struct dfu_status status;
+  int cmd_result = 0;
+  int aux_result;
+  
+  struct flip2_cmd cmd = {
+    FLIP2_CMD_GROUP_UPLOAD, FLIP2_CMD_READ_MEMORY, { 0, 0, 0, 0 }
+  };
+  
+  cmd.args[0] = (offset >> 8) & 0xFF;
+  cmd.args[1] = (offset >> 0) & 0xFF;
+  cmd.args[2] = ((offset+size-1) >> 8) & 0xFF;
+  cmd.args[3] = ((offset+size-1) >> 0) & 0xFF;
+
+  cmd_result = dfu_dnload(dfu, &cmd, sizeof(cmd));
+  
+  if (cmd_result != 0)
+    goto flip2_read_max1k_status;
+  
+  cmd_result = dfu_upload(dfu, (char*) ptr, size);
+
+flip2_read_max1k_status:
+
+  aux_result = dfu_getstatus(dfu, &status);
+
+  if (aux_result != 0)
+    return aux_result;
+  
+  if (status.bStatus != DFU_STATUS_OK) {
+    if (status.bStatus == ((FLIP2_STATUS_OUTOFRANGE >> 8) & 0xFF) &&
+        status.bState == ((FLIP2_STATUS_OUTOFRANGE >> 0) & 0xFF))
+    {
+      fprintf(stderr, "%s: Error: Address out of range [0x%04hX,0x%04hX]\n",
+        progname, offset, offset+size-1);
+    } else
+      fprintf(stderr, "%s: Error: DFU status %s\n", progname,
+        flip2_status_str(&status));
+    dfu_clrstatus(dfu);
+  }
+  
+  return cmd_result;
+}
+
+int flip2_write_max1k(struct dfu_dev *dfu,
+  unsigned short offset, const void *ptr, unsigned short size)
+{
+  char buffer[64+64+0x400];
+  unsigned short data_offset;
+  struct dfu_status status;
+  int cmd_result = 0;
+  int aux_result;
+  
+  struct flip2_cmd cmd = {
+    FLIP2_CMD_GROUP_DOWNLOAD, FLIP2_CMD_PROG_START, { 0, 0, 0, 0 }
+  };
+  
+  cmd.args[0] = (offset >> 8) & 0xFF;
+  cmd.args[1] = (offset >> 0) & 0xFF;
+  cmd.args[2] = ((offset+size-1) >> 8) & 0xFF;
+  cmd.args[3] = ((offset+size-1) >> 0) & 0xFF;
+
+  if (size > 0x400) {
+    fprintf(stderr, "%s: Error: Write block too large (%hu > 1024)\n",
+      progname, size);
+    exit(1);
+  }
+  
+  /* There are some special padding requirements for writes. The first packet
+   * must consist only of the FLIP2 command data, which must be padded to
+   * fill out the USB packet (the packet size is given by bMaxPacketSize0 in
+   * the device descriptor). In addition, the data must be padded so that the
+   * first byte of data to be written is at located at position (offset mod
+   * bMaxPacketSize0) within the packet.
+   */
+
+  data_offset = dfu->dev_desc.bMaxPacketSize0;
+  data_offset += offset % dfu->dev_desc.bMaxPacketSize0;
+  
+  memcpy(buffer, &cmd, sizeof(cmd));
+  memset(buffer + sizeof(cmd), 0, data_offset - sizeof(cmd));
+  memcpy(buffer + data_offset, ptr, size);
+  
+  cmd_result = dfu_dnload(dfu, buffer, data_offset + size);
+  
+  aux_result = dfu_getstatus(dfu, &status);
+
+  if (aux_result != 0)
+    return aux_result;
+  
+  if (status.bStatus != DFU_STATUS_OK) {
+    if (status.bStatus == ((FLIP2_STATUS_OUTOFRANGE >> 8) & 0xFF) &&
+        status.bState == ((FLIP2_STATUS_OUTOFRANGE >> 0) & 0xFF))
+    {
+      fprintf(stderr, "%s: Error: Address out of range [0x%04hX,0x%04hX]\n",
+        progname, offset, offset+size-1);
+    } else
+      fprintf(stderr, "%s: Error: DFU status %s\n", progname,
+        flip2_status_str(&status));
+    dfu_clrstatus(dfu);
+  }
+  
+  return cmd_result;
+}
+
+const char * flip2_status_str(const struct dfu_status *status)
+{
+  unsigned short selector;
+  
+  selector = (unsigned short) status->bStatus << 8;
+  selector |= status->bState;
+  
+  switch (selector) {
+    case FLIP2_STATUS_OK: return "OK";
+    case FLIP2_STATUS_STALL: return "STALL";
+    case FLIP2_STATUS_MEM_UKNOWN: return "MEM_UKNOWN";
+    case FLIP2_STATUS_MEM_PROTECTED: return "MEM_PROTECTED";
+    case FLIP2_STATUS_OUTOFRANGE: return "OUTOFRANGE";
+    case FLIP2_STATUS_BLANK_FAIL: return "BLANK_FAIL";
+    case FLIP2_STATUS_ERASE_ONGOING: return "ERASE_ONGOING";
+    default: return dfu_status_str(status->bStatus);
+  }
+}
+
+const char * flip2_mem_unit_str(enum flip2_mem_unit mem_unit)
+{
+  switch (mem_unit) {
+  case FLIP2_MEM_UNIT_FLASH: return "Flash";
+  case FLIP2_MEM_UNIT_EEPROM: return "EEPROM";
+  case FLIP2_MEM_UNIT_SECURITY: return "security";
+  case FLIP2_MEM_UNIT_CONFIGURATION: return "configuration";
+  case FLIP2_MEM_UNIT_BOOTLOADER: return "bootloader version";
+  case FLIP2_MEM_UNIT_SIGNATURE: return "signature";
+  case FLIP2_MEM_UNIT_USER: return "user";
+  case FLIP2_MEM_UNIT_INT_RAM: return "internal RAM";
+  case FLIP2_MEM_UNIT_EXT_MEM_CS0: return "EXT_MEM_CS0";
+  case FLIP2_MEM_UNIT_EXT_MEM_CS1: return "EXT_MEM_CS1";
+  case FLIP2_MEM_UNIT_EXT_MEM_CS2: return "EXT_MEM_CS2";
+  case FLIP2_MEM_UNIT_EXT_MEM_CS3: return "EXT_MEM_CS3";
+  case FLIP2_MEM_UNIT_EXT_MEM_CS4: return "EXT_MEM_CS4";
+  case FLIP2_MEM_UNIT_EXT_MEM_CS5: return "EXT_MEM_CS5";
+  case FLIP2_MEM_UNIT_EXT_MEM_CS6: return "EXT_MEM_CS6";
+  case FLIP2_MEM_UNIT_EXT_MEM_CS7: return "EXT_MEM_CS7";
+  case FLIP2_MEM_UNIT_EXT_MEM_DF: return "EXT_MEM_DF";
+  default: return "unknown";
+  }
+}
+
+enum flip2_mem_unit flip2_mem_unit(const char *name) {
+  if (strcasecmp(name, "application") == 0)
+    return FLIP2_MEM_UNIT_FLASH;
+  if (strcasecmp(name, "eeprom") == 0)
+    return FLIP2_MEM_UNIT_EEPROM;
+  if (strcasecmp(name, "signature") == 0)
+    return FLIP2_MEM_UNIT_SIGNATURE;
+  return FLIP2_MEM_UNIT_UNKNOWN;
+}
\ No newline at end of file

Property changes on: flip.c
___________________________________________________________________
Added: svn:executable
   + *

Index: flip.h
===================================================================
--- flip.h	(revision 0)
+++ flip.h	(revision 0)
@@ -0,0 +1,37 @@
+/*
+ * avrdude - A Downloader/Uploader for AVR device programmers
+ * Copyright (C) 2007 Limor Fried
+ *
+ * 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
+ */
+
+
+#ifndef flip_h
+#define flip_h
+
+#include "pgm.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern const char flip2_desc[];
+extern void flip2_initpgm(PROGRAMMER * pgm);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* flip_h */

Property changes on: flip.h
___________________________________________________________________
Added: svn:executable
   + *

Index: config_gram.y
===================================================================
--- config_gram.y	(revision 1118)
+++ config_gram.y	(working copy)
@@ -649,6 +649,13 @@
     }
   } |
 
+ K_USBPID TKN_EQUAL TKN_NUMBER {
+    {
+      current_part->usbpid = $3->value.number;
+      free_token($3);
+    }
+  } |
+
   K_PP_CONTROLSTACK TKN_EQUAL num_list {
     {
       TOKEN * t;
Index: avrdude.conf.in
===================================================================
--- avrdude.conf.in	(revision 1118)
+++ avrdude.conf.in	(working copy)
@@ -54,6 +54,7 @@
 #       stk500_devcode   = <num> ;                # numeric
 #       avr910_devcode   = <num> ;                # numeric
 #       signature        = <num> <num> <num> ;    # signature bytes
+#       usbpid           = <num> ;                # DFU USB PID
 #       chip_erase_delay = <num> ;                # micro-seconds
 #       reset            = dedicated | io;
 #       retry_pulse      = reset | sck;
@@ -927,6 +928,13 @@
   connection_type = usb;
 ;
 
+programmer
+  id    = "flip2";
+  desc  = "FLIPv2 USB DFU protocol (AVR4023)";
+  type  = "flip2";
+  connection_type = usb;
+;
+
 @HAVE_PARPORT_BEGIN@  Inclusion of the following depends on --enable-parport
 # Parallel port programmers.
 
@@ -1043,7 +1051,6 @@
   miso  = 10;
 ;
 
-
 # From the contributor of the "xil" jtag cable:
 # The "vcc" definition isn't really vcc (the cable gets its power from
 # the programming circuit) but is necessary to switch one of the
@@ -12542,6 +12549,16 @@
 ;
 
 #------------------------------------------------------------
+# ATxmega64A1U
+#------------------------------------------------------------
+
+part parent "x64a1"
+    id		= "x64a1u";
+    desc	= "ATxmega64A1U";
+    usbpid  = 0x2FE8;
+;
+
+#------------------------------------------------------------
 # ATxmega128A1
 #------------------------------------------------------------
 
@@ -12592,6 +12609,16 @@
 ;
 
 #------------------------------------------------------------
+# ATxmeg128A1U
+#------------------------------------------------------------
+
+part parent "x128a1"
+    id		= "x128a1u";
+    desc	= "ATxmega128A1U";
+    usbpid  = 0x2FED;
+;
+
+#------------------------------------------------------------
 # ATxmega128A1RevD
 #------------------------------------------------------------
 
@@ -12712,6 +12739,16 @@
 ;
 
 #------------------------------------------------------------
+# ATxmega64A3U
+#------------------------------------------------------------
+
+part parent "x64a3"
+    id		= "x64a3u";
+    desc	= "ATxmega64A3U";
+    usbpid  = 0x2FE5;
+;
+
+#------------------------------------------------------------
 # ATxmega128A3
 #------------------------------------------------------------
 
@@ -12722,6 +12759,16 @@
 ;
 
 #------------------------------------------------------------
+# ATxmega128A3U
+#------------------------------------------------------------
+
+part parent "x128a3"
+    id		= "x128a3u";
+    desc	= "ATxmega128A3U";
+    usbpid  = 0x2FE6;
+;
+
+#------------------------------------------------------------
 # ATxmega192A3
 #------------------------------------------------------------
 
@@ -12732,6 +12779,16 @@
 ;
 
 #------------------------------------------------------------
+# ATxmega192A3U
+#------------------------------------------------------------
+
+part parent "x192a3"
+    id		= "x192a3u";
+    desc	= "ATxmega192A3U";
+    usbpid  = 0x2FE7;
+;
+
+#------------------------------------------------------------
 # ATxmega256A3
 #------------------------------------------------------------
 
@@ -12742,6 +12799,16 @@
 ;
 
 #------------------------------------------------------------
+# ATxmega256A3U
+#------------------------------------------------------------
+
+part parent "x256a3"
+    id		= "x256a3u";
+    desc	= "ATxmega256A3U";
+    usbpid  = 0x2FEC;
+;
+
+#------------------------------------------------------------
 # ATxmega256A3B
 #------------------------------------------------------------
 
@@ -12752,6 +12819,16 @@
 ;
 
 #------------------------------------------------------------
+# ATxmega256A3BU
+#------------------------------------------------------------
+
+part parent "x256a3b"
+    id		= "x256a3bu";
+    desc	= "ATxmega256A3BU";
+    usbpid  = 0x2FE2;
+;
+
+#------------------------------------------------------------
 # ATxmega16A4
 #------------------------------------------------------------
 
@@ -12803,6 +12880,16 @@
 ;
 
 #------------------------------------------------------------
+# ATxmega16A4U
+#------------------------------------------------------------
+
+part parent "x16a4"
+    id		= "x16a4u";
+    desc	= "ATxmega16A4U";
+    usbpid  = 0x2FE3;
+;
+
+#------------------------------------------------------------
 # ATxmega32A4
 #------------------------------------------------------------
 
@@ -12854,6 +12941,16 @@
 ;
 
 #------------------------------------------------------------
+# ATxmega32A4U
+#------------------------------------------------------------
+
+part parent "x32a4"
+    id		= "x32a4u";
+    desc	= "ATxmega32A4U";
+    usbpid  = 0x2FE4;
+;
+
+#------------------------------------------------------------
 # ATxmega64A4
 #------------------------------------------------------------
 
@@ -12865,6 +12962,16 @@
 ;
 
 #------------------------------------------------------------
+# ATxmega64A4U
+#------------------------------------------------------------
+
+part parent "x64a4"
+    id		= "x64a4u";
+    desc	= "ATxmega64A4U";
+    usbpid  = 0x2FDD;
+;
+
+#------------------------------------------------------------
 # ATxmega128A4
 #------------------------------------------------------------
 
@@ -12876,6 +12983,104 @@
 ;
 
 #------------------------------------------------------------
+# ATxmega128A4U
+#------------------------------------------------------------
+
+part parent "x128a4"
+    id		= "x128a4u";
+    desc	= "ATxmega128A4U";
+    usbpid  = 0x2FDE;
+;
+
+#------------------------------------------------------------
+# ATxmega64B1
+#------------------------------------------------------------
+
+part parent "x64a1"
+    id		= "x64b1";
+    desc	= "ATxmega64B1";
+    signature	= 0x1e 0x96 0x52;
+    usbpid  = 0x2FE1;
+;
+
+#------------------------------------------------------------
+# ATxmega128B1
+#------------------------------------------------------------
+
+part parent "x128a1"
+    id		= "x128b1";
+    desc	= "ATxmega128B1";
+    signature	= 0x1e 0x97 0x4D;
+    usbpid  = 0x2FEA;
+;
+
+#------------------------------------------------------------
+# ATxmega64B3
+#------------------------------------------------------------
+
+part parent "x64a1"
+    id		= "x64b3";
+    desc	= "ATxmega64B3";
+    signature	= 0x1e 0x96 0x51;
+    usbpid  = 0x2FDF;
+;
+
+#------------------------------------------------------------
+# ATxmega128B3
+#------------------------------------------------------------
+
+part parent "x128a1"
+    id		= "x128b3";
+    desc	= "ATxmega128B3";
+    signature	= 0x1e 0x97 0x4B;
+    usbpid  = 0x2FE0;
+;
+
+#------------------------------------------------------------
+# ATxmega64C3
+#------------------------------------------------------------
+
+part parent "x64a1"
+    id		= "x64c3";
+    desc	= "ATxmega64C3";
+    signature	= 0x1e 0x96 0x49;
+    usbpid  = 0x2FD6;
+;
+
+#------------------------------------------------------------
+# ATxmega128C3
+#------------------------------------------------------------
+
+part parent "x128a1"
+    id		= "x128c3";
+    desc	= "ATxmega128C3";
+    signature	= 0x1e 0x97 0x52;
+    usbpid  = 0x2FD7;
+;
+
+#------------------------------------------------------------
+# ATxmega192C3
+#------------------------------------------------------------
+
+part parent "x192a1"
+    id		= "x192c3";
+    desc	= "ATxmega192C3";
+    signature	= 0x1e 0x97 0x51;
+    usbpid  = 0x2FDA;
+;
+
+#------------------------------------------------------------
+# ATxmega256C3
+#------------------------------------------------------------
+
+part parent "x256a1"
+    id		= "x256c3";
+    desc	= "ATxmega256C3";
+    signature	= 0x1e 0x98 0x46;
+    usbpid  = 0x2FDB;
+;
+
+#------------------------------------------------------------
 # ATxmega16D4
 #------------------------------------------------------------
 
Index: avrpart.h
===================================================================
--- avrpart.h	(revision 1118)
+++ avrpart.h	(working copy)
@@ -111,6 +111,7 @@
   unsigned char pagel;              /* for parallel programming */
   unsigned char bs2;                /* for parallel programming */
   unsigned char signature[3];       /* expected value of signature bytes */
+  unsigned short usbpid;            /* USB DFU product ID (0 = none) */
   int           reset_disposition;  /* see RESET_ enums */
   int           retry_pulse;        /* retry program enable by pulsing
                                        this pin (PIN_AVR_*) */
Index: Makefile.am
===================================================================
--- Makefile.am	(revision 1118)
+++ Makefile.am	(working copy)
@@ -109,8 +109,12 @@
 	confwin.h \
 	crc16.c \
 	crc16.h \
+	dfu.c \
+	dfu.h \
 	fileio.c \
 	fileio.h \
+	flip.c \
+	flip.h \
 	freebsd_ppi.h \
 	ft245r.c \
 	ft245r.h \
