/* * avrdude - A Downloader/Uploader for AVR device programmers * Copyright (C) 2006 Thomas Fischl * Copyright 2007 Joerg Wunsch * * 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 */ /* $Id: usbasp.c 897 2010-01-08 18:33:23Z fischl $ */ /* * Interface to the USBasp programmer. * * See http://www.fischl.de/usbasp/ */ #include "ac_cfg.h" #include #include #include #include #include #include #include "avrdude.h" #include "avr.h" #include "pgm.h" #include "usbasp.h" static int prot_ver = 0; static int prot_type = 0; #define is_pditpi() ((prot_type==USBASP_V2_TPI)||(prot_type ==USBASP_V2_PDI)) #define is_pdi() (prot_type ==USBASP_V2_PDI) #define is_tpi() (prot_type==USBASP_V2_TPI)) #define XXX // temporary debugging #ifdef HAVE_LIBUSB #include /* * Private data for this programmer. */ struct pdata { usb_dev_handle *usbhandle; int sckfreq_hz; }; #define PDATA(pgm) ((struct pdata *)(pgm->cookie)) static void usbasp_setup(PROGRAMMER * pgm) { if ((pgm->cookie = malloc(sizeof(struct pdata))) == 0) { fprintf(stderr, "%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); } /* * wrapper for usb_control_msg call */ static int usbasp_transmit(PROGRAMMER * pgm, unsigned char receive, unsigned char functionid, unsigned char send[4], unsigned char * buffer, int buffersize) { int nbytes; 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){ fprintf(stderr, "%s: error: usbasp_transmit: %s\n", progname, usb_strerror()); exit(1); } 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 */ 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; fprintf(stderr, "%s: Warning: cannot open USB device: %s\n", progname, usb_strerror()); continue; } if(vendorName == NULL && productName == NULL){ /* name does not matter */ break; } /* now check whether the names match: */ len = usb_get_string_simple(handle, dev->descriptor.iManufacturer, string, sizeof(string)); if(len < 0){ errorCode = USB_ERROR_IO; fprintf(stderr, "%s: Warning: cannot query manufacturer for device: %s\n", progname, usb_strerror()); }else{ errorCode = USB_ERROR_NOTFOUND; if (verbose > 1) fprintf(stderr, "%s: seen device from vendor ->%s<-\n", progname, string); if(strcmp(string, vendorName) == 0){ len = usb_get_string_simple(handle, dev->descriptor.iProduct, string, sizeof(string)); if(len < 0){ errorCode = USB_ERROR_IO; fprintf(stderr, "%s: Warning: cannot query product for device: %s\n", progname, usb_strerror()); }else{ errorCode = USB_ERROR_NOTFOUND; if (verbose > 1) fprintf(stderr, "%s: seen product ->%s<-\n", progname, string); if(strcmp(string, productName) == 0) break; } } } usb_close(handle); handle = NULL; } } if(handle) break; } if(handle != NULL){ errorCode = 0; *device = handle; } return errorCode; } static int usbasp_open(PROGRAMMER * pgm, char * port) { char *p; char vend_name[128]; char prod_name[128]; vend_name[0] = 0; vend_name[127] = 0; prod_name[0] = 0; prod_name[127] = 0; p = strchr(port,':'); if (p == port) { strncpy(prod_name, port+1, 127); } else if (p && p[1] == 0) { strncpy(vend_name, port, 127); vend_name[strlen(vend_name)-1] = 0; } else if (p) { strncpy(vend_name, port, 127); p = strchr(vend_name,':'); if (p) { *p = 0; strcpy(prod_name, p+1); } } if (!vend_name[0]) strcpy(vend_name, "www.fischl.de"); if (!prod_name[0]) strcpy(prod_name, "USBasp"); usb_init(); if ((usbOpenDevice(&PDATA(pgm)->usbhandle, USBASP_SHARED_VID, vend_name , USBASP_SHARED_PID, prod_name) != 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) { /* no USBasp found */ fprintf(stderr, "%s: error: could not find USB device " "\"USBasp\" with vid=0x%x pid=0x%x\n", progname, USBASP_SHARED_VID, USBASP_SHARED_PID); exit(1); } else { /* found USBasp with old IDs */ fprintf(stderr, "%s: Warning: Found USB device \"USBasp\" with " "old VID/PID! Please update firmware of USBasp!\n", progname); } } return 0; } /* * parse the -E string */ static int usbasp_parseexitspecs(PROGRAMMER * pgm, char *s) { char *cp; pgm->exit_reset = EXIT_RESET_DISABLED; // default while ((cp = strtok(s, ","))) { if (strcmp(cp, "reset") == 0) { pgm->exit_reset = EXIT_RESET_ENABLED; } else if (strcmp(cp, "noreset") == 0) { pgm->exit_reset = EXIT_RESET_DISABLED; } else { return -1; } s = 0; /* strtok() should be called with the actual string only once */ } return 0; } static void usbasp_close(PROGRAMMER * pgm) { unsigned char temp[4]; if (pgm->exit_reset == EXIT_RESET_ENABLED) { memset(temp, 0, sizeof(temp)); usbasp_transmit(pgm, 1, USBASP_FUNC_DISCONNECT, temp, temp, sizeof(temp)); } usb_close(PDATA(pgm)->usbhandle); } static int usbasp_initialize(PROGRAMMER * pgm, AVRPART * p) { unsigned char temp[4]; memset(temp, 0, sizeof(temp)); /* USBasp v2 */ if (!strncmp("USBasp2 (TPI)", pgm->desc, 13)) { prot_ver = USBASP_PROT_V2; prot_type = USBASP_V2_TPI; } else if (!strncmp("USBasp2 (PDI)", pgm->desc, 13)) { prot_ver = USBASP_PROT_V2; prot_type = USBASP_V2_PDI; } else if (!strncmp("USBasp2", pgm->desc, 7)) { prot_ver = USBASP_PROT_V2; prot_type = USBASP_V2_ISP2; if (p->flags & AVRPART_HAS_TPI) { prot_type = USBASP_V2_TPI; // select TPI } else if (p->flags & AVRPART_HAS_PDI) { prot_type = USBASP_V2_PDI; // select PDI } } else if (p->flags & AVRPART_HAS_TPI) { prot_ver = USBASP_PROT_V2; // USBASP v2 protocol prot_type = USBASP_V2_TPI; // select TPI } else if (p->flags & AVRPART_HAS_PDI) { prot_ver = USBASP_PROT_V2; // USBASP v2 protocol prot_type = USBASP_V2_PDI; // select PDI } temp[1] = prot_ver; temp[0] = prot_type; #ifdef XXX fprintf(stderr, "USBASP: ver %d type %d\n",prot_ver, prot_type); #endif /* set sck period */ pgm->set_sck_period(pgm, pgm->bitclock); /* connect to target device */ usbasp_transmit(pgm, 1, USBASP_FUNC_CONNECT, temp, temp, sizeof(temp)); #ifdef XXX if (is_pdi()) { fprintf(stderr, "USBASP_FUNC_CONNECT:\n"); } #endif /* wait, so device is ready to receive commands */ usleep(100000); return pgm->program_enable(pgm, p); } 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; } static int usbasp_cmd(PROGRAMMER * pgm, unsigned char cmd[4], unsigned char res[4]) { int nbytes = usbasp_transmit(pgm, 1, USBASP_FUNC_TRANSMIT, cmd, res, sizeof(res)); if(nbytes != 4){ fprintf(stderr, "%s: error: wrong responds size\n", progname); return -1; } return 0; } static int usbasp_set_longaddr(PROGRAMMER * pgm, AVRPART * p, unsigned long addr) { unsigned char cmd[4]; unsigned char temp[4]; memset(temp, 0, sizeof(temp)); cmd[0] = addr & 0xFF; cmd[1] = addr >> 8; cmd[2] = addr >> 16; cmd[3] = addr >> 24; usbasp_transmit(pgm, 1, USBASP_FUNC_SETLONGADDRESS, cmd, temp, sizeof(temp)); return 0; } static int usbasp_chk_busy(PROGRAMMER * pgm, AVRPART * p) { unsigned char cmd[4]; unsigned char res[4]; memset(res, 0, sizeof(res)); cmd[0] = ISPCMD_CHK_BUSY; cmd[1] = 0; cmd[2] = 0; cmd[3] = 0; pgm->cmd(pgm, cmd, res); return res[3]; } static int usbasp_read_cs(PROGRAMMER * pgm, AVRPART * p, unsigned long addr) { unsigned char cmd[4]; unsigned char res[4]; memset(res, 0, sizeof(res)); cmd[0] = ISPCMD_READ_EEPROM; cmd[1] = (addr >> 8); cmd[2] = addr; cmd[3] = 0; pgm->cmd(pgm, cmd, res); return ((int)res[2] << 8) | res[3]; } static int usbasp_write_cs(PROGRAMMER * pgm, AVRPART * p, unsigned long addr, unsigned char val) { unsigned char cmd[4]; unsigned char res[4]; memset(res, 0, sizeof(res)); cmd[0] = ISPCMD_WRITE_EEPROM; cmd[1] = (addr >> 8); cmd[2] = addr; cmd[3] = val; pgm->cmd(pgm, cmd, res); return 0; } static int usbasp_pdi_select(PROGRAMMER * pgm, AVRPART * p, char space) { unsigned char cmd[4]; unsigned char res[4]; memset(res, 0, sizeof(res)); cmd[0] = ISPCMD_ISP_CONF; cmd[1] = ISPCONF_SET_SPACE; cmd[2] = 0; cmd[3] = space; pgm->cmd(pgm, cmd, res); return 0; } #if 0 static int usbasp_pdi_reset(PROGRAMMER * pgm, int off) { unsigned char cmd[4]; unsigned char res[4]; memset(res, 0, sizeof(res)); cmd[0] = ISPCMD_ISP_CONF; cmd[1] = ISPCONF_RESET; cmd[2] = 0; cmd[3] = (off)? 0x00: 0x59; pgm->cmd(pgm, cmd, res); return 0; } #endif static int usbasp_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; #ifdef XXX if (is_pdi()) { fprintf(stderr, "USBASP_FUNC_ENABLEPROG:"); fflush(stderr); } #endif int nbytes = usbasp_transmit(pgm, 1, USBASP_FUNC_ENABLEPROG, cmd, res, sizeof(res)); if ((nbytes != 1) | (res[0] != 0)) { fprintf(stderr, "%s: error: programm enable: target doesn't answer. %x \n", progname, res[0]); return -1; } return 0; } static int usbasp_chip_erase(PROGRAMMER * pgm, AVRPART * p) { unsigned char cmd[4]; unsigned char res[4]; if (!is_pditpi() && (p->op[AVR_OP_CHIP_ERASE] == NULL)) { fprintf(stderr, "chip erase instruction not defined for part \"%s\"\n", p->desc); return -1; } memset(cmd, 0, sizeof(cmd)); if (!is_pditpi()) { avr_set_bits(p->op[AVR_OP_CHIP_ERASE], cmd); } else { cmd[0] = ISPCMD_ISP_CONF; cmd[1] = ISPCONF_CHIP_ERASE; cmd[2] = 0; cmd[3] = 0; } pgm->cmd(pgm, cmd, res); usleep(p->chip_erase_delay); pgm->initialize(pgm, p); return 0; } static int usbasp_read_sig_bytes(PROGRAMMER * pgm, AVRPART * p, AVRMEM *m) { int i; unsigned char cmd[4]; unsigned char res[4]; for (i=0; i<3; i++) { memset(cmd, 0, sizeof(cmd)); cmd[0] = ISPCMD_READ_SIGNATURE; cmd[1] = 0; cmd[2] = i; cmd[3] = 0; pgm->cmd(pgm, cmd, res); m->buf[i] = res[3]; } #ifdef XXX if (is_pdi()) { int r; fprintf(stderr, "ISPCMD_READ_SIGNATURE: %02x %02x %02x\n",m->buf[0],m->buf[1],m->buf[2]); r = usbasp_read_cs(pgm, p,PDI_CS_STATUS); fprintf(stderr," -- PDI_CS_STATUS = 0x%04x \n",r); r = usbasp_read_cs(pgm, p,PDI_CS_CTRL); fprintf(stderr," -- PDI_CS_CTRLA = 0x%04x \n",r); r = usbasp_write_cs(pgm, p,PDI_CS_CTRL, 0x02); r = usbasp_read_cs(pgm, p,PDI_CS_CTRL); fprintf(stderr," -- PDI_CS_CTRLA = 0x%04x \n",r); } #endif return 0; } static int usbasp_read_byte(PROGRAMMER * pgm, AVRPART * p, AVRMEM * m, unsigned long addr, unsigned char * value) { int n; int function; unsigned char buffer[4]; unsigned char cmd[4]; if (!is_pditpi()) { return avr_read_byte_default(pgm, p, m, addr, value); } function = USBASP_FUNC_READFLASH; addr += m->offset; if (prot_type == USBASP_V2_TPI) { if (strcmp(m->desc, "eeprom") == 0) { } if (strcmp(m->desc, "fuse") == 0) { } else if (strcmp(m->desc, "calibration") == 0) { } else if (strcmp(m->desc, "lockbits") == 0) { } else { return -2; } } else if (prot_type == USBASP_V2_PDI) { if (strcmp(m->desc, "eeprom") == 0) { usbasp_pdi_select(pgm, p, ISPCONF_SPACE_EEPROM); } else if (strcmp(m->desc, "signature") == 0) { usbasp_pdi_select(pgm, p, ISPCONF_SPACE_FLASH); } else if (strncmp(m->desc, "fuse", 4) == 0) { usbasp_pdi_select(pgm, p, ISPCONF_SPACE_FUSE); } else if (strcmp(m->desc, "lock") == 0) { usbasp_pdi_select(pgm, p, ISPCONF_SPACE_LOCK); } else if (strcmp(m->desc, "calibration") == 0) { usbasp_pdi_select(pgm, p, ISPCONF_SPACE_CALIB); } else { return -2; } } else { return -2; } /* set address */ usbasp_set_longaddr(pgm, p, addr); /* send command with address */ cmd[0] = addr & 0xFF; cmd[1] = addr >> 8; cmd[2] = 0; cmd[3] = 0; n = usbasp_transmit(pgm, 1, function, cmd, buffer, 1); if (n != 1) { fprintf(stderr, "%s: error: wrong reading bytes %x\n", progname, n); exit(1); } *value = buffer[0]; return 0; } static int usbasp_write_byte(PROGRAMMER * pgm, AVRPART * p, AVRMEM * m, unsigned long addr, unsigned char data) { int blocksize = 1; int n; int function; unsigned char buffer[4]; unsigned char cmd[4]; if (!is_pditpi()) { return avr_write_byte_default(pgm, p, m, addr, data); } memset(buffer,0, sizeof(buffer)); buffer[0] = data; function = USBASP_FUNC_WRITEFLASH; addr += m->offset; if (prot_type == USBASP_V2_TPI) { if (strcmp(m->desc, "fuse") == 0) { } else if (strcmp(m->desc, "calibration") == 0) { } else if (strcmp(m->desc, "lockbits") == 0) { } else { return -2; } usbasp_write_cs(pgm, p, TPI_NVMCMD, TPI_NVM_WRITE); blocksize = 2; } else if (prot_type == USBASP_V2_PDI) { if (strncmp(m->desc, "fuse", 4) == 0) { usbasp_write_cs(pgm, p, PDI_NVM_CMD, PDI_NVM_WRITE_FUSE); } else if (strcmp(m->desc, "lock") == 0) { usbasp_write_cs(pgm, p, PDI_NVM_CMD, PDI_NVM_WRITE_LOCKBIT); } else { return -2; } blocksize = 1; } else { return -2; } /* set address */ usbasp_set_longaddr(pgm, p, addr); cmd[0] = addr & 0xFF; cmd[1] = addr >> 8; cmd[2] = 0; cmd[3] = USBASP_BLOCKFLAG_FIRST|USBASP_BLOCKFLAG_LAST; n = usbasp_transmit(pgm, 0, function, cmd, buffer, blocksize); if (n != blocksize) { fprintf(stderr, "%s: error: wrong count at writing %x\n", progname, n); exit(1); } usbasp_chk_busy(pgm, p); return 0; } static int usbasp_paged_load(PROGRAMMER * pgm, AVRPART * p, AVRMEM * m, int page_size, int n_bytes) { int n; unsigned char cmd[4]; int address = 0; int wbytes = n_bytes; int blocksize; unsigned char * buffer = m->buf; int function = USBASP_FUNC_READFLASH; if (!is_pditpi()) { if (strcmp(m->desc, "flash") == 0) { function = USBASP_FUNC_READFLASH; } else if (strcmp(m->desc, "eeprom") == 0) { function = USBASP_FUNC_READEEPROM; } else { return -2; } } else if (prot_type == USBASP_V2_TPI) { address += m->offset; if (strcmp(m->desc, "flash") == 0) { } else { return -2; } } else if (prot_type == USBASP_V2_PDI) { address += m->offset; if (strcmp(m->desc, "eeprom") == 0) { usbasp_pdi_select(pgm, p, ISPCONF_SPACE_EEPROM); } else if (strcmp(m->desc, "boot") == 0) { usbasp_pdi_select(pgm, p, ISPCONF_SPACE_BOOT); } else if (strcmp(m->desc, "application") == 0) { usbasp_pdi_select(pgm, p, ISPCONF_SPACE_APP); } else if (strcmp(m->desc, "apptable") == 0) { usbasp_pdi_select(pgm, p, ISPCONF_SPACE_APP); } else if (strcmp(m->desc, "flash") == 0) { usbasp_pdi_select(pgm, p, ISPCONF_SPACE_FLASH); } else if (strcmp(m->desc, "prodsig") == 0) { usbasp_pdi_select(pgm, p, ISPCONF_SPACE_FLASH); } else if (strcmp(m->desc, "usersig") == 0) { usbasp_pdi_select(pgm, p, ISPCONF_SPACE_USERSIG); } 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 */ usbasp_set_longaddr(pgm, p, address); /* 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) { fprintf(stderr, "%s: error: wrong reading bytes %x\n", progname, n); exit(1); } buffer += blocksize; address += blocksize; report_progress (address, n_bytes, NULL); } return n_bytes; } static int usbasp_paged_write(PROGRAMMER * pgm, AVRPART * p, AVRMEM * m, int page_size, int n_bytes) { int n; unsigned char cmd[4]; int address = 0; int wbytes = n_bytes; int blocksize; unsigned char * buffer = m->buf; unsigned char blockflags = USBASP_BLOCKFLAG_FIRST; int function = USBASP_FUNC_WRITEFLASH;; if (!is_pditpi()) { if (strcmp(m->desc, "flash") == 0) { function = USBASP_FUNC_WRITEFLASH; } else if (strcmp(m->desc, "eeprom") == 0) { function = USBASP_FUNC_WRITEEEPROM; } else { return -2; } } else if (prot_type == USBASP_V2_TPI) { address += m->offset; if (strcmp(m->desc, "flash") == 0) { } else { return -2; } } else if (prot_type == USBASP_V2_PDI) { address += m->offset; if (strcmp(m->desc, "eeprom") == 0) { usbasp_pdi_select(pgm, p, ISPCONF_SPACE_EEPROM); } else if (strcmp(m->desc, "boot") == 0) { usbasp_pdi_select(pgm, p, ISPCONF_SPACE_BOOT); } else if (strcmp(m->desc, "application") == 0) { usbasp_pdi_select(pgm, p, ISPCONF_SPACE_APP); } else if (strcmp(m->desc, "usersig") == 0) { usbasp_pdi_select(pgm, p, ISPCONF_SPACE_USERSIG); } else if (strcmp(m->desc, "flash") == 0) { usbasp_pdi_select(pgm, p, ISPCONF_SPACE_FLASH); } 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; blockflags |= USBASP_BLOCKFLAG_LAST; } wbytes -= blocksize; /* set address */ usbasp_set_longaddr(pgm, p, address); /* 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) { fprintf(stderr, "%s: error: wrong count at writing %x\n", progname, n); exit(1); } buffer += blocksize; address += blocksize; report_progress (address, n_bytes, NULL); } 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 } }; static struct sckoptions_t usbaspSCKoptions2[] = { { USBASP_ISP_SCK_8000, 8000000 }, { USBASP_ISP_SCK_4000, 4000000 }, { USBASP_ISP_SCK_2000, 2000000 }, { USBASP_ISP_SCK_1000, 1000000 }, { USBASP_ISP_SCK_500, 500000 }, { USBASP_ISP_SCK_250, 250000 }, { USBASP_ISP_SCK_125, 125000 }, { USBASP_ISP_SCK_62_5, 62500 }, { 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_set_sck_period(PROGRAMMER *pgm, double sckperiod) { char clockoption = USBASP_ISP_SCK_AUTO; struct sckoptions_t *sckopt; int sckopt_len; unsigned char res[4]; unsigned char cmd[4]; memset(cmd, 0, sizeof(cmd)); memset(res, 0, sizeof(res)); if (prot_ver == USBASP_PROT_V2) { sckopt = usbaspSCKoptions2; sckopt_len = sizeof(usbaspSCKoptions2)/sizeof(usbaspSCKoptions2[0]); } else { sckopt = usbaspSCKoptions; sckopt_len = sizeof(usbaspSCKoptions)/sizeof(usbaspSCKoptions[0]); } /* reset global sck frequency to auto */ PDATA(pgm)->sckfreq_hz = 0; if (sckperiod == 0) { /* auto sck set */ if (verbose >= 1) fprintf(stderr, "%s: auto set sck period (because given equals null)\n", progname); } else { int sckfreq = 1 / sckperiod; /* sck in Hz */ int usefreq = 0; if (verbose >= 2) fprintf(stderr, "%s: try to set SCK period to %g s (= %i Hz)\n", progname, sckperiod, sckfreq); if (sckfreq >= sckopt[0].frequency) { clockoption = sckopt[0].id; usefreq = sckopt[0].frequency; } else { /* find clock option next to given clock */ int i; for (i = 0; i < sckopt_len; i++) { if (sckfreq >= sckopt[i].frequency - 1) { /* subtract 1 to compensate round errors */ clockoption = sckopt[i].id; usefreq = sckopt[i].frequency; break; } } } /* save used sck frequency */ PDATA(pgm)->sckfreq_hz = usefreq; fprintf(stderr, "%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)) { fprintf(stderr, "%s: warning: cannot set sck period. please check for usbasp firmware update.\n", progname); return -1; } return 0; } 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_program_enable; pgm->chip_erase = usbasp_chip_erase; pgm->cmd = usbasp_cmd; pgm->open = usbasp_open; pgm->close = usbasp_close; pgm->read_byte = usbasp_read_byte; pgm->write_byte = usbasp_write_byte; pgm->parseexitspecs = usbasp_parseexitspecs; pgm->read_sig_bytes = usbasp_read_sig_bytes; /* * optional functions */ pgm->paged_write = usbasp_paged_write; pgm->paged_load = usbasp_paged_load; pgm->setup = usbasp_setup; pgm->teardown = usbasp_teardown; pgm->set_sck_period = usbasp_set_sck_period; } #else /* HAVE_LIBUSB */ static int usbasp_nousb_open (struct programmer_t *pgm, char * name) { fprintf(stderr, "%s: error: no usb support. please compile again with libusb installed.\n", progname); exit(1); } void usbasp_initpgm(PROGRAMMER * pgm) { strcpy(pgm->type, "usbasp"); pgm->open = usbasp_nousb_open; } #endif /* HAVE_LIBUSB */