tools/fsusb/fsusb.c
author slime@unimatrix01.gamma-quadrant.de
Tue, 29 Jan 2008 22:31:52 +0100
changeset 2 2f55e5dd591d
permissions -rw-r--r--
inital checkin
slime@2
     1
/*
slime@2
     2
** This file is part of fsusb_picdem
slime@2
     3
**
slime@2
     4
** fsusb_picdem is free software; you can redistribute it and/or
slime@2
     5
** modify it under the terms of the GNU General Public License as
slime@2
     6
** published by the Free Software Foundation; either version 2 of the
slime@2
     7
** License, or (at your option) any later version.
slime@2
     8
**
slime@2
     9
** fsusb_picdem is distributed in the hope that it will be useful, but
slime@2
    10
** WITHOUT ANY WARRANTY; without even the implied warranty of
slime@2
    11
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
slime@2
    12
** General Public License for more details.
slime@2
    13
**
slime@2
    14
** You should have received a copy of the GNU General Public License
slime@2
    15
** along with fsusb_picdem; if not, write to the Free Software
slime@2
    16
** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
slime@2
    17
** 02110-1301, USA
slime@2
    18
*/
slime@2
    19
slime@2
    20
/*
slime@2
    21
** portions from usb_pickit by Orion Sky Lawlor, olawlor@acm.org
slime@2
    22
*/
slime@2
    23
slime@2
    24
#include <usb.h> /* libusb header */
slime@2
    25
#include <unistd.h> /* for geteuid */
slime@2
    26
#include <stdio.h>
slime@2
    27
#include <string.h>
slime@2
    28
#include "bootload.h"
slime@2
    29
#include "fsusb.h"
slime@2
    30
slime@2
    31
slime@2
    32
const static int fsusb_vendorID=0x04d8; // Microchip, Inc
slime@2
    33
const static int fsusb_productID=0x000b; // PICDEM-FS USB
slime@2
    34
const static int fsusb_configuration=1; /* 1: bootloader
slime@2
    35
                                         * ### may change in future firmware versions
slime@2
    36
                                         */
slime@2
    37
const static int fsusb_interface=0;
slime@2
    38
const static int fsusb_endpoint=1; /* first endpoint for everything
slime@2
    39
                                    * ### may change in future firmware versions
slime@2
    40
                                    */
slime@2
    41
const static int fsusb_timeout=1000; /* timeout in ms */
slime@2
    42
slime@2
    43
slime@2
    44
slime@2
    45
void bad(const char *why)
slime@2
    46
{
slime@2
    47
  fprintf(stderr,"Fatal error> %s\n",why);
slime@2
    48
  exit(17);
slime@2
    49
}
slime@2
    50
slime@2
    51
slime@2
    52
slime@2
    53
void recv_usb(picdem_handle *d, int len, byte *dest) {
slime@2
    54
  int r;
slime@2
    55
slime@2
    56
  r=usb_bulk_read(d, fsusb_endpoint, dest, len, fsusb_timeout);
slime@2
    57
slime@2
    58
  if (r!=len) {
slime@2
    59
    perror("usb PICDEM read");
slime@2
    60
    bad("USB read failed");
slime@2
    61
  }
slime@2
    62
  //  printf("read %i bytes\n", r);
slime@2
    63
}
slime@2
    64
slime@2
    65
slime@2
    66
slime@2
    67
void rjl_request_version(picdem_handle *d, unsigned char *ret)
slime@2
    68
{
slime@2
    69
  int r;
slime@2
    70
  char buf[4];
slime@2
    71
slime@2
    72
  // ### "\0\0\0\0\0" may not be correct in future firmware versions
slime@2
    73
  r=usb_bulk_write(d, fsusb_endpoint, "\0\0\0\0\0", 5, fsusb_timeout);
slime@2
    74
  if(r != 5) {
slime@2
    75
    perror("usb_bulk_write");
slime@2
    76
    bad("rjl_request_version(): USB write failed");
slime@2
    77
  }
slime@2
    78
slime@2
    79
  // command, len, minor, major
slime@2
    80
  recv_usb(d,4,buf);
slime@2
    81
  ret[0]=buf[3];
slime@2
    82
  ret[1]=buf[2];
slime@2
    83
}
slime@2
    84
slime@2
    85
slime@2
    86
slime@2
    87
