Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/prusa3d/PrusaSlicer.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'src/avrdude/usbasp.c')
-rw-r--r--src/avrdude/usbasp.c1221
1 files changed, 1221 insertions, 0 deletions
diff --git a/src/avrdude/usbasp.c b/src/avrdude/usbasp.c
new file mode 100644
index 000000000..e75eed1d7
--- /dev/null
+++ b/src/avrdude/usbasp.c
@@ -0,0 +1,1221 @@
+/*
+ * avrdude - A Downloader/Uploader for AVR device programmers
+ * Copyright (C) 2006 Thomas Fischl
+ * Copyright 2007 Joerg Wunsch <j@uriah.heep.sax.de>
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+
+/* $Id$ */
+
+/*
+ * Interface to the USBasp programmer.
+ *
+ * See http://www.fischl.de/usbasp/
+ */
+#include "ac_cfg.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdint.h>
+#include <errno.h>
+#include <sys/time.h>
+#include <unistd.h>
+
+#include "avrdude.h"
+#include "libavrdude.h"
+
+#include "usbasp.h"
+#include "usbdevs.h"
+
+#if defined(HAVE_LIBUSB) || defined(HAVE_LIBUSB_1_0)
+
+#ifdef HAVE_LIBUSB_1_0
+# define USE_LIBUSB_1_0
+#endif
+
+#if defined(USE_LIBUSB_1_0)
+# if defined(HAVE_LIBUSB_1_0_LIBUSB_H)
+# include <libusb-1.0/libusb.h>
+# else
+# include <libusb.h>
+# endif
+#else
+# if defined(HAVE_USB_H)
+# include <usb.h>
+# elif defined(HAVE_LUSB0_USB_H)
+# include <lusb0_usb.h>
+# else
+# error "libusb needs either <usb.h> or <lusb0_usb.h>"
+# endif
+#endif
+
+#ifdef USE_LIBUSB_1_0
+
+static libusb_context *ctx = NULL;
+
+static int libusb_to_errno(int result)
+{
+ switch (result) {
+ case LIBUSB_SUCCESS:
+ return 0;
+ case LIBUSB_ERROR_IO:
+ return EIO;
+ case LIBUSB_ERROR_INVALID_PARAM:
+ return EINVAL;
+ case LIBUSB_ERROR_ACCESS:
+ return EACCES;
+ case LIBUSB_ERROR_NO_DEVICE:
+ return ENXIO;
+ case LIBUSB_ERROR_NOT_FOUND:
+ return ENOENT;
+ case LIBUSB_ERROR_BUSY:
+ return EBUSY;
+#ifdef ETIMEDOUT
+ case LIBUSB_ERROR_TIMEOUT:
+ return ETIMEDOUT;
+#endif
+#ifdef EOVERFLOW
+ case LIBUSB_ERROR_OVERFLOW:
+ return EOVERFLOW;
+#endif
+ case LIBUSB_ERROR_PIPE:
+ return EPIPE;
+ case LIBUSB_ERROR_INTERRUPTED:
+ return EINTR;
+ case LIBUSB_ERROR_NO_MEM:
+ return ENOMEM;
+ case LIBUSB_ERROR_NOT_SUPPORTED:
+ return ENOSYS;
+ default:
+ return ERANGE;
+ }
+}
+
+#endif
+
+
+/*
+ * Private data for this programmer.
+ */
+struct pdata
+{
+#ifdef USE_LIBUSB_1_0
+ libusb_device_handle *usbhandle;
+#else
+ usb_dev_handle *usbhandle;
+#endif
+ int sckfreq_hz;
+ unsigned int capabilities;
+ int use_tpi;
+};
+
+#define PDATA(pgm) ((struct pdata *)(pgm->cookie))
+#define IMPORT_PDATA(pgm) struct pdata *pdata = PDATA(pgm)
+
+
+
+/* Prototypes */
+// interface - management
+static void usbasp_setup(PROGRAMMER * pgm);
+static void usbasp_teardown(PROGRAMMER * pgm);
+// internal functions
+static int usbasp_transmit(PROGRAMMER * pgm, unsigned char receive,
+ unsigned char functionid, const unsigned char *send,
+ unsigned char *buffer, int buffersize);
+#ifdef USE_LIBUSB_1_0
+static int usbOpenDevice(libusb_device_handle **device, int vendor, char *vendorName, int product, char *productName);
+#else
+static int usbOpenDevice(usb_dev_handle **device, int vendor, char *vendorName, int product, char *productName);
+#endif
+// interface - prog.
+static int usbasp_open(PROGRAMMER * pgm, char * port);
+static void usbasp_close(PROGRAMMER * pgm);
+// dummy functions
+static void usbasp_disable(PROGRAMMER * pgm);
+static void usbasp_enable(PROGRAMMER * pgm);
+static void usbasp_display(PROGRAMMER * pgm, const char * p);
+// universal functions
+static int usbasp_initialize(PROGRAMMER * pgm, AVRPART * p);
+// SPI specific functions
+static int usbasp_spi_cmd(PROGRAMMER * pgm, const unsigned char *cmd, unsigned char *res);
+static int usbasp_spi_program_enable(PROGRAMMER * pgm, AVRPART * p);
+static int usbasp_spi_chip_erase(PROGRAMMER * pgm, AVRPART * p);
+static int usbasp_spi_paged_load(PROGRAMMER * pgm, AVRPART * p, AVRMEM * m,
+ unsigned int page_size,
+ unsigned int addr, unsigned int n_bytes);
+static int usbasp_spi_paged_write(PROGRAMMER * pgm, AVRPART * p, AVRMEM * m,
+ unsigned int page_size,
+ unsigned int addr, unsigned int n_bytes);
+static int usbasp_spi_set_sck_period(PROGRAMMER *pgm, double sckperiod);
+// TPI specific functions
+static void usbasp_tpi_send_byte(PROGRAMMER * pgm, uint8_t b);
+static int usbasp_tpi_cmd(PROGRAMMER * pgm, const unsigned char *cmd, unsigned char *res);
+static int usbasp_tpi_program_enable(PROGRAMMER * pgm, AVRPART * p);
+static int usbasp_tpi_chip_erase(PROGRAMMER * pgm, AVRPART * p);
+static int usbasp_tpi_paged_load(PROGRAMMER * pgm, AVRPART * p, AVRMEM * m,
+ unsigned int page_size,
+ unsigned int addr, unsigned int n_bytes);
+static int usbasp_tpi_paged_write(PROGRAMMER * pgm, AVRPART * p, AVRMEM * m,
+ unsigned int page_size,
+ unsigned int addr, unsigned int n_bytes);
+static int usbasp_tpi_set_sck_period(PROGRAMMER *pgm, double sckperiod);
+static int usbasp_tpi_read_byte(PROGRAMMER * pgm, AVRPART * p, AVRMEM * m, unsigned long addr, unsigned char * value);
+static int usbasp_tpi_write_byte(PROGRAMMER * pgm, AVRPART * p, AVRMEM * m, unsigned long addr, unsigned char data);
+
+
+/* Interface - management */
+static void usbasp_setup(PROGRAMMER * pgm)
+{
+ if ((pgm->cookie = malloc(sizeof(struct pdata))) == 0) {
+ avrdude_message(MSG_INFO, "%s: usbasp_setup(): Out of memory allocating private data\n",
+ progname);
+ exit(1);
+ }
+ memset(pgm->cookie, 0, sizeof(struct pdata));
+}
+
+static void usbasp_teardown(PROGRAMMER * pgm)
+{
+ free(pgm->cookie);
+}
+
+/* Internal functions */
+
+static const char *usbasp_get_funcname(unsigned char functionid)
+{
+ switch (functionid) {
+ case USBASP_FUNC_CONNECT: return "USBASP_FUNC_CONNECT"; break;
+ case USBASP_FUNC_DISCONNECT: return "USBASP_FUNC_DISCONNECT"; break;
+ case USBASP_FUNC_TRANSMIT: return "USBASP_FUNC_TRANSMIT"; break;
+ case USBASP_FUNC_READFLASH: return "USBASP_FUNC_READFLASH"; break;
+ case USBASP_FUNC_ENABLEPROG: return "USBASP_FUNC_ENABLEPROG"; break;
+ case USBASP_FUNC_WRITEFLASH: return "USBASP_FUNC_WRITEFLASH"; break;
+ case USBASP_FUNC_READEEPROM: return "USBASP_FUNC_READEEPROM"; break;
+ case USBASP_FUNC_WRITEEEPROM: return "USBASP_FUNC_WRITEEEPROM"; break;
+ case USBASP_FUNC_SETLONGADDRESS: return "USBASP_FUNC_SETLONGADDRESS"; break;
+ case USBASP_FUNC_SETISPSCK: return "USBASP_FUNC_SETISPSCK"; break;
+ case USBASP_FUNC_TPI_CONNECT: return "USBASP_FUNC_TPI_CONNECT"; break;
+ case USBASP_FUNC_TPI_DISCONNECT: return "USBASP_FUNC_TPI_DISCONNECT"; break;
+ case USBASP_FUNC_TPI_RAWREAD: return "USBASP_FUNC_TPI_RAWREAD"; break;
+ case USBASP_FUNC_TPI_RAWWRITE: return "USBASP_FUNC_TPI_RAWWRITE"; break;
+ case USBASP_FUNC_TPI_READBLOCK: return "USBASP_FUNC_TPI_READBLOCK"; break;
+ case USBASP_FUNC_TPI_WRITEBLOCK: return "USBASP_FUNC_TPI_WRITEBLOCK"; break;
+ case USBASP_FUNC_GETCAPABILITIES: return "USBASP_FUNC_GETCAPABILITIES"; break;
+ default: return "Unknown USBASP function"; break;
+ }
+}
+
+/*
+ * wrapper for usb_control_msg call
+ */
+static int usbasp_transmit(PROGRAMMER * pgm,
+ unsigned char receive, unsigned char functionid,
+ const unsigned char *send,
+ unsigned char *buffer, int buffersize)
+{
+ int nbytes;
+
+ if (verbose > 3) {
+ avrdude_message(MSG_TRACE, "%s: usbasp_transmit(\"%s\", 0x%02x, 0x%02x, 0x%02x, 0x%02x)\n",
+ progname,
+ usbasp_get_funcname(functionid), send[0], send[1], send[2], send[3]);
+ if (!receive && buffersize > 0) {
+ int i;
+ avrdude_message(MSG_TRACE, "%s => ", progbuf);
+ for (i = 0; i < buffersize; i++)
+ avrdude_message(MSG_TRACE, "[%02x] ", buffer[i]);
+ avrdude_message(MSG_TRACE, "\n");
+ }
+ }
+
+#ifdef USE_LIBUSB_1_0
+ nbytes = libusb_control_transfer(PDATA(pgm)->usbhandle,
+ (LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE | (receive << 7)) & 0xff,
+ functionid & 0xff,
+ ((send[1] << 8) | send[0]) & 0xffff,
+ ((send[3] << 8) | send[2]) & 0xffff,
+ buffer,
+ buffersize & 0xffff,
+ 5000);
+ if(nbytes < 0){
+ avrdude_message(MSG_INFO, "%s: error: usbasp_transmit: %s\n", progname, strerror(libusb_to_errno(nbytes)));
+ return -1;
+ }
+#else
+ nbytes = usb_control_msg(PDATA(pgm)->usbhandle,
+ USB_TYPE_VENDOR | USB_RECIP_DEVICE | (receive << 7),
+ functionid,
+ (send[1] << 8) | send[0],
+ (send[3] << 8) | send[2],
+ (char *)buffer, buffersize,
+ 5000);
+ if(nbytes < 0){
+ avrdude_message(MSG_INFO, "%s: error: usbasp_transmit: %s\n", progname, usb_strerror());
+ return -1;
+ }
+#endif
+
+ if (verbose > 3 && receive && nbytes > 0) {
+ int i;
+ avrdude_message(MSG_TRACE, "%s<= ", progbuf);
+ for (i = 0; i < nbytes; i++)
+ avrdude_message(MSG_TRACE, "[%02x] ", buffer[i]);
+ avrdude_message(MSG_TRACE, "\n");
+ }
+
+ return nbytes;
+}
+
+
+/*
+ * Try to open USB device with given VID, PID, vendor and product name
+ * Parts of this function were taken from an example code by OBJECTIVE
+ * DEVELOPMENT Software GmbH (www.obdev.at) to meet conditions for
+ * shared VID/PID
+ */
+#ifdef USE_LIBUSB_1_0
+static int usbOpenDevice(libusb_device_handle **device, int vendor,
+ char *vendorName, int product, char *productName)
+{
+ libusb_device_handle *handle = NULL;
+ int errorCode = USB_ERROR_NOTFOUND;
+ static int didUsbInit = 0;
+ int j;
+ int r;
+
+ if(!didUsbInit){
+ didUsbInit = 1;
+ libusb_init(&ctx);
+ }
+
+ libusb_device **dev_list;
+ int dev_list_len = libusb_get_device_list(ctx, &dev_list);
+
+ for (j=0; j<dev_list_len; ++j) {
+ libusb_device *dev = dev_list[j];
+ struct libusb_device_descriptor descriptor;
+ libusb_get_device_descriptor(dev, &descriptor);
+ if (descriptor.idVendor == vendor && descriptor.idProduct == product) {
+ char string[256];
+ /* we need to open the device in order to query strings */
+ r = libusb_open(dev, &handle);
+ if (!handle) {
+ errorCode = USB_ERROR_ACCESS;
+ avrdude_message(MSG_INFO, "%s: Warning: cannot open USB device: %s\n",
+ progname, strerror(libusb_to_errno(r)));
+ continue;
+ }
+ errorCode = 0;
+ /* now check whether the names match: */
+ /* if vendorName not given ignore it (any vendor matches) */
+ r = libusb_get_string_descriptor_ascii(handle, descriptor.iManufacturer & 0xff, (unsigned char*)string, sizeof(string));
+ if (r < 0) {
+ if ((vendorName != NULL) && (vendorName[0] != 0)) {
+ errorCode = USB_ERROR_IO;
+ avrdude_message(MSG_INFO, "%s: Warning: cannot query manufacturer for device: %s\n",
+ progname, strerror(libusb_to_errno(r)));
+ }
+ } else {
+ avrdude_message(MSG_NOTICE2, "%s: seen device from vendor ->%s<-\n",
+ progname, string);
+ if ((vendorName != NULL) && (vendorName[0] != 0) && (strcmp(string, vendorName) != 0))
+ errorCode = USB_ERROR_NOTFOUND;
+ }
+ /* if productName not given ignore it (any product matches) */
+ r = libusb_get_string_descriptor_ascii(handle, descriptor.iProduct & 0xff, (unsigned char*)string, sizeof(string));
+ if (r < 0) {
+ if ((productName != NULL) && (productName[0] != 0)) {
+ errorCode = USB_ERROR_IO;
+ avrdude_message(MSG_INFO, "%s: Warning: cannot query product for device: %s\n",
+ progname, strerror(libusb_to_errno(r)));
+ }
+ } else {
+ avrdude_message(MSG_NOTICE2, "%s: seen product ->%s<-\n",
+ progname, string);
+ if((productName != NULL) && (productName[0] != 0) && (strcmp(string, productName) != 0))
+ errorCode = USB_ERROR_NOTFOUND;
+ }
+ if (errorCode == 0)
+ break;
+ libusb_close(handle);
+ handle = NULL;
+ }
+ }
+ libusb_free_device_list(dev_list,1);
+ if (handle != NULL){
+ errorCode = 0;
+ *device = handle;
+ }
+ return errorCode;
+}
+#else
+static int usbOpenDevice(usb_dev_handle **device, int vendor,
+ char *vendorName, int product, char *productName)
+{
+struct usb_bus *bus;
+struct usb_device *dev;
+usb_dev_handle *handle = NULL;
+int errorCode = USB_ERROR_NOTFOUND;
+static int didUsbInit = 0;
+
+ if(!didUsbInit){
+ didUsbInit = 1;
+ usb_init();
+ }
+ usb_find_busses();
+ usb_find_devices();
+ for(bus=usb_get_busses(); bus; bus=bus->next){
+ for(dev=bus->devices; dev; dev=dev->next){
+ if(dev->descriptor.idVendor == vendor &&
+ dev->descriptor.idProduct == product){
+ char string[256];
+ int len;
+ /* we need to open the device in order to query strings */
+ handle = usb_open(dev);
+ if(!handle){
+ errorCode = USB_ERROR_ACCESS;
+ avrdude_message(MSG_INFO, "%s: Warning: cannot open USB device: %s\n",
+ progname, usb_strerror());
+ continue;
+ }
+ errorCode = 0;
+ /* now check whether the names match: */
+ /* if vendorName not given ignore it (any vendor matches) */
+ len = usb_get_string_simple(handle, dev->descriptor.iManufacturer,
+ string, sizeof(string));
+ if(len < 0){
+ if ((vendorName != NULL) && (vendorName[0] != 0)) {
+ errorCode = USB_ERROR_IO;
+ avrdude_message(MSG_INFO, "%s: Warning: cannot query manufacturer for device: %s\n",
+ progname, usb_strerror());
+ }
+ } else {
+ avrdude_message(MSG_NOTICE2, "%s: seen device from vendor ->%s<-\n",
+ progname, string);
+ if((vendorName != NULL) && (vendorName[0] != 0) && (strcmp(string, vendorName) != 0))
+ errorCode = USB_ERROR_NOTFOUND;
+ }
+ /* if productName not given ignore it (any product matches) */
+ len = usb_get_string_simple(handle, dev->descriptor.iProduct,
+ string, sizeof(string));
+ if(len < 0){
+ if ((productName != NULL) && (productName[0] != 0)) {
+ errorCode = USB_ERROR_IO;
+ avrdude_message(MSG_INFO, "%s: Warning: cannot query product for device: %s\n",
+ progname, usb_strerror());
+ }
+ } else {
+ avrdude_message(MSG_NOTICE2, "%s: seen product ->%s<-\n",
+ progname, string);
+ if((productName != NULL) && (productName[0] != 0) && (strcmp(string, productName) != 0))
+ errorCode = USB_ERROR_NOTFOUND;
+ }
+ if (errorCode == 0)
+ break;
+ usb_close(handle);
+ handle = NULL;
+ }
+ }
+ if(handle)
+ break;
+ }
+ if(handle != NULL){
+ errorCode = 0;
+ *device = handle;
+ }
+ return errorCode;
+}
+#endif
+
+
+/* Interface - prog. */
+static int usbasp_open(PROGRAMMER * pgm, char * port)
+{
+ avrdude_message(MSG_DEBUG, "%s: usbasp_open(\"%s\")\n",
+ progname, port);
+
+ /* usb_init will be done in usbOpenDevice */
+ LNODEID usbpid = lfirst(pgm->usbpid);
+ int pid, vid;
+ if (usbpid) {
+ pid = *(int *)(ldata(usbpid));
+ if (lnext(usbpid))
+ avrdude_message(MSG_INFO, "%s: Warning: using PID 0x%04x, ignoring remaining PIDs in list\n",
+ progname, pid);
+ } else {
+ pid = USBASP_SHARED_PID;
+ }
+ vid = pgm->usbvid? pgm->usbvid: USBASP_SHARED_VID;
+ if (usbOpenDevice(&PDATA(pgm)->usbhandle, vid, pgm->usbvendor, pid, pgm->usbproduct) != 0) {
+ /* try alternatives */
+ if(strcasecmp(ldata(lfirst(pgm->id)), "usbasp") == 0) {
+ /* for id usbasp autodetect some variants */
+ if(strcasecmp(port, "nibobee") == 0) {
+ avrdude_message(MSG_INFO, "%s: warning: Using \"-C usbasp -P nibobee\" is deprecated,"
+ "use \"-C nibobee\" instead.\n",
+ progname);
+ if (usbOpenDevice(&PDATA(pgm)->usbhandle, USBASP_NIBOBEE_VID, "www.nicai-systems.com",
+ USBASP_NIBOBEE_PID, "NIBObee") != 0) {
+ avrdude_message(MSG_INFO, "%s: error: could not find USB device "
+ "\"NIBObee\" with vid=0x%x pid=0x%x\n",
+ progname, USBASP_NIBOBEE_VID, USBASP_NIBOBEE_PID);
+ return -1;
+ }
+ return 0;
+ }
+ /* check if device with old VID/PID is available */
+ if (usbOpenDevice(&PDATA(pgm)->usbhandle, USBASP_OLD_VID, "www.fischl.de",
+ USBASP_OLD_PID, "USBasp") == 0) {
+ /* found USBasp with old IDs */
+ avrdude_message(MSG_INFO, "%s: Warning: Found USB device \"USBasp\" with "
+ "old VID/PID! Please update firmware of USBasp!\n",
+ progname);
+ return 0;
+ }
+ /* original USBasp is specified in config file, so no need to check it again here */
+ /* no alternative found => fall through to generic error message */
+ }
+
+ avrdude_message(MSG_INFO, "%s: error: could not find USB device with vid=0x%x pid=0x%x",
+ progname, vid, pid);
+ if (pgm->usbvendor[0] != 0) {
+ avrdude_message(MSG_INFO, " vendor='%s'", pgm->usbvendor);
+ }
+ if (pgm->usbproduct[0] != 0) {
+ avrdude_message(MSG_INFO, " product='%s'", pgm->usbproduct);
+ }
+ avrdude_message(MSG_INFO, "\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+static void usbasp_close(PROGRAMMER * pgm)
+{
+ avrdude_message(MSG_DEBUG, "%s: usbasp_close()\n", progname);
+
+ if (PDATA(pgm)->usbhandle!=NULL) {
+ unsigned char temp[4];
+ memset(temp, 0, sizeof(temp));
+
+ if (PDATA(pgm)->use_tpi) {
+ usbasp_transmit(pgm, 1, USBASP_FUNC_TPI_DISCONNECT, temp, temp, sizeof(temp));
+ } else {
+ usbasp_transmit(pgm, 1, USBASP_FUNC_DISCONNECT, temp, temp, sizeof(temp));
+ }
+
+#ifdef USE_LIBUSB_1_0
+ libusb_close(PDATA(pgm)->usbhandle);
+#else
+ usb_close(PDATA(pgm)->usbhandle);
+#endif
+ }
+#ifdef USE_LIBUSB_1_0
+ libusb_exit(ctx);
+#else
+ /* nothing for usb 0.1 ? */
+#endif
+}
+
+
+/* Dummy functions */
+static void usbasp_disable(PROGRAMMER * pgm)
+{
+ /* Do nothing. */
+
+ return;
+}
+
+static void usbasp_enable(PROGRAMMER * pgm)
+{
+ /* Do nothing. */
+
+ return;
+}
+
+static void usbasp_display(PROGRAMMER * pgm, const char * p)
+{
+ return;
+}
+
+
+/* Universal functions: for both SPI and TPI */
+static int usbasp_initialize(PROGRAMMER * pgm, AVRPART * p)
+{
+ unsigned char temp[4];
+ unsigned char res[4];
+ IMPORT_PDATA(pgm);
+
+ avrdude_message(MSG_DEBUG, "%s: usbasp_initialize()\n", progname);
+
+ /* get capabilities */
+ memset(temp, 0, sizeof(temp));
+ if(usbasp_transmit(pgm, 1, USBASP_FUNC_GETCAPABILITIES, temp, res, sizeof(res)) == 4)
+ pdata->capabilities = res[0] | ((unsigned int)res[1] << 8) | ((unsigned int)res[2] << 16) | ((unsigned int)res[3] << 24);
+ else
+ pdata->capabilities = 0;
+
+ pdata->use_tpi = ((pdata->capabilities & USBASP_CAP_TPI) != 0 && (p->flags & AVRPART_HAS_TPI) != 0) ? 1 : 0;
+
+ if(pdata->use_tpi)
+ {
+ /* calc tpiclk delay */
+ int dly = 1500000.0 * pgm->bitclock;
+ if(dly < 1)
+ dly = 1;
+ else if(dly > 2047)
+ dly = 2047;
+ temp[0] = dly;
+ temp[1] = dly >> 8;
+
+ /* connect */
+ usbasp_transmit(pgm, 1, USBASP_FUNC_TPI_CONNECT, temp, res, sizeof(res));
+
+ /* change interface */
+ pgm->program_enable = usbasp_tpi_program_enable;
+ pgm->chip_erase = usbasp_tpi_chip_erase;
+ pgm->cmd = usbasp_tpi_cmd;
+ pgm->read_byte = usbasp_tpi_read_byte;
+ pgm->write_byte = usbasp_tpi_write_byte;
+ pgm->paged_write = usbasp_tpi_paged_write;
+ pgm->paged_load = usbasp_tpi_paged_load;
+ pgm->set_sck_period = usbasp_tpi_set_sck_period;
+ }
+ else
+ {
+ /* set sck period */
+ pgm->set_sck_period(pgm, pgm->bitclock);
+
+ /* connect to target device */
+ usbasp_transmit(pgm, 1, USBASP_FUNC_CONNECT, temp, res, sizeof(res));
+
+ /* change interface */
+ pgm->program_enable = usbasp_spi_program_enable;
+ pgm->chip_erase = usbasp_spi_chip_erase;
+ pgm->cmd = usbasp_spi_cmd;
+ pgm->read_byte = avr_read_byte_default;
+ pgm->write_byte = avr_write_byte_default;
+ pgm->paged_write = usbasp_spi_paged_write;
+ pgm->paged_load = usbasp_spi_paged_load;
+ pgm->set_sck_period = usbasp_spi_set_sck_period;
+ }
+
+ /* wait, so device is ready to receive commands */
+ usleep(100000);
+
+ return pgm->program_enable(pgm, p);
+}
+
+/* SPI specific functions */
+static int usbasp_spi_cmd(PROGRAMMER * pgm, const unsigned char *cmd,
+ unsigned char *res)
+{
+ avrdude_message(MSG_DEBUG, "%s: usbasp_spi_cmd(0x%02x, 0x%02x, 0x%02x, 0x%02x)%s",
+ progname, cmd[0], cmd[1], cmd[2], cmd[3],
+ verbose > 3? "...\n": "");
+
+ int nbytes =
+ usbasp_transmit(pgm, 1, USBASP_FUNC_TRANSMIT, cmd, res, 4);
+
+ if(nbytes != 4){
+ if (verbose == 3)
+ putc('\n', stderr);
+
+ avrdude_message(MSG_INFO, "%s: error: wrong responds size\n",
+ progname);
+ return -1;
+ }
+ avrdude_message(MSG_TRACE, "%s: usbasp_spi_cmd()", progname);
+ avrdude_message(MSG_DEBUG, " => 0x%02x, 0x%02x, 0x%02x, 0x%02x\n",
+ res[0], res[1], res[2], res[3]);
+
+ return 0;
+}
+
+static int usbasp_spi_program_enable(PROGRAMMER * pgm, AVRPART * p)
+{
+ unsigned char res[4];
+ unsigned char cmd[4];
+ memset(cmd, 0, sizeof(cmd));
+ memset(res, 0, sizeof(res));
+
+ cmd[0] = 0;
+
+ avrdude_message(MSG_DEBUG, "%s: usbasp_program_enable()\n",
+ progname);
+
+ int nbytes =
+ usbasp_transmit(pgm, 1, USBASP_FUNC_ENABLEPROG, cmd, res, sizeof(res));
+
+ if ((nbytes != 1) | (res[0] != 0)) {
+ avrdude_message(MSG_INFO, "%s: error: program enable: target doesn't answer. %x \n",
+ progname, res[0]);
+ return -1;
+ }
+
+ return 0;
+}
+
+static int usbasp_spi_chip_erase(PROGRAMMER * pgm, AVRPART * p)
+{
+ unsigned char cmd[4];
+ unsigned char res[4];
+
+ avrdude_message(MSG_DEBUG, "%s: usbasp_chip_erase()\n",
+ progname);
+
+ if (p->op[AVR_OP_CHIP_ERASE] == NULL) {
+ avrdude_message(MSG_INFO, "chip erase instruction not defined for part \"%s\"\n",
+ p->desc);
+ return -1;
+ }
+
+ memset(cmd, 0, sizeof(cmd));
+
+ avr_set_bits(p->op[AVR_OP_CHIP_ERASE], cmd);
+ pgm->cmd(pgm, cmd, res);
+ usleep(p->chip_erase_delay);
+ pgm->initialize(pgm, p);
+
+ return 0;
+}
+
+static int usbasp_spi_paged_load(PROGRAMMER * pgm, AVRPART * p, AVRMEM * m,
+ unsigned int page_size,
+ unsigned int address, unsigned int n_bytes)
+{
+ int n;
+ unsigned char cmd[4];
+ int wbytes = n_bytes;
+ int blocksize;
+ unsigned char *buffer = m->buf + address;
+ int function;
+
+ avrdude_message(MSG_DEBUG, "%s: usbasp_program_paged_load(\"%s\", 0x%x, %d)\n",
+ progname, m->desc, address, n_bytes);
+
+ if (strcmp(m->desc, "flash") == 0) {
+ function = USBASP_FUNC_READFLASH;
+ } else if (strcmp(m->desc, "eeprom") == 0) {
+ function = USBASP_FUNC_READEEPROM;
+ } else {
+ return -2;
+ }
+
+ /* set blocksize depending on sck frequency */
+ if ((PDATA(pgm)->sckfreq_hz > 0) && (PDATA(pgm)->sckfreq_hz < 10000)) {
+ blocksize = USBASP_READBLOCKSIZE / 10;
+ } else {
+ blocksize = USBASP_READBLOCKSIZE;
+ }
+
+ while (wbytes) {
+ if (wbytes <= blocksize) {
+ blocksize = wbytes;
+ }
+ wbytes -= blocksize;
+
+ /* set address (new mode) - if firmware on usbasp support newmode, then they use address from this command */
+ unsigned char temp[4];
+ memset(temp, 0, sizeof(temp));
+ cmd[0] = address & 0xFF;
+ cmd[1] = address >> 8;
+ cmd[2] = address >> 16;
+ cmd[3] = address >> 24;
+ usbasp_transmit(pgm, 1, USBASP_FUNC_SETLONGADDRESS, cmd, temp, sizeof(temp));
+
+ /* send command with address (compatibility mode) - if firmware on
+ usbasp doesn't support newmode, then they use address from this */
+ cmd[0] = address & 0xFF;
+ cmd[1] = address >> 8;
+ // for compatibility - previous version of usbasp.c doesn't initialize this fields (firmware ignore it)
+ cmd[2] = 0;
+ cmd[3] = 0;
+
+ n = usbasp_transmit(pgm, 1, function, cmd, buffer, blocksize);
+
+ if (n != blocksize) {
+ avrdude_message(MSG_INFO, "%s: error: wrong reading bytes %x\n",
+ progname, n);
+ return -3;
+ }
+
+ buffer += blocksize;
+ address += blocksize;
+ }
+
+ return n_bytes;
+}
+
+static int usbasp_spi_paged_write(PROGRAMMER * pgm, AVRPART * p, AVRMEM * m,
+ unsigned int page_size,
+ unsigned int address, unsigned int n_bytes)
+{
+ int n;
+ unsigned char cmd[4];
+ int wbytes = n_bytes;
+ int blocksize;
+ unsigned char *buffer = m->buf + address;
+ unsigned char blockflags = USBASP_BLOCKFLAG_FIRST;
+ int function;
+
+ avrdude_message(MSG_DEBUG, "%s: usbasp_program_paged_write(\"%s\", 0x%x, %d)\n",
+ progname, m->desc, address, n_bytes);
+
+ if (strcmp(m->desc, "flash") == 0) {
+ function = USBASP_FUNC_WRITEFLASH;
+ } else if (strcmp(m->desc, "eeprom") == 0) {
+ function = USBASP_FUNC_WRITEEEPROM;
+ } else {
+ return -2;
+ }
+
+ /* set blocksize depending on sck frequency */
+ if ((PDATA(pgm)->sckfreq_hz > 0) && (PDATA(pgm)->sckfreq_hz < 10000)) {
+ blocksize = USBASP_WRITEBLOCKSIZE / 10;
+ } else {
+ blocksize = USBASP_WRITEBLOCKSIZE;
+ }
+
+ while (wbytes) {
+
+ if (wbytes <= blocksize) {
+ blocksize = wbytes;
+ }
+ wbytes -= blocksize;
+
+
+ /* set address (new mode) - if firmware on usbasp support newmode, then
+ they use address from this command */
+ unsigned char temp[4];
+ memset(temp, 0, sizeof(temp));
+ cmd[0] = address & 0xFF;
+ cmd[1] = address >> 8;
+ cmd[2] = address >> 16;
+ cmd[3] = address >> 24;
+ usbasp_transmit(pgm, 1, USBASP_FUNC_SETLONGADDRESS, cmd, temp, sizeof(temp));
+
+ /* normal command - firmware what support newmode - use address from previous command,
+ firmware what doesn't support newmode - ignore previous command and use address from this command */
+
+ cmd[0] = address & 0xFF;
+ cmd[1] = address >> 8;
+ cmd[2] = page_size & 0xFF;
+ cmd[3] = (blockflags & 0x0F) + ((page_size & 0xF00) >> 4); //TP: Mega128 fix
+ blockflags = 0;
+
+ n = usbasp_transmit(pgm, 0, function, cmd, buffer, blocksize);
+
+ if (n != blocksize) {
+ avrdude_message(MSG_INFO, "%s: error: wrong count at writing %x\n",
+ progname, n);
+ return -3;
+ }
+
+
+ buffer += blocksize;
+ address += blocksize;
+ }
+
+ return n_bytes;
+}
+
+/* The list of SCK frequencies in Hz supported by USBasp */
+static struct sckoptions_t usbaspSCKoptions[] = {
+ { USBASP_ISP_SCK_1500, 1500000 },
+ { USBASP_ISP_SCK_750, 750000 },
+ { USBASP_ISP_SCK_375, 375000 },
+ { USBASP_ISP_SCK_187_5, 187500 },
+ { USBASP_ISP_SCK_93_75, 93750 },
+ { USBASP_ISP_SCK_32, 32000 },
+ { USBASP_ISP_SCK_16, 16000 },
+ { USBASP_ISP_SCK_8, 8000 },
+ { USBASP_ISP_SCK_4, 4000 },
+ { USBASP_ISP_SCK_2, 2000 },
+ { USBASP_ISP_SCK_1, 1000 },
+ { USBASP_ISP_SCK_0_5, 500 }
+};
+
+/*
+ * Set sck period (in seconds)
+ * Find next possible sck period and write it to the programmer.
+ */
+static int usbasp_spi_set_sck_period(PROGRAMMER *pgm, double sckperiod)
+{
+ char clockoption = USBASP_ISP_SCK_AUTO;
+ unsigned char res[4];
+ unsigned char cmd[4];
+
+ avrdude_message(MSG_DEBUG, "%s: usbasp_spi_set_sck_period(%g)\n",
+ progname, sckperiod);
+
+ memset(cmd, 0, sizeof(cmd));
+ memset(res, 0, sizeof(res));
+
+ /* reset global sck frequency to auto */
+ PDATA(pgm)->sckfreq_hz = 0;
+
+ if (sckperiod == 0) {
+ /* auto sck set */
+
+ avrdude_message(MSG_NOTICE, "%s: auto set sck period (because given equals null)\n", progname);
+
+ } else {
+
+ int sckfreq = 1 / sckperiod; /* sck in Hz */
+ int usefreq = 0;
+
+ avrdude_message(MSG_NOTICE2, "%s: try to set SCK period to %g s (= %i Hz)\n", progname, sckperiod, sckfreq);
+
+ if (sckfreq >= usbaspSCKoptions[0].frequency) {
+ clockoption = usbaspSCKoptions[0].id;
+ usefreq = usbaspSCKoptions[0].frequency;
+ } else {
+
+ /* find clock option next to given clock */
+ int i;
+ for (i = 0; i < sizeof(usbaspSCKoptions) / sizeof(usbaspSCKoptions[0]); i++) {
+ if (sckfreq >= usbaspSCKoptions[i].frequency - 1) { /* subtract 1 to compensate round errors */
+ clockoption = usbaspSCKoptions[i].id;
+ usefreq = usbaspSCKoptions[i].frequency;
+ break;
+ }
+ }
+ }
+
+ /* save used sck frequency */
+ PDATA(pgm)->sckfreq_hz = usefreq;
+
+ avrdude_message(MSG_INFO, "%s: set SCK frequency to %i Hz\n", progname, usefreq);
+ }
+
+ cmd[0] = clockoption;
+
+ int nbytes =
+ usbasp_transmit(pgm, 1, USBASP_FUNC_SETISPSCK, cmd, res, sizeof(res));
+
+ if ((nbytes != 1) | (res[0] != 0)) {
+ avrdude_message(MSG_INFO, "%s: warning: cannot set sck period. please check for usbasp firmware update.\n",
+ progname);
+ return -1;
+ }
+
+ return 0;
+}
+
+/* TPI specific functions */
+static void usbasp_tpi_send_byte(PROGRAMMER * pgm, uint8_t b)
+{
+ unsigned char temp[4];
+ memset(temp, 0, sizeof(temp));
+
+ temp[0] = b;
+
+ usbasp_transmit(pgm, 1, USBASP_FUNC_TPI_RAWWRITE, temp, temp, sizeof(temp));
+}
+
+
+static int usbasp_tpi_recv_byte(PROGRAMMER * pgm)
+{
+ unsigned char temp[4];
+ memset(temp, 0, sizeof(temp));
+
+ if(usbasp_transmit(pgm, 1, USBASP_FUNC_TPI_RAWREAD, temp, temp, sizeof(temp)) != 1)
+ {
+ avrdude_message(MSG_INFO, "%s: error: wrong responds size\n", progname);
+ return -1;
+ }
+
+ return temp[0];
+}
+
+
+static int usbasp_tpi_nvm_waitbusy(PROGRAMMER * pgm)
+{
+ int retry;
+
+ avrdude_message(MSG_DEBUG, "%s: usbasp_tpi_nvm_waitbusy() ...", progname);
+
+ for(retry=50; retry>0; retry--)
+ {
+ usbasp_tpi_send_byte(pgm, TPI_OP_SIN(NVMCSR));
+ if(usbasp_tpi_recv_byte(pgm) & NVMCSR_BSY)
+ continue;
+
+ avrdude_message(MSG_DEBUG, " ready\n");
+
+ return 0;
+ }
+
+ avrdude_message(MSG_DEBUG, " failure\n");
+
+ return -1;
+}
+
+static int usbasp_tpi_cmd(PROGRAMMER * pgm, const unsigned char *cmd, unsigned char *res)
+{
+ avrdude_message(MSG_INFO, "%s: error: spi_cmd used in TPI mode: not allowed\n", progname);
+ return -1;
+}
+
+static int usbasp_tpi_program_enable(PROGRAMMER * pgm, AVRPART * p)
+{
+ int retry;
+
+ avrdude_message(MSG_DEBUG, "%s: usbasp_tpi_program_enable()\n", progname);
+
+ /* change guard time */
+ usbasp_tpi_send_byte(pgm, TPI_OP_SSTCS(TPIPCR));
+ usbasp_tpi_send_byte(pgm, TPIPCR_GT_2b);
+
+ /* send SKEY */
+ usbasp_tpi_send_byte(pgm, 0xE0);
+ usbasp_tpi_send_byte(pgm, 0xFF);
+ usbasp_tpi_send_byte(pgm, 0x88);
+ usbasp_tpi_send_byte(pgm, 0xD8);
+ usbasp_tpi_send_byte(pgm, 0xCD);
+ usbasp_tpi_send_byte(pgm, 0x45);
+ usbasp_tpi_send_byte(pgm, 0xAB);
+ usbasp_tpi_send_byte(pgm, 0x89);
+ usbasp_tpi_send_byte(pgm, 0x12);
+
+ /* check if device is ready */
+ for(retry=0; retry<10; retry++)
+ {
+ usbasp_tpi_send_byte(pgm, TPI_OP_SLDCS(TPIIR));
+ if(usbasp_tpi_recv_byte(pgm) != 0x80)
+ continue;
+ usbasp_tpi_send_byte(pgm, TPI_OP_SLDCS(TPISR));
+ if((usbasp_tpi_recv_byte(pgm) & TPISR_NVMEN) == 0)
+ continue;
+ break;
+ }
+ if(retry >= 10)
+ {
+ avrdude_message(MSG_INFO, "%s: error: program enable: target doesn't answer.\n", progname);
+ return -1;
+ }
+
+ return 0;
+}
+
+static int usbasp_tpi_chip_erase(PROGRAMMER * pgm, AVRPART * p)
+{
+ avrdude_message(MSG_DEBUG, "%s: usbasp_tpi_chip_erase()\n", progname);
+
+ /* Set PR to flash */
+ usbasp_tpi_send_byte(pgm, TPI_OP_SSTPR(0));
+ usbasp_tpi_send_byte(pgm, 0x01);
+ usbasp_tpi_send_byte(pgm, TPI_OP_SSTPR(1));
+ usbasp_tpi_send_byte(pgm, 0x40);
+ /* select ERASE */
+ usbasp_tpi_send_byte(pgm, TPI_OP_SOUT(NVMCMD));
+ usbasp_tpi_send_byte(pgm, NVMCMD_CHIP_ERASE);
+ /* dummy write */
+ usbasp_tpi_send_byte(pgm, TPI_OP_SST_INC);
+ usbasp_tpi_send_byte(pgm, 0x00);
+ usbasp_tpi_nvm_waitbusy(pgm);
+
+ usleep(p->chip_erase_delay);
+ pgm->initialize(pgm, p);
+
+ return 0;
+}
+
+static int usbasp_tpi_paged_load(PROGRAMMER * pgm, AVRPART * p, AVRMEM * m,
+ unsigned int page_size,
+ unsigned int addr, unsigned int n_bytes)
+{
+ unsigned char cmd[4];
+ unsigned char* dptr;
+ int readed, clen, n;
+ uint16_t pr;
+
+
+ avrdude_message(MSG_DEBUG, "%s: usbasp_tpi_paged_load(\"%s\", 0x%0x, %d)\n",
+ progname, m->desc, addr, n_bytes);
+
+ dptr = addr + m->buf;
+ pr = addr + m->offset;
+ readed = 0;
+
+ while(readed < n_bytes)
+ {
+ clen = n_bytes - readed;
+ if(clen > 32)
+ clen = 32;
+
+ /* prepare READBLOCK cmd */
+ cmd[0] = pr & 0xFF;
+ cmd[1] = pr >> 8;
+ cmd[2] = 0;
+ cmd[3] = 0;
+ n = usbasp_transmit(pgm, 1, USBASP_FUNC_TPI_READBLOCK, cmd, dptr, clen);
+ if(n != clen)
+ {
+ avrdude_message(MSG_INFO, "%s: error: wrong reading bytes %x\n", progname, n);
+ return -3;
+ }
+
+ readed += clen;
+ pr += clen;
+ dptr += clen;
+ }
+
+ return n_bytes;
+}
+
+static int usbasp_tpi_paged_write(PROGRAMMER * pgm, AVRPART * p, AVRMEM * m,
+ unsigned int page_size,
+ unsigned int addr, unsigned int n_bytes)
+{
+ unsigned char cmd[4];
+ unsigned char* sptr;
+ int writed, clen, n;
+ uint16_t pr;
+
+
+ avrdude_message(MSG_DEBUG, "%s: usbasp_tpi_paged_write(\"%s\", 0x%0x, %d)\n",
+ progname, m->desc, addr, n_bytes);
+
+ sptr = addr + m->buf;
+ pr = addr + m->offset;
+ writed = 0;
+
+ /* Set PR to flash */
+ usbasp_tpi_send_byte(pgm, TPI_OP_SSTPR(0));
+ usbasp_tpi_send_byte(pgm, (pr & 0xFF) | 1 );
+ usbasp_tpi_send_byte(pgm, TPI_OP_SSTPR(1));
+ usbasp_tpi_send_byte(pgm, (pr >> 8) );
+
+ while(writed < n_bytes)
+ {
+ clen = n_bytes - writed;
+ if(clen > 32)
+ clen = 32;
+
+ /* prepare WRITEBLOCK cmd */
+ cmd[0] = pr & 0xFF;
+ cmd[1] = pr >> 8;
+ cmd[2] = 0;
+ cmd[3] = 0;
+ n = usbasp_transmit(pgm, 0, USBASP_FUNC_TPI_WRITEBLOCK, cmd, sptr, clen);
+ if(n != clen)
+ {
+ avrdude_message(MSG_INFO, "%s: error: wrong count at writing %x\n", progname, n);
+ return -3;
+ }
+
+ writed += clen;
+ pr += clen;
+ sptr += clen;
+ }
+
+ return n_bytes;
+}
+
+static int usbasp_tpi_set_sck_period(PROGRAMMER *pgm, double sckperiod)
+{
+ return 0;
+}
+static int usbasp_tpi_read_byte(PROGRAMMER * pgm, AVRPART * p, AVRMEM * m, unsigned long addr, unsigned char * value)
+{
+ unsigned char cmd[4];
+ int n;
+ uint16_t pr;
+
+
+ avrdude_message(MSG_DEBUG, "%s: usbasp_tpi_read_byte(\"%s\", 0x%0lx)\n",
+ progname, m->desc, addr);
+
+ pr = m->offset + addr;
+
+ /* READBLOCK */
+ cmd[0] = pr & 0xFF;
+ cmd[1] = pr >> 8;
+ cmd[2] = 0;
+ cmd[3] = 0;
+ n = usbasp_transmit(pgm, 1, USBASP_FUNC_TPI_READBLOCK, cmd, value, 1);
+ if(n != 1)
+ {
+ avrdude_message(MSG_INFO, "%s: error: wrong reading bytes %x\n", progname, n);
+ return -3;
+ }
+ return 0;
+}
+
+static int usbasp_tpi_write_byte(PROGRAMMER * pgm, AVRPART * p, AVRMEM * m, unsigned long addr, unsigned char data)
+{
+ avrdude_message(MSG_INFO, "%s: error: usbasp_write_byte in TPI mode: all writes have to be done at page level\n", progname);
+ return -1;
+}
+
+
+void usbasp_initpgm(PROGRAMMER * pgm)
+{
+ strcpy(pgm->type, "usbasp");
+
+ /*
+ * mandatory functions
+ */
+
+ pgm->initialize = usbasp_initialize;
+ pgm->display = usbasp_display;
+ pgm->enable = usbasp_enable;
+ pgm->disable = usbasp_disable;
+ pgm->program_enable = usbasp_spi_program_enable;
+ pgm->chip_erase = usbasp_spi_chip_erase;
+ pgm->cmd = usbasp_spi_cmd;
+ pgm->open = usbasp_open;
+ pgm->close = usbasp_close;
+ pgm->read_byte = avr_read_byte_default;
+ pgm->write_byte = avr_write_byte_default;
+
+ /*
+ * optional functions
+ */
+
+ pgm->paged_write = usbasp_spi_paged_write;
+ pgm->paged_load = usbasp_spi_paged_load;
+ pgm->setup = usbasp_setup;
+ pgm->teardown = usbasp_teardown;
+ pgm->set_sck_period = usbasp_spi_set_sck_period;
+
+}
+
+
+#else /* HAVE_LIBUSB */
+
+static int usbasp_nousb_open (struct programmer_t *pgm, char * name)
+{
+ avrdude_message(MSG_INFO, "%s: error: no usb support. please compile again with libusb installed.\n",
+ progname);
+
+ return -1;
+}
+
+void usbasp_initpgm(PROGRAMMER * pgm)
+{
+ strcpy(pgm->type, "usbasp");
+
+ pgm->open = usbasp_nousb_open;
+}
+
+#endif /* HAVE_LIBUSB */
+
+const char usbasp_desc[] = "USBasp programmer, see http://www.fischl.de/usbasp/";
+