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