1 /*---------------------------------------------------------------------------*
2   Project:  TwlSDK - CARD - libraries
3   File:     card_backup.c
4 
5   Copyright 2007-2009 Nintendo. All rights reserved.
6 
7   These coded instructions, statements, and computer programs contain
8   proprietary information of Nintendo of America Inc. and/or Nintendo
9   Company Ltd., and are protected by Federal copyright law. They may
10   not be disclosed to third parties or copied or duplicated in any form,
11   in whole or in part, without the prior written consent of Nintendo.
12 
13   $Date:: 2009-06-26#$
14   $Rev: 10827 $
15   $Author: yosizaki $
16 
17  *---------------------------------------------------------------------------*/
18 
19 
20 #include <nitro.h>
21 
22 #include "../include/card_common.h"
23 #include "../include/card_spi.h"
24 
25 
26 #ifndef SDK_ARM9
27 SDK_ERROR("this code is only for ARM9"!
28 #endif // SDK_ARM9
29 
30 
31 /*---------------------------------------------------------------------------*/
32 /* Constants */
33 
34 #include <nitro/version_begin.h>
35 SDK_DEFINE_MIDDLEWARE(cardi_backup_assert, "NINTENDO", "BACKUP");
36 #include <nitro/version_end.h>
37 #define SDK_USING_BACKUP() SDK_USING_MIDDLEWARE(cardi_backup_assert)
38 
39 
40 /*---------------------------------------------------------------------------*/
41 /* Variables */
42 
43 /* Cache of backup page last sent */
44 static u8 CARDi_backup_cache_page_buf[256] ATTRIBUTE_ALIGN(32);
45 
46 
47 /*---------------------------------------------------------------------------*/
48 /* Functions */
49 
50 /*---------------------------------------------------------------------------*
51   Name:         CARDi_OnFifoRecv
52 
53   Description:  PXI FIFO word receive callback.
54 
55   Arguments:    tag: PXI tag (always PXI_FIFO_TAG_FS)
56                 data: Receive data
57                 err: Error bit (according to old specs)
58 
59   Returns:      None.
60  *---------------------------------------------------------------------------*/
61 void CARDi_OnFifoRecv(PXIFifoTag tag, u32 data, BOOL err)
62 {
63 #pragma unused(data)
64     if ((tag == PXI_FIFO_TAG_FS) && err)
65     {
66         CARDiCommon *const p = &cardi_common;
67         /* Receive reply from ARM7 and send a notification of completion */
68         SDK_ASSERT(data == CARD_REQ_ACK);
69         p->flag &= ~CARD_STAT_WAITFOR7ACK;
70         OS_WakeupThreadDirect(p->current_thread_9);
71     }
72 }
73 
74 /*---------------------------------------------------------------------------*
75   Name:         CARDi_Request
76 
77   Description:  Sends request from ARM9 to ARM7 and blocks completion.
78                 If the result is not CARD_RESULT_SUCCESS, retries the specified number of times.
79                 (Locking of the specified bus and exclusive control of the task thread are guaranteed by the caller of this function.)
80 
81                 Sub-process repeatedly called in another command
82 
83   Arguments:    req_type: Command request type
84                 retry_max: Max. number of times to retry
85 
86   Returns:      If the result is CARD_RESULT_SUCCESS, TRUE.
87  *---------------------------------------------------------------------------*/
88 static BOOL CARDi_Request(CARDiCommon *p, int req_type, int retry_count)
89 {
90     // Execute here if PXI not initialized
91     if ((p->flag & CARD_STAT_INIT_CMD) == 0)
92     {
93         p->flag |= CARD_STAT_INIT_CMD;
94         while (!PXI_IsCallbackReady(PXI_FIFO_TAG_FS, PXI_PROC_ARM7))
95         {
96             OS_SpinWait(100);
97         }
98         // Send the first INIT command (recursive)
99         (void)CARDi_Request(p, CARD_REQ_INIT, 1);
100     }
101     // Flush the shared memory that has been set
102     DC_FlushRange(p->cmd, sizeof(*p->cmd));
103     DC_WaitWriteBufferEmpty();
104 
105     // Register the thread pointer to receive a command response
106     p->current_thread_9 = OS_GetCurrentThread();
107 
108     do
109     {
110         // Send command request
111         p->flag |= CARD_STAT_WAITFOR7ACK;
112         CARDi_SendPxi((u32)req_type);
113         // If there are more arguments, perform additional sends
114         switch (req_type)
115         {
116         case CARD_REQ_INIT:
117             CARDi_SendPxi((u32)p->cmd);
118             break;
119         }
120         {
121             // Wait for the completion of the request from ARM7
122             OSIntrMode bak_psr = OS_DisableInterrupts();
123             while ((p->flag & CARD_STAT_WAITFOR7ACK) != 0)
124             {
125                 OS_SleepThread(NULL);
126             }
127             (void)OS_RestoreInterrupts(bak_psr);
128         }
129         DC_InvalidateRange(p->cmd, sizeof(*p->cmd));
130     }
131     while ((p->cmd->result == CARD_RESULT_TIMEOUT) && (--retry_count > 0));
132 
133     return (p->cmd->result == CARD_RESULT_SUCCESS);
134 }
135 
136 /*---------------------------------------------------------------------------*
137   Name:         CARDi_RequestStreamCommandCore
138 
139   Description:  Core of command request processing that transfers data.
140                 Called synchronously and asynchronously.
141 
142   Arguments:    p: Library's work buffer (passed by argument for efficiency)
143 
144   Returns:      None.
145  *---------------------------------------------------------------------------*/
146 static void CARDi_RequestStreamCommandCore(CARDiCommon * p)
147 {
148     const int req_type = p->req_type;
149     const int req_mode = p->req_mode;
150     const int retry_count = p->req_retry;
151     u32     size = sizeof(CARDi_backup_cache_page_buf);
152 
153     SDK_USING_BACKUP();
154 
155     /* Request at the page or sector level */
156     if (req_type == CARD_REQ_ERASE_SECTOR_BACKUP)
157     {
158         size = CARD_GetBackupSectorSize();
159     }
160     else if (req_type == CARD_REQ_ERASE_SUBSECTOR_BACKUP)
161     {
162         size = cardi_common.cmd->spec.subsect_size;
163     }
164     do
165     {
166         const u32 len = (size < p->len) ? size : p->len;
167         p->cmd->len = len;
168 
169         /* Stops here if there has been a cancel request */
170         if ((p->flag & CARD_STAT_CANCEL) != 0)
171         {
172             p->flag &= ~CARD_STAT_CANCEL;
173             p->cmd->result = CARD_RESULT_CANCELED;
174             break;
175         }
176         switch (req_mode)
177         {
178         case CARD_REQUEST_MODE_RECV:
179             /* Invalidate the buffer if command is receive-related */
180             DC_InvalidateRange(CARDi_backup_cache_page_buf, len);
181             p->cmd->src = (u32)p->src;
182             p->cmd->dst = (u32)CARDi_backup_cache_page_buf;
183             break;
184         case CARD_REQUEST_MODE_SEND:
185         case CARD_REQUEST_MODE_SEND_VERIFY:
186             /* If command is send-related, copy the data to a temporary buffer */
187             MI_CpuCopy8((const void *)p->src, CARDi_backup_cache_page_buf, len);
188             DC_FlushRange(CARDi_backup_cache_page_buf, len);
189             DC_WaitWriteBufferEmpty();
190             p->cmd->src = (u32)CARDi_backup_cache_page_buf;
191             p->cmd->dst = (u32)p->dst;
192             break;
193         case CARD_REQUEST_MODE_SPECIAL:
194             /* Buffer operations are unnecessary */
195             p->cmd->src = (u32)p->src;
196             p->cmd->dst = (u32)p->dst;
197             break;
198         }
199         /* Send a request */
200         if (!CARDi_Request(p, req_type, retry_count))
201         {
202             break;
203         }
204         /* If specified, make another verify request with the same settings. */
205         if (req_mode == CARD_REQUEST_MODE_SEND_VERIFY)
206         {
207             if (!CARDi_Request(p, CARD_REQ_VERIFY_BACKUP, 1))
208             {
209                 break;
210             }
211         }
212         else if (req_mode == CARD_REQUEST_MODE_RECV)
213         {
214             /* Copy from cache */
215             MI_CpuCopy8(CARDi_backup_cache_page_buf, (void *)p->dst, len);
216         }
217         p->src += len;
218         p->dst += len;
219         p->len -= len;
220     }
221     while (p->len > 0);
222 }
223 
224 /*---------------------------------------------------------------------------*
225   Name:         CARDi_RequestWriteSectorCommandCore
226 
227   Description:  Erases sectors and is the core process for program requests.
228                 Called synchronously and asynchronously.
229 
230   Arguments:    p: Library's work buffer (passed by argument for efficiency)
231 
232   Returns:      None.
233  *---------------------------------------------------------------------------*/
234 static void CARDi_RequestWriteSectorCommandCore(CARDiCommon * p)
235 {
236     const u32 sector_size = CARD_GetBackupSectorSize();
237     SDK_USING_BACKUP();
238 
239     /* Return failure if the processing range is not an integer multiple of sector units */
240     if ((((u32)p->dst | p->len) & (sector_size - 1)) != 0)
241     {
242         p->flag &= ~CARD_STAT_CANCEL;
243         p->cmd->result = CARD_RESULT_INVALID_PARAM;
244     }
245     else
246     {
247         /* Sector unit processing */
248         for (; p->len > 0; p->len -= sector_size)
249         {
250             u32     len = sector_size;
251             /* Stops here if there has been a cancel request */
252             if ((p->flag & CARD_STAT_CANCEL) != 0)
253             {
254                 p->flag &= ~CARD_STAT_CANCEL;
255                 p->cmd->result = CARD_RESULT_CANCELED;
256                 break;
257             }
258             /* Sector deletion */
259             p->cmd->dst = (u32)p->dst;
260             p->cmd->len = len;
261             if (!CARDi_Request(p, CARD_REQ_ERASE_SECTOR_BACKUP, 1))
262             {
263                 break;
264             }
265             while (len > 0)
266             {
267                 const u32 page = sizeof(CARDi_backup_cache_page_buf);
268                 /* Stops here if there has been a cancel request */
269                 if ((p->flag & CARD_STAT_CANCEL) != 0)
270                 {
271                     p->flag &= ~CARD_STAT_CANCEL;
272                     p->cmd->result = CARD_RESULT_CANCELED;
273                     break;
274                 }
275                 /* Program */
276                 MI_CpuCopy8((const void *)p->src, CARDi_backup_cache_page_buf, page);
277                 DC_FlushRange(CARDi_backup_cache_page_buf, page);
278                 DC_WaitWriteBufferEmpty();
279                 p->cmd->src = (u32)CARDi_backup_cache_page_buf;
280                 p->cmd->dst = (u32)p->dst;
281                 p->cmd->len = page;
282                 if (!CARDi_Request(p, CARD_REQ_PROGRAM_BACKUP, CARD_RETRY_COUNT_MAX))
283                 {
284                     break;
285                 }
286                 /* Verify if needed */
287                 if (p->req_mode == CARD_REQUEST_MODE_SEND_VERIFY)
288                 {
289                     if (!CARDi_Request(p, CARD_REQ_VERIFY_BACKUP, 1))
290                     {
291                         break;
292                     }
293                 }
294                 p->src += page;
295                 p->dst += page;
296                 len -= page;
297             }
298         }
299     }
300 }
301 
302 /*---------------------------------------------------------------------------*
303   Name:         CARDi_AccessStatusCore
304 
305   Description:  Core access processing for status register.
306                 Called synchronously and asynchronously.
307 
308   Arguments:    p: Library's work buffer (passed by argument for efficiency)
309 
310   Returns:      None.
311  *---------------------------------------------------------------------------*/
312 static void CARDi_AccessStatusCore(CARDiCommon *p)
313 {
314     CARDRequest command = (CARDRequest)CARDi_backup_cache_page_buf[1];
315     DC_FlushRange(CARDi_backup_cache_page_buf, 1);
316     p->cmd->src = (u32)CARDi_backup_cache_page_buf;
317     p->cmd->dst = (u32)CARDi_backup_cache_page_buf;
318     (void)CARDi_Request(p, command, 1);
319     DC_InvalidateRange(CARDi_backup_cache_page_buf, 1);
320 }
321 
322 /*---------------------------------------------------------------------------*
323   Name:         CARDi_IdentifyBackupCore2
324 
325   Description:  Identifies the device type.
326 
327   Arguments:    type: Device type to be identified
328 
329   Returns:      None.
330  *---------------------------------------------------------------------------*/
331 static void CARDi_IdentifyBackupCore2(CARDBackupType type)
332 {
333     /*
334      * Saves the obtained parameter in CARDiCommandArg.
335      * Ultimately this is completed by discarding the table.
336      */
337     {
338         CARDiCommandArg *const p = cardi_common.cmd;
339 
340         /* First, clear all parameters and set to NOT_USE state */
341         MI_CpuFill8(&p->spec, 0, sizeof(p->spec));
342         p->type = type;
343         p->spec.caps = (CARD_BACKUP_CAPS_AVAILABLE | CARD_BACKUP_CAPS_READ_STATUS);
344         if (type != CARD_BACKUP_TYPE_NOT_USE)
345         {
346             /*
347              * Device type, total capacity and vendor can be obtained from 'type'.
348              * The vendor number is 0 unless the same type was adopted by several manufacturers and these types needed to be distinguished for some reason (for example, due to problems or bugs for some of them).
349              *
350              */
351             const u32 size = (u32)(1 << ((type >> CARD_BACKUP_TYPE_SIZEBIT_SHIFT) &
352                                          CARD_BACKUP_TYPE_SIZEBIT_MASK));
353             const int device =
354                 ((type >> CARD_BACKUP_TYPE_DEVICE_SHIFT) & CARD_BACKUP_TYPE_DEVICE_MASK);
355             const int vender =
356                 ((type >> CARD_BACKUP_TYPE_VENDER_SHIFT) & CARD_BACKUP_TYPE_VENDER_MASK);
357 
358             p->spec.total_size = size;
359             /* Use 0xFF if the status register does not need to be corrected. (This is usually the case.) */
360             p->spec.initial_status = 0xFF;
361             if (device == CARD_BACKUP_TYPE_DEVICE_EEPROM)
362             {
363                 switch (size)
364                 {
365                 default:
366                     goto invalid_type;
367                 case 0x000200:        // CARD_BACKUP_TYPE_EEPROM_4KBITS
368                     p->spec.page_size = 0x10;
369                     p->spec.addr_width = 1;
370                     p->spec.program_page = 5;
371                     p->spec.initial_status = 0xF0;
372                     break;
373                 case 0x002000:        // CARD_BACKUP_TYPE_EEPROM_64KBITS
374                     p->spec.page_size = 0x0020;
375                     p->spec.addr_width = 2;
376                     p->spec.program_page = 5;
377                     p->spec.initial_status = 0x00;
378                     break;
379                 case 0x010000:        // CARD_BACKUP_TYPE_EEPROM_512KBITS
380                     p->spec.page_size = 0x0080;
381                     p->spec.addr_width = 2;
382                     p->spec.program_page = 10;
383                     p->spec.initial_status = 0x00;
384                     break;
385 				case 0x020000:	      // CARD_BACKUP_TYPE_EEPROM_1MBITS
386 					p->spec.page_size = 0x0100;
387 					p->spec.addr_width = 3;
388 					p->spec.program_page = 5;
389                     p->spec.initial_status = 0x00;
390 					break;
391                 }
392                 p->spec.sect_size = p->spec.page_size;
393                 p->spec.caps |= CARD_BACKUP_CAPS_READ;
394                 p->spec.caps |= CARD_BACKUP_CAPS_PROGRAM;
395                 p->spec.caps |= CARD_BACKUP_CAPS_VERIFY;
396                 p->spec.caps |= CARD_BACKUP_CAPS_WRITE_STATUS;
397             }
398             else if (device == CARD_BACKUP_TYPE_DEVICE_FLASH)
399             {
400                 switch (size)
401                 {
402                 default:
403                     goto invalid_type;
404                 case 0x040000:        // CARD_BACKUP_TYPE_FLASH_2MBITS
405                 case 0x080000:        // CARD_BACKUP_TYPE_FLASH_4MBITS
406                 case 0x100000:        // CARD_BACKUP_TYPE_FLASH_8MBITS
407                     p->spec.write_page = 25;
408                     p->spec.write_page_total = 300;
409                     p->spec.erase_page = 300;
410                     p->spec.erase_sector = 5000;
411                     p->spec.caps |= CARD_BACKUP_CAPS_WRITE;
412                     p->spec.caps |= CARD_BACKUP_CAPS_ERASE_PAGE;
413                     break;
414                 case 0x200000:        // CARD_BACKUP_TYPE_FLASH_16MBITS
415                     p->spec.write_page = 23;
416                     p->spec.write_page_total = 300;
417                     p->spec.erase_sector = 500;
418                     p->spec.erase_sector_total = 5000;
419                     p->spec.erase_chip = 10000;
420                     p->spec.erase_chip_total = 60000;
421                     p->spec.initial_status = 0x00;
422                     p->spec.caps |= CARD_BACKUP_CAPS_WRITE;
423                     p->spec.caps |= CARD_BACKUP_CAPS_ERASE_PAGE;
424                     p->spec.caps |= CARD_BACKUP_CAPS_ERASE_CHIP;
425                     p->spec.caps |= CARD_BACKUP_CAPS_WRITE_STATUS;
426                     break;
427                 case 0x400000:        // CARD_BACKUP_TYPE_FLASH_32MBITS
428                     p->spec.erase_sector = 600;
429                     p->spec.erase_sector_total = 3000;
430                     p->spec.erase_subsector = 70;
431                     p->spec.erase_subsector_total = 150;
432                     p->spec.erase_chip = 23000;
433                     p->spec.erase_chip_total = 800000;
434                     p->spec.initial_status = 0x00;
435                     p->spec.subsect_size = 0x1000;
436                     p->spec.caps |= CARD_BACKUP_CAPS_ERASE_SUBSECTOR;
437                     p->spec.caps |= CARD_BACKUP_CAPS_ERASE_CHIP;
438                     p->spec.caps |= CARD_BACKUP_CAPS_WRITE_STATUS;
439                     break;
440                 case 0x800000:
441                     if (vender == 0)  // CARD_BACKUP_TYPE_FLASH_64MBITS
442                     {
443                         p->spec.erase_sector = 1000;
444                         p->spec.erase_sector_total = 3000;
445                         p->spec.erase_chip = 68000;
446                         p->spec.erase_chip_total = 160000;
447                         p->spec.initial_status = 0x00;
448                         p->spec.caps |= CARD_BACKUP_CAPS_ERASE_CHIP;
449                         p->spec.caps |= CARD_BACKUP_CAPS_WRITE_STATUS;
450                     }
451                     else if (vender == 1)   // CARD_BACKUP_TYPE_FLASH_64MBITS_EX
452                     {
453                         p->spec.erase_sector = 1000;
454                         p->spec.erase_sector_total = 3000;
455                         p->spec.erase_chip = 68000;
456                         p->spec.erase_chip_total = 160000;
457                         p->spec.initial_status = 0x84;
458                         p->spec.caps |= CARD_BACKUP_CAPS_ERASE_CHIP;
459                         p->spec.caps |= CARD_BACKUP_CAPS_WRITE_STATUS;
460                     }
461                     break;
462                 }
463                 p->spec.sect_size = 0x010000;
464                 p->spec.page_size = 0x0100;
465                 p->spec.addr_width = 3;
466                 p->spec.program_page = 5;
467                 p->spec.caps |= CARD_BACKUP_CAPS_READ;
468                 p->spec.caps |= CARD_BACKUP_CAPS_PROGRAM;
469                 p->spec.caps |= CARD_BACKUP_CAPS_VERIFY;
470                 p->spec.caps |= CARD_BACKUP_CAPS_ERASE_SECTOR;
471             }
472             else if (device == CARD_BACKUP_TYPE_DEVICE_FRAM)
473             {
474                 switch (size)
475                 {
476                 default:
477                     goto invalid_type;
478                 case 0x002000:        // #CARD_BACKUP_TYPE_FRAM_64KBITS
479                 case 0x008000:        // #CARD_BACKUP_TYPE_FRAM_256KBITS
480                     break;
481                 }
482                 p->spec.page_size = size;
483                 p->spec.sect_size = size;
484                 p->spec.addr_width = 2;
485                 p->spec.initial_status = 0x00;
486                 p->spec.caps |= CARD_BACKUP_CAPS_READ;
487                 p->spec.caps |= CARD_BACKUP_CAPS_PROGRAM;
488                 p->spec.caps |= CARD_BACKUP_CAPS_VERIFY;
489                 p->spec.caps |= CARD_BACKUP_CAPS_WRITE_STATUS;
490             }
491             else
492             {
493               invalid_type:
494                 p->type = CARD_BACKUP_TYPE_NOT_USE;
495                 p->spec.total_size = 0;
496                 cardi_common.cmd->result = CARD_RESULT_UNSUPPORTED;
497                 return;
498             }
499         }
500     }
501 }
502 
503 /*---------------------------------------------------------------------------*
504   Name:         CARDi_IdentifyBackupCore
505 
506   Description:  Core process for identifying the device type.
507                 Called synchronously and asynchronously.
508 
509   Arguments:    p: Library's work buffer (passed by argument for efficiency)
510 
511   Returns:      None.
512  *---------------------------------------------------------------------------*/
513 static void CARDi_IdentifyBackupCore(CARDiCommon * p)
514 {
515     (void)CARDi_Request(p, CARD_REQ_IDENTIFY, 1);
516     /*
517      * Issue a read command for the first byte and get the result value.
518      * If there is a contact problem, damage, or lifespan problem, return TIMEOUT, regardless of the value.
519      * (TIMEOUT can be determined using a Read-Status command regardless of the device type)
520      */
521     p->cmd->src = 0;
522     p->cmd->dst = (u32)CARDi_backup_cache_page_buf;
523     p->cmd->len = 1;
524     (void)CARDi_Request(p, CARD_REQ_READ_BACKUP, 1);
525 }
526 
527 /*---------------------------------------------------------------------------*
528   Name:         CARDi_BeginBackupCommand
529 
530   Description:  Starting process for backup operation command.
531 
532   Arguments:    level: Access mode requested for backups
533                 callback: Completion callback (NULL if not used)
534                 arg: Argument of completion callback (ignored if not used)
535 
536   Returns:      None.
537  *---------------------------------------------------------------------------*/
538 static void CARDi_BeginBackupCommand(CARDAccessLevel level, MIDmaCallback callback, void *arg)
539 {
540     SDK_USING_BACKUP();
541     SDK_ASSERT(CARD_IsAvailable());
542     SDK_TASSERTMSG(CARDi_GetTargetMode() == CARD_TARGET_BACKUP,
543                   "[CARD] current locking target is not backup.");
544     CARD_CheckEnabled();
545     if ((CARDi_GetAccessLevel() & level) != level)
546     {
547         OS_TPanic("this program cannot %s%s CARD-backup!",
548                 (level & CARD_ACCESS_LEVEL_BACKUP_R) ? "READ" : "",
549                 (level & CARD_ACCESS_LEVEL_BACKUP_W) ? "WRITE" : "");
550     }
551     (void)CARDi_WaitForTask(&cardi_common, TRUE, callback, arg);
552 }
553 
554 /*---------------------------------------------------------------------------*
555   Name:         CARDi_RequestStreamCommand
556 
557   Description:  Issues request for command to transfer data.
558 
559   Arguments:    src: Transfer source offset or memory address
560                 dst: Transfer destination offset or memory address
561                 len: Transfer size
562                 callback: Completion callback (NULL if not used)
563                 arg: Argument of completion callback (ignored if not used)
564                 is_async: If async operation was specified, TRUE
565                 req_type: Command request type
566                 req_retry: Maximum number of retries when command request fails
567                 req_mode: Command request operation mode
568 
569   Returns:      TRUE if the process was successful.
570  *---------------------------------------------------------------------------*/
571 BOOL CARDi_RequestStreamCommand(u32 src, u32 dst, u32 len,
572                                 MIDmaCallback callback, void *arg, BOOL is_async,
573                                 CARDRequest req_type, int req_retry, CARDRequestMode req_mode)
574 {
575     CARDAccessLevel level = (req_mode == CARD_REQUEST_MODE_RECV) ? CARD_ACCESS_LEVEL_BACKUP_R : CARD_ACCESS_LEVEL_BACKUP_W;
576     SDK_ASSERT(CARD_GetCurrentBackupType() != CARD_BACKUP_TYPE_NOT_USE);
577 
578     CARDi_BeginBackupCommand(level, callback, arg);
579 
580     {
581         CARDiCommon *p = &cardi_common;
582         p->src = src;
583         p->dst = dst;
584         p->len = len;
585         p->req_type = req_type;
586         p->req_retry = req_retry;
587         p->req_mode = req_mode;
588     }
589 
590     return CARDi_ExecuteOldTypeTask(CARDi_RequestStreamCommandCore, is_async);
591 }
592 
593 /*---------------------------------------------------------------------------*
594   Name:         CARDi_AccessStatus
595 
596   Description:  Status read or write (for testing).
597 
598   Arguments:    command: CARD_REQ_READ_STATUS or CARD_REQ_WRITE_STATUS
599                 value: Value to write, if CARD_REQ_WRITE_STATUS
600 
601   Returns:      Returns a value of 0 or higher if successful; a negative number otherwise.
602  *---------------------------------------------------------------------------*/
603 int CARDi_AccessStatus(CARDRequest command, u8 value)
604 {
605     SDK_ASSERT(CARD_GetCurrentBackupType() != CARD_BACKUP_TYPE_NOT_USE);
606 
607     CARDi_BeginBackupCommand(CARD_ACCESS_LEVEL_NONE, NULL, NULL);
608 
609     // Use temporary buffer instead of the task argument
610     CARDi_backup_cache_page_buf[0] = value;
611     CARDi_backup_cache_page_buf[1] = (u8)command;
612 
613     return CARDi_ExecuteOldTypeTask(CARDi_AccessStatusCore, FALSE) ?
614            CARDi_backup_cache_page_buf[0] : -1;
615 }
616 
617 /*---------------------------------------------------------------------------*
618   Name:         CARDi_RequestWriteSectorCommand
619 
620   Description:  Erases sectors and issues program requests.
621 
622   Arguments:    src: Transfer source memory address
623                 dst: Transfer destination offset
624                 len: Transfer size
625                 verify: TRUE when performing a verify
626                 callback: Completion callback (NULL if not used)
627                 arg: Argument of completion callback (ignored if not used)
628                 is_async: If async operation was specified, TRUE
629 
630   Returns:      TRUE if the process was successful.
631  *---------------------------------------------------------------------------*/
632 BOOL CARDi_RequestWriteSectorCommand(u32 src, u32 dst, u32 len, BOOL verify,
633                                      MIDmaCallback callback, void *arg, BOOL is_async)
634 {
635     SDK_ASSERT(CARD_GetCurrentBackupType() != CARD_BACKUP_TYPE_NOT_USE);
636 
637     CARDi_BeginBackupCommand(CARD_ACCESS_LEVEL_BACKUP_W, callback, arg);
638 
639     {
640         CARDiCommon *p = &cardi_common;
641         p->src = src;
642         p->dst = dst;
643         p->len = len;
644         p->req_mode = verify ? CARD_REQUEST_MODE_SEND_VERIFY : CARD_REQUEST_MODE_SEND;
645     }
646 
647     return CARDi_ExecuteOldTypeTask(CARDi_RequestWriteSectorCommandCore, is_async);
648 }
649 
650 /*---------------------------------------------------------------------------*
651   Name:         CARD_IdentifyBackup
652 
653   Description:  Specifies the card backup device type.
654 
655   Arguments:    type: Device classification of the CARDBackupType type
656 
657   Returns:      TRUE if the read test was successful.
658  *---------------------------------------------------------------------------*/
659 BOOL CARD_IdentifyBackup(CARDBackupType type)
660 {
661     if (type == CARD_BACKUP_TYPE_NOT_USE)
662     {
663         OS_TPanic("cannot specify CARD_BACKUP_TYPE_NOT_USE.");
664     }
665 
666     CARDi_BeginBackupCommand(CARD_ACCESS_LEVEL_NONE, NULL, NULL);
667 
668     CARDi_IdentifyBackupCore2(type);
669 
670     return CARDi_ExecuteOldTypeTask(CARDi_IdentifyBackupCore, FALSE);
671 }
672 
673 /*---------------------------------------------------------------------------*
674   Name:         CARD_GetCurrentBackupType
675 
676   Description:  Gets backup device type currently specified.
677 
678   Arguments:    None.
679 
680   Returns:      Backup device type currently specified.
681  *---------------------------------------------------------------------------*/
682 CARDBackupType CARD_GetCurrentBackupType(void)
683 {
684     SDK_ASSERT(CARD_IsAvailable());
685 
686     return cardi_common.cmd->type;
687 }
688 
689 /*---------------------------------------------------------------------------*
690   Name:         CARD_GetBackupTotalSize
691 
692   Description:  Gets the overall size of the backup device currently specified.
693 
694   Arguments:    None.
695 
696   Returns:      Overall size of the backup device.
697  *---------------------------------------------------------------------------*/
698 u32 CARD_GetBackupTotalSize(void)
699 {
700     SDK_ASSERT(CARD_IsAvailable());
701 
702     return cardi_common.cmd->spec.total_size;
703 }
704 
705 /*---------------------------------------------------------------------------*
706   Name:         CARD_GetBackupSectorSize
707 
708   Description:  Gets sector size of the backup device currently specified.
709 
710   Arguments:    None.
711 
712   Returns:      Sector size of the backup device.
713  *---------------------------------------------------------------------------*/
714 u32 CARD_GetBackupSectorSize(void)
715 {
716     SDK_ASSERT(CARD_IsAvailable());
717 
718     return cardi_common.cmd->spec.sect_size;
719 }
720 
721 /*---------------------------------------------------------------------------*
722   Name:         CARD_GetBackupPageSize
723 
724   Description:  Gets page size of the backup device currently specified.
725 
726   Arguments:    None.
727 
728   Returns:      Page size of the backup device.
729  *---------------------------------------------------------------------------*/
730 u32 CARD_GetBackupPageSize(void)
731 {
732     SDK_ASSERT(CARD_IsAvailable());
733 
734     return cardi_common.cmd->spec.page_size;
735 }
736 
737 /*---------------------------------------------------------------------------*
738   Name:         CARD_WaitBackupAsync
739 
740   Description:  Waits until the backup device access function is completed.
741 
742   Arguments:    None.
743 
744   Returns:      TRUE if the backup device access function that was called last is completed with CARD_RESULT_SUCCESS. FALSE, otherwise.
745 
746  *---------------------------------------------------------------------------*/
747 BOOL CARD_WaitBackupAsync(void)
748 {
749     return CARDi_WaitAsync();
750 }
751 
752 /*---------------------------------------------------------------------------*
753   Name:         CARD_TryWaitBackupAsync
754 
755   Description:  Determines whether the backup device access function is completed.
756 
757   Arguments:    None.
758 
759   Returns:      TRUE if the backup device access function is completed.
760  *---------------------------------------------------------------------------*/
761 BOOL CARD_TryWaitBackupAsync(void)
762 {
763     return CARDi_TryWaitAsync();
764 }
765 
766 /*---------------------------------------------------------------------------*
767   Name:         CARD_CancelBackupAsync
768 
769   Description:  Requests termination to a backup device access function that is processing.
770 
771   Arguments:    None.
772 
773   Returns:      None.
774  *---------------------------------------------------------------------------*/
775 void CARD_CancelBackupAsync(void)
776 {
777     OSIntrMode bak_cpsr = OS_DisableInterrupts();
778     cardi_common.flag |= CARD_STAT_CANCEL;
779     (void)OS_RestoreInterrupts(bak_cpsr);
780 }
781