Support Dediprog SF100 bulk read.
Packet size is 512 bytes. Depending on your USB hardware and the Dediprog firmware version, this may not work at all. Untested, experimental, may hang/crash the programmer.
Read tests of random images are appreciated.
Signed-off-by: Carl-Daniel Hailfinger c-d.hailfinger.devel.2006@gmx.net
Index: flashrom-dediprog_read_bulk/dediprog.c =================================================================== --- flashrom-dediprog_read_bulk/dediprog.c (Revision 1225) +++ flashrom-dediprog_read_bulk/dediprog.c (Arbeitskopie) @@ -26,6 +26,7 @@
#define DEFAULT_TIMEOUT 3000 static usb_dev_handle *dediprog_handle; +static int dediprog_endpoint;
#if 0 /* Might be useful for other pieces of code as well. */ @@ -148,9 +149,36 @@
int dediprog_spi_read(struct flashchip *flash, uint8_t *buf, int start, int len) { + int ret; + int i; + int chunksize = 0x200; /* 512 */ + int count = flash->total_size * 1024 / chunksize; + /* Guessed. */ + const char count_and_chunk[] = {(count >> 8) & 0xff, + count & 0xff, + (chunksize >> 8) & 0xff, + chunksize & 0xff}; + msg_pspew("%s, start=0x%x, len=0x%x\n", __func__, start, len); - /* Chosen read length is 16 bytes for now. */ - return spi_read_chunked(flash, buf, start, len, 16); + if ((len != flash->total_size * 1024) || (start != 0)) { + msg_perr("Only a full chip read is supported for now. Wanted " + "start=%i, length=%i\n.", start, len); + return 1; + } + + /* Command Read SPI Bulk. No idea which read command is used on the SPI side. */ + usb_control_msg(dediprog_handle, 0x42, 0x20, 0x0000, 0x0000, (char *)count_and_chunk, 0x0004, DEFAULT_TIMEOUT); + + for (i = 0; i < count; i++) { + ret = usb_bulk_read(dediprog_handle, dediprog_endpoint, (char *)buf + i * chunksize, chunksize, DEFAULT_TIMEOUT); + if (ret != chunksize) { + msg_perr("SPI bulk read failed, expected %i, got %i %s!\n", + chunksize, ret, usb_strerror()); + return 1; + } + } + + return 0; }
int dediprog_spi_send_command(unsigned int writecnt, unsigned int readcnt, @@ -301,6 +329,7 @@ dediprog_handle = usb_open(dev); usb_set_configuration(dediprog_handle, 1); usb_claim_interface(dediprog_handle, 0); + dediprog_endpoint = 2; /* URB 6. Command A. */ if (dediprog_command_a()) return 1;
* Carl-Daniel Hailfinger c-d.hailfinger.devel.2006@gmx.net [101109 21:41]:
Support Dediprog SF100 bulk read.
Packet size is 512 bytes. Depending on your USB hardware and the Dediprog firmware version, this may not work at all. Untested, experimental, may hang/crash the programmer.
Read tests of random images are appreciated.
Signed-off-by: Carl-Daniel Hailfinger c-d.hailfinger.devel.2006@gmx.net
Acked-by: Stefan Reinauer stepan@coreboot.org
On 09.11.2010 22:57, Stefan Reinauer wrote:
- Carl-Daniel Hailfinger c-d.hailfinger.devel.2006@gmx.net [101109 21:41]:
Support Dediprog SF100 bulk read.
Packet size is 512 bytes. Depending on your USB hardware and the Dediprog firmware version, this may not work at all. Untested, experimental, may hang/crash the programmer.
Read tests of random images are appreciated.
Signed-off-by: Carl-Daniel Hailfinger c-d.hailfinger.devel.2006@gmx.net
Acked-by: Stefan Reinauer stepan@coreboot.org
Thanks for the ack. The code is not working yet, so I'm holding off with the commit.
New version follows. While it may still fail, the error messages should be way more useful.
Support Dediprog SF100 bulk read.
Packet size is 512 bytes. Depending on your USB hardware and the Dediprog firmware version, this may not work at all. Add lots of error checking where it was missing before. Untested, experimental, may hang/crash the programmer.
Read tests of random images are appreciated.
Please note that flashrom needs full access permissions for the USB device.
Signed-off-by: Carl-Daniel Hailfinger c-d.hailfinger.devel.2006@gmx.net
Index: flashrom-dediprog_read_bulk/dediprog.c =================================================================== --- flashrom-dediprog_read_bulk/dediprog.c (Revision 1227) +++ flashrom-dediprog_read_bulk/dediprog.c (Arbeitskopie) @@ -27,6 +27,7 @@
#define DEFAULT_TIMEOUT 3000 static usb_dev_handle *dediprog_handle; +static int dediprog_endpoint;
#if 0 /* Might be useful for other pieces of code as well. */ @@ -150,9 +151,43 @@
int dediprog_spi_read(struct flashchip *flash, uint8_t *buf, int start, int len) { + int ret; + int i; + int chunksize = 0x200; /* 512 */ + int count = flash->total_size * 1024 / chunksize; + /* Guessed. */ + const char count_and_chunk[] = {(count >> 8) & 0xff, + count & 0xff, + (chunksize >> 8) & 0xff, + chunksize & 0xff}; + msg_pspew("%s, start=0x%x, len=0x%x\n", __func__, start, len); - /* Chosen read length is 16 bytes for now. */ - return spi_read_chunked(flash, buf, start, len, 16); + if ((len != flash->total_size * 1024) || (start != 0)) { + msg_perr("Only a full chip read is supported for now. Wanted " + "start=%i, length=%i\n.", start, len); + return 1; + } + + /* Command Read SPI Bulk. No idea which read command is used on the + * SPI side. + */ + ret = usb_control_msg(dediprog_handle, 0x42, 0x20, 0x0000, 0x0000, (char *)count_and_chunk, sizeof(count_and_chunk), DEFAULT_TIMEOUT); + if (ret != sizeof(count_and_chunk)) { + msg_perr("Command Read SPI Bulk failed, %i %s!\n", ret, + usb_strerror()); + return 1; + } + + for (i = 0; i < count; i++) { + ret = usb_bulk_read(dediprog_handle, 0x80 | dediprog_endpoint, (char *)buf + i * chunksize, chunksize, DEFAULT_TIMEOUT); + if (ret != chunksize) { + msg_perr("SPI bulk read failed, expected %i, got %i " + "%s!\n", chunksize, ret, usb_strerror()); + return 1; + } + } + + return 0; }
int dediprog_spi_send_command(unsigned int writecnt, unsigned int readcnt, @@ -345,6 +380,7 @@ struct usb_device *dev; char *voltage; int millivolt = 3500; + int ret;
msg_pspew("%s\n", __func__);
@@ -371,8 +407,23 @@ dev->descriptor.idVendor, dev->descriptor.idProduct); dediprog_handle = usb_open(dev); - usb_set_configuration(dediprog_handle, 1); - usb_claim_interface(dediprog_handle, 0); + ret = usb_set_configuration(dediprog_handle, 1); + if (ret < 0) { + msg_perr("Could not set USB device configuration: %i %s\n", + ret, usb_strerror()); + if (usb_close(dediprog_handle)) + msg_perr("Could not close USB device!\n"); + return 1; + } + ret = usb_claim_interface(dediprog_handle, 0); + if (ret < 0) { + msg_perr("Could not claim USB device interface %i: %i %s\n", + 0, ret, usb_strerror()); + if (usb_close(dediprog_handle)) + msg_perr("Could not close USB device!\n"); + return 1; + } + dediprog_endpoint = 2; /* URB 6. Command A. */ if (dediprog_command_a()) return 1; @@ -461,8 +512,12 @@ if (dediprog_set_spi_voltage(0x0)) return 1;
+ if (usb_release_interface(dediprog_handle, 0)) { + msg_perr("Could not release USB interface!\n"); + return 1; + } if (usb_close(dediprog_handle)) { - msg_perr("Couldn't close USB device!\n"); + msg_perr("Could not close USB device!\n"); return 1; } return 0;
New version: Fix endianness issues.
Support Dediprog SF100 bulk read.
Packet size is 512 bytes. Depending on your USB hardware and the Dediprog firmware version, this may not work at all. Add lots of error checking where it was missing before. Untested, experimental, may hang/crash the programmer.
Read tests of random images are appreciated.
Please note that flashrom needs full access permissions for the USB device.
Signed-off-by: Carl-Daniel Hailfinger c-d.hailfinger.devel.2006@gmx.net
Index: flashrom-dediprog_read_bulk/dediprog.c =================================================================== --- flashrom-dediprog_read_bulk/dediprog.c (Revision 1232) +++ flashrom-dediprog_read_bulk/dediprog.c (Arbeitskopie) @@ -27,6 +27,7 @@
#define DEFAULT_TIMEOUT 3000 static usb_dev_handle *dediprog_handle; +static int dediprog_endpoint;
#if 0 /* Might be useful for other pieces of code as well. */ @@ -150,9 +151,45 @@
int dediprog_spi_read(struct flashchip *flash, uint8_t *buf, int start, int len) { + int ret; + int i; + int chunksize = 0x200; /* 512 */ + int count = flash->total_size * 1024 / chunksize; + /* Guessed. */ + const char count_and_chunk[] = { + count & 0xff, + (count >> 8) & 0xff, + chunksize & 0xff, + (chunksize >> 8) & 0xff}; + msg_pspew("%s, start=0x%x, len=0x%x\n", __func__, start, len); - /* Chosen read length is 16 bytes for now. */ - return spi_read_chunked(flash, buf, start, len, 16); + if ((len != flash->total_size * 1024) || (start != 0)) { + msg_perr("Only a full chip read is supported for now. Wanted " + "start=%i, length=%i\n.", start, len); + return 1; + } + + /* Command Read SPI Bulk. No idea which read command is used on the + * SPI side. + */ + ret = usb_control_msg(dediprog_handle, 0x42, 0x20, 0x0000, 0x0000, (char *)count_and_chunk, sizeof(count_and_chunk), DEFAULT_TIMEOUT); + if (ret != sizeof(count_and_chunk)) { + msg_perr("Command Read SPI Bulk failed, %i %s!\n", ret, + usb_strerror()); + return 1; + } + + for (i = 0; i < count; i++) { + msg_pspew("."); + ret = usb_bulk_read(dediprog_handle, 0x80 | dediprog_endpoint, (char *)buf + i * chunksize, chunksize, DEFAULT_TIMEOUT); + if (ret != chunksize) { + msg_perr("SPI bulk read %i failed, expected %i, got %i " + "%s!\n", i, chunksize, ret, usb_strerror()); + return 1; + } + } + + return 0; }
int dediprog_spi_send_command(unsigned int writecnt, unsigned int readcnt, @@ -345,6 +382,7 @@ struct usb_device *dev; char *voltage; int millivolt = 3500; + int ret;
msg_pspew("%s\n", __func__);
@@ -371,8 +409,23 @@ dev->descriptor.idVendor, dev->descriptor.idProduct); dediprog_handle = usb_open(dev); - usb_set_configuration(dediprog_handle, 1); - usb_claim_interface(dediprog_handle, 0); + ret = usb_set_configuration(dediprog_handle, 1); + if (ret < 0) { + msg_perr("Could not set USB device configuration: %i %s\n", + ret, usb_strerror()); + if (usb_close(dediprog_handle)) + msg_perr("Could not close USB device!\n"); + return 1; + } + ret = usb_claim_interface(dediprog_handle, 0); + if (ret < 0) { + msg_perr("Could not claim USB device interface %i: %i %s\n", + 0, ret, usb_strerror()); + if (usb_close(dediprog_handle)) + msg_perr("Could not close USB device!\n"); + return 1; + } + dediprog_endpoint = 2; /* URB 6. Command A. */ if (dediprog_command_a()) return 1; @@ -461,8 +514,12 @@ if (dediprog_set_spi_voltage(0x0)) return 1;
+ if (usb_release_interface(dediprog_handle, 0)) { + msg_perr("Could not release USB interface!\n"); + return 1; + } if (usb_close(dediprog_handle)) { - msg_perr("Couldn't close USB device!\n"); + msg_perr("Could not close USB device!\n"); return 1; } return 0;
New version: More guesswork, split read chunk size from bulk transfer buffer size.
Might even work for plain reads. Verify and write will be corrupt because that code path is not handled yet. Tests with chunksize = 0x20 and chunksize = 0x1 would be appreciated. They should be a lot slower, but still yield correct images. Tests with chunksize = 0x200 and offset = 0x1 would be appreciated. The resulting image should be shifted by 512 bytes.
Support Dediprog SF100 bulk read.
Packet size is 512 bytes. Depending on your USB hardware and the Dediprog firmware version, this may not work at all. Add lots of error checking where it was missing before. Untested, experimental, may hang/crash the programmer.
Read tests of random images are appreciated.
Please note that flashrom needs full access permissions for the USB device.
Signed-off-by: Carl-Daniel Hailfinger c-d.hailfinger.devel.2006@gmx.net
Index: flashrom-dediprog_read_bulk/dediprog.c =================================================================== --- flashrom-dediprog_read_bulk/dediprog.c (Revision 1232) +++ flashrom-dediprog_read_bulk/dediprog.c (Arbeitskopie) @@ -27,6 +27,7 @@
#define DEFAULT_TIMEOUT 3000 static usb_dev_handle *dediprog_handle; +static int dediprog_endpoint;
#if 0 /* Might be useful for other pieces of code as well. */ @@ -150,9 +151,50 @@
int dediprog_spi_read(struct flashchip *flash, uint8_t *buf, int start, int len) { + int ret; + int i; + int chunksize = 0x200; /* 512, other sizes may not work at all. */ + const int bulktransfer_chunksize = 0x200; /* 512, other sizes may not work at all. */ + int count = flash->total_size * 1024 / chunksize; + /* Guessed. */ + const char count_and_chunk[] = { + count & 0xff, + (count >> 8) & 0xff, + chunksize & 0xff, + (chunksize >> 8) & 0xff}; + int offset = 0; + char tmpbuf[bulktransfer_chunksize]; + msg_pspew("%s, start=0x%x, len=0x%x\n", __func__, start, len); - /* Chosen read length is 16 bytes for now. */ - return spi_read_chunked(flash, buf, start, len, 16); + if ((len != flash->total_size * 1024) || (start != 0)) { + msg_perr("Only a full chip read is supported for now. Wanted " + "start=%i, length=%i\n.", start, len); + return 1; + } + + /* Command Read SPI Bulk. No idea which read command is used on the + * SPI side. offset is a total guess, I only saw it being 0 everywhere. + */ + ret = usb_control_msg(dediprog_handle, 0x42, 0x20, 0x0000, offset, (char *)count_and_chunk, sizeof(count_and_chunk), DEFAULT_TIMEOUT); + if (ret != sizeof(count_and_chunk)) { + msg_perr("Command Read SPI Bulk failed, %i %s!\n", ret, + usb_strerror()); + return 1; + } + + for (i = 0; i < count; i++) { + /* Crude progress bar, enable with -VV */ + msg_pspew("."); + ret = usb_bulk_read(dediprog_handle, 0x80 | dediprog_endpoint, tmpbuf, bulktransfer_chunksize, DEFAULT_TIMEOUT); + memcpy(buf + i * chunksize, tmpbuf, chunksize); + if (ret != chunksize) { + msg_perr("SPI bulk read %i failed, expected %i, got %i " + "%s!\n", i, chunksize, ret, usb_strerror()); + return 1; + } + } + + return 0; }
int dediprog_spi_send_command(unsigned int writecnt, unsigned int readcnt, @@ -345,6 +387,7 @@ struct usb_device *dev; char *voltage; int millivolt = 3500; + int ret;
msg_pspew("%s\n", __func__);
@@ -371,8 +414,23 @@ dev->descriptor.idVendor, dev->descriptor.idProduct); dediprog_handle = usb_open(dev); - usb_set_configuration(dediprog_handle, 1); - usb_claim_interface(dediprog_handle, 0); + ret = usb_set_configuration(dediprog_handle, 1); + if (ret < 0) { + msg_perr("Could not set USB device configuration: %i %s\n", + ret, usb_strerror()); + if (usb_close(dediprog_handle)) + msg_perr("Could not close USB device!\n"); + return 1; + } + ret = usb_claim_interface(dediprog_handle, 0); + if (ret < 0) { + msg_perr("Could not claim USB device interface %i: %i %s\n", + 0, ret, usb_strerror()); + if (usb_close(dediprog_handle)) + msg_perr("Could not close USB device!\n"); + return 1; + } + dediprog_endpoint = 2; /* URB 6. Command A. */ if (dediprog_command_a()) return 1; @@ -461,8 +519,12 @@ if (dediprog_set_spi_voltage(0x0)) return 1;
+ if (usb_release_interface(dediprog_handle, 0)) { + msg_perr("Could not release USB interface!\n"); + return 1; + } if (usb_close(dediprog_handle)) { - msg_perr("Couldn't close USB device!\n"); + msg_perr("Could not close USB device!\n"); return 1; } return 0;
New version: Even more guesswork, and support for partial reads. If the tests of the previous version have the results I hope for, this version will allow partial reads without any regressions.
On 12.11.2010 03:29, Carl-Daniel Hailfinger wrote:
New version: More guesswork, split read chunk size from bulk transfer buffer size.
Support bulk read on Dediprog SF100. Should result in native speed for plain read and erase. Should result in a measurable speedup for writes due to a fast verify.
Read tests with chunksize = 0x20 would be appreciated. Read tests with chunksize = 0x1 would be appreciated. Both should be a lot slower, but still yield correct images.
Packet size is 512 bytes. Depending on your USB hardware and the Dediprog firmware version, this may not work at all. Add lots of error checking where it was missing before. Somewhat tested, experimental, may hang/crash the programmer.
Write tests of random images are appreciated.
Please note that flashrom needs full access permissions for the USB device.
Signed-off-by: Carl-Daniel Hailfinger c-d.hailfinger.devel.2006@gmx.net
Index: flashrom-dediprog_read_bulk/dediprog.c =================================================================== --- flashrom-dediprog_read_bulk/dediprog.c (Revision 1232) +++ flashrom-dediprog_read_bulk/dediprog.c (Arbeitskopie) @@ -27,6 +27,7 @@
#define DEFAULT_TIMEOUT 3000 static usb_dev_handle *dediprog_handle; +static int dediprog_endpoint;
#if 0 /* Might be useful for other pieces of code as well. */ @@ -150,9 +151,63 @@
int dediprog_spi_read(struct flashchip *flash, uint8_t *buf, int start, int len) { + int ret = 0; + int i; + int chunksize = 0x200; /* 512, other sizes may not work at all. */ + const int bulktransfer_chunksize = 0x200; /* 512, other sizes may not work at all. */ + /* count only covers full chunksize blocks. */ + int count = (len - start % chunksize) / chunksize; + /* Guessed. */ + const char count_and_chunk[] = { + count & 0xff, + (count >> 8) & 0xff, + chunksize & 0xff, + (chunksize >> 8) & 0xff}; + int residue = start % chunksize ? chunksize - start % chunksize : 0; + int bulkoffset = (start + residue) / chunksize; + char tmpbuf[bulktransfer_chunksize]; + msg_pspew("%s, start=0x%x, len=0x%x\n", __func__, start, len); - /* Chosen read length is 16 bytes for now. */ - return spi_read_chunked(flash, buf, start, len, 16); + if (residue) { + msg_pdbg("Slow read for partial block from 0x%x, length 0x%x\n", + start, residue); + ret = spi_read_chunked(flash, buf, start, residue, 16); + } + if (ret) + return ret; + + /* Command Read SPI Bulk. No idea which read command is used on the + * SPI side. offset is a total guess, I only saw it being 0 everywhere. + */ + ret = usb_control_msg(dediprog_handle, 0x42, 0x20, 0x0000, bulkoffset, (char *)count_and_chunk, sizeof(count_and_chunk), DEFAULT_TIMEOUT); + if (ret != sizeof(count_and_chunk)) { + msg_perr("Command Read SPI Bulk failed, %i %s!\n", ret, + usb_strerror()); + return 1; + } + + for (i = 0; i < count; i++) { + /* Crude progress bar, enable with -VV */ + msg_pspew("."); + ret = usb_bulk_read(dediprog_handle, 0x80 | dediprog_endpoint, tmpbuf, bulktransfer_chunksize, DEFAULT_TIMEOUT); + memcpy(buf + residue + i * chunksize, tmpbuf, chunksize); + if (ret != chunksize) { + msg_perr("SPI bulk read %i failed, expected %i, got %i " + "%s!\n", i, chunksize, ret, usb_strerror()); + return 1; + } + } + len -= residue + i * chunksize; + if (len) { + msg_pdbg("Slow read for partial block from 0x%x, length 0x%x\n", + start, len); + ret = spi_read_chunked(flash, buf + residue + i * chunksize, + start + residue + i * chunksize, len, 16); + } + if (ret) + return ret; + + return 0; }
int dediprog_spi_send_command(unsigned int writecnt, unsigned int readcnt, @@ -345,6 +400,7 @@ struct usb_device *dev; char *voltage; int millivolt = 3500; + int ret;
msg_pspew("%s\n", __func__);
@@ -371,8 +427,23 @@ dev->descriptor.idVendor, dev->descriptor.idProduct); dediprog_handle = usb_open(dev); - usb_set_configuration(dediprog_handle, 1); - usb_claim_interface(dediprog_handle, 0); + ret = usb_set_configuration(dediprog_handle, 1); + if (ret < 0) { + msg_perr("Could not set USB device configuration: %i %s\n", + ret, usb_strerror()); + if (usb_close(dediprog_handle)) + msg_perr("Could not close USB device!\n"); + return 1; + } + ret = usb_claim_interface(dediprog_handle, 0); + if (ret < 0) { + msg_perr("Could not claim USB device interface %i: %i %s\n", + 0, ret, usb_strerror()); + if (usb_close(dediprog_handle)) + msg_perr("Could not close USB device!\n"); + return 1; + } + dediprog_endpoint = 2; /* URB 6. Command A. */ if (dediprog_command_a()) return 1; @@ -461,8 +532,12 @@ if (dediprog_set_spi_voltage(0x0)) return 1;
+ if (usb_release_interface(dediprog_handle, 0)) { + msg_perr("Could not release USB interface!\n"); + return 1; + } if (usb_close(dediprog_handle)) { - msg_perr("Couldn't close USB device!\n"); + msg_perr("Could not close USB device!\n"); return 1; } return 0;
hi carl, i tried your patch, the read seems very good. But i found that the readback.rom is not exactly the same as i flashed with the factory tools. but that does not mean that flashrom read comand is not correct, because i had faced that the factory tools also could cause some byte flashed incorrectly. the log is attached which i test with my SF100. Best wishes Wang Qing Pei Phone: 86+18930528086
On Fri, Nov 12, 2010 at 12:29 PM, Carl-Daniel Hailfinger < c-d.hailfinger.devel.2006@gmx.net> wrote:
New version: Even more guesswork, and support for partial reads. If the tests of the previous version have the results I hope for, this version will allow partial reads without any regressions.
On 12.11.2010 03:29, Carl-Daniel Hailfinger wrote:
New version: More guesswork, split read chunk size from bulk transfer buffer size.
Support bulk read on Dediprog SF100. Should result in native speed for plain read and erase. Should result in a measurable speedup for writes due to a fast verify.
Read tests with chunksize = 0x20 would be appreciated. Read tests with chunksize = 0x1 would be appreciated. Both should be a lot slower, but still yield correct images.
Packet size is 512 bytes. Depending on your USB hardware and the Dediprog firmware version, this may not work at all. Add lots of error checking where it was missing before. Somewhat tested, experimental, may hang/crash the programmer.
Write tests of random images are appreciated.
Please note that flashrom needs full access permissions for the USB device.
Signed-off-by: Carl-Daniel Hailfinger c-d.hailfinger.devel.2006@gmx.net
Index: flashrom-dediprog_read_bulk/dediprog.c
--- flashrom-dediprog_read_bulk/dediprog.c (Revision 1232) +++ flashrom-dediprog_read_bulk/dediprog.c (Arbeitskopie) @@ -27,6 +27,7 @@
#define DEFAULT_TIMEOUT 3000 static usb_dev_handle *dediprog_handle; +static int dediprog_endpoint;
#if 0 /* Might be useful for other pieces of code as well. */ @@ -150,9 +151,63 @@
int dediprog_spi_read(struct flashchip *flash, uint8_t *buf, int start, int len) {
int ret = 0;
int i;
int chunksize = 0x200; /* 512, other sizes may not work at all. */
const int bulktransfer_chunksize = 0x200; /* 512, other sizes may
not work at all. */
/* count only covers full chunksize blocks. */
int count = (len - start % chunksize) / chunksize;
/* Guessed. */
const char count_and_chunk[] = {
count & 0xff,
(count >> 8) & 0xff,
chunksize & 0xff,
(chunksize >> 8) & 0xff};
int residue = start % chunksize ? chunksize - start % chunksize :
0;
int bulkoffset = (start + residue) / chunksize;
char tmpbuf[bulktransfer_chunksize];
msg_pspew("%s, start=0x%x, len=0x%x\n", __func__, start, len);
/* Chosen read length is 16 bytes for now. */
return spi_read_chunked(flash, buf, start, len, 16);
if (residue) {
msg_pdbg("Slow read for partial block from 0x%x, length
0x%x\n",
start, residue);
ret = spi_read_chunked(flash, buf, start, residue, 16);
}
if (ret)
return ret;
/* Command Read SPI Bulk. No idea which read command is used on the
* SPI side. offset is a total guess, I only saw it being 0
everywhere.
*/
ret = usb_control_msg(dediprog_handle, 0x42, 0x20, 0x0000,
bulkoffset, (char *)count_and_chunk, sizeof(count_and_chunk), DEFAULT_TIMEOUT);
if (ret != sizeof(count_and_chunk)) {
msg_perr("Command Read SPI Bulk failed, %i %s!\n", ret,
usb_strerror());
return 1;
}
for (i = 0; i < count; i++) {
/* Crude progress bar, enable with -VV */
msg_pspew(".");
ret = usb_bulk_read(dediprog_handle, 0x80 |
dediprog_endpoint, tmpbuf, bulktransfer_chunksize, DEFAULT_TIMEOUT);
memcpy(buf + residue + i * chunksize, tmpbuf, chunksize);
if (ret != chunksize) {
msg_perr("SPI bulk read %i failed, expected %i, got
%i "
"%s!\n", i, chunksize, ret,
usb_strerror());
return 1;
}
}
len -= residue + i * chunksize;
if (len) {
msg_pdbg("Slow read for partial block from 0x%x, length
0x%x\n",
start, len);
ret = spi_read_chunked(flash, buf + residue + i *
chunksize,
start + residue + i * chunksize,
len, 16);
}
if (ret)
return ret;
return 0;
}
int dediprog_spi_send_command(unsigned int writecnt, unsigned int readcnt, @@ -345,6 +400,7 @@ struct usb_device *dev; char *voltage; int millivolt = 3500;
int ret; msg_pspew("%s\n", __func__);
@@ -371,8 +427,23 @@ dev->descriptor.idVendor, dev->descriptor.idProduct); dediprog_handle = usb_open(dev);
usb_set_configuration(dediprog_handle, 1);
usb_claim_interface(dediprog_handle, 0);
ret = usb_set_configuration(dediprog_handle, 1);
if (ret < 0) {
msg_perr("Could not set USB device configuration: %i %s\n",
ret, usb_strerror());
if (usb_close(dediprog_handle))
msg_perr("Could not close USB device!\n");
return 1;
}
ret = usb_claim_interface(dediprog_handle, 0);
if (ret < 0) {
msg_perr("Could not claim USB device interface %i: %i
%s\n",
0, ret, usb_strerror());
if (usb_close(dediprog_handle))
msg_perr("Could not close USB device!\n");
return 1;
}
dediprog_endpoint = 2; /* URB 6. Command A. */ if (dediprog_command_a()) return 1;
@@ -461,8 +532,12 @@ if (dediprog_set_spi_voltage(0x0)) return 1;
if (usb_release_interface(dediprog_handle, 0)) {
msg_perr("Could not release USB interface!\n");
return 1;
} if (usb_close(dediprog_handle)) {
msg_perr("Couldn't close USB device!\n");
msg_perr("Could not close USB device!\n"); return 1; } return 0;
flashrom mailing list flashrom@flashrom.org http://www.flashrom.org/mailman/listinfo/flashrom
New version: Fix error handling. libusb returns the number of bytes read/written, and those are nonzero in our case, triggering a false abort.
Support bulk read on Dediprog SF100. Should result in native speed for plain read and erase. Should result in a measurable speedup for writes due to a fast verify.
Read tests with chunksize = 0x20 would be appreciated. Read tests with chunksize = 0x1 would be appreciated. Both should be a lot slower, but still yield correct images.
Packet size is 512 bytes. Depending on your USB hardware and the Dediprog firmware version, this may not work at all. Add lots of error checking where it was missing before. Somewhat tested, experimental, may hang/crash the programmer.
Write tests of random images are appreciated.
Please note that flashrom needs full access permissions for the USB device.
Signed-off-by: Carl-Daniel Hailfinger c-d.hailfinger.devel.2006@gmx.net
Index: flashrom-dediprog_read_bulk/dediprog.c =================================================================== --- flashrom-dediprog_read_bulk/dediprog.c (Revision 1232) +++ flashrom-dediprog_read_bulk/dediprog.c (Arbeitskopie) @@ -27,6 +27,7 @@
#define DEFAULT_TIMEOUT 3000 static usb_dev_handle *dediprog_handle; +static int dediprog_endpoint;
#if 0 /* Might be useful for other pieces of code as well. */ @@ -150,9 +151,68 @@
int dediprog_spi_read(struct flashchip *flash, uint8_t *buf, int start, int len) { + int ret = 0; + int i; + int chunksize = 0x200; /* 512, other sizes may not work at all. */ + const int bulktransfer_chunksize = 0x200; /* 512, other sizes may not work at all. */ + /* count only covers full chunksize blocks. */ + int count = (len - start % chunksize) / chunksize; + /* Guessed. */ + const char count_and_chunk[] = { + count & 0xff, + (count >> 8) & 0xff, + chunksize & 0xff, + (chunksize >> 8) & 0xff}; + int residue = start % chunksize ? chunksize - start % chunksize : 0; + int bulkoffset = (start + residue) / chunksize; + char tmpbuf[bulktransfer_chunksize]; + msg_pspew("%s, start=0x%x, len=0x%x\n", __func__, start, len); - /* Chosen read length is 16 bytes for now. */ - return spi_read_chunked(flash, buf, start, len, 16); + if (residue) { + msg_pdbg("Slow read for partial block from 0x%x, length 0x%x\n", + start, residue); + ret = spi_read_chunked(flash, buf, start, residue, 16); + } + if (ret) + return ret; + + /* Command Read SPI Bulk. No idea which read command is used on the + * SPI side. offset is a total guess, I only saw it being 0 everywhere. + */ + ret = usb_control_msg(dediprog_handle, 0x42, 0x20, 0x0000, bulkoffset, (char *)count_and_chunk, sizeof(count_and_chunk), DEFAULT_TIMEOUT); + if (ret != sizeof(count_and_chunk)) { + msg_perr("Command Read SPI Bulk failed, %i %s!\n", ret, + usb_strerror()); + return 1; + } + /* ret was 4 if successful. Reset it. */ + ret = 0; + + for (i = 0; i < count; i++) { + /* Crude progress bar, enable with -VV */ + msg_pspew("."); + ret = usb_bulk_read(dediprog_handle, 0x80 | dediprog_endpoint, tmpbuf, bulktransfer_chunksize, DEFAULT_TIMEOUT); + memcpy(buf + residue + i * chunksize, tmpbuf, chunksize); + if (ret != chunksize) { + msg_perr("SPI bulk read %i failed, expected %i, got %i " + "%s!\n", i, chunksize, ret, usb_strerror()); + return 1; + } + /* ret was 512 if successful. Reset it. */ + ret = 0; + } + + len -= residue + i * chunksize; + if (len) { + msg_pdbg("Slow read for partial block from 0x%x, length 0x%x\n", + start, len); + ret = spi_read_chunked(flash, buf + residue + i * chunksize, + start + residue + i * chunksize, len, 16); + if (ret) + return ret; + } + + return 0; }
int dediprog_spi_send_command(unsigned int writecnt, unsigned int readcnt, @@ -345,6 +405,7 @@ struct usb_device *dev; char *voltage; int millivolt = 3500; + int ret;
msg_pspew("%s\n", __func__);
@@ -371,8 +432,23 @@ dev->descriptor.idVendor, dev->descriptor.idProduct); dediprog_handle = usb_open(dev); - usb_set_configuration(dediprog_handle, 1); - usb_claim_interface(dediprog_handle, 0); + ret = usb_set_configuration(dediprog_handle, 1); + if (ret < 0) { + msg_perr("Could not set USB device configuration: %i %s\n", + ret, usb_strerror()); + if (usb_close(dediprog_handle)) + msg_perr("Could not close USB device!\n"); + return 1; + } + ret = usb_claim_interface(dediprog_handle, 0); + if (ret < 0) { + msg_perr("Could not claim USB device interface %i: %i %s\n", + 0, ret, usb_strerror()); + if (usb_close(dediprog_handle)) + msg_perr("Could not close USB device!\n"); + return 1; + } + dediprog_endpoint = 2; /* URB 6. Command A. */ if (dediprog_command_a()) return 1; @@ -445,9 +521,9 @@ /* URB 136 is just URB 9. */ /* URB 137 is just URB 11. */
- /* Command I is probably Start Bulk Read. Data is u16 blockcount, u16 blocksize. */ - /* Command J is probably Start Bulk Write. Data is u16 blockcount, u16 blocksize. */ - /* Bulk transfer sizes for Command I/J are always 512 bytes, rest is filled with 0xff. */ + /* Command Start Bulk Read. Data is u16 blockcount, u16 blocksize. */ + /* Command Start Bulk Write. Data is u16 blockcount, u16 blocksize. */ + /* Bulk transfer sizes for Command Start Bulk Read/Write are always 512 bytes, rest is filled with 0xff. */
return 0; } @@ -461,8 +537,12 @@ if (dediprog_set_spi_voltage(0x0)) return 1;
+ if (usb_release_interface(dediprog_handle, 0)) { + msg_perr("Could not release USB interface!\n"); + return 1; + } if (usb_close(dediprog_handle)) { - msg_perr("Couldn't close USB device!\n"); + msg_perr("Could not close USB device!\n"); return 1; } return 0;
On 12.11.2010 12:18, Carl-Daniel Hailfinger wrote:
New version: Fix error handling. libusb returns the number of bytes read/written, and those are nonzero in our case, triggering a false abort.
Support bulk read on Dediprog SF100. Should result in native speed for plain read and erase. Should result in a measurable speedup for writes due to a fast verify.
Read tests with chunksize = 0x20 would be appreciated. Read tests with chunksize = 0x1 would be appreciated. Both should be a lot slower, but still yield correct images.
Packet size is 512 bytes. Depending on your USB hardware and the Dediprog firmware version, this may not work at all. Add lots of error checking where it was missing before. Somewhat tested, experimental, may hang/crash the programmer.
Write tests of random images are appreciated.
Please note that flashrom needs full access permissions for the USB device.
Signed-off-by: Carl-Daniel Hailfinger c-d.hailfinger.devel.2006@gmx.net
Here is a totally nonportable test script which downloads flashrom, applies the patch, performs all tests and leaves behind two files with the results in a temporary directory. Just run it from anywhere in your system.
#!/bin/bash # Test script for flashrom patchwork 2306 # Copyright 2010 Carl-Daniel Hailfinger # Licensed under the GNU General Public License version 2.0
timecheck=$(which time)
OLDDIR=$(pwd)
# test data location mytmpdir=$(mktemp -d -t flashrom_test.XXXXXXXXXX) if [ "$?" != "0" ] ; then echo "Could not create temporary directory" exit 1 fi
cd $mytmpdir
svn co svn://coreboot.org/flashrom/trunk flashrom cd flashrom svn revert -R . svn up make distclean curl -s http://patchwork.coreboot.org/patch/2306/raw/%7Cpatch -p1
a=2306_plain echo Running test $a cp -a dediprog.c dediprog.c_$a rm -f dediprog.o make CONFIG_INTERNAL=no CONFIG_SERPROG=no CONFIG_RAYER_SPI=no CONFIG_NIC3COM=no CONFIG_GFXNVIDIA=no CONFIG_SATASII=no CONFIG_FT2232_SPI=no CONFIG_DRKAISER=no CONFIG_NICREALTEK=no CONFIG_NICINTEL_SPI=no CONFIG_BUSPIRATE_SPI=no CONFIG_DEDIPROG=yes CONFIG_DUMMY=no >dediprog_$a.buildlog 2>&1 $timecheck ./flashrom -p dediprog -V -r dediprog_readback_$a.rom >dediprog_$a.log 2>&1
sed -i 's/([[:blank:]]+chunksize[[:blank:]]*=)[[:blank:]]*0x[0-9a-f]*/\1 0x100/' dediprog.c a=2306_chunk0x100 echo Running test $a cp -a dediprog.c dediprog.c_$a rm -f dediprog.o make CONFIG_INTERNAL=no CONFIG_SERPROG=no CONFIG_RAYER_SPI=no CONFIG_NIC3COM=no CONFIG_GFXNVIDIA=no CONFIG_SATASII=no CONFIG_FT2232_SPI=no CONFIG_DRKAISER=no CONFIG_NICREALTEK=no CONFIG_NICINTEL_SPI=no CONFIG_BUSPIRATE_SPI=no CONFIG_DEDIPROG=yes CONFIG_DUMMY=no >dediprog_$a.buildlog 2>&1 $timecheck ./flashrom -p dediprog -V -r dediprog_readback_$a.rom >dediprog_$a.log 2>&1
sed -i 's/([[:blank:]]+chunksize[[:blank:]]*=)[[:blank:]]*0x[0-9a-f]*/\1 0x20/' dediprog.c a=2306_chunk0x20 echo Running test $a cp -a dediprog.c dediprog.c_$a rm -f dediprog.o make CONFIG_INTERNAL=no CONFIG_SERPROG=no CONFIG_RAYER_SPI=no CONFIG_NIC3COM=no CONFIG_GFXNVIDIA=no CONFIG_SATASII=no CONFIG_FT2232_SPI=no CONFIG_DRKAISER=no CONFIG_NICREALTEK=no CONFIG_NICINTEL_SPI=no CONFIG_BUSPIRATE_SPI=no CONFIG_DEDIPROG=yes CONFIG_DUMMY=no >dediprog_$a.buildlog 2>&1 $timecheck ./flashrom -p dediprog -V -r dediprog_readback_$a.rom >dediprog_$a.log 2>&1
sed -i 's/([[:blank:]]+chunksize[[:blank:]]*=)[[:blank:]]*0x[0-9a-f]*/\1 0x01/' dediprog.c a=2306_chunk0x01 echo Running test $a cp -a dediprog.c dediprog.c_$a rm -f dediprog.o make CONFIG_INTERNAL=no CONFIG_SERPROG=no CONFIG_RAYER_SPI=no CONFIG_NIC3COM=no CONFIG_GFXNVIDIA=no CONFIG_SATASII=no CONFIG_FT2232_SPI=no CONFIG_DRKAISER=no CONFIG_NICREALTEK=no CONFIG_NICINTEL_SPI=no CONFIG_BUSPIRATE_SPI=no CONFIG_DEDIPROG=yes CONFIG_DUMMY=no >dediprog_$a.buildlog 2>&1 $timecheck ./flashrom -p dediprog -V -r dediprog_readback_$a.rom >dediprog_$a.log 2>&1
sed -i 's/([[:blank:]]+chunksize[[:blank:]]*=)[[:blank:]]*0x[0-9a-f]*/\1 0x200/' dediprog.c sed -i 's/([[:blank:]]+offset[[:blank:]]*=)[[:blank:]]*0[0-9a-fx]*/\1 0x0/' dediprog.c a=2306_chunk0x200_offset_0x0 echo Running test $a cp -a dediprog.c dediprog.c_$a rm -f dediprog.o make CONFIG_INTERNAL=no CONFIG_SERPROG=no CONFIG_RAYER_SPI=no CONFIG_NIC3COM=no CONFIG_GFXNVIDIA=no CONFIG_SATASII=no CONFIG_FT2232_SPI=no CONFIG_DRKAISER=no CONFIG_NICREALTEK=no CONFIG_NICINTEL_SPI=no CONFIG_BUSPIRATE_SPI=no CONFIG_DEDIPROG=yes CONFIG_DUMMY=no >dediprog_$a.buildlog 2>&1 $timecheck ./flashrom -p dediprog -V -r dediprog_readback_$a.rom >dediprog_$a.log 2>&1
sed -i 's/([[:blank:]]+chunksize[[:blank:]]*=)[[:blank:]]*0x[0-9a-f]*/\1 0x200/' dediprog.c sed -i 's/([[:blank:]]+offset[[:blank:]]*=)[[:blank:]]*0[0-9a-fx]*/\1 0x1/' dediprog.c a=2306_chunk0x200_offset_0x1 echo Running test $a cp -a dediprog.c dediprog.c_$a rm -f dediprog.o make CONFIG_INTERNAL=no CONFIG_SERPROG=no CONFIG_RAYER_SPI=no CONFIG_NIC3COM=no CONFIG_GFXNVIDIA=no CONFIG_SATASII=no CONFIG_FT2232_SPI=no CONFIG_DRKAISER=no CONFIG_NICREALTEK=no CONFIG_NICINTEL_SPI=no CONFIG_BUSPIRATE_SPI=no CONFIG_DEDIPROG=yes CONFIG_DUMMY=no >dediprog_$a.buildlog 2>&1 $timecheck ./flashrom -p dediprog -V -r dediprog_readback_$a.rom >dediprog_$a.log 2>&1
sed -i 's/([[:blank:]]+chunksize[[:blank:]]*=)[[:blank:]]*0x[0-9a-f]*/\1 0x200/' dediprog.c sed -i 's/([[:blank:]]+offset[[:blank:]]*=)[[:blank:]]*0[0-9a-fx]*/\1 0x10/' dediprog.c a=2306_chunk0x200_offset_0x10 echo Running test $a cp -a dediprog.c dediprog.c_$a rm -f dediprog.o make CONFIG_INTERNAL=no CONFIG_SERPROG=no CONFIG_RAYER_SPI=no CONFIG_NIC3COM=no CONFIG_GFXNVIDIA=no CONFIG_SATASII=no CONFIG_FT2232_SPI=no CONFIG_DRKAISER=no CONFIG_NICREALTEK=no CONFIG_NICINTEL_SPI=no CONFIG_BUSPIRATE_SPI=no CONFIG_DEDIPROG=yes CONFIG_DUMMY=no >dediprog_$a.buildlog 2>&1 $timecheck ./flashrom -p dediprog -V -r dediprog_readback_$a.rom >dediprog_$a.log 2>&1
sed -i 's/([[:blank:]]+chunksize[[:blank:]]*=)[[:blank:]]*0x[0-9a-f]*/\1 0x100/' dediprog.c sed -i 's/([[:blank:]]+offset[[:blank:]]*=)[[:blank:]]*0[0-9a-fx]*/\1 0x0/' dediprog.c a=2306_chunk0x100_offset_0x0 echo Running test $a cp -a dediprog.c dediprog.c_$a rm -f dediprog.o make CONFIG_INTERNAL=no CONFIG_SERPROG=no CONFIG_RAYER_SPI=no CONFIG_NIC3COM=no CONFIG_GFXNVIDIA=no CONFIG_SATASII=no CONFIG_FT2232_SPI=no CONFIG_DRKAISER=no CONFIG_NICREALTEK=no CONFIG_NICINTEL_SPI=no CONFIG_BUSPIRATE_SPI=no CONFIG_DEDIPROG=yes CONFIG_DUMMY=no >dediprog_$a.buildlog 2>&1 $timecheck ./flashrom -p dediprog -V -r dediprog_readback_$a.rom >dediprog_$a.log 2>&1
sed -i 's/([[:blank:]]+chunksize[[:blank:]]*=)[[:blank:]]*0x[0-9a-f]*/\1 0x100/' dediprog.c sed -i 's/([[:blank:]]+offset[[:blank:]]*=)[[:blank:]]*0[0-9a-fx]*/\1 0x1/' dediprog.c a=2306_chunk0x100_offset_0x1 echo Running test $a cp -a dediprog.c dediprog.c_$a rm -f dediprog.o make CONFIG_INTERNAL=no CONFIG_SERPROG=no CONFIG_RAYER_SPI=no CONFIG_NIC3COM=no CONFIG_GFXNVIDIA=no CONFIG_SATASII=no CONFIG_FT2232_SPI=no CONFIG_DRKAISER=no CONFIG_NICREALTEK=no CONFIG_NICINTEL_SPI=no CONFIG_BUSPIRATE_SPI=no CONFIG_DEDIPROG=yes CONFIG_DUMMY=no >dediprog_$a.buildlog 2>&1 $timecheck ./flashrom -p dediprog -V -r dediprog_readback_$a.rom >dediprog_$a.log 2>&1
sed -i 's/([[:blank:]]+chunksize[[:blank:]]*=)[[:blank:]]*0x[0-9a-f]*/\1 0x100/' dediprog.c sed -i 's/([[:blank:]]+offset[[:blank:]]*=)[[:blank:]]*0[0-9a-fx]*/\1 0x10/' dediprog.c a=2306_chunk0x100_offset_0x10 echo Running test $a cp -a dediprog.c dediprog.c_$a rm -f dediprog.o make CONFIG_INTERNAL=no CONFIG_SERPROG=no CONFIG_RAYER_SPI=no CONFIG_NIC3COM=no CONFIG_GFXNVIDIA=no CONFIG_SATASII=no CONFIG_FT2232_SPI=no CONFIG_DRKAISER=no CONFIG_NICREALTEK=no CONFIG_NICINTEL_SPI=no CONFIG_BUSPIRATE_SPI=no CONFIG_DEDIPROG=yes CONFIG_DUMMY=no >dediprog_$a.buildlog 2>&1 $timecheck ./flashrom -p dediprog -V -r dediprog_readback_$a.rom >dediprog_$a.log 2>&1
sha1sum dediprog_readback_*.rom >dediprog_images.sha1
# Pack the results echo Packing the results tar czf ../flashrom_patchwork_2306_testresults.tar.gz dediprog.c_* dediprog_*.buildlog dediprog_*.log dediprog_images.sha1 tar cf ../flashrom_patchwork_2306_images.tar dediprog_readback_*.rom
# Clean up echo Cleaning up rm -f dediprog.c_* dediprog_*.buildlog dediprog_*.log dediprog_images.sha1 dediprog_readback_*.rom make distclean svn revert -R . cd .. rm -f -rf flashrom
# Tell the user echo echo The following files contain the test results: echo $mytmpdir/flashrom_patchwork_2306_testresults.tar.gz $mytmpdir/flashrom_patchwork_2306_images.tar
On 13.11.2010 01:54, Carl-Daniel Hailfinger wrote:
On 12.11.2010 12:18, Carl-Daniel Hailfinger wrote:
Support bulk read on Dediprog SF100.
Here is a totally nonportable test script which downloads flashrom, applies the patch, performs all tests and leaves behind two files with the results in a temporary directory. Just run it from anywhere in your system.
Please use the Windows Dediprog tool to write a random image to the flash chip before running this test script.
Regards, Carl-Daniel
New patch, this time hopefully in a version that can handle smaller chunksize.
Might even work for plain reads. Verify and write will be corrupt because that code path is not handled yet. Tests with chunksize = 0x20 and chunksize = 0x1 would be appreciated. They should be a lot slower, but still yield correct images. Tests with chunksize = 0x200 and offset = 0x1 would be appreciated. The resulting image should be shifted by 512 bytes.
Support Dediprog SF100 bulk read.
Packet size is 512 bytes. Depending on your USB hardware and the Dediprog firmware version, this may not work at all. Add lots of error checking where it was missing before. Untested, experimental, may hang/crash the programmer.
Read tests of random images are appreciated.
Please note that flashrom needs full access permissions for the USB device.
Signed-off-by: Carl-Daniel Hailfinger c-d.hailfinger.devel.2006@gmx.net
Index: flashrom-dediprog_read_bulk/dediprog.c =================================================================== --- flashrom-dediprog_read_bulk/dediprog.c (Revision 1232) +++ flashrom-dediprog_read_bulk/dediprog.c (Arbeitskopie) @@ -27,6 +27,7 @@
#define DEFAULT_TIMEOUT 3000 static usb_dev_handle *dediprog_handle; +static int dediprog_endpoint;
#if 0 /* Might be useful for other pieces of code as well. */ @@ -150,9 +151,49 @@
int dediprog_spi_read(struct flashchip *flash, uint8_t *buf, int start, int len) { + int ret; + int i; + int chunksize = 0x200; /* 512, other sizes may not work at all. */ + const int bulktransfer_chunksize = 0x200; /* 512, other sizes may not work at all. */ + int count = flash->total_size * 1024 / chunksize; + /* Guessed. */ + const char count_and_chunk[] = { + count & 0xff, + (count >> 8) & 0xff, + chunksize & 0xff, + (chunksize >> 8) & 0xff}; + int offset = 0; + char tmpbuf[bulktransfer_chunksize]; + msg_pspew("%s, start=0x%x, len=0x%x\n", __func__, start, len); - /* Chosen read length is 16 bytes for now. */ - return spi_read_chunked(flash, buf, start, len, 16); + if ((len != flash->total_size * 1024) || (start != 0)) { + msg_perr("Only a full chip read is supported for now. Wanted " + "start=%i, length=%i\n.", start, len); + return 1; + } + + /* Command Read SPI Bulk. No idea which read command is used on the + * SPI side. offset is a total guess, I only saw it being 0 everywhere. + */ + ret = usb_control_msg(dediprog_handle, 0x42, 0x20, 0x0000, offset, (char *)count_and_chunk, sizeof(count_and_chunk), DEFAULT_TIMEOUT); + if (ret != sizeof(count_and_chunk)) { + msg_perr("Command Read SPI Bulk failed, %i %s!\n", ret, + usb_strerror()); + return 1; + } + + for (i = 0; i < count; i++) { + /* Crude progress bar, enable with -VV */ + ret = usb_bulk_read(dediprog_handle, 0x80 | dediprog_endpoint, tmpbuf, bulktransfer_chunksize, DEFAULT_TIMEOUT); + memcpy(buf + i * chunksize, tmpbuf, chunksize); + if (ret != bulktransfer_chunksize) { + msg_perr("SPI bulk read %i failed, expected %i, got %i " + "%s!\n", i, chunksize, ret, usb_strerror()); + return 1; + } + } + + return 0; }
int dediprog_spi_send_command(unsigned int writecnt, unsigned int readcnt, @@ -345,6 +386,7 @@ struct usb_device *dev; char *voltage; int millivolt = 3500; + int ret;
msg_pspew("%s\n", __func__);
@@ -371,8 +413,23 @@ dev->descriptor.idVendor, dev->descriptor.idProduct); dediprog_handle = usb_open(dev); - usb_set_configuration(dediprog_handle, 1); - usb_claim_interface(dediprog_handle, 0); + ret = usb_set_configuration(dediprog_handle, 1); + if (ret < 0) { + msg_perr("Could not set USB device configuration: %i %s\n", + ret, usb_strerror()); + if (usb_close(dediprog_handle)) + msg_perr("Could not close USB device!\n"); + return 1; + } + ret = usb_claim_interface(dediprog_handle, 0); + if (ret < 0) { + msg_perr("Could not claim USB device interface %i: %i %s\n", + 0, ret, usb_strerror()); + if (usb_close(dediprog_handle)) + msg_perr("Could not close USB device!\n"); + return 1; + } + dediprog_endpoint = 2; /* URB 6. Command A. */ if (dediprog_command_a()) return 1; @@ -461,8 +518,12 @@ if (dediprog_set_spi_voltage(0x0)) return 1;
+ if (usb_release_interface(dediprog_handle, 0)) { + msg_perr("Could not release USB interface!\n"); + return 1; + } if (usb_close(dediprog_handle)) { - msg_perr("Couldn't close USB device!\n"); + msg_perr("Could not close USB device!\n"); return 1; } return 0;
New patch, incorporates the latest reverse engineering results.
Might even work for plain reads. Verify and write will be corrupt because that code path is not handled yet. Tests with offset=0x1, offset=0x200 and offset=0x10000 would be appreciated. The resulting images should be shifted by 1, 512 and 65536 bytes.
Support Dediprog SF100 bulk read.
Packet size is 512 bytes. Depending on your USB hardware and the Dediprog firmware version, this may not work at all. Add lots of error checking where it was missing before. Untested, experimental, may hang/crash the programmer.
Read tests of random images are appreciated.
Please note that flashrom needs full access permissions for the USB device.
Signed-off-by: Carl-Daniel Hailfinger c-d.hailfinger.devel.2006@gmx.net
Index: flashrom-dediprog_read_bulk/dediprog.c =================================================================== --- flashrom-dediprog_read_bulk/dediprog.c (Revision 1232) +++ flashrom-dediprog_read_bulk/dediprog.c (Arbeitskopie) @@ -27,6 +27,7 @@
#define DEFAULT_TIMEOUT 3000 static usb_dev_handle *dediprog_handle; +static int dediprog_endpoint;
#if 0 /* Might be useful for other pieces of code as well. */ @@ -150,9 +151,47 @@
int dediprog_spi_read(struct flashchip *flash, uint8_t *buf, int start, int len) { + int ret; + int i; + const int chunksize = 0x200; /* Other sizes will NOT work at all. */ + int count = flash->total_size * 1024 / chunksize; + /* Guessed. */ + const char count_and_chunk[] = { + count & 0xff, + (count >> 8) & 0xff, + chunksize & 0xff, + (chunksize >> 8) & 0xff}; + char tmpbuf[chunksize]; /* FIXME: Read directly into buf? */ + int offset = 0; /* start address. */ + msg_pspew("%s, start=0x%x, len=0x%x\n", __func__, start, len); - /* Chosen read length is 16 bytes for now. */ - return spi_read_chunked(flash, buf, start, len, 16); + if ((len != flash->total_size * 1024) || (start != 0)) { + msg_perr("Only a full chip read is supported for now. Wanted " + "start=%i, length=%i\n.", start, len); + return 1; + } + + /* Command Read SPI Bulk. No idea which read command is used on the + * SPI side. + */ + ret = usb_control_msg(dediprog_handle, 0x42, 0x20, offset % 0x10000, offset / 0x10000, (char *)count_and_chunk, sizeof(count_and_chunk), DEFAULT_TIMEOUT); + if (ret != sizeof(count_and_chunk)) { + msg_perr("Command Read SPI Bulk failed, %i %s!\n", ret, + usb_strerror()); + return 1; + } + + for (i = 0; i < count; i++) { + ret = usb_bulk_read(dediprog_handle, 0x80 | dediprog_endpoint, tmpbuf, chunksize, DEFAULT_TIMEOUT); + memcpy(buf + i * chunksize, tmpbuf, chunksize); + if (ret != chunksize) { + msg_perr("SPI bulk read %i failed, expected %i, got %i " + "%s!\n", i, chunksize, ret, usb_strerror()); + return 1; + } + } + + return 0; }
int dediprog_spi_send_command(unsigned int writecnt, unsigned int readcnt, @@ -345,6 +384,7 @@ struct usb_device *dev; char *voltage; int millivolt = 3500; + int ret;
msg_pspew("%s\n", __func__);
@@ -371,8 +411,23 @@ dev->descriptor.idVendor, dev->descriptor.idProduct); dediprog_handle = usb_open(dev); - usb_set_configuration(dediprog_handle, 1); - usb_claim_interface(dediprog_handle, 0); + ret = usb_set_configuration(dediprog_handle, 1); + if (ret < 0) { + msg_perr("Could not set USB device configuration: %i %s\n", + ret, usb_strerror()); + if (usb_close(dediprog_handle)) + msg_perr("Could not close USB device!\n"); + return 1; + } + ret = usb_claim_interface(dediprog_handle, 0); + if (ret < 0) { + msg_perr("Could not claim USB device interface %i: %i %s\n", + 0, ret, usb_strerror()); + if (usb_close(dediprog_handle)) + msg_perr("Could not close USB device!\n"); + return 1; + } + dediprog_endpoint = 2; /* URB 6. Command A. */ if (dediprog_command_a()) return 1; @@ -461,8 +516,12 @@ if (dediprog_set_spi_voltage(0x0)) return 1;
+ if (usb_release_interface(dediprog_handle, 0)) { + msg_perr("Could not release USB interface!\n"); + return 1; + } if (usb_close(dediprog_handle)) { - msg_perr("Couldn't close USB device!\n"); + msg_perr("Could not close USB device!\n"); return 1; } return 0;
Final version.
Support bulk read on Dediprog SF100. Should result in native speed for plain read and erase. Should result in a measurable speedup for writes due to a fast verify. Packet size is 512 bytes. Depending on your USB hardware and the Dediprog firmware version, this may not work at all. That said, it worked on the hardware we tested.
Add lots of error checking where it was missing before.
Signed-off-by: Carl-Daniel Hailfinger c-d.hailfinger.devel.2006@gmx.net
Index: flashrom-dediprog_read_bulk/dediprog.c =================================================================== --- flashrom-dediprog_read_bulk/dediprog.c (Revision 1232) +++ flashrom-dediprog_read_bulk/dediprog.c (Arbeitskopie) @@ -27,6 +27,7 @@
#define DEFAULT_TIMEOUT 3000 static usb_dev_handle *dediprog_handle; +static int dediprog_endpoint;
#if 0 /* Might be useful for other pieces of code as well. */ @@ -148,11 +149,93 @@ } #endif
+/* Bulk read interface, will read multiple 512 byte chunks aligned to 512 bytes. + * @start start address + * @len length + * @return 0 on success, 1 on failure + */ +static int dediprog_spi_bulk_read(struct flashchip *flash, uint8_t *buf, + int start, int len) +{ + int ret; + int i; + /* chunksize must be 512, other sizes will NOT work at all. */ + const int chunksize = 0x200; + const int count = len / chunksize; + const char count_and_chunk[] = {count & 0xff, + (count >> 8) & 0xff, + chunksize & 0xff, + (chunksize >> 8) & 0xff}; + + if ((start % chunksize) || (len % chunksize)) { + msg_perr("%s: Unaligned start=%i, len=%i! Please report a bug " + "at flashrom@flashrom.org\n", __func__, start, len); + return 1; + } + + /* No idea if the hardware can handle empty reads, so chicken out. */ + if (!len) + return 0; + /* Command Read SPI Bulk. No idea which read command is used on the + * SPI side. + */ + ret = usb_control_msg(dediprog_handle, 0x42, 0x20, start % 0x10000, + start / 0x10000, (char *)count_and_chunk, + sizeof(count_and_chunk), DEFAULT_TIMEOUT); + if (ret != sizeof(count_and_chunk)) { + msg_perr("Command Read SPI Bulk failed, %i %s!\n", ret, + usb_strerror()); + return 1; + } + + for (i = 0; i < count; i++) { + ret = usb_bulk_read(dediprog_handle, 0x80 | dediprog_endpoint, + (char *)buf + i * chunksize, chunksize, + DEFAULT_TIMEOUT); + if (ret != chunksize) { + msg_perr("SPI bulk read %i failed, expected %i, got %i " + "%s!\n", i, chunksize, ret, usb_strerror()); + return 1; + } + } + + return 0; +} + int dediprog_spi_read(struct flashchip *flash, uint8_t *buf, int start, int len) { - msg_pspew("%s, start=0x%x, len=0x%x\n", __func__, start, len); - /* Chosen read length is 16 bytes for now. */ - return spi_read_chunked(flash, buf, start, len, 16); + int ret; + /* chunksize must be 512, other sizes will NOT work at all. */ + const int chunksize = 0x200; + int residue = start % chunksize ? chunksize - start % chunksize : 0; + int bulklen; + + if (residue) { + msg_pdbg("Slow read for partial block from 0x%x, length 0x%x\n", + start, residue); + ret = spi_read_chunked(flash, buf, start, residue, 16); + if (ret) + return ret; + } + + /* Round down. */ + bulklen = (len - residue) / chunksize * chunksize; + ret = dediprog_spi_bulk_read(flash, buf + residue, start + residue, + bulklen); + if (ret) + return ret; + + len -= residue + bulklen; + if (len) { + msg_pdbg("Slow read for partial block from 0x%x, length 0x%x\n", + start, len); + ret = spi_read_chunked(flash, buf + residue + bulklen, + start + residue + bulklen, len, 16); + if (ret) + return ret; + } + + return 0; }
int dediprog_spi_send_command(unsigned int writecnt, unsigned int readcnt, @@ -345,6 +428,7 @@ struct usb_device *dev; char *voltage; int millivolt = 3500; + int ret;
msg_pspew("%s\n", __func__);
@@ -371,8 +455,23 @@ dev->descriptor.idVendor, dev->descriptor.idProduct); dediprog_handle = usb_open(dev); - usb_set_configuration(dediprog_handle, 1); - usb_claim_interface(dediprog_handle, 0); + ret = usb_set_configuration(dediprog_handle, 1); + if (ret < 0) { + msg_perr("Could not set USB device configuration: %i %s\n", + ret, usb_strerror()); + if (usb_close(dediprog_handle)) + msg_perr("Could not close USB device!\n"); + return 1; + } + ret = usb_claim_interface(dediprog_handle, 0); + if (ret < 0) { + msg_perr("Could not claim USB device interface %i: %i %s\n", + 0, ret, usb_strerror()); + if (usb_close(dediprog_handle)) + msg_perr("Could not close USB device!\n"); + return 1; + } + dediprog_endpoint = 2; /* URB 6. Command A. */ if (dediprog_command_a()) return 1; @@ -461,8 +560,12 @@ if (dediprog_set_spi_voltage(0x0)) return 1;
+ if (usb_release_interface(dediprog_handle, 0)) { + msg_perr("Could not release USB interface!\n"); + return 1; + } if (usb_close(dediprog_handle)) { - msg_perr("Couldn't close USB device!\n"); + msg_perr("Could not close USB device!\n"); return 1; } return 0;
On Mon, Nov 15, 2010 at 8:54 PM, Carl-Daniel Hailfinger c-d.hailfinger.devel.2006@gmx.net wrote:
Final version.
Support bulk read on Dediprog SF100. Should result in native speed for plain read and erase. Should result in a measurable speedup for writes due to a fast verify. Packet size is 512 bytes. Depending on your USB hardware and the Dediprog firmware version, this may not work at all. That said, it worked on the hardware we tested.
Add lots of error checking where it was missing before.
Signed-off-by: Carl-Daniel Hailfinger c-d.hailfinger.devel.2006@gmx.net
Tested with a Dediprog SF100 firmware V:5.1.5
Works both pre and post svn r1233
Acked-By: Richard A. Smith richard@laptop.org
On 16.11.2010 18:47, Richard Smith wrote:
On Mon, Nov 15, 2010 at 8:54 PM, Carl-Daniel Hailfinger c-d.hailfinger.devel.2006@gmx.net wrote:
Final version.
Support bulk read on Dediprog SF100. Should result in native speed for plain read and erase. Should result in a measurable speedup for writes due to a fast verify. Packet size is 512 bytes. Depending on your USB hardware and the Dediprog firmware version, this may not work at all. That said, it worked on the hardware we tested.
Add lots of error checking where it was missing before.
Signed-off-by: Carl-Daniel Hailfinger c-d.hailfinger.devel.2006@gmx.net
Tested with a Dediprog SF100 firmware V:5.1.5
Works both pre and post svn r1233
Acked-By: Richard A. Smith richard@laptop.org
I got the following Ack on IRC: Acked-By: Mathias Krause mathias.krause@secunet.com
and committed in r1234.
Regards, Carl-Daniel