/* change by Xiaofan */
/* fsusb.c for the Win32 platform */
/* modified from the original Linux program at
http://internetking.org/fsusb/ by Rick Luddy.
*/
/*
** This file is part of fsusb_picdem
**
** fsusb_picdem 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.
**
** fsusb_picdem 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 fsusb_picdem; if not, write to the Free Software
** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
** 02110-1301, USA
*/
/*
** portions from usb_pickit by Orion Sky Lawlor, olawlor@acm.org
*/
/* change by Xiaofan */
/* Email: xiaofan AT sg dot pepperl-fuchs dot com */
/* Port to Windows platform using MingW and libusb-win32
MingW version: gcc-3.4.2 (mingw special)
libusb-win32: 0.1.10.1
To use the program, both the following two options can be used.
1) install libusb-win32 filter driver and use the original Microchip driver
2) do not install the filter driver, use the libusb-win32 device driver
instead of Microchip driver.
Test platform: Windows XP SP2
*/
/* Special thanks goes to Stephan Meyer, the developer of libusb-win32
for the porting efforts
*/
#include /* libusb header */
#include /* for geteuid */
#include
#include
#include "bootload.h"
#include "fsusb.h"
const static int fsusb_vendorID=0x04d8; // Microchip, Inc
const static int fsusb_productID=0x000b; // PICDEM-FS USB
const static int fsusb_configuration=1; /* 1: bootloader
* ### may change in future firmware versions
*/
const static int fsusb_interface=0;
/* change by Xiaofan */
/* libusb-win32 requires the correct endpoint address
including the direction bits. This is the most important
differece between libusb-win32 and libusb.
*/
//const static int fsusb_endpoint=1;
const static int fsusb_endpoint_in=1;
const static int fsusb_endpoint_out=0x81; /* first endpoint for everything
* ### may change in future firmware versions
*/
const static int fsusb_timeout=1000; /* timeout in ms */
void bad(const char *why)
{
fprintf(stderr,"Fatal error> %s\n",why);
exit(17);
}
void recv_usb(picdem_handle *d, int len, byte *dest) {
int r;
/* change by Xiaofan */
//r=usb_bulk_read(d, fsusb_endpoint, dest, len, fsusb_timeout);
r=usb_bulk_read(d, fsusb_endpoint_out, dest, len, fsusb_timeout);
if (r!=len) {
perror("usb PICDEM read");
bad("USB read failed");
}
// printf("read %i bytes\n", r);
}
void rjl_request_version(picdem_handle *d, unsigned char *ret)
{
int r;
char buf[4];
// ### "\0\0\0\0\0" may not be correct in future firmware versions
/* change by Xiaofan */
//r=usb_bulk_write(d, fsusb_endpoint, "\0\0\0\0\0", 5, fsusb_timeout);
r=usb_bulk_write(d, fsusb_endpoint_in, "\0\0\0\0\0", 5, fsusb_timeout);
if(r != 5) {
perror("usb_bulk_write");
bad("rjl_request_version(): USB write failed");
}
// command, len, minor, major
recv_usb(d,4,buf);
ret[0]=buf[3];
ret[1]=buf[2];
}
void rjl_request_flash(picdem_handle *d, int offset, int len, bl_packet *pack)
{
int r;
bl_packet p;
p.command=READ_FLASH;
p.address.low=(offset & 0xff)>>0;
p.address.high=(offset & 0xff00)>>8;
p.address.upper=(offset & 0xf0000)>>16;
p.len=len;
/* change by Xiaofan */
//r=usb_bulk_write(d, fsusb_endpoint, (char*)&p, 5, fsusb_timeout);
r=usb_bulk_write(d, fsusb_endpoint_in, (char*)&p, 5, fsusb_timeout);
if(r != 5) {
perror("usb_bulk_write");
bad("rjl_request_flash(): USB write failed");
}
recv_usb(d,len+5,(byte*)pack);
}
/* write in 16-byte boundary-aligned blocks only in this version of
* the bootloader
*/
void rjl_write_flash(picdem_handle *d, int offset, int len, byte *data, bl_packet *pack)
{
int r;
bl_packet p;
int i;
byte retbuf[5];
if(offset & 0x0f) {
printf("*** WARNING: not boundary-aligned\n");
return;
}
if(len != 16) {
printf("*** WARNING: not 16 bytes\n");
return;
}
p.command=WRITE_FLASH;
p.address.low=(offset & 0xff)>>0;
p.address.high=(offset & 0xff00)>>8;
p.address.upper=(offset & 0xf0000)>>16;
p.len=len;
for(i=0;i>0;
p.address.high=(offset & 0xff00)>>8;
p.address.upper=(offset & 0xf0000)>>16;
p.len=1;
/* change by Xiaofan */
//r=usb_bulk_write(d, fsusb_endpoint, (char*)&p, 5, fsusb_timeout);
r=usb_bulk_write(d, fsusb_endpoint_in, (char*)&p, 5, fsusb_timeout);
if(r != 5) {
perror("usb_bulk_write");
bad("rjl_write_block(): USB write failed");
}
recv_usb(d,1,retbuf);
// printf("erase reply is %x\n", retbuf[0]);
for(subblock=0;subblock<4;subblock++) {
p.command=WRITE_FLASH;
p.address.low=((offset+16*subblock) & 0xff)>>0;
p.address.high=((offset+16*subblock) & 0xff00)>>8;
p.address.upper=((offset+16*subblock) & 0xf0000)>>16;
p.len=16;
memcpy(p.data, data+(subblock*16), 16);
/* change by Xiaofan */
// r=usb_bulk_write(d, fsusb_endpoint, (char*)&p, 5+16, fsusb_timeout);
r=usb_bulk_write(d, fsusb_endpoint_in, (char*)&p, 5+16, fsusb_timeout);
if(r != 5+16) {
perror("usb_bulk_write");
bad("rjl_write_block(): USB write failed");
}
recv_usb(d,1,retbuf);
// printf("write reply is %x\n", retbuf[0]);
}
}
// 59ish bytes max
void rjl_write_config_block(picdem_handle *d, int offset, int len, byte *data)
{
int r;
bl_packet p;
// int i;
byte retbuf[5];
if(len>=BL_DATA_LEN) {
printf("*** ERROR: config block too big\n");
return;
}
/* The firmware clips the erase to a 64-byte block, which
* we don't worry about because in any real device
* the config starts on a 64-byte boundary.
*/
p.command=ERASE_FLASH;
p.address.low=(offset & 0xff)>>0;
p.address.high=(offset & 0xff00)>>8;
p.address.upper=(offset & 0xf0000)>>16;
p.len=1;
/* change by Xiaofan */
//r=usb_bulk_write(d, fsusb_endpoint, (char*)&p, 5, fsusb_timeout);
r=usb_bulk_write(d, fsusb_endpoint_in, (char*)&p, 5, fsusb_timeout);
if(r != 5) {
perror("usb_bulk_write");
bad("rjl_write_config_block(): USB write failed");
}
recv_usb(d,1,retbuf);
// printf("erase reply is %x\n", retbuf[0]);
// config writes have no alignment restriction
p.command=WRITE_CONFIG;
p.address.low=(offset & 0xff)>>0;
p.address.high=(offset & 0xff00)>>8;
p.address.upper=(offset & 0xf0000)>>16;
p.len=len;
memcpy(p.data, data, len);
/* change by Xiaofan */
//r=usb_bulk_write(d, fsusb_endpoint, (char*)&p, 5+len, fsusb_timeout);
r=usb_bulk_write(d, fsusb_endpoint_in, (char*)&p, 5+len, fsusb_timeout);
if(r != 5+len) {
perror("usb_bulk_write");
bad("rjl_write_config_block(): USB write failed");
}
recv_usb(d,1,retbuf);
// printf("write reply is %x\n", retbuf[0]);
}
// write on 64-byte boundaries only in blocks of 64 bytes
void rjl_erase_block(picdem_handle *d, int offset)
{
int r;
bl_packet p;
byte retbuf[5];
if(offset & 0x3f) {
printf("*** WARNING: not boundary-aligned\n");
return;
}
p.command=ERASE_FLASH;
p.address.low=(offset & 0xff)>>0;
p.address.high=(offset & 0xff00)>>8;
p.address.upper=(offset & 0xf0000)>>16;
p.len=1;
/* change by Xiaofan */
//r=usb_bulk_write(d, fsusb_endpoint, (char*)&p, 5, fsusb_timeout);
r=usb_bulk_write(d, fsusb_endpoint_in, (char*)&p, 5, fsusb_timeout);
if(r != 5) {
perror("usb_bulk_write");
bad("rjl_erase_block(): USB write failed");
}
recv_usb(d,1,retbuf);
// printf("erase reply is %x\n", retbuf[0]);
}
/* Find the first USB device with this vendor and product.
* Exits on errors, like if the device couldn't be found. -osl
*
* This function is heavily based upon Orion Sky Lawlor's
* usb_pickit program, which was a very useful reference
* for all the USB stuff. Thanks!
*/
picdem_handle *rjl_fsusb_open(void)
{
struct usb_device *device;
struct usb_bus* bus;
unsigned char buf[2];
/* change by Xiaofan */
/* remove call to geteuid() for Windows */
/*
if (geteuid()!=0) {
bad("This program must be run as root, or made setuid root");
}
*/
#ifdef USB_DEBUG
usb_debug=4;
#endif
// added the two debug lines
usb_set_debug(255);
printf("setting USB debug on by adding usb_set_debug(255) \n");
//End of added codes
printf("Locating USB Microchip(tm) PICDEM-FS USB(tm) (vendor 0x%04x/product 0x%04x)\n",
fsusb_vendorID,fsusb_productID);
/* (libusb setup code stolen from John Fremlin's cool "usb-robot") -osl */
usb_init();
usb_find_busses();
usb_find_devices();
/* change by Xiaofan */
/* libusb-win32: not using global variable like usb_busses*/
/* for (bus=usb_busses;bus!=NULL;bus=bus->next) */
for (bus=usb_get_busses();bus!=NULL;bus=bus->next) {
struct usb_device* usb_devices = bus->devices;
for(device=usb_devices;device!=NULL;device=device->next) {
if (device->descriptor.idVendor == fsusb_vendorID
&& device->descriptor.idProduct == fsusb_productID) {
usb_dev_handle *d;
printf( "Found USB PICDEM-FS USB as device '%s' on USB bus %s\n",
device->filename,
device->bus->dirname);
d=usb_open(device);
if (d) { /* This is our device-- claim it */
if (usb_set_configuration(d,fsusb_configuration)) {
bad("Error setting USB configuration.\n");
}
if (usb_claim_interface(d,fsusb_interface)) {
bad("Claim failed-- the USB PICDEM is in use by another driver.\n"
"Do a `dmesg` to see which kernel driver has claimed it--\n"
"You may need to `rmmod hid` or patch your kernel's hid driver.\n");
}
rjl_request_version(d, buf);
printf("Communication established. Onboard firmware version is %d.%d\n",
(int)buf[0],(int)buf[1]);
if (buf[0]!=0x01u) {
bad("This PICDEM's version is too new (only support version 1.x !)\n");
}
return d;
} else
bad("Open failed for USB device");
}
/* else some other vendor's device-- keep looking... -osl*/
}
}
bad("Could not find USB PICDEM device--\n"
"you might try lsusb to see if it's actually there.");
return NULL;
}