URL
https://opencores.org/ocsvn/usb_nand_reader/usb_nand_reader/trunk
Subversion Repositories usb_nand_reader
Compare Revisions
- This comparison shows the changes necessary to convert path
/usb_nand_reader
- from Rev 1 to Rev 2
- ↔ Reverse comparison
Rev 1 → Rev 2
/trunk/pc/actions.c
0,0 → 1,234
|
#include <stdio.h> |
#include <stdlib.h> |
#include <string.h> |
#include <libusb-1.0/libusb.h> |
#include "include/opcodes.h" |
#include "include/actions.h" |
#include "include/nand_vendors.h" |
|
unsigned char ioBuffer[64]; |
int dataTransfered; |
|
int |
usb_write(libusb_device_handle* usb, unsigned char* data, int len) |
{ |
int ds; |
int i = 0; |
int l = (len < 64)? 64 : len; |
|
while(i < l) |
{ |
libusb_bulk_transfer(usb, 0x01, data + i, l - i, &ds, 1000); |
i += ds; |
} |
return i; |
} |
|
int |
usb_read(libusb_device_handle* usb, unsigned char* data, int len) |
{ |
int ds; |
int i = 0, r; |
if(len % 64 != 0) |
{ |
fprintf(stderr, "\nIncorrect read length\n"); |
return 0; |
} |
while(i < len) |
{ |
if(0 > (r = libusb_bulk_transfer(usb, 0x81, data + i, len - i, &ds, 10000))) |
{ |
fprintf(stderr, "libusb_bulk_transfer() returned %d\n", r); |
//exit(-4); |
} |
i += ds; |
if(0 == ds) |
exit(-3); |
} |
return i; |
} |
|
USB_ACTION(nand_reset) |
{ |
ioBuffer[0] = NAND_CHIP_RESET; |
usb_write(usb, ioBuffer, 1); |
return 0; |
} |
|
USB_ACTION(nand_enable, int dieIndex) |
{ |
ioBuffer[0] = NAND_CHIP_ENABLE; |
ioBuffer[1] = (unsigned char)(dieIndex & 3); |
usb_write(usb, ioBuffer, 2); |
return 0; |
} |
|
USB_ACTION(nand_disble) |
{ |
ioBuffer[0] = NAND_CHIP_DISABLE; |
usb_write(usb, ioBuffer, 1); |
return 0; |
} |
|
USB_ACTION(nand_read_id, unsigned char* idBuffer) |
{ |
ioBuffer[0] = NAND_CHIP_READ_ID; |
usb_write(usb, ioBuffer, 1); |
usb_read(usb, ioBuffer, 64); |
memcpy(idBuffer, ioBuffer, 5); |
return 0; |
} |
|
USB_ACTION(nand_is_onfi, unsigned char* signature) |
{ |
ioBuffer[0] = NAND_CHIP_READ_ID_ONFI; |
usb_write(usb, ioBuffer, 1); |
usb_read(usb, ioBuffer, 64); |
memcpy(signature, ioBuffer, 4); |
if(ioBuffer[0] == 'O' && ioBuffer[1] == 'N' && ioBuffer[2] == 'F' && ioBuffer[3] == 'I') |
return 1; |
return 0; |
} |
|
USB_ACTION(nand_read_onfi_param_page, unsigned char* paramPageBuffer) |
{ |
ioBuffer[0] = NAND_CHIP_READ_PARAM_PAGE; |
usb_write(usb, ioBuffer, 1); |
usb_read(usb, paramPageBuffer, 256); |
return 0; |
} |
|
USB_ACTION(nand_set_config_data, pnand_t nand) |
{ |
ioBuffer[0] = NAND_SET_CONFIG_DATA; |
*(int*)(&ioBuffer[1]) = nand->bytesPerPage + nand->oobPerPage; |
ioBuffer[5] = (unsigned char)(nand->addressCycles & 0xff); |
ioBuffer[6] = (unsigned char)(nand->busWidth); |
usb_write(usb, ioBuffer, 6); |
return 0; |
} |
|
USB_ACTION(nand_read_page, unsigned int pageAddress, pnand_t nand) |
{ |
//struct timespec start = {0, 0}, end = {0, 0}; |
ioBuffer[0] = NAND_CHIP_READ_PAGE; |
ioBuffer[1] = ioBuffer[2] = 0; |
*(unsigned int*)(&ioBuffer[3]) = (pageAddress & 0x00ffffff); |
//clock_gettime(CLOCK_MONOTONIC, &start); |
usb_write(usb, ioBuffer, 64); |
//printf("read %d bytes\n", usb_read(usb, nand->pageBuffer, nand->bytesPerPage + nand->oobPerPage)); |
|
usb_read(usb, nand->pageBuffer, nand->bytesPerPage + nand->oobPerPage); |
//clock_gettime(CLOCK_MONOTONIC, &end); |
//printf("\r\tPage read in %.10f seconds.", ((double)end.tv_sec + 1.0e-9 * end.tv_nsec) - ((double)start.tv_sec + 1.0e-9 * start.tv_nsec)); |
//fflush(stdout); |
return 0; |
} |
|
USB_ACTION(nand_read_page_cache, unsigned int startPageAddress, int pageCount, FILE* storeTo, pnand_t nand) |
{ |
int currentPage, blocks = 0; |
unsigned int sa = startPageAddress; |
|
if(0 != pageCount % nand->pagesPerBlock) |
return -1; |
|
while(blocks < pageCount / nand->pagesPerBlock) |
{ |
fprintf(stderr,"\rBlock #%d (%0.4f%%)", blocks, (float)blocks / ((float)(pageCount / nand->pagesPerBlock) / 100.0f)); |
ioBuffer[0] = NAND_CHIP_READ_CACHE_SEQ; |
ioBuffer[1] = ioBuffer[2] = 0; |
*(unsigned int*)(&ioBuffer[3]) = (sa & 0x00ffffff); |
*(int*)(&ioBuffer[6]) = nand->pagesPerBlock; |
usb_write(usb, ioBuffer, 64); |
|
for(currentPage = 0; currentPage < nand->pagesPerBlock; currentPage++) |
{ |
usb_read(usb, nand->pageBuffer, nand->bytesPerPage + nand->oobPerPage); |
if(NULL != storeTo) |
store_page(storeTo, nand); |
//fprintf(stderr,"\rBlock #%d %0.2f%% completed", blocks, (float)currentPage / ((float)nand->pagesPerBlock / 100.0f)); |
} |
blocks++; |
sa += nand->pagesPerBlock; |
} |
fprintf(stderr, "\n"); |
return 0; |
} |
|
USB_ACTION(nand_read_status, unsigned char* status) |
{ |
ioBuffer[0] = NAND_CHIP_READ_STATUS; |
usb_write(usb, ioBuffer, 64); |
usb_read(usb, ioBuffer, 64); |
if(status) |
*status = ioBuffer[0]; |
return (int)ioBuffer[0]; |
} |
|
USB_ACTION(nand_read_status_enhanced, unsigned int address, unsigned char* status) |
{ |
ioBuffer[0] = NAND_CHIP_READ_STATUS; |
*(unsigned int*)(&ioBuffer[1]) = address & 0xffffff; |
usb_write(usb, ioBuffer, 64); |
usb_read(usb, ioBuffer, 64); |
if(status) |
*status = ioBuffer[0]; |
return (int)ioBuffer[0]; |
} |
|
USB_ACTION(nand_read_unique_id, unsigned char* uid) |
{ |
ioBuffer[0] = NAND_CHIP_READ_UNIQUE_ID; |
usb_write(usb, ioBuffer, 64); |
usb_read(usb, ioBuffer, 64); |
memcpy(uid, ioBuffer, 64); |
return 0; |
} |
|
int nand_check_uid(unsigned char* buffer) |
{ |
int i; |
for(i = 0; i < 16; i++) |
{ |
if(0xFF != (*(buffer + i) ^ *(buffer + i + 16))) |
return 0; |
} |
return 1; |
} |
|
|
USB_ACTION(nand_block_erase, unsigned int blockAddress) |
{ |
ioBuffer[0] = NAND_CHIP_BLOCK_ERASE; |
*(unsigned int*)(&ioBuffer[1]) = (blockAddress & 0x00ffffff); |
usb_write(usb, ioBuffer, 64); |
return 0; |
} |
|
USB_ACTION(nand_toggle_wp) |
{ |
ioBuffer[0] = NAND_CHIP_TOGGLE_WP; |
usb_write(usb, ioBuffer, 64); |
return 0; |
} |
|
USB_ACTION(nand_page_program, unsigned int pageAddress, pnand_t nand) |
{ |
//int i; |
|
ioBuffer[0] = NAND_CHIP_PAGE_PROGRAM; |
ioBuffer[1] = ioBuffer[2] = 0; |
*(unsigned int*)(&ioBuffer[3]) = (pageAddress & 0x00ffffff); |
usb_write(usb, ioBuffer, 64); |
/* |
for(i = 0; i < nand->bytesPerPage + nand->oobPerPage; i += 64) |
{ |
fprintf(stderr, "Written %d bytes\n", usb_write(usb, nand->pageBuffer + i, 64)); |
} |
*/ |
|
fprintf(stderr, "Written %d bytes\n", usb_write(usb, nand->pageBuffer, nand->bytesPerPage + nand->oobPerPage)); |
return 0; |
} |
/trunk/pc/include/actions.h
0,0 → 1,26
#ifndef ACTIONS_H |
#define ACTIONS_H |
|
#include "include/nand_vendors.h" |
|
#define USB_ACTION(pname, ...) int pname(libusb_device_handle* usb, ##__VA_ARGS__) |
|
|
USB_ACTION(nand_reset); |
USB_ACTION(nand_enable, int dieIndex); |
USB_ACTION(nand_disble); |
USB_ACTION(nand_read_id, unsigned char* idBuffer); |
USB_ACTION(nand_is_onfi, unsigned char* signature); |
USB_ACTION(nand_read_onfi_param_page, unsigned char* paramPageBuffer); |
USB_ACTION(nand_set_config_data, pnand_t nand); |
USB_ACTION(nand_read_page, unsigned int pageAddress, pnand_t nand); |
USB_ACTION(nand_read_page_cache, unsigned int startPageAddress, int pageCount, FILE* storeTo, pnand_t nand); |
USB_ACTION(nand_read_status, unsigned char* status); |
USB_ACTION(nand_read_status_enhanced, unsigned int address, unsigned char* status); |
USB_ACTION(nand_read_unique_id, unsigned char* uid); |
int nand_check_uid(unsigned char* buffer); |
USB_ACTION(nand_block_erase, unsigned int blockAddress); |
USB_ACTION(nand_toggle_wp); |
USB_ACTION(nand_page_program, unsigned int pageAddress, pnand_t nand); |
|
#endif /* ACTIONS_H */ |
/trunk/pc/include/nand_vendors.h
0,0 → 1,33
#ifndef NAND_VENDORS_H |
#define NAND_VENDORS_H |
|
|
|
|
|
typedef struct |
{ |
int bytesPerPage; |
int oobPerPage; |
int pagesPerBlock; |
int blocksPerPlane; |
int planesPerLun; |
int numLuns; |
int addressCycles; |
int busWidth; // x8 or x16 |
unsigned char id[5]; |
unsigned char onfiSignature[4]; |
unsigned char* onfiParameterPage; |
unsigned char* pageBuffer; |
char* manufacturer; |
char* device; |
}nand_t, *pnand_t; |
|
|
int get_nand_configuration(pnand_t nand); |
void free_nand_info(pnand_t* nand); |
void print_nand_configuration(pnand_t nand); |
void dump_page(pnand_t nand); |
void store_page(FILE* f, pnand_t nand); |
|
#endif /* NAND_VENDORS_H */ |
/trunk/pc/include/opcodes.h
0,0 → 1,21
#ifndef OPCODES_H |
#define OPCODES_H |
|
#define NAND_CHIP_ENABLE 1 |
#define NAND_CHIP_DISABLE 2 |
#define NAND_CHIP_RESET 3 |
#define NAND_CHIP_READ_ID 4 |
#define NAND_CHIP_READ_ID_ONFI 5 |
#define NAND_CHIP_READ_PARAM_PAGE 6 |
#define NAND_CHIP_READ_PAGE 7 |
#define NAND_SET_CONFIG_DATA 8 // Sets configuration data for non ONFI chips (page size, address cycles, etc) |
#define NAND_CHIP_READ_CACHE_SEQ 9 // READ_PAGE_CACHE_SEQUENTIAL |
#define NAND_CHIP_READ_STATUS 10 |
#define NAND_CHIP_READ_UNIQUE_ID 11 |
#define NAND_CHIP_BLOCK_ERASE 12 |
#define NAND_CHIP_TOGGLE_WP 13 // Toggles write protect (WP = 0 on reset/powerup) |
#define NAND_CHIP_PAGE_PROGRAM 14 |
#define NAND_CHIP_READ_STATUS_ENHANCED 15 |
|
|
#endif /* OPCODES_H */ |
/trunk/pc/main.c
0,0 → 1,174
#include <stdio.h> |
#include <libusb-1.0/libusb.h> |
#include <stdlib.h> |
#include <string.h> |
#include <unistd.h> |
|
#include "include/opcodes.h" |
#include "include/actions.h" |
#include "include/nand_vendors.h" |
|
int main(int argc, char **argv) |
{ |
FILE* dump; |
libusb_context* ctx; |
libusb_device** list; |
libusb_device_handle* hDevice = NULL; |
struct libusb_device_descriptor descr; |
int count, i; |
|
unsigned char bufferOut[64]; |
unsigned char status; |
|
pnand_t nand; |
|
libusb_init(&ctx); |
|
count = libusb_get_device_list(ctx, &list); |
|
if(0 == count) |
{ |
fprintf(stderr, "Could not get device list\n"); |
exit(-1); |
} |
|
for(i = 0; i < count; i++) |
{ |
libusb_device* tmpDevice = list[i]; |
libusb_get_device_descriptor(tmpDevice, &descr); |
|
if(0x1234 == descr.idVendor && 0x1 == descr.idProduct) |
{ |
libusb_open(tmpDevice, &hDevice); |
break; |
} |
} |
libusb_free_device_list(list,1); |
|
if(NULL == hDevice) |
{ |
fprintf(stderr, "Could not find the device\n"); |
exit(-1); |
} |
else |
{ |
printf("Device opened\n"); |
} |
|
|
if(libusb_kernel_driver_active(hDevice, 0) == 1) |
{ |
printf("Detaching driver\n"); |
libusb_detach_kernel_driver(hDevice, 0); |
} |
|
libusb_claim_interface(hDevice, 0); |
//libusb_reset_device(hDevice); |
|
//============================== |
// USB initialization completed. |
//============================== |
|
nand = (pnand_t)malloc(sizeof(nand_t)); |
memset(nand, 0, sizeof(nand_t)); |
|
memset(bufferOut, 0, 64); |
|
nand_enable(hDevice, 0); |
nand_reset(hDevice); |
nand_read_id(hDevice, nand->id); |
if(nand_is_onfi(hDevice, nand->onfiSignature)) |
{ |
nand->onfiParameterPage = (unsigned char*)malloc(sizeof(unsigned char) * 256); |
|
|
nand_read_onfi_param_page(hDevice, nand->onfiParameterPage); |
|
} |
|
if(1 != get_nand_configuration(nand)) |
{ |
printf("Could not get configuration for this chip\n"); |
nand_disble(hDevice); |
libusb_close(hDevice); |
libusb_exit(ctx); |
return -1; |
} |
|
// Set configuration data if chip is not ONFI compliant or has corrupted ONFI parameter page/signature |
if(NULL == nand->onfiParameterPage) |
{ |
printf("Setting configuration data\n"); |
nand_set_config_data(hDevice, nand); |
} |
|
print_nand_configuration(nand); |
|
/* |
printf("Status: %02x\n", nand_read_status(hDevice, NULL)); |
nand_toggle_wp(hDevice); |
|
fprintf(stderr, "Erasing block\n"); |
nand_block_erase(hDevice, 0); |
//sleep(1); |
printf("Status: %02x\n", nand_read_status_enhanced(hDevice, 0, NULL)); |
|
fprintf(stderr, "Programming page\n"); |
|
{ |
int x; |
for(x = 0; x < nand->bytesPerPage + nand->oobPerPage; x++) |
{ |
nand->pageBuffer[x] = (unsigned char)((x) & 0xf0); |
} |
} |
|
nand_page_program(hDevice, 0, nand); |
|
printf("Status: %02x\n", nand_read_status_enhanced(hDevice, 0, NULL)); |
|
nand_toggle_wp(hDevice); |
*/ |
printf("Dumping flash\n"); |
i = 0; |
dump = fopen("flash_dump.bin", "wb"); |
|
nand_read_status_enhanced(hDevice, 0, &status); |
printf("Status: %02x\n", status); |
|
/* |
for(count = 0; count < nand->pagesPerBlock * nand->blocksPerPlane * nand->planesPerLun * nand->numLuns; count++) |
{ |
if(count % 64 == 0) |
{ |
printf("\rBlock #%d", i++); |
fflush(stdout); |
} |
nand_read_page(hDevice, (unsigned int)count, nand); |
store_page(dump, nand); |
} |
*/ |
printf("Dumping %d pages\n", nand->pagesPerBlock * nand->blocksPerPlane * nand->planesPerLun * nand->numLuns); |
//nand_read_page_cache(hDevice, 0, nand->pagesPerBlock * nand->blocksPerPlane * nand->planesPerLun * nand->numLuns, dump, nand); |
nand_read_page_cache(hDevice, 0, 640, dump, nand); |
|
nand_read_status(hDevice, &status); |
printf("Status: %02x\n", status); |
|
fclose(dump); |
printf("\rdone.\n"); |
|
free_nand_info(&nand); |
|
nand_disble(hDevice); |
|
//================= |
// Close USB stuff. |
//================= |
|
libusb_close(hDevice); |
|
libusb_exit(ctx); |
|
return 0; |
} |
/trunk/pc/nand_vendors.c
0,0 → 1,181
|
#include <stdlib.h> |
#include <string.h> |
#include <stdio.h> |
#include <ctype.h> |
#include "include/nand_vendors.h" |
|
|
int |
get_nand_configuration(pnand_t nand) |
{ |
int result = 0; |
|
printf("Getting configuration\n"); |
|
if(NULL != nand->onfiParameterPage) |
{ |
nand->manufacturer = strndup((char*)nand->onfiParameterPage + 32, 12); |
nand->device = strndup((char*)nand->onfiParameterPage + 44, 20); |
nand->bytesPerPage = *(int*)(nand->onfiParameterPage + 80); |
nand->oobPerPage = (int)*(short*)(nand->onfiParameterPage + 84); |
nand->pagesPerBlock = *(int*)(nand->onfiParameterPage + 92); |
nand->planesPerLun = 1; |
nand->blocksPerPlane = *(int*)(nand->onfiParameterPage + 96); |
nand->numLuns = (int)*(nand->onfiParameterPage +100); |
nand->addressCycles = (*(nand->onfiParameterPage + 101) & 0x0f) + ((*(nand->onfiParameterPage + 101) >> 4) & 0x0f); |
nand->busWidth = 8 << (*(nand->onfiParameterPage + 6) & 0x01); |
result = 1; |
} |
else |
{ |
switch(nand->id[0]) |
{ |
case 0x2c: // Micron |
printf("Micron NAND flash detected\n"); |
nand->manufacturer = strdup("Micron"); |
|
if(nand->id[1] == 0xa1) |
nand->device = strdup("MT29F1G08ABBDA"); |
else if(nand->id[1] == 0xaa) |
nand->device = strdup("MT29F2G08ABBEA"); |
else if(nand->id[1] == 0xb1) |
nand->device = strdup("MT29F1G16ABBDA"); |
else if(nand->id[1] == 0xba) |
nand->device = strdup("MT29F2G16ABBEA"); |
else if(nand->id[1] == 0xca) |
nand->device = strdup("MT29F2G16ABAEA"); |
else if(nand->id[1] == 0xda) |
nand->device = strdup("MT29F2G08ABAEA"); |
else |
{ |
printf("Unknown device\n"); |
break; |
} |
|
if((nand->id[3] & 3) == 1) |
nand->bytesPerPage = 2048; |
else |
{ |
printf("Could not get number of bytes per page\n"); |
break; |
} |
|
if((nand->id[3] & 4) == 4) |
nand->oobPerPage = 64; |
else |
{ |
printf("Could not get number of OOB bytes per page\n"); |
break; |
} |
|
|
nand->pagesPerBlock = ((64 << ((nand->id[3] >> 4) & 3)) * 1024) / nand->bytesPerPage; |
nand->busWidth = 8 << ((nand->id[3] >> 4) & 1); |
|
nand->numLuns = 1; |
nand->planesPerLun = 1 << ((nand->id[4] >> 2) & 3); |
nand->blocksPerPlane = (((1024 * 1024 * 1024) / 8) << ((nand->id[4] >> 4) & 7)) / (nand->pagesPerBlock * nand->bytesPerPage); |
nand->addressCycles = 5; |
|
result = 1; |
break; |
|
case 0x98: // Toshiba |
printf("Toshiba NAND flash detected (JEDEC ID: %02X%02X%02X%02X%02X)\n", nand->id[0], nand->id[1], nand->id[2], nand->id[3], nand->id[4]); |
nand->manufacturer = strdup("Toshiba"); |
|
if(nand->id[1] == 0xda) |
{ |
nand->device = strdup("TC58NVG1S3HTA00"); |
nand->busWidth = 8; |
nand->bytesPerPage = 2048; |
nand->oobPerPage = 128; |
nand->pagesPerBlock = 64; |
nand->numLuns = 1; |
nand->planesPerLun = 1; |
nand->blocksPerPlane = 2048; |
nand->addressCycles = 5; |
result = 1; |
} |
else |
break; |
break; |
|
|
default: |
printf("Device manufacturer %02x could not be identified.\n", nand->id[0]); |
break; |
} |
} |
if(result) |
nand->pageBuffer = (unsigned char*)malloc(sizeof(unsigned char) * (nand->bytesPerPage + nand->oobPerPage)); |
return result; |
} |
|
void free_nand_info(pnand_t* nand) |
{ |
if(NULL == nand || NULL == *nand) |
return; |
|
if(NULL != (*nand)->manufacturer) |
free((*nand)->manufacturer); |
if(NULL != (*nand)->device) |
free((*nand)->device); |
if(NULL != (*nand)->onfiParameterPage) |
free((*nand)->onfiParameterPage); |
if(NULL != (*nand)->pageBuffer) |
free((*nand)->pageBuffer); |
free(*nand); |
*nand = NULL; |
} |
|
void print_nand_configuration(pnand_t nand) |
{ |
printf("\n***********************************\n"); |
printf("***** NAND configuration data *****\n"); |
printf("***********************************\n"); |
printf("Manufacturer: %s\n", nand->manufacturer); |
printf("Device: %s\n", nand->device); |
printf("ID: %02x %02x %02x %02x %02x\n", nand->id[0], nand->id[1], nand->id[2], nand->id[3], nand->id[4]); |
printf("ONFI compliant: %s\n", (NULL == nand->onfiParameterPage)? "No" : "Yes"); |
printf("Data bus width: %d\n", nand->busWidth); |
printf("Bytes per page: %d bytes\n", nand->bytesPerPage); |
printf("OOB per page: %d bytes\n", nand->oobPerPage); |
printf("Pages per block: %d\n", nand->pagesPerBlock); |
printf("Blocks per plane: %d\n", nand->blocksPerPlane); |
printf("Planes per LUN: %d\n", nand->planesPerLun); |
printf("Number of LUNs: %d\n", nand->numLuns); |
printf("Address cycles: %d\n", nand->addressCycles); |
printf("ONFI signature bytes: %02x %02x %02x %02x\n\n", nand->onfiSignature[0], nand->onfiSignature[1], nand->onfiSignature[2], nand->onfiSignature[3]); |
} |
|
|
void dump_page(pnand_t nand) |
{ |
int i, j; |
|
for(i = 0; i < nand->bytesPerPage + nand->oobPerPage; i += 16) |
{ |
for(j = 0; j < 16; j++) |
{ |
printf("%02x ", nand->pageBuffer[i + j]); |
} |
|
printf("\t\t"); |
|
for(j = 0; j < 16; j++) |
{ |
if(isprint(nand->pageBuffer[i + j])) |
printf("%c", nand->pageBuffer[i + j]); |
else |
printf("."); |
} |
printf("\n"); |
} |
} |
|
void store_page(FILE* f, pnand_t nand) |
{ |
fwrite(nand->pageBuffer, nand->bytesPerPage + nand->oobPerPage, 1, f); |
} |