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/pickit2.c')
-rw-r--r--src/avrdude/pickit2.c1340
1 files changed, 1340 insertions, 0 deletions
diff --git a/src/avrdude/pickit2.c b/src/avrdude/pickit2.c
new file mode 100644
index 000000000..bbf8b9ad7
--- /dev/null
+++ b/src/avrdude/pickit2.c
@@ -0,0 +1,1340 @@
+/*
+ * avrdude - A Downloader/Uploader for AVR device programmers
+ * Copyright (C) 2005 Erik Walthinsen
+ * Copyright (C) 2002-2004 Brian S. Dean <bsd@bsdhome.com>
+ * Copyright (C) 2006 David Moore
+ * Copyright (C) 2006,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: pickit2.c 2010-05-03 dbrown$ */
+/* Based on Id: stk500v2.c 836 2009-07-10 22:39:37Z joerg_wunsch */
+
+/*
+ * avrdude interface for PicKit2 programmer
+ *
+ * The PicKit2 programmer is a cheap device capable
+ * of 2 (bidirectional data line), 3, 4 wire SPI comms
+ *
+ * The PICkit2 software license doesn't allow the source to be
+ * modified to program other devices - nor can we distribute
+ * their source code. This program is not derived from nor does it
+ * contain any of the pickit2 source and should be exempt from any
+ * licensing issues.
+ *
+ * ISP Pinout (AVR - PICKit2 (pin)):
+ * RST - VPP/MCLR (1)
+ * VDD - VDD Target (2) -- possibly optional if AVR self powered
+ * GND - GND (3)
+ * MISO - PGD (4)
+ * SCLK - PDC (5)
+ * MOSI - AUX (6)
+ */
+
+#include "ac_cfg.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <inttypes.h>
+#include <unistd.h>
+
+#include "avrdude.h"
+#include "libavrdude.h"
+
+#if defined(HAVE_LIBUSB) || (defined(WIN32NATIVE) && defined(HAVE_LIBHID))
+
+#if (defined(WIN32NATIVE) && defined(HAVE_LIBHID))
+#include <windows.h>
+#if defined(HAVE_DDK_HIDSDI_H)
+# include <ddk/hidsdi.h>
+#else
+# include "my_ddk_hidsdi.h"
+#endif
+#include <setupapi.h>
+#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
+
+#if 0
+#define DEBUG(...) do { avrdude_message(MSG_DEBUG, __VA_ARGS__); } while(0)
+#else
+#define DEBUG(...) ((void)0)
+#endif
+
+#if 0
+#define DEBUGRECV(...) do { avrdude_message(MSG_DEBUG, __VA_ARGS__); } while(0)
+#else
+#define DEBUGRECV(...) ((void)0)
+#endif
+
+#define PICKIT2_VID 0x04d8
+#define PICKIT2_PID 0x0033
+
+#define SPI_MAX_CHUNK (64 - 10) // max packet size less the command overhead
+
+// win32native only:
+#if (defined(WIN32NATIVE) && defined(HAVE_LIBHID))
+static HANDLE open_hid(unsigned short vid, unsigned short pid);
+const char *usb_strerror()
+{
+ return "";
+}
+#else
+static int usb_open_device(struct usb_dev_handle **dev, int vid, int pid);
+//#define INVALID_HANDLE_VALUE NULL
+#define USB_ERROR_NONE 0
+#define USB_ERROR_ACCESS 1
+#define USB_ERROR_NOTFOUND 2
+#define USB_ERROR_BUSY 16
+#define USB_ERROR_IO 5
+#endif // WIN32NATIVE
+
+static int pickit2_write_report(PROGRAMMER *pgm, const unsigned char report[65]);
+static int pickit2_read_report(PROGRAMMER *pgm, unsigned char report[65]);
+
+#ifndef MIN
+#define MIN(X,Y) ((X) < (Y) ? (X) : (Y))
+#endif
+
+/*
+ * Private data for this programmer.
+ */
+struct pdata
+{
+#if (defined(WIN32NATIVE) && defined(HAVE_LIBHID))
+ HANDLE usb_handle, write_event, read_event;
+#else
+ struct usb_dev_handle *usb_handle; // LIBUSB STUFF
+#endif
+ uint8_t clock_period; // SPI clock period in us
+ int transaction_timeout; // usb trans timeout in ms
+};
+
+#define PDATA(pgm) ((struct pdata *)(pgm->cookie))
+
+#define CMD_NOP 0x5A
+#define CMD_GET_VERSION 0x76
+#define CMD_SET_VDD_4(v) 0xA0, (uint8_t)((v)*2048+672), (uint8_t)(((v)*2048+672)/256), (uint8_t)((v)*36)
+#define CMD_SET_VPP_4(v) 0xA1, 0x40, (uint8_t)((v)*18.61), (uint8_t)((v)*13)
+#define CMD_READ_VDD_VPP 0xA3
+#define CMD_EXEC_SCRIPT_2(len) 0xA6, (len)
+#define CMD_CLR_DLOAD_BUFF 0xA7
+#define CMD_DOWNLOAD_DATA_2(len) 0xA8, (len)
+#define CMD_CLR_ULOAD_BUFF 0xA9
+#define CMD_UPLOAD_DATA 0xAA
+#define CMD_UPLOAD_DATA_NO_LEN 0xAC
+#define CMD_END_OF_BUFFER 0xAD
+
+#define SCR_VDD_ON 0xFF
+#define SCR_VDD_OFF 0xFE
+#define SCR_VPP_ON 0xFB
+#define SCR_VPP_OFF 0xFA
+#define SCR_VPP_PWM_ON 0xF9
+#define SCR_VPP_PWM_OFF 0xF8
+#define SCR_MCLR_GND_ON 0xF7
+#define SCR_MCLR_GND_OFF 0xF6
+#define SCR_BUSY_LED_ON 0xF5
+#define SCR_BUSY_LED_OFF 0xF4
+#define SCR_SET_ICSP_DELAY_2(us) 0xEA,(us)
+#define SCR_SET_PINS_2(dd, cd, dv, cv) 0xF3, (((cd)!=0) | (((dd)!=0)<<1) | (((cv)!=0)<<2) | (((dv)!=0)<<3))
+#define SCR_GET_PINS 0xDC
+#define SCR_LOOP_3(rel, cnt) 0xE9, rel, cnt
+#define SCR_DELAY_2(sec) ((sec)>0.0054528?0xE8:0xE7), (uint8_t)((sec)>0.0054528?(.999+(sec)/.00546):(.999+(sec)/.0000213))
+#define SCR_SET_AUX_2(ad, av) 0xCF, (((ad)!=0) | (((av)!=0)<<1))
+#define SCR_SPI_SETUP_PINS_4 SCR_SET_PINS_2(1,0,0,0), SCR_SET_AUX_2(0,0)
+#define SCR_SPI 0xC3
+#define SCR_SPI_LIT_2(v) 0xC7,(v)
+
+static void pickit2_setup(PROGRAMMER * pgm)
+{
+ if ((pgm->cookie = malloc(sizeof(struct pdata))) == 0)
+ {
+ avrdude_message(MSG_INFO, "%s: pickit2_setup(): Out of memory allocating private data\n",
+ progname);
+ exit(1);
+ }
+ memset(pgm->cookie, 0, sizeof(struct pdata));
+
+ PDATA(pgm)->transaction_timeout = 1500; // default value, may be overridden with -x timeout=ms
+ PDATA(pgm)->clock_period = 10; // default value, may be overridden with -x clockrate=us or -B or -i
+}
+
+static void pickit2_teardown(PROGRAMMER * pgm)
+{
+ free(pgm->cookie);
+}
+
+static int pickit2_open(PROGRAMMER * pgm, char * port)
+{
+#if (defined(WIN32NATIVE) && defined(HAVE_LIBHID))
+ PDATA(pgm)->usb_handle = open_hid(PICKIT2_VID, PICKIT2_PID);
+
+ if (PDATA(pgm)->usb_handle == INVALID_HANDLE_VALUE)
+ {
+ /* no PICkit2 found */
+ avrdude_message(MSG_INFO, "%s: error: could not find PICkit2 with vid=0x%x pid=0x%x\n",
+ progname, PICKIT2_VID, PICKIT2_PID);
+ return -1;
+ }
+ else
+ {
+ // get the device description while we're at it
+ short buff[PGM_DESCLEN-1], i;
+ HidD_GetProductString(PDATA(pgm)->usb_handle, buff, PGM_DESCLEN-1);
+
+ // convert from wide chars, but do not overwrite trailing '\0'
+ memset(&(pgm->type), 0, PGM_DESCLEN);
+ for (i = 0; i < (PGM_DESCLEN-1) && buff[i]; i++)
+ {
+ pgm->type[i] = (char)buff[i]; // TODO what about little/big endian???
+ }
+ }
+#else
+ if (usb_open_device(&(PDATA(pgm)->usb_handle), PICKIT2_VID, PICKIT2_PID) < 0)
+ {
+ /* no PICkit2 found */
+ avrdude_message(MSG_INFO, "%s: error: could not find PICkit2 with vid=0x%x pid=0x%x\n",
+ progname, PICKIT2_VID, PICKIT2_PID);
+ return -1;
+ }
+#endif
+
+ if (pgm->ispdelay > 0)
+ {
+ PDATA(pgm)->clock_period = MIN(pgm->ispdelay, 255);
+ }
+ else if (pgm->bitclock > 0.0)
+ {
+ PDATA(pgm)->clock_period = MIN(pgm->bitclock * 1e6, 255);
+ }
+
+ return 0;
+}
+
+
+static void pickit2_close(PROGRAMMER * pgm)
+{
+#if (defined(WIN32NATIVE) && defined(HAVE_LIBHID))
+ CloseHandle(PDATA(pgm)->usb_handle);
+ CloseHandle(PDATA(pgm)->read_event);
+ CloseHandle(PDATA(pgm)->write_event);
+#else
+ usb_close(PDATA(pgm)->usb_handle);
+#endif // WIN32NATIVE
+}
+
+
+static int pickit2_initialize(PROGRAMMER * pgm, AVRPART * p)
+{
+ unsigned char temp[4];
+ memset(temp, 0, sizeof(temp));
+
+ int errorCode = 0;
+
+ /* set sck period */
+ if (pgm->set_sck_period)
+ pgm->set_sck_period(pgm, pgm->bitclock);
+
+ /* connect to target device -- we'll just ask for the firmware version */
+ static const unsigned char report[65] = {0, CMD_GET_VERSION, CMD_END_OF_BUFFER};
+ if ((errorCode = pickit2_write_report(pgm, report)) > 0)
+ {
+ unsigned char report[65] = {0};
+ //memset(report, 0, sizeof(report));
+ if ((errorCode = pickit2_read_report(pgm, report)) >= 4)
+ {
+ avrdude_message(MSG_NOTICE, "%s: %s firmware version %d.%d.%d\n", progname, pgm->desc, (int)report[1], (int)report[2], (int)report[3]);
+
+ // set the pins, apply reset,
+ // TO DO: apply vtarget (if requested though -x option)
+ unsigned char report[65] =
+ {
+ 0, CMD_SET_VDD_4(5),
+ CMD_SET_VPP_4(5),
+ CMD_EXEC_SCRIPT_2(24),
+ SCR_SPI_SETUP_PINS_4, // SDO, SDI, SCK
+ SCR_SET_ICSP_DELAY_2(PDATA(pgm)->clock_period), // slow down the SPI
+ SCR_VDD_ON,
+ SCR_MCLR_GND_OFF, // let reset float high
+ SCR_VPP_PWM_ON,
+ SCR_DELAY_2(.1),
+ SCR_VPP_ON,
+ SCR_DELAY_2(.1),
+ SCR_VPP_OFF,
+ SCR_DELAY_2(.01),
+
+ SCR_MCLR_GND_ON, // reset low - programming mode
+ SCR_DELAY_2(.1),
+
+ SCR_BUSY_LED_ON,
+ SCR_DELAY_2(.3),
+ SCR_BUSY_LED_OFF,
+
+ CMD_CLR_DLOAD_BUFF,
+ CMD_CLR_ULOAD_BUFF,
+
+ CMD_END_OF_BUFFER
+ };
+
+ if (pickit2_write_report(pgm, report) < 0)
+ {
+ avrdude_message(MSG_INFO, "pickit2_read_report failed (ec %d). %s\n", errorCode, usb_strerror());
+ return -1;
+ }
+ }
+ else
+ {
+ avrdude_message(MSG_INFO, "pickit2_read_report failed (ec %d). %s\n", errorCode, usb_strerror());
+ return -1;
+ }
+ }
+ else
+ {
+ avrdude_message(MSG_INFO, "pickit2_write_report failed (ec %d). %s\n", errorCode, usb_strerror());
+ return -1;
+ }
+
+ if (pgm->program_enable)
+ return pgm->program_enable(pgm, p);
+ else
+ return -1;
+}
+
+static void pickit2_disable(PROGRAMMER * pgm)
+{
+ /* make sure all pins are floating & all voltages are off */
+ static const unsigned char report[65] =
+ {
+ 0, CMD_EXEC_SCRIPT_2(8),
+ SCR_SET_PINS_2(1,1,0,0),
+ SCR_SET_AUX_2(1,0),
+ SCR_MCLR_GND_OFF,
+ SCR_VPP_OFF,
+ SCR_VDD_OFF,
+ SCR_BUSY_LED_OFF,
+ CMD_END_OF_BUFFER
+ };
+
+ pickit2_write_report(pgm, report);
+
+ return;
+}
+
+static void pickit2_enable(PROGRAMMER * pgm)
+{
+ /* Do nothing. */
+
+ return;
+}
+
+static void pickit2_display(PROGRAMMER * pgm, const char * p)
+{
+ DEBUG( "%s: Found \"%s\" version %d.%d.%d\n", progname, p, 1, 1, 1);
+ return;
+}
+
+#define sendReport(x)
+#define readReport(x) 0
+
+#if 0
+static int pickit2_rdy_led (struct programmer_t * pgm, int value)
+{
+ // no rdy led
+ return 0;
+}
+
+static int pickit2_err_led(struct programmer_t * pgm, int value)
+{
+ // there is no error led, so just flash the busy led a few times
+ uint8_t report[65] =
+ {
+ 0, CMD_EXEC_SCRIPT_2(9),
+ SCR_BUSY_LED_ON,
+ SCR_DELAY_2(.2),
+ SCR_BUSY_LED_OFF,
+ SCR_DELAY_2(.2),
+ SCR_LOOP_3(6, 9),
+ CMD_END_OF_BUFFER
+ };
+
+ // busy stops flashing by itself, so just return
+ if (!value)
+ {
+ return 0;
+ }
+
+ return pickit2_write_report(pgm, report) != -1;
+}
+#endif
+
+static int pickit2_pgm_led (struct programmer_t * pgm, int value)
+{
+ // script to set busy led appropriately
+ uint8_t report[65] = {0, CMD_EXEC_SCRIPT_2(1),
+ value ? SCR_BUSY_LED_ON : SCR_BUSY_LED_OFF,
+ CMD_END_OF_BUFFER
+ };
+
+ return pickit2_write_report(pgm, report) != -1;
+}
+
+static int pickit2_vfy_led (struct programmer_t * pgm, int value)
+{
+ // no such thing - maybe just call pgm_led
+
+ return pgm->pgm_led(pgm, value);
+}
+
+static void pickit2_powerup(struct programmer_t * pgm)
+{
+ // turn vdd on?
+}
+
+static void pickit2_powerdown(struct programmer_t * pgm)
+{
+ // do what?
+ pgm->disable(pgm);
+}
+
+static int pickit2_program_enable(struct programmer_t * pgm, AVRPART * p)
+{
+ unsigned char cmd[4];
+ unsigned char res[4];
+
+ if (p->op[AVR_OP_PGM_ENABLE] == NULL)
+ {
+ avrdude_message(MSG_INFO, "program enable instruction not defined for part \"%s\"\n",
+ p->desc);
+ return -1;
+ }
+
+ memset(cmd, 0, sizeof(cmd));
+ avr_set_bits(p->op[AVR_OP_PGM_ENABLE], cmd);
+ pgm->cmd(pgm, cmd, res);
+
+ {
+ int i;
+ avrdude_message(MSG_DEBUG, "program_enable(): sending command. Resp = ");
+
+ for (i = 0; i < 4; i++)
+ {
+ avrdude_message(MSG_DEBUG, "%x ", (int)res[i]);
+ }
+ avrdude_message(MSG_DEBUG, "\n");
+ }
+
+ // check for sync character
+ if (res[2] != cmd[1])
+ return -2;
+
+ return 0;
+}
+
+static int pickit2_chip_erase(struct programmer_t * pgm, AVRPART * p)
+{
+ unsigned char cmd[4];
+ unsigned char res[4];
+
+ 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;
+ }
+
+ pgm->pgm_led(pgm, ON);
+
+ 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);
+
+ pgm->pgm_led(pgm, OFF);
+
+ return 0;
+}
+
+static int pickit2_paged_load(PROGRAMMER * pgm, AVRPART * p, AVRMEM * mem,
+ unsigned int page_size, unsigned int addr, unsigned int n_bytes)
+{
+ // only supporting flash & eeprom page reads
+ if ((!mem->paged || page_size <= 1) || (strcmp(mem->desc, "flash") != 0 && strcmp(mem->desc, "eeprom") != 0))
+ {
+ return -1;
+ }
+
+ DEBUG( "paged read ps %d, mem %s\n", page_size, mem->desc);
+
+ OPCODE *readop = 0, *lext = mem->op[AVR_OP_LOAD_EXT_ADDR];
+ uint8_t data = 0, cmd[SPI_MAX_CHUNK], res[SPI_MAX_CHUNK];
+ unsigned int addr_base;
+ unsigned int max_addr = addr + n_bytes;
+
+ pgm->pgm_led(pgm, ON);
+
+ for (addr_base = addr; addr_base < max_addr; )
+ {
+ if ((addr_base == 0 || (addr_base % /*ext_address_boundary*/ 65536) == 0)
+ && lext != NULL)
+ {
+ memset(cmd, 0, sizeof(cmd));
+
+ avr_set_bits(lext, cmd);
+ avr_set_addr(lext, cmd, addr_base);
+ pgm->cmd(pgm, cmd, res);
+ }
+
+ // bytes to send in the next packet -- not necessary as pickit2_spi() handles breaking up
+ // the data into packets -- but we need to keep transfers frequent so that we can update the
+ // status indicator bar
+ uint32_t blockSize = MIN(65536 - (addr_base % 65536), MIN(max_addr - addr_base, SPI_MAX_CHUNK / 4));
+
+ memset(cmd, 0, sizeof(cmd));
+ memset(res, 0, sizeof(res));
+
+ uint8_t addr_off;
+ for (addr_off = 0; addr_off < blockSize; addr_off++)
+ {
+ int addr = addr_base + addr_off, caddr = addr;
+
+ if (mem->op[AVR_OP_READ_LO] != NULL && mem->op[AVR_OP_READ_HI] != NULL)
+ {
+ if (addr & 0x00000001)
+ readop = mem->op[AVR_OP_READ_HI];
+ else
+ readop = mem->op[AVR_OP_READ_LO];
+
+ caddr /= 2;
+ }
+ else if (mem->op[AVR_OP_READ] != NULL)
+ {
+ readop = mem->op[AVR_OP_READ];
+ }
+ else
+ {
+ avrdude_message(MSG_INFO, "no read command specified\n");
+ return -1;
+ }
+
+ avr_set_bits(readop, &cmd[addr_off*4]);
+ avr_set_addr(readop, &cmd[addr_off*4], caddr);
+ }
+
+ int bytes_read = pgm->spi(pgm, cmd, res, blockSize*4);
+
+ if (bytes_read < 0)
+ {
+ avrdude_message(MSG_INFO, "Failed @ pgm->spi()\n");
+ pgm->err_led(pgm, ON);
+ return -1;
+ }
+
+ DEBUG( "\npaged_load @ %X, wrote: %d, read: %d bytes\n", addr_base, blockSize*4, bytes_read);
+
+ for (addr_off = 0; addr_off < bytes_read / 4; addr_off++)
+ {
+ data = 0;
+ avr_get_output(readop, &res[addr_off*4], &data);
+ mem->buf[addr_base + addr_off] = data;
+
+ DEBUG( "%2X(%c)", (int)data, data<0x20?'.':data);
+ }
+ DEBUG( "\n");
+
+ addr_base += blockSize;
+ }
+
+ pgm->pgm_led(pgm, OFF);
+
+ return n_bytes;
+}
+
+
+static int pickit2_commit_page(PROGRAMMER * pgm, AVRPART * p, AVRMEM * mem,
+ unsigned long addr)
+{
+ OPCODE * wp, * lext;
+
+ wp = mem->op[AVR_OP_WRITEPAGE];
+ if (wp == NULL)
+ {
+ avrdude_message(MSG_INFO, "pickit2_commit_page(): memory \"%s\" not configured for page writes\n",
+ mem->desc);
+ return -1;
+ }
+
+ // adjust the address if this memory is word-addressable
+ if ((mem->op[AVR_OP_LOADPAGE_LO]) || (mem->op[AVR_OP_READ_LO]))
+ addr /= 2;
+
+ unsigned char cmd[8];
+ memset(cmd, 0, sizeof(cmd));
+
+ // use the "load extended address" command, if available
+ lext = mem->op[AVR_OP_LOAD_EXT_ADDR];
+ if (lext != NULL)
+ {
+ avr_set_bits(lext, cmd);
+ avr_set_addr(lext, cmd, addr);
+ }
+
+ // make up the write page command in the 2nd cmd position
+ avr_set_bits(wp, &cmd[4]);
+ avr_set_addr(wp, &cmd[4], addr);
+
+ if (lext != NULL)
+ {
+ // write the load extended address cmd && the write_page cmd
+ pgm->spi(pgm, cmd, NULL, 8);
+ }
+ else
+ {
+ // write just the write_page cmd
+ pgm->spi(pgm, &cmd[4], NULL, 4);
+ }
+
+ // just delay the max (we could do the delay in the PICkit2 if we wanted)
+ usleep(mem->max_write_delay);
+
+ return 0;
+}
+
+// not actually a paged write, but a bulk/batch write
+static int pickit2_paged_write(PROGRAMMER * pgm, AVRPART * p, AVRMEM * mem,
+ unsigned int page_size, unsigned int addr, unsigned int n_bytes)
+{
+ // only paged write for flash implemented
+ if (strcmp(mem->desc, "flash") != 0 && strcmp(mem->desc, "eeprom") != 0)
+ {
+ avrdude_message(MSG_INFO, "Part does not support %d paged write of %s\n", page_size, mem->desc);
+ return -1;
+ }
+
+ DEBUG( "page size %d mem %s supported: %d\n", page_size, mem->desc, mem->paged);
+ DEBUG( "loadpagehi %x, loadpagelow %x, writepage %x\n", (int)mem->op[AVR_OP_LOADPAGE_HI], (int)mem->op[AVR_OP_LOADPAGE_LO], (int)mem->op[AVR_OP_WRITEPAGE]);
+
+ OPCODE *writeop;
+ uint8_t cmd[SPI_MAX_CHUNK], res[SPI_MAX_CHUNK];
+ unsigned int addr_base;
+ unsigned int max_addr = addr + n_bytes;
+
+ pgm->pgm_led(pgm, ON);
+
+ for (addr_base = addr; addr_base < max_addr; )
+ {
+ uint32_t blockSize;
+
+ if (mem->paged)
+ {
+ blockSize = MIN(page_size - (addr_base % page_size), MIN(max_addr - addr_base, SPI_MAX_CHUNK/4) ); // bytes remaining in page
+ }
+ else
+ {
+ blockSize = 1;
+ }
+
+ memset(cmd, 0, sizeof(cmd));
+ memset(res, 0, sizeof(res));
+
+ uint8_t addr_off;
+ for (addr_off = 0; addr_off < blockSize; addr_off++)
+ {
+ int addr = addr_base + addr_off;
+ int caddr = 0;
+
+ /*
+ * determine which memory opcode to use
+ */
+ if (mem->paged && mem->op[AVR_OP_LOADPAGE_HI] && mem->op[AVR_OP_LOADPAGE_LO])
+ {
+ if (addr & 0x01)
+ writeop = mem->op[AVR_OP_LOADPAGE_HI];
+ else
+ writeop = mem->op[AVR_OP_LOADPAGE_LO];
+ caddr = addr / 2;
+ }
+ else if (mem->paged && mem->op[AVR_OP_LOADPAGE_LO])
+ {
+ writeop = mem->op[AVR_OP_LOADPAGE_LO];
+ caddr = addr;
+ }
+ else if (mem->op[AVR_OP_WRITE_LO])
+ {
+ writeop = mem->op[AVR_OP_WRITE_LO];
+ caddr = addr; // maybe this should divide by 2 & use the write_high opcode also
+
+ avrdude_message(MSG_INFO, "Error AVR_OP_WRITE_LO defined only (where's the HIGH command?)\n");
+ return -1;
+ }
+ else
+ {
+ writeop = mem->op[AVR_OP_WRITE];
+ caddr = addr;
+ }
+
+ if (writeop == NULL)
+ {
+ pgm->err_led(pgm, ON);
+ // not supported!
+ return -1;
+ }
+
+ avr_set_bits(writeop, &cmd[addr_off*4]);
+ avr_set_addr(writeop, &cmd[addr_off*4], caddr);
+ avr_set_input(writeop, &cmd[addr_off*4], mem->buf[addr]);
+ }
+
+ int bytes_read = pgm->spi(pgm, cmd, res, blockSize*4);
+
+ if (bytes_read < 0)
+ {
+ avrdude_message(MSG_INFO, "Failed @ pgm->spi()\n");
+ pgm->err_led(pgm, ON);
+ return -1;
+ }
+
+ addr_base += blockSize;
+
+ // write the page - this function looks after extended address also
+ if (mem->paged && (((addr_base % page_size) == 0) || (addr_base == max_addr)))
+ {
+ DEBUG( "Calling pickit2_commit_page()\n");
+ pickit2_commit_page(pgm, p, mem, addr_base-1);
+ }
+ else if (!mem->paged)
+ {
+ usleep(mem->max_write_delay);
+ }
+ }
+
+ pgm->pgm_led(pgm, OFF);
+
+ return n_bytes;
+}
+
+
+static int pickit2_cmd(struct programmer_t * pgm, const unsigned char *cmd,
+ unsigned char *res)
+{
+ return pgm->spi(pgm, cmd, res, 4);
+}
+
+// breaks up the cmd[] data into packets & sends to the pickit2. Data shifted in is stored in res[].
+static int pickit2_spi(struct programmer_t * pgm, const unsigned char *cmd,
+ unsigned char *res, int n_bytes)
+{
+ int retval = 0, temp1 = 0, temp2 = 0, count = n_bytes;
+
+ while (count > 0)
+ {
+ uint8_t i, blockSize = MIN(count, SPI_MAX_CHUNK);
+ uint8_t report[65] = {0, CMD_DOWNLOAD_DATA_2(blockSize)};
+ uint8_t *repptr = report + 3;
+
+ memset(report + 3, CMD_END_OF_BUFFER, sizeof(report) - 3);
+
+ // append some data to write to SPI
+ for (i = 0; i < blockSize; i++)
+ {
+ *repptr++ = *cmd++;
+ count--; // 1 less byte to pack
+ }
+
+ if (blockSize == 1)
+ {
+ *repptr++ = 0xa6; //CMD_EXECUTE_SCRIPT;
+ *repptr++ = 1;
+ *repptr++ = SCR_SPI;
+ }
+ else
+ {
+ *repptr++ = 0xa6; //CMD_EXECUTE_SCRIPT_2;
+ *repptr++ = 4;
+ *repptr++ = SCR_SPI;
+ *repptr++ = 0xe9; //SCR_LOOP_3;
+ *repptr++ = 1;
+ *repptr++ = blockSize - 1;
+ }
+
+ // request the data read to be sent to us
+ *repptr++ = CMD_UPLOAD_DATA;
+
+ // check return values
+ if ((temp1=pickit2_write_report(pgm, report)) < 0 ||
+ (temp2=pickit2_read_report(pgm, report)) < 0)
+ {
+ return -1;
+ }/*
+ else
+ {
+ int i;
+ DEBUG( "in spi. wrote %d, read %d\n", temp1, temp2);
+
+ for (i = 0; i < temp2; i++)
+ {
+ DEBUG( "%2.2x ", report[i]);
+ }
+
+ DEBUG( "\n");
+ }*/
+
+ retval = report[1]; // upload-length field
+ repptr = &report[2]; // actual data starts here
+
+ if (res) // copy data if user has specified a storage location
+ {
+ memcpy(res, repptr, retval);
+ res += retval;
+ }
+ }
+
+ return n_bytes;
+}
+
+#if (defined(WIN32NATIVE) && defined(HAVE_LIBHID))
+/*
+ Func: open_hid()
+ Desc: finds & opens device having specified VID & PID.
+ Retn: Handle of open device or INVALID_HANDLE_VALUE on fail
+
+ Note this routine is a modified function from:
+ usbhidiocDlg.cpp : implementation file
+ Project: usbhidioc.cpp
+ Version: 3.0
+ Date: 7/18/05
+ by Jan Axelson (jan@Lvr.com)
+*/
+static HANDLE open_hid(unsigned short vid, unsigned short pid)
+{
+ //Use a series of API calls to find a HID with a specified Vendor IF and Product ID.
+ HANDLE returnHandle = INVALID_HANDLE_VALUE;
+ HIDD_ATTRIBUTES Attributes;
+// DWORD DeviceUsage;
+ SP_DEVICE_INTERFACE_DATA devInfoData;
+ BOOL LastDevice = FALSE;
+ int MemberIndex = 0;
+ LONG Result;
+
+ // were global, now just local scrap
+ DWORD Length = 0;
+ PSP_DEVICE_INTERFACE_DETAIL_DATA detailData = NULL;
+ HANDLE DeviceHandle=NULL;
+ GUID HidGuid;
+ HANDLE hDevInfo;
+ ULONG Required;
+ BOOL MyDeviceDetected = 0;
+
+ /*
+ API function: HidD_GetHidGuid
+ Get the GUID for all system HIDs.
+ Returns: the GUID in HidGuid.
+ */
+
+ HidD_GetHidGuid(&HidGuid);
+ DEBUG("\nHidD_GetHidGuid returned.\n");
+
+ /*
+ API function: SetupDiGetClassDevs
+ Returns: a handle to a device information set for all installed devices.
+ Requires: the GUID returned by GetHidGuid.
+ */
+
+ hDevInfo=SetupDiGetClassDevs
+ (&HidGuid,
+ NULL,
+ NULL,
+ DIGCF_PRESENT|DIGCF_INTERFACEDEVICE);
+
+ DEBUG("\nSetupDiGetClassDevs returned 0x%x\n", hDevInfo);
+ devInfoData.cbSize = sizeof(devInfoData);
+
+ //Step through the available devices looking for the one we want.
+ //Quit on detecting the desired device or checking all available devices without success.
+
+ MemberIndex = 0;
+ LastDevice = FALSE;
+
+ do
+ {
+ /*
+ API function: SetupDiEnumDeviceInterfaces
+ On return, MyDeviceInterfaceData contains the handle to a
+ SP_DEVICE_INTERFACE_DATA structure for a detected device.
+ Requires:
+ The DeviceInfoSet returned in SetupDiGetClassDevs.
+ The HidGuid returned in GetHidGuid.
+ An index to specify a device.
+ */
+
+
+ Result=SetupDiEnumDeviceInterfaces
+ (hDevInfo,
+ 0,
+ &HidGuid,
+ MemberIndex,
+ &devInfoData);
+
+ DEBUG("\nSetupDiEnumDeviceInterfaces returned 0x%x\n", Result);
+
+ if (Result != 0)
+ {
+ //A device has been detected, so get more information about it.
+
+ /*
+ API function: SetupDiGetDeviceInterfaceDetail
+ Returns: an SP_DEVICE_INTERFACE_DETAIL_DATA structure
+ containing information about a device.
+ To retrieve the information, call this function twice.
+ The first time returns the size of the structure in Length.
+ The second time returns a pointer to the data in DeviceInfoSet.
+ Requires:
+ A DeviceInfoSet returned by SetupDiGetClassDevs
+ The SP_DEVICE_INTERFACE_DATA structure returned by SetupDiEnumDeviceInterfaces.
+
+ The final parameter is an optional pointer to an SP_DEV_INFO_DATA structure.
+ This application doesn't retrieve or use the structure.
+ If retrieving the structure, set
+ MyDeviceInfoData.cbSize = length of MyDeviceInfoData.
+ and pass the structure's address.
+ */
+
+ //Get the Length value.
+ //The call will return with a "buffer too small" error which can be ignored.
+ Result = SetupDiGetDeviceInterfaceDetail
+ (hDevInfo,
+ &devInfoData,
+ NULL,
+ 0,
+ &Length,
+ NULL);
+
+ DEBUG("\nSetupDiGetDeviceInterfaceDetail returned 0x%x\n", Result);
+
+ //Allocate memory for the hDevInfo structure, using the returned Length.
+
+ detailData = (PSP_DEVICE_INTERFACE_DETAIL_DATA)malloc(Length);
+
+ //Set cbSize in the detailData structure.
+
+ detailData -> cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);
+
+ //Call the function again, this time passing it the returned buffer size.
+
+ Result = SetupDiGetDeviceInterfaceDetail
+ (hDevInfo,
+ &devInfoData,
+ detailData,
+ Length,
+ &Required,
+ NULL);
+
+ // Open a handle to the device.
+ // To enable retrieving information about a system mouse or keyboard,
+ // don't request Read or Write access for this handle.
+
+ /*
+ API function: CreateFile
+ Returns: a handle that enables reading and writing to the device.
+ Requires:
+ The DevicePath in the detailData structure
+ returned by SetupDiGetDeviceInterfaceDetail.
+ */
+
+ DeviceHandle=CreateFile
+ (detailData->DevicePath,
+ 0,
+ FILE_SHARE_READ|FILE_SHARE_WRITE,
+ (LPSECURITY_ATTRIBUTES)NULL,
+ OPEN_EXISTING,
+ 0,
+ NULL);
+
+ DEBUG("CreateFile(): %s\n", detailData->DevicePath);
+ /*
+ API function: HidD_GetAttributes
+ Requests information from the device.
+ Requires: the handle returned by CreateFile.
+ Returns: a HIDD_ATTRIBUTES structure containing
+ the Vendor ID, Product ID, and Product Version Number.
+ Use this information to decide if the detected device is
+ the one we're looking for.
+ */
+
+ //Set the Size to the number of bytes in the structure.
+
+ Attributes.Size = sizeof(Attributes);
+
+ Result = HidD_GetAttributes
+ (DeviceHandle,
+ &Attributes);
+
+ DEBUG("HidD_GetAttributes returned 0x%x\n", Result);
+ DEBUG("VID: %.4X PID: %.4X\n", Attributes.VendorID, Attributes.ProductID);
+
+ //Is it the desired device?
+ MyDeviceDetected = FALSE;
+ if (Attributes.VendorID == vid)
+ {
+ if (Attributes.ProductID == pid)
+ {
+ //Both the Vendor ID and Product ID match.
+
+ MyDeviceDetected = TRUE;
+
+ // Get a handle for us to use.
+
+ returnHandle = CreateFile
+ (detailData->DevicePath,
+ GENERIC_WRITE | GENERIC_READ,
+ FILE_SHARE_READ|FILE_SHARE_WRITE,
+ (LPSECURITY_ATTRIBUTES)NULL,
+ OPEN_EXISTING,
+ FILE_FLAG_OVERLAPPED,
+ NULL);
+
+ } //if (Attributes.ProductID == ProductID)
+
+ else
+ //The Product ID doesn't match.
+
+ CloseHandle(DeviceHandle);
+
+ } //if (Attributes.VendorID == VendorID)
+
+ else
+ //The Vendor ID doesn't match.
+
+ CloseHandle(DeviceHandle);
+
+ //Free the memory used by the detailData structure (no longer needed).
+
+ free(detailData);
+
+ } //if (Result != 0)
+
+ else
+ //SetupDiEnumDeviceInterfaces returned 0, so there are no more devices to check.
+
+ LastDevice=TRUE;
+
+ //If we haven't found the device yet, and haven't tried every available device,
+ //try the next one.
+
+ MemberIndex = MemberIndex + 1;
+
+ } //do
+
+ while ((LastDevice == FALSE) && (MyDeviceDetected == FALSE));
+
+ if (MyDeviceDetected == FALSE)
+ DEBUG("Device not detected\n");
+ else
+ DEBUG("Device detected\n");
+
+ //Free the memory reserved for hDevInfo by SetupDiClassDevs.
+
+ DEBUG("Calling SetupDiDestroyDeviceInfoList\n");
+ SetupDiDestroyDeviceInfoList(hDevInfo);
+
+ return returnHandle;
+}
+
+// simple read with timeout
+static int usb_read_interrupt(PROGRAMMER *pgm, void *buff, int size, int timeout)
+{
+ OVERLAPPED ovr;
+ DWORD bytesRead = 0;
+
+ if (PDATA(pgm)->read_event == NULL)
+ {
+ PDATA(pgm)->read_event = CreateEvent(0, 0, 0, 0);
+ }
+
+ memset(&ovr, 0, sizeof(ovr));
+ ovr.hEvent = PDATA(pgm)->read_event;
+
+ ReadFile(PDATA(pgm)->usb_handle, buff, size, &bytesRead, &ovr);
+ if (WaitForSingleObject(PDATA(pgm)->read_event, timeout) == WAIT_TIMEOUT)
+ {
+ CancelIo(PDATA(pgm)->usb_handle);
+ return -1;
+ }
+
+ GetOverlappedResult(PDATA(pgm)->usb_handle, &ovr, &bytesRead, 0);
+
+ return bytesRead > 0 ? bytesRead : -1;
+}
+
+// simple write with timeout
+static int usb_write_interrupt(PROGRAMMER *pgm, const void *buff, int size, int timeout)
+{
+ OVERLAPPED ovr;
+ DWORD bytesWritten = 0;
+
+ if (PDATA(pgm)->write_event == NULL)
+ {
+ PDATA(pgm)->write_event = CreateEvent(0, 0, 0, 0);
+ }
+
+ memset(&ovr, 0, sizeof(ovr));
+ ovr.hEvent = PDATA(pgm)->write_event;
+
+ WriteFile(PDATA(pgm)->usb_handle, buff, size, &bytesWritten, &ovr);
+ if (WaitForSingleObject(PDATA(pgm)->write_event, timeout) == WAIT_TIMEOUT)
+ {
+ CancelIo(PDATA(pgm)->usb_handle);
+ return -1;
+ }
+
+ GetOverlappedResult(PDATA(pgm)->usb_handle, &ovr, &bytesWritten, 0);
+
+ return bytesWritten > 0 ? bytesWritten : -1;
+}
+
+static int pickit2_write_report(PROGRAMMER * pgm, const unsigned char report[65])
+{
+ return usb_write_interrupt(pgm, report, 65, PDATA(pgm)->transaction_timeout); // XXX
+}
+
+static int pickit2_read_report(PROGRAMMER * pgm, unsigned char report[65])
+{
+ return usb_read_interrupt(pgm, report, 65, PDATA(pgm)->transaction_timeout);
+}
+
+#else // WIN32NATIVE
+/* taken (modified) from avrdude usbasp.c */
+static int usb_open_device(struct usb_dev_handle **device, int vendor, int product)
+{
+ 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)
+ {
+ DEBUG( "Enumerating device list.. VID: 0x%4.4x, PID: 0x%4.4x\n", dev->descriptor.idVendor, dev->descriptor.idProduct);
+ if (dev->descriptor.idVendor == vendor && dev->descriptor.idProduct == product)
+ {
+ /* we need to open the device in order to query strings */
+ handle = usb_open(dev);
+ if (handle == NULL)
+ {
+ errorCode = USB_ERROR_ACCESS;
+ avrdude_message(MSG_INFO, "%s: Warning: cannot open USB device: %s\n", progname, usb_strerror());
+ continue;
+ }
+
+ // return with opened device handle
+ else
+ {
+ avrdude_message(MSG_NOTICE, "Device %p seemed to open OK.\n", handle);
+
+ if ((errorCode = usb_set_configuration(handle, 1)) < 0)
+ {
+ avrdude_message(MSG_INFO, "Could not set configuration. Error code %d, %s.\n"
+ "You may need to run avrdude as root or set up correct usb port permissions.", errorCode, usb_strerror());
+ }
+
+ if ((errorCode = usb_claim_interface(handle, 0)) < 0)
+ {
+ avrdude_message(MSG_INFO, "Could not claim interface. Error code %d, %s\n"
+ "You may need to run avrdude as root or set up correct usb port permissions.", errorCode, usb_strerror());
+ }
+
+ errorCode = 0;
+ *device = handle;
+ return 0;
+ }
+ }
+ }
+ }
+
+ return -1;
+}
+
+static int pickit2_write_report(PROGRAMMER * pgm, const unsigned char report[65])
+{
+ // endpoint 1 OUT??
+ return usb_interrupt_write(PDATA(pgm)->usb_handle, USB_ENDPOINT_OUT | 1, (const char*)(report+1), 64, PDATA(pgm)->transaction_timeout);
+}
+
+static int pickit2_read_report(PROGRAMMER * pgm, unsigned char report[65])
+{
+ // endpoint 1 IN??
+ return usb_interrupt_read(PDATA(pgm)->usb_handle, USB_ENDPOINT_IN | 1, (char*)(report+1), 64, PDATA(pgm)->transaction_timeout);
+}
+#endif // WIN323NATIVE
+
+static int pickit2_parseextparams(struct programmer_t * pgm, LISTID extparms)
+{
+ LNODEID ln;
+ const char *extended_param;
+ int rv = 0;
+
+ for (ln = lfirst(extparms); ln; ln = lnext(ln))
+ {
+ extended_param = ldata(ln);
+
+ if (strncmp(extended_param, "clockrate=", strlen("clockrate=")) == 0)
+ {
+ int clock_rate;
+ if (sscanf(extended_param, "clockrate=%i", &clock_rate) != 1 || clock_rate <= 0)
+ {
+ avrdude_message(MSG_INFO, "%s: pickit2_parseextparms(): invalid clockrate '%s'\n",
+ progname, extended_param);
+ rv = -1;
+ continue;
+ }
+
+ int clock_period = MIN(1000000 / clock_rate, 255); // max period is 255
+ clock_rate = (int)(1000000 / (clock_period + 5e-7)); // assume highest speed is 2MHz - should probably check this
+
+ avrdude_message(MSG_NOTICE2, "%s: pickit2_parseextparms(): clockrate set to 0x%02x\n",
+ progname, clock_rate);
+ PDATA(pgm)->clock_period = clock_period;
+
+ continue;
+ }
+
+ if (strncmp(extended_param, "timeout=", strlen("timeout=")) == 0)
+ {
+ int timeout;
+ if (sscanf(extended_param, "timeout=%i", &timeout) != 1 || timeout <= 0)
+ {
+ avrdude_message(MSG_INFO, "%s: pickit2_parseextparms(): invalid timeout '%s'\n",
+ progname, extended_param);
+ rv = -1;
+ continue;
+ }
+
+ avrdude_message(MSG_NOTICE2, "%s: pickit2_parseextparms(): usb timeout set to 0x%02x\n",
+ progname, timeout);
+ PDATA(pgm)->transaction_timeout = timeout;
+
+ continue;
+ }
+
+ avrdude_message(MSG_INFO, "%s: pickit2_parseextparms(): invalid extended parameter '%s'\n",
+ progname, extended_param);
+ rv = -1;
+ }
+
+ return rv;
+}
+
+
+void pickit2_initpgm (PROGRAMMER * pgm)
+{
+ /*
+ * mandatory functions - these are called without checking to see
+ * whether they are assigned or not
+ */
+
+ pgm->initialize = pickit2_initialize;
+ pgm->display = pickit2_display;
+ pgm->enable = pickit2_enable;
+ pgm->disable = pickit2_disable;
+ pgm->powerup = pickit2_powerup;
+ pgm->powerdown = pickit2_powerdown;
+ pgm->program_enable = pickit2_program_enable;
+ pgm->chip_erase = pickit2_chip_erase;
+ pgm->open = pickit2_open;
+ pgm->close = pickit2_close;
+
+ pgm->read_byte = avr_read_byte_default;
+ pgm->write_byte = avr_write_byte_default;
+
+ /*
+ * predefined functions - these functions have a valid default
+ * implementation. Hence, they don't need to be defined in
+ * the programmer.
+ */
+ //pgm->rdy_led = pickit2_rdy_led;
+ //pgm->err_led = pickit2_err_led;
+ pgm->pgm_led = pickit2_pgm_led;
+ pgm->vfy_led = pickit2_vfy_led;
+
+ /*
+ * optional functions - these are checked to make sure they are
+ * assigned before they are called
+ */
+
+ pgm->cmd = pickit2_cmd;
+ pgm->spi = pickit2_spi;
+ pgm->paged_write = pickit2_paged_write;
+ pgm->paged_load = pickit2_paged_load;
+ //pgm->write_setup = NULL;
+ //pgm->read_sig_bytes = NULL;
+ //pgm->set_vtarget = NULL;//pickit2_vtarget;
+ //pgm->set_varef = NULL;
+ //pgm->set_fosc = NULL;
+ //pgm->perform_osccal = NULL;
+
+ pgm->parseextparams = pickit2_parseextparams;
+
+ pgm->setup = pickit2_setup;
+ pgm->teardown = pickit2_teardown;
+ // pgm->page_size = 256; // not sure what this does... maybe the max page size that the page read/write function can handle
+
+ strncpy(pgm->type, "pickit2", sizeof(pgm->type));
+}
+#else
+static int pickit2_nousb_open (struct programmer_t *pgm, char * name) {
+ avrdude_message(MSG_INFO,
+#ifdef WIN32NATIVE
+ "%s: error: no usb or hid support. Please compile again with libusb or HID support from Win32 DDK installed.\n",
+#else
+ "%s: error: no usb support. Please compile again with libusb installed.\n",
+#endif
+ progname);
+
+ return -1;
+}
+
+void pickit2_initpgm (PROGRAMMER * pgm)
+{
+ /*
+ * mandatory functions - these are called without checking to see
+ * whether they are assigned or not
+ */
+
+ pgm->open = pickit2_nousb_open;
+
+ strncpy(pgm->type, "pickit2", sizeof(pgm->type));
+}
+
+#endif /* defined(HAVE_LIBUSB) || (defined(WIN32NATIVE) && defined(HAVE_LIBHID)) */
+
+const char pickit2_desc[] = "Microchip's PICkit2 Programmer";
+