00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040 #include "libstoragemedia.h"
00041
00042 #include <string.h>
00043 #include <assert.h>
00044
00045
00046
00047
00048
00049 #define MODEL(interface) ((struct NandFlashModel *) interface)
00050 #define TRANSLATED(interface) ((struct TranslatedNandFlash *) interface)
00051
00052
00053
00054
00055 #define min( a, b ) (((a) < (b)) ? (a) : (b))
00056
00057
00058
00059
00060
00061 static Media *currentMedia;
00062
00063 static uint8_t pageWriteBuffer[NandCommon_MAXPAGEDATASIZE];
00064 static int16_t currentWriteBlock;
00065 static int16_t currentWritePage;
00066
00067 static uint8_t pageReadBuffer[NandCommon_MAXPAGEDATASIZE];
00068 static int16_t currentReadBlock;
00069 static int16_t currentReadPage;
00070
00071
00072
00073
00074
00075
00076
00077
00078 static uint8_t FlushCurrentPage( Media *media )
00079 {
00080
00081 if ( currentWritePage == -1 ) {
00082 return 0 ;
00083 }
00084
00085 TRACE_DEBUG("FlushCurrentPage(B#%d:P#%d)\n\r",
00086 currentWriteBlock, currentWritePage);
00087
00088
00089 if (TranslatedNandFlash_WritePage(TRANSLATED(media->interface),
00090 currentWriteBlock,
00091 currentWritePage,
00092 pageWriteBuffer,
00093 0)) {
00094 TRACE_ERROR("FlushCurrentPage: Failed to write page.\n\r");
00095 return 1;
00096 }
00097
00098
00099 currentWriteBlock = -1;
00100 currentWritePage = -1;
00101 return 0;
00102 }
00103
00104
00105
00106
00107
00108
00109
00110
00111
00112
00113
00114
00115
00116 static uint8_t UnalignedWritePage(
00117 Media *media,
00118 uint16_t block,
00119 uint16_t page,
00120 uint16_t offset,
00121 uint8_t *buffer,
00122 uint32_t size)
00123 {
00124 uint8_t error;
00125 uint16_t pageDataSize = NandFlashModel_GetPageDataSize(MODEL(media->interface));
00126 uint8_t writePage = ((size + offset) == pageDataSize);
00127 uint8_t medChange = (currentMedia != media);
00128
00129 TRACE_DEBUG( "UnalignedWritePage(B%d:P%d@%d, %d)\n\r",
00130 (int)block, (int)page, (int)offset, (int)size ) ;
00131 assert( (size + offset) <= pageDataSize ) ;
00132
00133
00134
00135 if ( size == 0 ) {
00136 return 0 ;
00137 }
00138
00139
00140 if ((currentWriteBlock != block) || (currentWritePage != page) || (medChange)) {
00141
00142 if (currentMedia != 0) FlushCurrentPage(currentMedia);
00143 TRACE_DEBUG("Current write page: B#%d:P#%d\n\r", block, page);
00144 currentMedia = media;
00145 currentWriteBlock = block;
00146 currentWritePage = page;
00147
00148
00149
00150 if (size != pageDataSize) {
00151 error = TranslatedNandFlash_ReadPage(TRANSLATED(media->interface),
00152 block,
00153 page,
00154 pageWriteBuffer,
00155 0);
00156 if (error) {
00157 TRACE_ERROR(
00158 "UnalignedWrite: Could not read existing page data\n\r");
00159 return 1;
00160 }
00161 }
00162 }
00163
00164
00165 memcpy(&(pageWriteBuffer[offset]), buffer, size);
00166
00167 if ((currentReadPage == currentWritePage)
00168 && (currentReadBlock == currentWriteBlock)
00169 && (!medChange)) {
00170
00171 TRACE_DEBUG("Updating current read buffer\n\r");
00172 memcpy(&(pageReadBuffer[offset]), buffer, size);
00173 }
00174
00175
00176 if (writePage) {
00177 FlushCurrentPage(media);
00178 }
00179 return 0;
00180 }
00181
00182
00183
00184
00185
00186
00187
00188
00189
00190
00191
00192
00193
00194 static uint8_t MEDNandFlash_Write(
00195 Media *media,
00196 uint32_t address,
00197 void *data,
00198 uint32_t length,
00199 MediaCallback callback,
00200 void *argument)
00201 {
00202 uint16_t pageDataSize =
00203 NandFlashModel_GetPageDataSize(MODEL(media->interface));
00204 uint16_t blockSize =
00205 NandFlashModel_GetBlockSizeInPages(MODEL(media->interface));
00206 uint16_t block, page, offset;
00207 uint32_t writeSize;
00208 uint8_t *buffer = (uint8_t *) data;
00209 uint32_t remainingLength;
00210 uint8_t status;
00211
00212 TRACE_INFO("MEDNandFlash_Write(0x%08X, %d)\n\r", address, (int)length);
00213
00214
00215 if (NandFlashModel_TranslateAccess(MODEL(media->interface),
00216 address,
00217 length,
00218 &block,
00219 &page,
00220 &offset)) {
00221
00222 TRACE_ERROR("MEDNandFlash_Write: Could not start write.\n\r");
00223 return MED_STATUS_ERROR;
00224 }
00225
00226 TRACE_DEBUG("MEDNandFlash_Write(B#%d:P#%d@%d, %d)\n\r",
00227 block, page, offset, (int)length);
00228
00229
00230 remainingLength = length;
00231 status = MED_STATUS_SUCCESS;
00232 while ((status == MED_STATUS_SUCCESS) && (remainingLength > 0)) {
00233
00234
00235 writeSize = min((uint32_t)(pageDataSize-offset), remainingLength);
00236 if (UnalignedWritePage(media, block, page, offset, buffer, writeSize)) {
00237
00238 TRACE_ERROR("MEDNandFlash_Write: Failed to write page\n\r");
00239 status = MED_STATUS_ERROR;
00240 }
00241 else {
00242
00243
00244 remainingLength -= writeSize;
00245 buffer += writeSize;
00246 offset = 0;
00247 page++;
00248 if (page == blockSize) {
00249
00250 page = 0;
00251 block++;
00252 }
00253 }
00254 }
00255
00256
00257 if (callback) {
00258
00259 callback(argument, status, length - remainingLength, remainingLength);
00260 }
00261
00262 return status;
00263
00264 }
00265
00266
00267
00268
00269
00270
00271
00272
00273
00274
00275
00276
00277 static uint8_t UnalignedReadPage(
00278 Media *media,
00279 uint16_t block,
00280 uint16_t page,
00281 uint16_t offset,
00282 uint8_t *buffer,
00283 uint32_t size)
00284 {
00285 uint8_t error;
00286 uint16_t pageDataSize = NandFlashModel_GetPageDataSize(MODEL(media->interface));
00287 uint8_t medChange = (media != currentMedia);
00288
00289 TRACE_DEBUG("UnalignedReadPage(B%d:P%d@%d, %d)\n\r",
00290 (int)block, (int)page, (int)offset, (int)size);
00291
00292
00293 if( (size + offset) > pageDataSize ) {
00294 TRACE_ERROR("UnalignedReadPage: Read size & offset exceed page data size\n\r");
00295 return 1;
00296 }
00297
00298 if ((block != currentReadBlock) || (page != currentReadPage) || (medChange)) {
00299 if (medChange) FlushCurrentPage(currentMedia);
00300 TRACE_DEBUG("Current read page: B#%d:P#%d\n\r", block, page);
00301 currentMedia = media;
00302 currentReadBlock = block;
00303 currentReadPage = page;
00304
00305
00306 if ((currentReadBlock == currentWriteBlock)
00307 && (currentReadPage == currentWritePage)
00308 && (!medChange)) {
00309
00310 TRACE_DEBUG("Reading current write page\n\r");
00311 memcpy(pageReadBuffer, pageWriteBuffer, NandCommon_MAXPAGEDATASIZE);
00312 }
00313 else {
00314
00315
00316 error = TranslatedNandFlash_ReadPage(TRANSLATED(media->interface),
00317 block,
00318 page,
00319 pageReadBuffer,
00320 0);
00321 if (error) {
00322
00323 TRACE_ERROR("UnalignedRead: Could not read page\n\r");
00324 return 1;
00325 }
00326 }
00327 }
00328
00329
00330 memcpy(buffer, &(pageReadBuffer[offset]), size);
00331
00332 return 0;
00333 }
00334
00335
00336
00337
00338
00339
00340
00341
00342
00343
00344
00345
00346 static uint8_t MEDNandFlash_Read(
00347 Media *media,
00348 uint32_t address,
00349 void *data,
00350 uint32_t length,
00351 MediaCallback callback,
00352 void *argument)
00353 {
00354 uint16_t block, page, offset;
00355 uint16_t pageDataSize = NandFlashModel_GetPageDataSize(MODEL(media->interface));
00356 uint16_t blockSizeInPages = NandFlashModel_GetBlockSizeInPages(MODEL(media->interface));
00357 uint32_t remainingLength;
00358 uint32_t readSize;
00359 uint8_t *buffer = (uint8_t *) data;
00360 uint8_t status;
00361
00362 TRACE_INFO("MEDNandFlash_Read(0x%08X, %d)\n\r", address, (int)length);
00363
00364
00365 if (NandFlashModel_TranslateAccess(MODEL(media->interface),
00366 address,
00367 length,
00368 &block,
00369 &page,
00370 &offset)) {
00371
00372 TRACE_ERROR("MEDNandFlash_Read: Cannot perform access\n\r");
00373 return MED_STATUS_ERROR;
00374 }
00375
00376
00377 remainingLength = length;
00378 status = MED_STATUS_SUCCESS;
00379 while ((status == MED_STATUS_SUCCESS) && (remainingLength > 0)) {
00380
00381
00382 readSize = min((uint32_t)(pageDataSize-offset), remainingLength);
00383 if (UnalignedReadPage(media, block, page, offset, buffer, readSize)) {
00384
00385 TRACE_ERROR("MEDNandFlash_Read: Could not read page\n\r");
00386 status = MED_STATUS_ERROR;
00387 }
00388 else {
00389
00390 remainingLength -= readSize;
00391 buffer += readSize;
00392 offset = 0;
00393 page++;
00394 if (page == blockSizeInPages) {
00395 page = 0;
00396 block++;
00397 }
00398 }
00399 }
00400
00401
00402 if (callback) {
00403 callback(argument, status, length - remainingLength, remainingLength);
00404 }
00405
00406 return status;
00407 }
00408
00409
00410
00411
00412
00413
00414 static uint8_t MEDNandFlash_Flush(Media *media)
00415 {
00416 TRACE_INFO("MEDNandFlash_Flush()\n\r");
00417
00418 if (FlushCurrentPage(media)) {
00419
00420 TRACE_ERROR("MEDNandFlash_Flush: Could not flush current page\n\r");
00421 return MED_STATUS_ERROR;
00422 }
00423
00424 if (TranslatedNandFlash_Flush(TRANSLATED(media->interface))) {
00425
00426 TRACE_ERROR("MEDNandFlash_Flush: Could not flush translated NAND\n\r");
00427 return MED_STATUS_ERROR;
00428 }
00429
00430 if (TranslatedNandFlash_SaveLogicalMapping(TRANSLATED(media->interface))) {
00431
00432 TRACE_ERROR("MEDNandFlash_Flush: Could not save the logical mapping\n\r");
00433 return MED_STATUS_ERROR;
00434 }
00435
00436 return MED_STATUS_SUCCESS;
00437 }
00438
00439
00440
00441
00442
00443
00444 static void MEDNandFlash_InterruptHandler(Media *media)
00445 {
00446 TRACE_DEBUG("Flush timer expired\n\r");
00447 MEDNandFlash_Flush(media);
00448
00449
00450
00451 }
00452
00453
00454
00455
00456
00457
00458
00459
00460
00461 void MEDNandFlash_Initialize( sMedia* pMedia, struct TranslatedNandFlash *translated )
00462 {
00463 TRACE_INFO( "MEDNandFlash_Initialize()\n\r" ) ;
00464
00465 pMedia->write = (Media_write)MEDNandFlash_Write;
00466 pMedia->read = (Media_read)MEDNandFlash_Read;
00467 pMedia->lock = 0;
00468 pMedia->unlock = 0;
00469 pMedia->flush = MEDNandFlash_Flush;
00470 pMedia->handler = MEDNandFlash_InterruptHandler;
00471
00472 pMedia->interface = translated;
00473
00474 pMedia->baseAddress = 0;
00475 pMedia->blockSize = 1;
00476 pMedia->size = TranslatedNandFlash_GetDeviceSizeInBytes( translated ) ;
00477
00478 TRACE_INFO( "NF Size: %d\n\r", (int)pMedia->size ) ;
00479
00480 pMedia->mappedRD = 0;
00481 pMedia->mappedWR = 0;
00482 pMedia->protected = 0;
00483 pMedia->removable = 0;
00484 pMedia->state = MED_STATE_READY;
00485
00486 currentMedia = NULL;
00487 currentWriteBlock = -1;
00488 currentWritePage = -1;
00489 currentReadBlock = -1;
00490 currentReadPage = -1;
00491
00492 }
00493