1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/tools/fsusb/fsusb.c Tue Jan 29 22:31:52 2008 +0100
1.3 @@ -0,0 +1,388 @@
1.4 +/*
1.5 +** This file is part of fsusb_picdem
1.6 +**
1.7 +** fsusb_picdem is free software; you can redistribute it and/or
1.8 +** modify it under the terms of the GNU General Public License as
1.9 +** published by the Free Software Foundation; either version 2 of the
1.10 +** License, or (at your option) any later version.
1.11 +**
1.12 +** fsusb_picdem is distributed in the hope that it will be useful, but
1.13 +** WITHOUT ANY WARRANTY; without even the implied warranty of
1.14 +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
1.15 +** General Public License for more details.
1.16 +**
1.17 +** You should have received a copy of the GNU General Public License
1.18 +** along with fsusb_picdem; if not, write to the Free Software
1.19 +** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
1.20 +** 02110-1301, USA
1.21 +*/
1.22 +
1.23 +/*
1.24 +** portions from usb_pickit by Orion Sky Lawlor, olawlor@acm.org
1.25 +*/
1.26 +
1.27 +#include <usb.h> /* libusb header */
1.28 +#include <unistd.h> /* for geteuid */
1.29 +#include <stdio.h>
1.30 +#include <string.h>
1.31 +#include "bootload.h"
1.32 +#include "fsusb.h"
1.33 +
1.34 +
1.35 +const static int fsusb_vendorID=0x04d8; // Microchip, Inc
1.36 +const static int fsusb_productID=0x000b; // PICDEM-FS USB
1.37 +const static int fsusb_configuration=1; /* 1: bootloader
1.38 + * ### may change in future firmware versions
1.39 + */
1.40 +const static int fsusb_interface=0;
1.41 +const static int fsusb_endpoint=1; /* first endpoint for everything
1.42 + * ### may change in future firmware versions
1.43 + */
1.44 +const static int fsusb_timeout=1000; /* timeout in ms */
1.45 +
1.46 +
1.47 +
1.48 +void bad(const char *why)
1.49 +{
1.50 + fprintf(stderr,"Fatal error> %s\n",why);
1.51 + exit(17);
1.52 +}
1.53 +
1.54 +
1.55 +
1.56 +void recv_usb(picdem_handle *d, int len, byte *dest) {
1.57 + int r;
1.58 +
1.59 + r=usb_bulk_read(d, fsusb_endpoint, dest, len, fsusb_timeout);
1.60 +
1.61 + if (r!=len) {
1.62 + perror("usb PICDEM read");
1.63 + bad("USB read failed");
1.64 + }
1.65 + // printf("read %i bytes\n", r);
1.66 +}
1.67 +
1.68 +
1.69 +
1.70 +void rjl_request_version(picdem_handle *d, unsigned char *ret)
1.71 +{
1.72 + int r;
1.73 + char buf[4];
1.74 +
1.75 + // ### "\0\0\0\0\0" may not be correct in future firmware versions
1.76 + r=usb_bulk_write(d, fsusb_endpoint, "\0\0\0\0\0", 5, fsusb_timeout);
1.77 + if(r != 5) {
1.78 + perror("usb_bulk_write");
1.79 + bad("rjl_request_version(): USB write failed");
1.80 + }
1.81 +
1.82 + // command, len, minor, major
1.83 + recv_usb(d,4,buf);
1.84 + ret[0]=buf[3];
1.85 + ret[1]=buf[2];
1.86 +}
1.87 +
1.88 +
1.89 +
1.90 +void rjl_request_flash(picdem_handle *d, int offset, int len, bl_packet *pack)
1.91 +{
1.92 + int r;
1.93 + bl_packet p;
1.94 +
1.95 +
1.96 + p.command=READ_FLASH;
1.97 + p.address.low=(offset & 0xff)>>0;
1.98 + p.address.high=(offset & 0xff00)>>8;
1.99 + p.address.upper=(offset & 0xf0000)>>16;
1.100 + p.len=len;
1.101 +
1.102 +
1.103 + r=usb_bulk_write(d, fsusb_endpoint, (char*)&p, 5, fsusb_timeout);
1.104 + if(r != 5) {
1.105 + perror("usb_bulk_write");
1.106 + bad("rjl_request_flash(): USB write failed");
1.107 + }
1.108 +
1.109 +
1.110 + recv_usb(d,len+5,(byte*)pack);
1.111 +}
1.112 +
1.113 +
1.114 +
1.115 +/* write in 16-byte boundary-aligned blocks only in this version of
1.116 + * the bootloader
1.117 + */
1.118 +void rjl_write_flash(picdem_handle *d, int offset, int len, byte *data, bl_packet *pack)
1.119 +{
1.120 + int r;
1.121 + bl_packet p;
1.122 + int i;
1.123 + byte retbuf[5];
1.124 +
1.125 +
1.126 +
1.127 + if(offset & 0x0f) {
1.128 + printf("*** WARNING: not boundary-aligned\n");
1.129 + return;
1.130 + }
1.131 + if(len != 16) {
1.132 + printf("*** WARNING: not 16 bytes\n");
1.133 + return;
1.134 + }
1.135 +
1.136 +
1.137 +
1.138 + p.command=WRITE_FLASH;
1.139 + p.address.low=(offset & 0xff)>>0;
1.140 + p.address.high=(offset & 0xff00)>>8;
1.141 + p.address.upper=(offset & 0xf0000)>>16;
1.142 + p.len=len;
1.143 + for(i=0;i<len;i++) {
1.144 + p.data[i]=data[i];
1.145 + }
1.146 +
1.147 +
1.148 + r=usb_bulk_write(d, fsusb_endpoint, (char*)&p, 5+len, fsusb_timeout);
1.149 + if(r != 5+len) {
1.150 + perror("usb_bulk_write");
1.151 + bad("rjl_write_flash(): USB write failed");
1.152 + }
1.153 +
1.154 + recv_usb(d,1,retbuf);
1.155 + // printf("write reply is %x\n", retbuf[0]);
1.156 +}
1.157 +
1.158 +
1.159 +
1.160 +/* write on 64-byte boundaries only in blocks of 64 bytes.
1.161 + * It's a feature.
1.162 + */
1.163 +void rjl_write_block(picdem_handle *d, int offset, byte *data)
1.164 +{
1.165 + int r;
1.166 + bl_packet p;
1.167 + byte retbuf[5];
1.168 + int subblock=0;
1.169 +
1.170 +
1.171 + if(offset & 0x3f) {
1.172 + printf("*** WARNING: not boundary-aligned\n");
1.173 + return;
1.174 + }
1.175 +
1.176 +
1.177 + p.command=ERASE_FLASH;
1.178 + p.address.low=(offset & 0xff)>>0;
1.179 + p.address.high=(offset & 0xff00)>>8;
1.180 + p.address.upper=(offset & 0xf0000)>>16;
1.181 + p.len=1;
1.182 +
1.183 +
1.184 + r=usb_bulk_write(d, fsusb_endpoint, (char*)&p, 5, fsusb_timeout);
1.185 + if(r != 5) {
1.186 + perror("usb_bulk_write");
1.187 + bad("rjl_write_block(): USB write failed");
1.188 + }
1.189 +
1.190 +
1.191 + recv_usb(d,1,retbuf);
1.192 + // printf("erase reply is %x\n", retbuf[0]);
1.193 +
1.194 +
1.195 + for(subblock=0;subblock<4;subblock++) {
1.196 + p.command=WRITE_FLASH;
1.197 + p.address.low=((offset+16*subblock) & 0xff)>>0;
1.198 + p.address.high=((offset+16*subblock) & 0xff00)>>8;
1.199 + p.address.upper=((offset+16*subblock) & 0xf0000)>>16;
1.200 + p.len=16;
1.201 + memcpy(p.data, data+(subblock*16), 16);
1.202 +
1.203 +
1.204 + r=usb_bulk_write(d, fsusb_endpoint, (char*)&p, 5+16, fsusb_timeout);
1.205 + if(r != 5+16) {
1.206 + perror("usb_bulk_write");
1.207 + bad("rjl_write_block(): USB write failed");
1.208 + }
1.209 +
1.210 +
1.211 + recv_usb(d,1,retbuf);
1.212 + // printf("write reply is %x\n", retbuf[0]);
1.213 + }
1.214 +}
1.215 +
1.216 +
1.217 +
1.218 +// 59ish bytes max
1.219 +void rjl_write_config_block(picdem_handle *d, int offset, int len, byte *data)
1.220 +{
1.221 + int r;
1.222 + bl_packet p;
1.223 + // int i;
1.224 + byte retbuf[5];
1.225 +
1.226 +
1.227 + if(len>=BL_DATA_LEN) {
1.228 + printf("*** ERROR: config block too big\n");
1.229 + return;
1.230 + }
1.231 +
1.232 +
1.233 +
1.234 + /* The firmware clips the erase to a 64-byte block, which
1.235 + * we don't worry about because in any real device
1.236 + * the config starts on a 64-byte boundary.
1.237 + */
1.238 + p.command=ERASE_FLASH;
1.239 + p.address.low=(offset & 0xff)>>0;
1.240 + p.address.high=(offset & 0xff00)>>8;
1.241 + p.address.upper=(offset & 0xf0000)>>16;
1.242 + p.len=1;
1.243 +
1.244 +
1.245 + r=usb_bulk_write(d, fsusb_endpoint, (char*)&p, 5, fsusb_timeout);
1.246 + if(r != 5) {
1.247 + perror("usb_bulk_write");
1.248 + bad("rjl_write_config_block(): USB write failed");
1.249 + }
1.250 +
1.251 +
1.252 + recv_usb(d,1,retbuf);
1.253 + // printf("erase reply is %x\n", retbuf[0]);
1.254 +
1.255 +
1.256 + // config writes have no alignment restriction
1.257 + p.command=WRITE_CONFIG;
1.258 + p.address.low=(offset & 0xff)>>0;
1.259 + p.address.high=(offset & 0xff00)>>8;
1.260 + p.address.upper=(offset & 0xf0000)>>16;
1.261 + p.len=len;
1.262 + memcpy(p.data, data, len);
1.263 +
1.264 +
1.265 + r=usb_bulk_write(d, fsusb_endpoint, (char*)&p, 5+len, fsusb_timeout);
1.266 + if(r != 5+len) {
1.267 + perror("usb_bulk_write");
1.268 + bad("rjl_write_config_block(): USB write failed");
1.269 + }
1.270 +
1.271 +
1.272 + recv_usb(d,1,retbuf);
1.273 + // printf("write reply is %x\n", retbuf[0]);
1.274 +}
1.275 +
1.276 +
1.277 +
1.278 +// write on 64-byte boundaries only in blocks of 64 bytes
1.279 +void rjl_erase_block(picdem_handle *d, int offset)
1.280 +{
1.281 + int r;
1.282 + bl_packet p;
1.283 + byte retbuf[5];
1.284 +
1.285 +
1.286 + if(offset & 0x3f) {
1.287 + printf("*** WARNING: not boundary-aligned\n");
1.288 + return;
1.289 + }
1.290 +
1.291 +
1.292 +
1.293 + p.command=ERASE_FLASH;
1.294 + p.address.low=(offset & 0xff)>>0;
1.295 + p.address.high=(offset & 0xff00)>>8;
1.296 + p.address.upper=(offset & 0xf0000)>>16;
1.297 + p.len=1;
1.298 +
1.299 +
1.300 + r=usb_bulk_write(d, fsusb_endpoint, (char*)&p, 5, fsusb_timeout);
1.301 + if(r != 5) {
1.302 + perror("usb_bulk_write");
1.303 + bad("rjl_erase_block(): USB write failed");
1.304 + }
1.305 +
1.306 +
1.307 + recv_usb(d,1,retbuf);
1.308 + // printf("erase reply is %x\n", retbuf[0]);
1.309 +}
1.310 +
1.311 +
1.312 +
1.313 +/* Find the first USB device with this vendor and product.
1.314 + * Exits on errors, like if the device couldn't be found. -osl
1.315 + *
1.316 + * This function is heavily based upon Orion Sky Lawlor's
1.317 + * usb_pickit program, which was a very useful reference
1.318 + * for all the USB stuff. Thanks!
1.319 + */
1.320 +picdem_handle *rjl_fsusb_open(void)
1.321 +{
1.322 + struct usb_device *device;
1.323 + struct usb_bus* bus;
1.324 + unsigned char buf[2];
1.325 +
1.326 +
1.327 + if (geteuid()!=0) {
1.328 + bad("This program must be run as root, or made setuid root");
1.329 + }
1.330 +
1.331 +#ifdef USB_DEBUG
1.332 + usb_debug=4;
1.333 +#endif
1.334 +
1.335 + printf("Locating USB Microchip(tm) PICDEM-FS USB(tm) (vendor 0x%04x/product 0x%04x)\n",
1.336 + fsusb_vendorID,fsusb_productID);
1.337 + /* (libusb setup code stolen from John Fremlin's cool "usb-robot") -osl */
1.338 + usb_init();
1.339 + usb_find_busses();
1.340 + usb_find_devices();
1.341 +
1.342 + for (bus=usb_busses;bus!=NULL;bus=bus->next) {
1.343 + struct usb_device* usb_devices = bus->devices;
1.344 + for(device=usb_devices;device!=NULL;device=device->next) {
1.345 +
1.346 +
1.347 + if (device->descriptor.idVendor == fsusb_vendorID
1.348 + && device->descriptor.idProduct == fsusb_productID) {
1.349 +
1.350 + usb_dev_handle *d;
1.351 + printf( "Found USB PICDEM-FS USB as device '%s' on USB bus %s\n",
1.352 + device->filename,
1.353 + device->bus->dirname);
1.354 + d=usb_open(device);
1.355 +
1.356 +
1.357 + if (d) { /* This is our device-- claim it */
1.358 + if (usb_set_configuration(d,fsusb_configuration)) {
1.359 + bad("Error setting USB configuration.\n");
1.360 + }
1.361 +
1.362 + if (usb_claim_interface(d,fsusb_interface)) {
1.363 + bad("Claim failed-- the USB PICDEM is in use by another driver.\n"
1.364 + "Do a `dmesg` to see which kernel driver has claimed it--\n"
1.365 + "You may need to `rmmod hid` or patch your kernel's hid driver.\n");
1.366 + }
1.367 +
1.368 + rjl_request_version(d, buf);
1.369 +
1.370 + printf("Communication established. Onboard firmware version is %d.%d\n",
1.371 + (int)buf[0],(int)buf[1]);
1.372 +
1.373 + if (buf[0]!=0x01u) {
1.374 + bad("This PICDEM's version is too new (only support version 1.x !)\n");
1.375 + }
1.376 +
1.377 + return d;
1.378 + } else
1.379 + bad("Open failed for USB device");
1.380 + }
1.381 +
1.382 +
1.383 + /* else some other vendor's device-- keep looking... -osl*/
1.384 + }
1.385 + }
1.386 +
1.387 + bad("Could not find USB PICDEM device--\n"
1.388 + "you might try lsusb to see if it's actually there.");
1.389 +
1.390 + return NULL;
1.391 +}