void rjl_request_flash(picdem_handle *d, int offset, int len, bl_packet *pack)
slime@2
    88
{
slime@2
    89
  int r;
slime@2
    90
  bl_packet p;
slime@2
    91
slime@2
    92
slime@2
    93
  p.command=READ_FLASH;
slime@2
    94
  p.address.low=(offset & 0xff)>>0;
slime@2
    95
  p.address.high=(offset & 0xff00)>>8;
slime@2
    96
  p.address.upper=(offset & 0xf0000)>>16;
slime@2
    97
  p.len=len;
slime@2
    98
slime@2
    99
slime@2
   100
  r=usb_bulk_write(d, fsusb_endpoint, (char*)&p, 5, fsusb_timeout);
slime@2
   101
  if(r != 5) {
slime@2
   102
    perror("usb_bulk_write");
slime@2
   103
    bad("rjl_request_flash(): USB write failed");
slime@2
   104
  }
slime@2
   105
slime@2
   106
slime@2
   107
  recv_usb(d,len+5,(byte*)pack);
slime@2
   108
}
slime@2
   109
slime@2
   110
slime@2
   111
slime@2
   112
/* write in 16-byte boundary-aligned blocks only in this version of
slime@2
   113
 * the bootloader
slime@2
   114
 */
slime@2
   115
void rjl_write_flash(picdem_handle *d, int offset, int len, byte *data, bl_packet *pack)
slime@2
   116
{
slime@2
   117
  int r;
slime@2
   118
  bl_packet p;
slime@2
   119
  int i;
slime@2
   120
  byte retbuf[5];
slime@2
   121
slime@2
   122
slime@2
   123
slime@2
   124
  if(offset & 0x0f) {
slime@2
   125
    printf("*** WARNING: not boundary-aligned\n");
slime@2
   126
    return;
slime@2
   127
  }
slime@2
   128
  if(len != 16) {
slime@2
   129
    printf("*** WARNING: not 16 bytes\n");
slime@2
   130
    return;
slime@2
   131
  }
slime@2
   132
slime@2
   133
slime@2
   134
slime@2
   135
  p.command=WRITE_FLASH;
slime@2
   136
  p.address.low=(offset & 0xff)>>0;
slime@2
   137
  p.address.high=(offset & 0xff00)>>8;
slime@2
   138
  p.address.upper=(offset & 0xf0000)>>16;
slime@2
   139
  p.len=len;
slime@2
   140
  for(i=0;i<len;i++) {
slime@2
   141
    p.data[i]=data[i];
slime@2
   142
  }
slime@2
   143
slime@2
   144
slime@2
   145
  r=usb_bulk_write(d, fsusb_endpoint, (char*)&p, 5+len, fsusb_timeout);
slime@2
   146
  if(r != 5+len) {
slime@2
   147
    perror("usb_bulk_write");
slime@2
   148
    bad("rjl_write_flash(): USB write failed");
slime@2
   149
  }
slime@2
   150
slime@2
   151
  recv_usb(d,1,retbuf);
slime@2
   152
  //  printf("write reply is %x\n", retbuf[0]);
slime@2
   153
}
slime@2
   154
slime@2
   155
slime@2
   156
slime@2
   157
/* write on 64-byte boundaries only in blocks of 64 bytes.
slime@2
   158
 *  It's a feature.
slime@2
   159
 */
slime@2
   160
void rjl_write_block(picdem_handle *d, int offset, byte *data)
slime@2
   161
{
slime@2
   162
  int r;
slime@2
   163
  bl_packet p;
slime@2
   164
  byte retbuf[5];
slime@2
   165
  int subblock=0;
slime@2
   166
slime@2
   167
slime@2
   168
  if(offset & 0x3f) {
slime@2
   169
    printf("*** WARNING: not boundary-aligned\n");
slime@2
   170
    return;
slime@2
   171
  }
slime@2
   172
slime@2
   173
slime@2
   174
  p.command=ERASE_FLASH;
slime@2
   175
  p.address.low=(offset & 0xff)>>0;
slime@2
   176
  p.address.high=(offset & 0xff00)>>8;
slime@2
   177
  p.address.upper=(offset & 0xf0000)>>16;
slime@2
   178
  p.len=1;
slime@2
   179
slime@2
   180
slime@2
   181
  r=usb_bulk_write(d, fsusb_endpoint, (char*)&p, 5, fsusb_timeout);
slime@2
   182
  if(r != 5) {
slime@2
   183
    perror("usb_bulk_write");
slime@2
   184
    bad("rjl_write_block(): USB write failed");
slime@2
   185
  }
slime@2
   186
slime@2
   187
slime@2
   188
  recv_usb(d,1,retbuf);
slime@2
   189
  //  printf("erase reply is %x\n", retbuf[0]);
slime@2
   190
slime@2
   191
slime@2
   192
  for(subblock=0;subblock<4;subblock++) {
slime@2
   193
    p.command=WRITE_FLASH;
slime@2
   194
    p.address.low=((offset+16*subblock) & 0xff)>>0;
slime@2
   195
    p.address.high=((offset+16*subblock) & 0xff00)>>8;
slime@2
   196
    p.address.upper=((offset+16*subblock) & 0xf0000)>>16;
slime@2
   197
    p.len=16;
slime@2
   198
    memcpy(p.data, data+(subblock*16), 16);
slime@2
   199
slime@2
   200
slime@2
   201
    r=usb_bulk_write(d, fsusb_endpoint, (char*)&p, 5+16, fsusb_timeout);
slime@2
   202
    if(r != 5+16) {
slime@2
   203
      perror("usb_bulk_write");
slime@2
   204
      bad("rjl_write_block(): USB write failed");
slime@2
   205
    }
slime@2
   206
slime@2
   207
slime@2
   208
    recv_usb(d,1,retbuf);
slime@2
   209
    //  printf("write reply is %x\n", retbuf[0]);
slime@2
   210
  }
slime@2
   211
}
slime@2
   212
