fsusb.c 9.0 KB

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