1 /*---------------------------------------------------------------------------*
2   Project:  TwlSDK - CARD - libraries
3   File:     card_backup.c
4 
5   Copyright 2007-2008 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-01-13#$
14   $Rev: 9813 $
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:    callback: Completion callback (NULL if not used)
533                 arg: Argument of completion callback (ignored if not used)
534 
535   Returns:      None.
536  *---------------------------------------------------------------------------*/
537 static void CARDi_BeginBackupCommand(MIDmaCallback callback, void *arg)
538 {
539     SDK_USING_BACKUP();
540     SDK_ASSERT(CARD_IsAvailable());
541     SDK_ASSERTMSG(CARDi_GetTargetMode() == CARD_TARGET_BACKUP,
542                   "[CARD] current locking target is not backup.");
543     CARD_CheckEnabled();
544     if ((CARDi_GetAccessLevel() & CARD_ACCESS_LEVEL_BACKUP) == 0)
545     {
546         OS_TPanic("this program cannot access CARD-backup!");
547     }
548     (void)CARDi_WaitForTask(&cardi_common, TRUE, callback, arg);
549 }
550 
551 /*---------------------------------------------------------------------------*
552   Name:         CARDi_RequestStreamCommand
553 
554   Description:  Issues request for command to transfer data.
555 
556   Arguments:    src: Transfer source offset or memory address
557                 dst: Transfer destination offset or memory address
558                 len: Transfer size
559                 callback: Completion callback (NULL if not used)
560                 arg: Argument of completion callback (ignored if not used)
561                 is_async: If async operation was specified, TRUE
562                 req_type: Command request type
563                 req_retry: Maximum number of retries when command request fails
564                 req_mode: Command request operation mode
565 
566   Returns:      TRUE if the process was successful.
567  *---------------------------------------------------------------------------*/
568 BOOL CARDi_RequestStreamCommand(u32 src, u32 dst, u32 len,
569                                 MIDmaCallback callback, void *arg, BOOL is_async,
570                                 CARDRequest req_type, int req_retry, CARDRequestMode req_mode)
571 {
572     SDK_ASSERT(CARD_GetCurrentBackupType() != CARD_BACKUP_TYPE_NOT_USE);
573 
574     CARDi_BeginBackupCommand(callback, arg);
575 
576     {
577         CARDiCommon *p = &cardi_common;
578         p->src = src;
579         p->dst = dst;
580         p->len = len;
581         p->req_type = req_type;
582         p->req_retry = req_retry;
583         p->req_mode = req_mode;
584     }
585 
586     return CARDi_ExecuteOldTypeTask(CARDi_RequestStreamCommandCore, is_async);
587 }
588 
589 /*---------------------------------------------------------------------------*
590   Name:         CARDi_AccessStatus
591 
592   Description:  Status read or write (for testing).
593 
594   Arguments:    command: CARD_REQ_READ_STATUS or CARD_REQ_WRITE_STATUS
595                 value: The value to write, if CARD_REQ_WRITE_STATUS
596 
597   Returns:      Returns a value of 0 or higher if successful; a negative number otherwise.
598  *---------------------------------------------------------------------------*/
599 int CARDi_AccessStatus(CARDRequest command, u8 value)
600 {
601     SDK_ASSERT(CARD_GetCurrentBackupType() != CARD_BACKUP_TYPE_NOT_USE);
602 
603     CARDi_BeginBackupCommand(NULL, NULL);
604 
605     // Use temporary buffer instead of the task argument
606     CARDi_backup_cache_page_buf[0] = value;
607     CARDi_backup_cache_page_buf[1] = (u8)command;
608 
609     return CARDi_ExecuteOldTypeTask(CARDi_AccessStatusCore, FALSE) ?
610            CARDi_backup_cache_page_buf[0] : -1;
611 }
612 
613 /*---------------------------------------------------------------------------*
614   Name:         CARDi_RequestWriteSectorCommand
615 
616   Description:  Erases sectors and issues program requests.
617 
618   Arguments:    src: Transfer source memory address
619                 dst: Transfer destination offset
620                 len: Transfer size
621                 verify: TRUE when performing a verify
622                 callback: Completion callback (NULL if not used)
623                 arg: Argument of completion callback (ignored if not used)
624                 is_async: If async operation was specified, TRUE
625 
626   Returns:      TRUE if the process was successful.
627  *---------------------------------------------------------------------------*/
628 BOOL CARDi_RequestWriteSectorCommand(u32 src, u32 dst, u32 len, BOOL verify,
629                                      MIDmaCallback callback, void *arg, BOOL is_async)
630 {
631     SDK_ASSERT(CARD_GetCurrentBackupType() != CARD_BACKUP_TYPE_NOT_USE);
632 
633     CARDi_BeginBackupCommand(callback, arg);
634 
635     {
636         CARDiCommon *p = &cardi_common;
637         p->src = src;
638         p->dst = dst;
639         p->len = len;
640         p->req_mode = verify ? CARD_REQUEST_MODE_SEND_VERIFY : CARD_REQUEST_MODE_SEND;
641     }
642 
643     return CARDi_ExecuteOldTypeTask(CARDi_RequestWriteSectorCommandCore, is_async);
644 }
645 
646 /*---------------------------------------------------------------------------*
647   Name:         CARD_IdentifyBackup
648 
649   Description:  Specifies the card backup device type.
650 
651   Arguments:    type: Device classification of the CARDBackupType type
652 
653   Returns:      TRUE if the read test was successful.
654  *---------------------------------------------------------------------------*/
655 BOOL CARD_IdentifyBackup(CARDBackupType type)
656 {
657     if (type == CARD_BACKUP_TYPE_NOT_USE)
658     {
659         OS_TPanic("cannot specify CARD_BACKUP_TYPE_NOT_USE.");
660     }
661 
662     CARDi_BeginBackupCommand(NULL, NULL);
663 
664     CARDi_IdentifyBackupCore2(type);
665 
666     return CARDi_ExecuteOldTypeTask(CARDi_IdentifyBackupCore, FALSE);
667 }
668 
669 /*---------------------------------------------------------------------------*
670   Name:         CARD_GetCurrentBackupType
671 
672   Description:  Gets backup device type currently specified.
673 
674   Arguments:    None.
675 
676   Returns:      Backup device type currently specified.
677  *---------------------------------------------------------------------------*/
678 CARDBackupType CARD_GetCurrentBackupType(void)
679 {
680     SDK_ASSERT(CARD_IsAvailable());
681 
682     return cardi_common.cmd->type;
683 }
684 
685 /*---------------------------------------------------------------------------*
686   Name:         CARD_GetBackupTotalSize
687 
688   Description:  Gets the overall size of the backup device currently specified.
689 
690   Arguments:    None.
691 
692   Returns:      Overall size of the backup device.
693  *---------------------------------------------------------------------------*/
694 u32 CARD_GetBackupTotalSize(void)
695 {
696     SDK_ASSERT(CARD_IsAvailable());
697 
698     return cardi_common.cmd->spec.total_size;
699 }
700 
701 /*---------------------------------------------------------------------------*
702   Name:         CARD_GetBackupSectorSize
703 
704   Description:  Gets sector size of the backup device currently specified.
705 
706   Arguments:    None.
707 
708   Returns:      Sector size of the backup device.
709  *---------------------------------------------------------------------------*/
710 u32 CARD_GetBackupSectorSize(void)
711 {
712     SDK_ASSERT(CARD_IsAvailable());
713 
714     return cardi_common.cmd->spec.sect_size;
715 }
716 
717 /*---------------------------------------------------------------------------*
718   Name:         CARD_GetBackupPageSize
719 
720   Description:  Gets page size of the backup device currently specified.
721 
722   Arguments:    None.
723 
724   Returns:      Page size of the backup device.
725  *---------------------------------------------------------------------------*/
726 u32 CARD_GetBackupPageSize(void)
727 {
728     SDK_ASSERT(CARD_IsAvailable());
729 
730     return cardi_common.cmd->spec.page_size;
731 }
732 
733 /*---------------------------------------------------------------------------*
734   Name:         CARD_WaitBackupAsync
735 
736   Description:  Waits until the backup device access function is completed.
737 
738   Arguments:    None.
739 
740   Returns:      TRUE if the backup device access function that was called last is completed with CARD_RESULT_SUCCESS. FALSE, otherwise.
741 
742  *---------------------------------------------------------------------------*/
743 BOOL CARD_WaitBackupAsync(void)
744 {
745     return CARDi_WaitAsync();
746 }
747 
748 /*---------------------------------------------------------------------------*
749   Name:         CARD_TryWaitBackupAsync
750 
751   Description:  Determines whether the backup device access function is completed.
752 
753   Arguments:    None.
754 
755   Returns:      TRUE if the backup device access function is completed.
756  *---------------------------------------------------------------------------*/
757 BOOL CARD_TryWaitBackupAsync(void)
758 {
759     return CARDi_TryWaitAsync();
760 }
761 
762 /*---------------------------------------------------------------------------*
763   Name:         CARD_CancelBackupAsync
764 
765   Description:  Requests termination to a backup device access function that is processing.
766 
767   Arguments:    None.
768 
769   Returns:      None.
770  *---------------------------------------------------------------------------*/
771 void CARD_CancelBackupAsync(void)
772 {
773     OSIntrMode bak_cpsr = OS_DisableInterrupts();
774     cardi_common.flag |= CARD_STAT_CANCEL;
775     (void)OS_RestoreInterrupts(bak_cpsr);
776 }
777