slime@2
   213
slime@2
   214
slime@2
   215
// 59ish bytes max
slime@2
   216
void rjl_write_config_block(picdem_handle *d, int offset, int len, byte *data)
slime@2
   217
{
slime@2
   218
  int r;
slime@2
   219
  bl_packet p;
slime@2
   220
  //  int i;
slime@2
   221
  byte retbuf[5];
slime@2
   222
slime@2
   223
slime@2
   224
  if(len>=BL_DATA_LEN) {
slime@2
   225
    printf("*** ERROR: config block too big\n");
slime@2
   226
    return;
slime@2
   227
  }
slime@2
   228
slime@2
   229
slime@2
   230
slime@2
   231
  /* The firmware clips the erase to a 64-byte block, which
slime@2
   232
   *  we don't worry about because in any real device
slime@2
   233
   *  the config starts on a 64-byte boundary.
slime@2
   234
   */
slime@2
   235
  p.command=ERASE_FLASH;
slime@2
   236
  p.address.low=(offset & 0xff)>>0;
slime@2
   237
  p.address.high=(offset & 0xff00)>>8;
slime@2
   238
  p.address.upper=(offset & 0xf0000)>>16;
slime@2
   239
  p.len=1;
slime@2
   240
slime@2
   241
slime@2
   242
  r=usb_bulk_write(d, fsusb_endpoint, (char*)&p, 5, fsusb_timeout);
slime@2
   243
  if(r != 5) {
slime@2
   244
    perror("usb_bulk_write");
slime@2
   245
    bad("rjl_write_config_block(): USB write failed");
slime@2
   246
  }
slime@2
   247
slime@2
   248
slime@2
   249
  recv_usb(d,1,retbuf);
slime@2
   250
  //  printf("erase reply is %x\n", retbuf[0]);
slime@2
   251
slime@2
   252
slime@2
   253
  // config writes have no alignment restriction
slime@2
   254
  p.command=WRITE_CONFIG;
slime@2
   255
  p.address.low=(offset & 0xff)>>0;
slime@2
   256
  p.address.high=(offset & 0xff00)>>8;
slime@2
   257
  p.address.upper=(offset & 0xf0000)>>16;
slime@2
   258
  p.len=len;
slime@2
   259
  memcpy(p.data, data, len);
slime@2
   260
slime@2
   261
slime@2
   262
  r=usb_bulk_write(d, fsusb_endpoint, (char*)&p, 5+len, fsusb_timeout);
slime@2
   263
  if(r != 5+len) {
slime@2
   264
    perror("usb_bulk_write");
slime@2
   265
    bad("rjl_write_config_block(): USB write failed");
slime@2
   266
  }
slime@2
   267
slime@2
   268
slime@2
   269
  recv_usb(d,1,retbuf);
slime@2
   270
  //  printf("write reply is %x\n", retbuf[0]);
slime@2
   271
}
slime@2
   272
slime@2
   273
slime@2
   274
slime@2
   275
// write on 64-byte boundaries only in blocks of 64 bytes
slime@2
   276
void rjl_erase_block(picdem_handle *d, int offset)
slime@2
   277
{
slime@2
   278
  int r;
slime@2
   279
  bl_packet p;
slime@2
   280
  byte retbuf[5];
slime@2
   281
slime@2
   282
slime@2
   283
  if(offset & 0x3f) {
slime@2
   284
    printf("*** WARNING: not boundary-aligned\n");
slime@2
   285
    return;
slime@2
   286
  }
slime@2
   287
slime@2
   288
slime@2
   289
slime@2
   290
  p.command=ERASE_FLASH;
slime@2
   291
  p.address.low=(offset & 0xff)>>0;
slime@2
   292
  p.address.high=(offset & 0xff00)>>8;
slime@2
   293
  p.address.upper=(offset & 0xf0000)>>16;
slime@2
   294
  p.len=1;
slime@2
   295
slime@2
   296
slime@2
   297
  r=usb_bulk_write(d, fsusb_endpoint, (char*)&p, 5, fsusb_timeout);
slime@2
   298
  if(r != 5) {
slime@2
   299
    perror("usb_bulk_write");
slime@2
   300
    bad("rjl_erase_block(): USB write failed");
slime@2
   301
  }
slime@2
   302
slime@2
   303
slime@2
   304
  recv_usb(d,1,retbuf);
slime@2
   305
  //  printf("erase reply is %x\n", retbuf[0]);
slime@2
   306
}
slime@2
   307
slime@2
   308
slime@2
   309
slime@2
   310
/* Find the first USB device with this vendor and product.
slime@2
   311
 *  Exits on errors, like if the device couldn't be found. -osl
slime@2
   312
 *
slime@2
   313
 * This function is heavily based upon Orion Sky Lawlor's
slime@2
   314
 *  usb_pickit program, which was a very useful reference
slime@2
   315
 *  for all the USB stuff.  Thanks!
slime@2
   316
 */
slime@2
   317
picdem_handle *rjl_fsusb_open(void)
slime@2
   318
{
slime@2
   319
  struct usb_device *device;
slime@2
   320
  struct usb_bus* bus;
slime@2
   321
  unsigned char buf[2];
slime@2
   322
slime@2
   323
slime@2
   324
  if (geteuid()!=0) {
slime@2
   325
    bad("This program must be run as root, or made setuid root");
slime@2
   326
  }
slime@2
   327
slime@2
   328
#ifdef USB_DEBUG
slime@2
   329
  usb_debug=4; 
slime@2
   330
#endif
slime@2
   331
slime@2
   332
  printf("Locating USB Microchip(tm) PICDEM-FS USB(tm) (vendor 0x%04x/product 0x%04x)\n",
slime@2
   333
  	fsusb_vendorID,fsusb_productID);
slime@2
   334
  /* (libusb setup code stolen from John Fremlin's cool "usb-robot") -osl */
slime@2
   335
  usb_init();
slime@2
   336
  usb_find_busses();
slime@2
   337
  usb_find_devices();
slime@2
   338
slime@2
   339
  for (bus=usb_busses;bus!=NULL;bus=bus->next) {
slime@2
   340
    struct usb_device* usb_devices = bus->devices;
slime@2
   341
    for(device=usb_devices;device!=NULL;device=device->next) {
slime@2
   342
slime@2
   343
slime@2
   344
      if (device->descriptor.idVendor == fsusb_vendorID
slime@2
   345
          && device->descriptor.idProduct == fsusb_productID) {
slime@2
   346
slime@2
   347
        usb_dev_handle *d;
slime@2
   348
        printf( "Found USB PICDEM-FS USB as device '%s' on USB bus %s\n",
slime@2
   349
                device->filename,
slime@2
   350
                device->bus->dirname);
slime@2
   351
        d=usb_open(device);
slime@2
   352
slime@2
   353
slime@2
   354
        if (d) { /* This is our device-- claim it */
slime@2
   355
          if (usb_set_configuration(d,fsusb_configuration)) {
slime@2
   356
            bad("Error setting USB configuration.\n");
slime@2
   357
          }
slime@2
   358
slime@2
   359
          if (usb_claim_interface(d,fsusb_interface)) {
slime@2
   360
            bad("Claim failed-- the USB PICDEM is in use by another driver.\n"
slime@2
   361
                "Do a `dmesg` to see which kernel driver has claimed it--\n"
slime@2
   362
                "You may need to `rmmod hid` or patch your kernel's hid driver.\n");
slime@2
   363
          }
slime@2
   364
slime@2
   365
          rjl_request_version(d, buf);
slime@2
   366
slime@2
   367
          printf("Communication established.  Onboard firmware version is %d.%d\n",
slime@2
   368
                 (int)buf[0],(int)buf[1]);
slime@2
   369
slime@2
   370
          if (buf[0]!=0x01u) {
slime@2
   371
            bad("This PICDEM's version is too new (only support version 1.x !)\n");
slime@2
   372
          }
slime@2
   373
slime@2
   374
          return d;
slime@2
   375
        } else 
slime@2
   376
          bad("Open failed for USB device");
slime@2
   377
      }
slime@2
   378
slime@2
   379
slime@2
   380
      /* else some other vendor's device-- keep looking... -osl*/
slime@2
   381
    }
slime@2
   382
  }
slime@2
   383
slime@2
   384
  bad("Could not find USB PICDEM device--\n"
slime@2
   385
      "you might try lsusb to see if it's actually there.");
slime@2
   386
slime@2
   387
  return NULL;
slime@2
   388
}