Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1233 lines
40 KiB

  1. /*
  2. * $Log: P:/user/amir/lite/vcs/cfiscs.c_v $
  3. *
  4. * Rev 1.19 06 Oct 1997 9:53:30 danig
  5. * VPP functions under #ifdef
  6. *
  7. * Rev 1.18 18 Sep 1997 10:05:40 danig
  8. * Warnings
  9. *
  10. * Rev 1.17 10 Sep 1997 16:31:16 danig
  11. * Got rid of generic names
  12. *
  13. * Rev 1.16 04 Sep 1997 18:19:34 danig
  14. * Debug messages
  15. *
  16. * Rev 1.15 31 Aug 1997 14:50:52 danig
  17. * Registration routine return status
  18. *
  19. * Rev 1.14 27 Jul 1997 15:00:38 danig
  20. * FAR -> FAR0
  21. *
  22. * Rev 1.13 21 Jul 1997 19:58:24 danig
  23. * No watchDogTimer
  24. *
  25. * Rev 1.12 15 Jul 1997 19:18:32 danig
  26. * Ver 2.0
  27. *
  28. * Rev 1.11 09 Jul 1997 10:58:52 danig
  29. * Fixed byte erase bug & changed identification routines
  30. *
  31. * Rev 1.10 20 May 1997 14:48:02 danig
  32. * Changed overwrite to mode in write routines
  33. *
  34. * Rev 1.9 18 May 1997 13:54:58 danig
  35. * JEDEC ID independent
  36. *
  37. * Rev 1.8 13 May 1997 16:43:10 danig
  38. * Added getMultiplier.
  39. *
  40. * Rev 1.7 08 May 1997 19:56:12 danig
  41. * Added cfiscsByteSize
  42. *
  43. * Rev 1.6 04 May 1997 14:01:16 danig
  44. * Changed cfiscsByteErase and added multiplier
  45. *
  46. * Rev 1.4 15 Apr 1997 11:38:52 danig
  47. * Changed word identification and IDs.
  48. *
  49. * Rev 1.3 15 Jan 1997 18:21:40 danig
  50. * Bigger ID string buffers and removed unused definitions.
  51. *
  52. * Rev 1.2 08 Jan 1997 14:54:06 danig
  53. * Changes in specification
  54. *
  55. * Rev 1.1 25 Dec 1996 18:21:44 danig
  56. * Initial revision
  57. */
  58. /************************************************************************/
  59. /* */
  60. /* FAT-FTL Lite Software Development Kit */
  61. /* Copyright (C) M-Systems Ltd. 1995-1997 */
  62. /* */
  63. /************************************************************************/
  64. /*----------------------------------------------------------------------*/
  65. /* This MTD supports the SCS/CFI technology. */
  66. /*----------------------------------------------------------------------*/
  67. #include "flflash.h"
  68. #ifdef FL_BACKGROUND
  69. #include "backgrnd.h"
  70. #endif
  71. /* JEDEC-IDs */
  72. #define VOYAGER_ID 0x8915
  73. #define KING_COBRA_ID 0xb0d0
  74. /* command set IDs */
  75. #define INTEL_COMMAND_SET 0x0001
  76. #define AMDFUJ_COMMAND_SET 0x0002
  77. #define INTEL_ALT_COMMAND_SET 0x0001
  78. #define AMDFUJ_ALT_COMMAND_SET 0x0004
  79. #define ALT_NOT_SUPPORTED 0x0000
  80. /* CFI identification strings */
  81. #define ID_STR_LENGTH 3
  82. #define QUERY_ID_STR "QRY"
  83. #define PRIMARY_ID_STR "PRI"
  84. #define ALTERNATE_ID_STR "ALT"
  85. /* commands */
  86. #define CONFIRM_SET_LOCK_BIT 0x01
  87. #define SETUP_BLOCK_ERASE 0x20
  88. #define SETUP_QUEUE_ERASE 0x28
  89. #define SETUP_CHIP_ERASE 0x30
  90. #define CLEAR_STATUS 0x50
  91. #define SET_LOCK_BIT 0x60
  92. #define CLEAR_LOCK_BIT 0x60
  93. #define READ_STATUS 0x70
  94. #define READ_ID 0x90
  95. #define QUERY 0x98
  96. #define SUSPEND_WRITE 0xb0
  97. #define SUSPEND_ERASE 0xb0
  98. #define CONFIG 0xb8
  99. #define CONFIRM_WRITE 0xd0
  100. #define RESUME_WRITE 0xd0
  101. #define CONFIRM_ERASE 0xd0
  102. #define RESUME_ERASE 0xd0
  103. #define CONFIRM_CLEAR_LOCK_BIT 0xd0
  104. #define WRITE_TO_BUFFER 0xe8
  105. #define READ_ARRAY 0xff
  106. /* status register bits */
  107. #define WSM_ERROR 0x3a
  108. #define SR_BLOCK_LOCK 0x02
  109. #define SR_WRITE_SUSPEND 0x04
  110. #define SR_VPP_ERROR 0x08
  111. #define SR_WRITE_ERROR 0x10
  112. #define SR_LOCK_SET_ERROR 0x10
  113. #define SR_ERASE_ERROR 0x20
  114. #define SR_LOCK_RESET_ERROR 0x20
  115. #define SR_ERASE_SUSPEND 0x40
  116. #define SR_READY 0x80
  117. /* optional commands support */
  118. #define CHIP_ERASE_SUPPORT 0x0001
  119. #define SUSPEND_ERASE_SUPPORT 0x0002
  120. #define SUSPEND_WRITE_SUPPORT 0x0004
  121. #define LOCK_SUPPORT 0x0008
  122. #define QUEUED_ERASE_SUPPORT 0x0010
  123. /* supported functions after suspend */
  124. #define WRITE_AFTER_SUSPEND_SUPPORT 0x0001
  125. /* a structure that hold important CFI data. */
  126. typedef struct {
  127. ULONG commandSetId; /* id of a specific command set. */
  128. ULONG altCommandSetId; /* id of alternate command set. */
  129. FLBoolean wordMode; /* TRUE - word mode. */
  130. /* FALSE - byte mode. */
  131. LONG multiplier; /* the number of times each byte */
  132. /* of data appears in READ_ID */
  133. /* and QUERY commands. */
  134. ULONG maxBytesWrite; /* maximum number of bytes */
  135. /* in multi-byte write. */
  136. FLBoolean vpp; /* if = TRUE, need vpp. */
  137. LONG optionalCommands; /* optional commands supported */
  138. /* (1 = yes, 0 = no): */
  139. /* bit 0 - chip erase. */
  140. /* bit 1 - suspend erase. */
  141. /* bit 2 - suspend write */
  142. /* bit 3 - lock/unlock. */
  143. /* bit 4 - queued erase. */
  144. ULONG afterSuspend; /* functions supported after */
  145. /* suspend (1 = yes, 0 = no): */
  146. /* bit 0 - write after erase */
  147. /* suspend. */
  148. } CFI;
  149. CFI mtdVars_cfiscs[SOCKETS];
  150. #define thisCFI ((CFI *)vol.mtdVars)
  151. /*----------------------------------------------------------------------*/
  152. /* c f i s c s B y t e S i z e */
  153. /* */
  154. /* Identify the card size for byte mode. */
  155. /* Sets the value of flash.noOfChips. */
  156. /* */
  157. /* Parameters: */
  158. /* vol : Pointer identifying drive */
  159. /* amdCmdRoutine : Routine to read-id AMD/Fujitsu style at */
  160. /* a specific location. If null, Intel procedure */
  161. /* is used. */
  162. /* idOffset : Chip offset to use for identification */
  163. /* */
  164. /* Returns: */
  165. /* FLStatus : 0 = OK, otherwise failed (invalid Flash array)*/
  166. /*----------------------------------------------------------------------*/
  167. FLStatus cfiscsByteSize(FLFlash vol)
  168. {
  169. CHAR queryIdStr[ID_STR_LENGTH + 1] = QUERY_ID_STR;
  170. FlashPTR flashPtr = (FlashPTR) flMap(vol.socket, 0);
  171. tffsWriteByteFlash(flashPtr + (0x55 * vol.interleaving), QUERY);
  172. /* We leave the first chip in QUERY mode, so that we can */
  173. /* discover an address wraparound. */
  174. for (vol.noOfChips = 0; /* Scan the chips */
  175. vol.noOfChips < 2000; /* Big enough ? */
  176. vol.noOfChips += vol.interleaving) {
  177. LONG i;
  178. flashPtr = (FlashPTR) flMap(vol.socket, vol.noOfChips * vol.chipSize);
  179. /* Check for address wraparound to the first chip */
  180. if (vol.noOfChips > 0 &&
  181. (queryIdStr[0] == tffsReadByteFlash(flashPtr +
  182. 0x10 * vol.interleaving * thisCFI->multiplier) &&
  183. queryIdStr[1] == tffsReadByteFlash(flashPtr +
  184. 0x11 * vol.interleaving * thisCFI->multiplier) &&
  185. queryIdStr[2] == tffsReadByteFlash(flashPtr +
  186. 0x12 * vol.interleaving * thisCFI->multiplier)))
  187. goto noMoreChips; /* wraparound */
  188. /* Check if chip displays the "QRY" ID string */
  189. for (i = (vol.noOfChips ? 0 : 1); i < vol.interleaving; i++) {
  190. tffsWriteByteFlash(flashPtr + vol.interleaving * 0x55 + i, QUERY);
  191. if (queryIdStr[0] != tffsReadByteFlash(flashPtr +
  192. 0x10 * vol.interleaving * thisCFI->multiplier + i) ||
  193. queryIdStr[1] != tffsReadByteFlash(flashPtr +
  194. 0x11 * vol.interleaving * thisCFI->multiplier + i) ||
  195. queryIdStr[2] != tffsReadByteFlash(flashPtr +
  196. 0x12 * vol.interleaving * thisCFI->multiplier + i))
  197. goto noMoreChips; /* This "chip" doesn't respond correctly, so we're done */
  198. tffsWriteByteFlash(flashPtr+i, READ_ARRAY);
  199. }
  200. }
  201. noMoreChips:
  202. flashPtr = (FlashPTR) flMap(vol.socket, 0);
  203. tffsWriteByteFlash(flashPtr, READ_ARRAY); /* reset the original chip */
  204. return (vol.noOfChips == 0) ? flUnknownMedia : flOK;
  205. }
  206. /*----------------------------------------------------------------------*/
  207. /* c f i s c s B y t e I d e n t i f y */
  208. /* */
  209. /* Identify the Flash type for cards in byte mode. */
  210. /* Sets the value of flash.type (JEDEC id) & flash.interleaving. */
  211. /* Calculate the number of times each byte of data appears in READ_ID */
  212. /* and QUERY commands. */
  213. /* */
  214. /* Parameters: */
  215. /* vol : Pointer identifying drive */
  216. /* */
  217. /* Returns: */
  218. /* FLStatus : 0 = OK, otherwise failed (invalid Flash array)*/
  219. /*----------------------------------------------------------------------*/
  220. FLStatus cfiscsByteIdentify(FLFlash vol)
  221. {
  222. LONG inlv, mul;
  223. FlashPTR flashPtr = (FlashPTR) flMap(vol.socket, 0);
  224. for (inlv = 1; inlv <= 8; inlv++) /* let us assume that interleaving is 8 */
  225. tffsWriteByteFlash(flashPtr+inlv, READ_ARRAY); /* and reset all the interleaved chips */
  226. for (inlv = 1; inlv <= 8; inlv++) {
  227. for (mul = 1; mul <= 8; mul++) { /* try all possibilities */
  228. LONG letter;
  229. tffsWriteByteFlash(flashPtr + 0x55 * inlv, QUERY);
  230. for (letter = 0; letter < ID_STR_LENGTH; letter++) { /* look for "QRY" id string */
  231. CHAR idChar = '?';
  232. LONG offset, counter;
  233. switch (letter) {
  234. case 0:
  235. idChar = 'Q';
  236. break;
  237. case 1:
  238. idChar = 'R';
  239. break;
  240. case 2:
  241. idChar = 'Y';
  242. break;
  243. }
  244. for (counter = 0, offset = (0x10 + letter) * inlv * mul;
  245. counter < mul;
  246. counter++, offset += inlv) /* each character should appear mul times */
  247. if (tffsReadByteFlash(flashPtr+offset) != idChar)
  248. break;
  249. if (counter < mul) /* no match */
  250. break;
  251. }
  252. tffsWriteByteFlash(flashPtr + 0x55 * inlv, READ_ARRAY); /* reset the chip */
  253. if (letter >= ID_STR_LENGTH)
  254. goto checkInlv;
  255. }
  256. }
  257. checkInlv:
  258. if (inlv > 8) /* too much */
  259. return flUnknownMedia;
  260. if (inlv & (inlv - 1))
  261. return flUnknownMedia; /* not a power of 2, no way ! */
  262. vol.interleaving = (unsigned short)inlv;
  263. thisCFI->multiplier = mul;
  264. tffsWriteByteFlash(flashPtr + 0x55 * inlv, QUERY);
  265. vol.type = (FlashType) ((tffsReadByteFlash(flashPtr) << 8) |
  266. tffsReadByteFlash(flashPtr + inlv * thisCFI->multiplier));
  267. tffsWriteByteFlash(flashPtr+inlv, READ_ARRAY);
  268. return flOK;
  269. }
  270. /*----------------------------------------------------------------------*/
  271. /* c f i s c s W o r d S i z e */
  272. /* */
  273. /* Identify the card size for a word-mode Flash array. */
  274. /* Sets the value of flash.noOfChips. */
  275. /* */
  276. /* Parameters: */
  277. /* vol : Pointer identifying drive */
  278. /* */
  279. /* Returns: */
  280. /* FLStatus : 0 = OK, otherwise failed (invalid Flash array)*/
  281. /*----------------------------------------------------------------------*/
  282. FLStatus cfiscsWordSize(FLFlash vol)
  283. {
  284. CHAR queryIdStr[ID_STR_LENGTH + 1] = QUERY_ID_STR;
  285. FlashWPTR flashPtr = (FlashWPTR) flMap(vol.socket, 0);
  286. tffsWriteWordFlash(flashPtr, CLEAR_STATUS);
  287. tffsWriteWordFlash(flashPtr+0x55, QUERY);
  288. /* We leave the first chip in QUERY mode, so that we can */
  289. /* discover an address wraparound. */
  290. for (vol.noOfChips = 1; /* Scan the chips */
  291. vol.noOfChips < 2000; /* Big enough ? */
  292. vol.noOfChips++) {
  293. flashPtr = (FlashWPTR) flMap(vol.socket, vol.noOfChips * vol.chipSize);
  294. if ((tffsReadWordFlash(flashPtr+0x10) == (USHORT)queryIdStr[0]) &&
  295. (tffsReadWordFlash(flashPtr+0x11) == (USHORT)queryIdStr[1]) &&
  296. (tffsReadWordFlash(flashPtr+0x12) == (USHORT)queryIdStr[2]))
  297. break; /* We've wrapped around to the first chip ! */
  298. tffsWriteWordFlash(flashPtr+0x55, QUERY);
  299. if ((tffsReadWordFlash(flashPtr+0x10) != (USHORT)queryIdStr[0]) ||
  300. (tffsReadWordFlash(flashPtr+0x11) != (USHORT)queryIdStr[1]) ||
  301. (tffsReadWordFlash(flashPtr+0x12) != (USHORT)queryIdStr[2]))
  302. break;
  303. tffsWriteWordFlash(flashPtr, CLEAR_STATUS);
  304. tffsWriteWordFlash(flashPtr, READ_ARRAY);
  305. }
  306. flashPtr = (FlashWPTR) flMap(vol.socket, 0);
  307. tffsWriteWordFlash(flashPtr, READ_ARRAY);
  308. return flOK;
  309. }
  310. /*----------------------------------------------------------------------*/
  311. /* g e t B y t e C F I */
  312. /* */
  313. /* Load important CFI data to the CFI structure in a byte-mode. */
  314. /* */
  315. /* Parameters: */
  316. /* vol : Pointer identifying drive */
  317. /* */
  318. /* Returns: */
  319. /* FLStatus : 0 = OK, otherwise failed. */
  320. /*----------------------------------------------------------------------*/
  321. FLStatus getByteCFI(FLFlash vol)
  322. {
  323. ULONG primaryTable, secondaryTable;
  324. CHAR queryIdStr[ID_STR_LENGTH + 1] = QUERY_ID_STR;
  325. CHAR priIdStr[ID_STR_LENGTH + 1] = PRIMARY_ID_STR;
  326. FlashPTR flashPtr;
  327. DEBUG_PRINT(("Debug: reading CFI for byte mode.\n"));
  328. flashPtr = (FlashPTR)flMap(vol.socket, 0);
  329. tffsWriteByteFlash(flashPtr + 0x55 * vol.interleaving, QUERY);
  330. vol.interleaving *= (unsigned short)thisCFI->multiplier; /* jump over the copies of the
  331. same byte */
  332. /* look for the query identification string "QRY" */
  333. if (queryIdStr[0] != tffsReadByteFlash(flashPtr + 0x10 * vol.interleaving) ||
  334. queryIdStr[1] != tffsReadByteFlash(flashPtr + 0x11 * vol.interleaving) ||
  335. queryIdStr[2] != tffsReadByteFlash(flashPtr + 0x12 * vol.interleaving)) {
  336. DEBUG_PRINT(("Debug: did not recognize CFI.\n"));
  337. return flUnknownMedia;
  338. }
  339. /* check the command set ID */
  340. thisCFI->commandSetId = tffsReadByteFlash(flashPtr +0x13 * vol.interleaving) |
  341. ((ULONG)tffsReadByteFlash(flashPtr + 0x14 * vol.interleaving) << 8);
  342. if (thisCFI->commandSetId != INTEL_COMMAND_SET &&
  343. thisCFI->commandSetId != AMDFUJ_COMMAND_SET) {
  344. DEBUG_PRINT(("Debug: did not recognize command set.\n"));
  345. return flUnknownMedia;
  346. }
  347. /* get address for primary algorithm extended table. */
  348. primaryTable = tffsReadByteFlash(flashPtr + 0x15 * vol.interleaving) |
  349. ((ULONG)tffsReadByteFlash(flashPtr + 0x16 * vol.interleaving) << 8);
  350. /* check alternate command set ID. */
  351. thisCFI->altCommandSetId = tffsReadByteFlash(flashPtr + 0x17 * vol.interleaving) |
  352. ((ULONG)tffsReadByteFlash(flashPtr + 0x18 * vol.interleaving) << 8);
  353. if (thisCFI->altCommandSetId != INTEL_ALT_COMMAND_SET &&
  354. thisCFI->altCommandSetId != AMDFUJ_ALT_COMMAND_SET &&
  355. thisCFI->altCommandSetId != ALT_NOT_SUPPORTED)
  356. return flUnknownMedia;
  357. /* get address for secondary algorithm extended table. */
  358. secondaryTable = tffsReadByteFlash(flashPtr + 0x19 * vol.interleaving) |
  359. ((ULONG)tffsReadByteFlash(flashPtr + 0x1a * vol.interleaving) << 8);
  360. thisCFI->vpp = tffsReadByteFlash(flashPtr + 0x1d * vol.interleaving);
  361. vol.chipSize = 1L << tffsReadByteFlash(flashPtr + 0x27 * vol.interleaving);
  362. thisCFI->maxBytesWrite = 1L << (tffsReadByteFlash(flashPtr + 0x2a * vol.interleaving) |
  363. ((ULONG)tffsReadByteFlash(flashPtr + 0x2b * vol.interleaving) << 8));
  364. /* divide by multiplier because interleaving is multiplied by multiplier */
  365. vol.erasableBlockSize = (tffsReadByteFlash(flashPtr + 0x2f * vol.interleaving) |
  366. ((ULONG)tffsReadByteFlash(flashPtr + 0x30 * vol.interleaving)) << 8) *
  367. 0x100L * vol.interleaving / thisCFI->multiplier;
  368. /* In this part we access the primary extended table implemented by Intel.
  369. If the device uses a different extended table, it should be accessed
  370. according to the vendor specifications. */
  371. if ((primaryTable) && (thisCFI->commandSetId == INTEL_COMMAND_SET)) {
  372. /* look for the primary table identification string "PRI" */
  373. if (priIdStr[0] != tffsReadByteFlash(flashPtr + primaryTable * vol.interleaving) ||
  374. priIdStr[1] != tffsReadByteFlash(flashPtr + (primaryTable + 1) * vol.interleaving) ||
  375. priIdStr[2] != tffsReadByteFlash(flashPtr + (primaryTable + 2) * vol.interleaving))
  376. return flUnknownMedia;
  377. thisCFI->optionalCommands = tffsReadByteFlash(flashPtr + (primaryTable + 5) * vol.interleaving) |
  378. ((LONG)tffsReadByteFlash(flashPtr + (primaryTable + 6) *
  379. vol.interleaving) << 8) |
  380. ((LONG)tffsReadByteFlash(flashPtr + (primaryTable + 7) *
  381. vol.interleaving) << 16) |
  382. ((LONG)tffsReadByteFlash(flashPtr + (primaryTable + 8) *
  383. vol.interleaving) << 24);
  384. thisCFI->afterSuspend = tffsReadByteFlash(flashPtr + (primaryTable + 9) * vol.interleaving);
  385. }
  386. else {
  387. thisCFI->optionalCommands = 0;
  388. thisCFI->afterSuspend = 0;
  389. }
  390. tffsWriteByteFlash(flashPtr, READ_ARRAY);
  391. vol.interleaving /= (unsigned short)thisCFI->multiplier; /* return to the real interleaving*/
  392. return flOK;
  393. }
  394. /*----------------------------------------------------------------------*/
  395. /* g e t W o r d C F I */
  396. /* */
  397. /* Load important CFI data to the CFI structure in a word-mode. */
  398. /* */
  399. /* Parameters: */
  400. /* vol : Pointer identifying drive */
  401. /* */
  402. /* Returns: */
  403. /* FLStatus : 0 = OK, otherwise failed. */
  404. /*----------------------------------------------------------------------*/
  405. FLStatus getWordCFI(FLFlash vol)
  406. {
  407. ULONG primaryTable, secondaryTable;
  408. CHAR queryIdStr[ID_STR_LENGTH + 1] = QUERY_ID_STR;
  409. CHAR priIdStr[ID_STR_LENGTH + 1] = PRIMARY_ID_STR;
  410. FlashWPTR flashPtr;
  411. DEBUG_PRINT(("Debug: reading CFI for word mode.\n"));
  412. flashPtr = (FlashWPTR)flMap(vol.socket, 0);
  413. tffsWriteWordFlash(flashPtr+0x55, QUERY);
  414. /* look for the query identification string "QRY" */
  415. if (queryIdStr[0] != (CHAR)tffsReadWordFlash(flashPtr+0x10) ||
  416. queryIdStr[1] != (CHAR)tffsReadWordFlash(flashPtr+0x11) ||
  417. queryIdStr[2] != (CHAR)tffsReadWordFlash(flashPtr+0x12)) {
  418. DEBUG_PRINT(("Debug: did not recognize CFI.\n"));
  419. return flUnknownMedia;
  420. }
  421. /* check the command set ID */
  422. thisCFI->commandSetId = tffsReadWordFlash(flashPtr+0x13) |
  423. (tffsReadWordFlash(flashPtr+0x14) << 8);
  424. if (thisCFI->commandSetId != INTEL_COMMAND_SET &&
  425. thisCFI->commandSetId != AMDFUJ_COMMAND_SET) {
  426. DEBUG_PRINT(("Debug: did not recognize command set.\n"));
  427. return flUnknownMedia;
  428. }
  429. /* get address for primary algorithm extended table. */
  430. primaryTable = tffsReadWordFlash(flashPtr+0x15) |
  431. (tffsReadWordFlash(flashPtr+0x16) << 8);
  432. /* check alternate command set ID. */
  433. thisCFI->altCommandSetId = tffsReadWordFlash(flashPtr+0x17) |
  434. (tffsReadWordFlash(flashPtr+0x18) << 8);
  435. if (thisCFI->altCommandSetId != INTEL_ALT_COMMAND_SET &&
  436. thisCFI->altCommandSetId != AMDFUJ_ALT_COMMAND_SET &&
  437. thisCFI->altCommandSetId != ALT_NOT_SUPPORTED)
  438. return flUnknownMedia;
  439. /* get address for secondary algorithm extended table. */
  440. secondaryTable = tffsReadWordFlash(flashPtr+0x19) |
  441. (tffsReadWordFlash(flashPtr+0x1a) << 8);
  442. thisCFI->vpp = tffsReadWordFlash(flashPtr+0x1d);
  443. vol.chipSize = 1L << tffsReadWordFlash(flashPtr+0x27);
  444. thisCFI->maxBytesWrite = 1L << (tffsReadWordFlash(flashPtr+0x2a) |
  445. (tffsReadWordFlash(flashPtr+0x2b) << 8));
  446. vol.erasableBlockSize = (tffsReadWordFlash(flashPtr+0x2f) |
  447. (tffsReadWordFlash(flashPtr+0x30) << 8)) * 0x100L;
  448. /* In this part we access the primary extended table implemented by Intel.
  449. If the device uses a different extended table, it should be accessed
  450. according to the vendor specifications. */
  451. if ((primaryTable) && (thisCFI->commandSetId == INTEL_COMMAND_SET)) {
  452. /* look for the primary table identification string "PRI" */
  453. if (priIdStr[0] != (CHAR)tffsReadWordFlash(flashPtr+primaryTable) ||
  454. priIdStr[1] != (CHAR)tffsReadWordFlash(flashPtr+primaryTable + 1) ||
  455. priIdStr[2] != (CHAR)tffsReadWordFlash(flashPtr+primaryTable + 2))
  456. return flUnknownMedia;
  457. thisCFI->optionalCommands = tffsReadWordFlash(flashPtr+primaryTable + 5) |
  458. (tffsReadWordFlash(flashPtr+primaryTable + 6) << 8) |
  459. ((LONG)tffsReadWordFlash(flashPtr+primaryTable + 7) << 16) |
  460. ((LONG)tffsReadWordFlash(flashPtr+primaryTable + 8) << 24);
  461. thisCFI->afterSuspend = tffsReadWordFlash(flashPtr+primaryTable + 9);
  462. }
  463. else {
  464. thisCFI->optionalCommands = 0;
  465. thisCFI->afterSuspend = 0;
  466. }
  467. tffsWriteWordFlash(flashPtr, READ_ARRAY);
  468. return flOK;
  469. }
  470. /*----------------------------------------------------------------------*/
  471. /* c f i s c s B y t e W r i t e */
  472. /* */
  473. /* Write a block of bytes to Flash in a byte-mode. */
  474. /* */
  475. /* This routine will be registered as the MTD flash.write routine */
  476. /* */
  477. /* Parameters: */
  478. /* vol : Pointer identifying drive */
  479. /* address : Card address to write to */
  480. /* buffer : Address of data to write */
  481. /* length : Number of bytes to write */
  482. /* mode : write mode (overwrite yes/no) */
  483. /* */
  484. /* Returns: */
  485. /* FLStatus : 0 on success, failed otherwise */
  486. /*----------------------------------------------------------------------*/
  487. FLStatus cfiscsByteWrite(FLFlash vol,
  488. CardAddress address,
  489. const VOID FAR1 *buffer,
  490. dword length,
  491. word mode)
  492. {
  493. FLStatus status = flOK;
  494. FlashPTR flashPtr;
  495. ULONG i, from, eachWrite;
  496. const CHAR FAR1 *temp = (const CHAR FAR1 *)buffer;
  497. /* Set timeout to 5 seconds from now */
  498. ULONG writeTimeout = flMsecCounter + 5000;
  499. if (flWriteProtected(vol.socket))
  500. return flWriteProtect;
  501. #ifdef SOCKET_12_VOLTS
  502. if (thisCFI->vpp)
  503. checkStatus(flNeedVpp(vol.socket));
  504. #endif
  505. if (thisCFI->maxBytesWrite > 1) /* multi-byte write supported */
  506. eachWrite = thisCFI->maxBytesWrite * vol.interleaving;
  507. else
  508. eachWrite = vol.interleaving;
  509. for (from = 0; from < (ULONG) length && status == flOK; from += eachWrite) {
  510. LONG thisLength = length - from;
  511. FlashPTR currPtr;
  512. ULONG tailBytes, lengthByte;
  513. CHAR FAR1 *fromPtr;
  514. UCHAR byteToWrite;
  515. if ((ULONG)thisLength > eachWrite)
  516. thisLength = eachWrite;
  517. lengthByte = thisLength / vol.interleaving;
  518. tailBytes = thisLength % vol.interleaving;
  519. flashPtr = (FlashPTR) flMap(vol.socket, address + from);
  520. for (i = 0, currPtr = flashPtr;
  521. i < (ULONG) vol.interleaving && i < (ULONG) thisLength;
  522. i++, currPtr++) {
  523. do {
  524. tffsWriteByteFlash(currPtr, WRITE_TO_BUFFER);
  525. } while (!(tffsReadByteFlash(currPtr) & SR_READY) && (flMsecCounter < writeTimeout));
  526. if (!(tffsReadByteFlash(currPtr) & SR_READY)) {
  527. DEBUG_PRINT(("Debug: timeout error in CFISCS write.\n"));
  528. status = flWriteFault;
  529. }
  530. byteToWrite = i < tailBytes ? (UCHAR) lengthByte : (UCHAR) (lengthByte - 1);
  531. tffsWriteByteFlash(currPtr, byteToWrite);
  532. }
  533. for(i = 0, currPtr = flashPtr,fromPtr = (CHAR *)temp + from;
  534. i < (ULONG) thisLength;
  535. i++, flashPtr++, fromPtr++)
  536. tffsWriteByteFlash(currPtr, *fromPtr);
  537. for (i = 0, currPtr = flashPtr;
  538. i < (ULONG) vol.interleaving && i < (ULONG) thisLength;
  539. i++, currPtr++)
  540. tffsWriteByteFlash(currPtr, CONFIRM_WRITE);
  541. for (i = 0, currPtr = flashPtr;
  542. i < (ULONG) vol.interleaving && i < (ULONG) thisLength;
  543. i++, currPtr++) {
  544. while (!(tffsReadByteFlash(currPtr) & SR_READY) && (flMsecCounter < writeTimeout))
  545. ;
  546. if (!(tffsReadByteFlash(currPtr) & SR_READY)) {
  547. DEBUG_PRINT(("Debug: timeout error in CFISCS write.\n"));
  548. status = flWriteFault;
  549. }
  550. if (tffsReadByteFlash(currPtr) & WSM_ERROR) {
  551. DEBUG_PRINT(("Debug: error in CFISCS write.\n"));
  552. status = (tffsReadByteFlash(currPtr) & SR_VPP_ERROR) ? flVppFailure : flWriteFault;
  553. tffsWriteByteFlash(currPtr, CLEAR_STATUS);
  554. }
  555. tffsWriteByteFlash(currPtr, READ_ARRAY);
  556. }
  557. }
  558. #ifdef SOCKET_12_VOLTS
  559. if (thisCFI->vpp)
  560. flDontNeedVpp(vol.socket);
  561. #endif
  562. flashPtr = (FlashPTR) flMap(vol.socket, address);
  563. /* verify the data */
  564. if (status == flOK) {
  565. for(i = 0; i < (ULONG) length - 4; i += 4) {
  566. if (tffsReadDwordFlash((PUCHAR)(flashPtr+i)) != *(ULONG *)(temp+i)) {
  567. DEBUG_PRINT(("Debug: CFISCS write failed in verification.\n"));
  568. status = flWriteFault;
  569. }
  570. }
  571. for(; i < (ULONG) length; i++) {
  572. if (tffsReadByteFlash(flashPtr+i) != *(UCHAR *)(temp+i)) {
  573. DEBUG_PRINT(("Debug: CFISCS write failed in verification.\n"));
  574. status = flWriteFault;
  575. }
  576. }
  577. }
  578. return status;
  579. }
  580. /*----------------------------------------------------------------------*/
  581. /* c f i s c s W o r d W r i t e */
  582. /* */
  583. /* Write a block of bytes to Flash in a word-mode. */
  584. /* */
  585. /* This routine will be registered as the MTD flash.write routine */
  586. /* */
  587. /* Parameters: */
  588. /* vol : Pointer identifying drive */
  589. /* address : Card address to write to */
  590. /* buffer : Address of data to write */
  591. /* length : Number of bytes to write */
  592. /* mode : write mode (overwrite yes/no) */
  593. /* */
  594. /* Returns: */
  595. /* FLStatus : 0 on success, failed otherwise */
  596. /*----------------------------------------------------------------------*/
  597. FLStatus cfiscsWordWrite(FLFlash vol,
  598. CardAddress address,
  599. const VOID FAR1 *buffer,
  600. dword length,
  601. word mode)
  602. {
  603. FLStatus status = flOK;
  604. FlashPTR byteFlashPtr;
  605. FlashWPTR flashPtr;
  606. ULONG from;
  607. ULONG i, eachWrite;
  608. const CHAR FAR1 *temp = (const CHAR FAR1 *)buffer;
  609. /* Set timeout to 5 seconds from now */
  610. ULONG writeTimeout = flMsecCounter + 5000;
  611. if (flWriteProtected(vol.socket))
  612. return flWriteProtect;
  613. if ((length & 1) || (address & 1)) /* Only write words on word-boundary */
  614. return flBadParameter;
  615. #ifdef SOCKET_12_VOLTS
  616. if (thisCFI->vpp)
  617. checkStatus(flNeedVpp(vol.socket));
  618. #endif
  619. if (thisCFI->maxBytesWrite > 1) /* multi-byte write supported */
  620. eachWrite = thisCFI->maxBytesWrite / 2; /* we are counting words */
  621. else
  622. eachWrite = 1;
  623. /* we assume that the interleaving is 1. */
  624. for (from = 0; (from < length / 2) && (status == flOK); from += eachWrite) {
  625. USHORT *fromPtr;
  626. ULONG thisLength = (length / 2) - from;
  627. if (thisLength > eachWrite)
  628. thisLength = eachWrite;
  629. flashPtr = (FlashWPTR)flMap(vol.socket, address + from * 2);
  630. do {
  631. tffsWriteWordFlash(flashPtr, WRITE_TO_BUFFER);
  632. } while (!(tffsReadByteFlash(flashPtr) & SR_READY) && (flMsecCounter < writeTimeout));
  633. if (!(tffsReadByteFlash(flashPtr) & SR_READY)) {
  634. DEBUG_PRINT(("Debug: timeout error in CFISCS write.\n"));
  635. status = flWriteFault;
  636. }
  637. tffsWriteWordFlash(flashPtr, (USHORT) (thisLength - 1));
  638. for(i = 0, fromPtr = (USHORT *)(temp + from * 2);
  639. i < thisLength;
  640. i++, fromPtr++)
  641. tffsWriteWordFlash(flashPtr + i, *fromPtr);
  642. tffsWriteWordFlash(flashPtr, CONFIRM_WRITE);
  643. while (!(tffsReadByteFlash(flashPtr) & SR_READY) && (flMsecCounter < writeTimeout))
  644. ;
  645. if (!(tffsReadByteFlash(flashPtr) & SR_READY)) {
  646. DEBUG_PRINT(("Debug: timeout error in CFISCS write.\n"));
  647. status = flWriteFault;
  648. }
  649. if (tffsReadByteFlash(flashPtr) & WSM_ERROR) {
  650. DEBUG_PRINT(("Debug: CFISCS write error.\n"));
  651. status = (tffsReadByteFlash(flashPtr) & SR_VPP_ERROR) ? flVppFailure : flWriteFault;
  652. tffsWriteWordFlash(flashPtr, CLEAR_STATUS);
  653. }
  654. tffsWriteWordFlash(flashPtr, READ_ARRAY);
  655. }
  656. #ifdef SOCKET_12_VOLTS
  657. if (thisCFI->vpp)
  658. flDontNeedVpp(vol.socket);
  659. #endif
  660. byteFlashPtr = (FlashPTR) flMap(vol.socket, address);
  661. /* verify the data */
  662. if (status == flOK) {
  663. for(i = 0; i < length - 4; i += 4) {
  664. if (tffsReadDwordFlash((PUCHAR)(byteFlashPtr+i)) != *(ULONG *)(temp+i)) {
  665. DEBUG_PRINT(("Debug: CFISCS write failed in verification.\n"));
  666. status = flWriteFault;
  667. }
  668. }
  669. for(; i < length; i++) {
  670. if (tffsReadByteFlash(byteFlashPtr+i) != *(UCHAR *)(temp+i)) {
  671. DEBUG_PRINT(("Debug: CFISCS write failed in verification.\n"));
  672. status = flWriteFault;
  673. }
  674. }
  675. }
  676. return status;
  677. }
  678. /************************************************************************/
  679. /* Auxiliary routines for cfiscsByteErase */
  680. /************************************************************************/
  681. /*----------------------------------------------------------------------*/
  682. /* m a k e C o m m a n d */
  683. /* */
  684. /* Create a command to write to the flash. This routine is used for */
  685. /* byte mode, write command to the relevant chip and 0xff to the other */
  686. /* chip if interleaving is greater than 1, or write the command if */
  687. /* interleaving is 1. */
  688. /* */
  689. /* Parameters: */
  690. /* vol : Pointer identifying drive */
  691. /* command : Command to be written to the media */
  692. /* chip : first chip (0) or second chip (1) */
  693. /* */
  694. /* Returns: */
  695. /* The command that should be written to the media */
  696. /*----------------------------------------------------------------------*/
  697. USHORT makeCommand(FLFlash vol, USHORT command, LONG chip)
  698. {
  699. if ((vol.interleaving == 1) || (chip == 0))
  700. return command | 0xff00;
  701. else
  702. return (command << 8) | 0xff;
  703. }
  704. /*----------------------------------------------------------------------*/
  705. /* g e t D a t a */
  706. /* */
  707. /* Read the lower byte or the upper byte from a given word. */
  708. /* */
  709. /* Parameters: */
  710. /* vol : Pointer identifying drive */
  711. /* wordData : the given word */
  712. /* chip : if chip = 0 read lower byte */
  713. /* if chip = 1 read upper byte */
  714. /* */
  715. /* Returns: */
  716. /* The byte that was read. */
  717. /*----------------------------------------------------------------------*/
  718. UCHAR getData(FLFlash vol, USHORT wordData, LONG chip)
  719. {
  720. if ((vol.interleaving == 1) || (chip == 0))
  721. return (UCHAR)wordData; /* lower byte */
  722. else
  723. return (UCHAR)(wordData >> 8); /* upper byte */
  724. }
  725. /*----------------------------------------------------------------------*/
  726. /* c f i s c s B y t e E r a s e */
  727. /* */
  728. /* Erase one or more contiguous Flash erasable blocks in a byte-mode. */
  729. /* */
  730. /* This routine will be registered as the MTD flash.erase routine */
  731. /* */
  732. /* Parameters: */
  733. /* vol : Pointer identifying drive */
  734. /* firstErasableBlock : Number of first block to erase */
  735. /* numOfErasableBlocks: Number of blocks to erase */
  736. /* */
  737. /* Returns: */
  738. /* FLStatus : 0 on success, failed otherwise */
  739. /*----------------------------------------------------------------------*/
  740. FLStatus cfiscsByteErase(FLFlash vol,
  741. word firstErasableBlock,
  742. word numOfErasableBlocks)
  743. {
  744. LONG iBlock;
  745. /* Set timeout to 5 seconds from now */
  746. ULONG writeTimeout = flMsecCounter + 5000;
  747. FLStatus status = flOK; /* unless proven otherwise */
  748. if (flWriteProtected(vol.socket))
  749. return flWriteProtect;
  750. #ifdef SOCKET_12_VOLTS
  751. if (thisCFI->vpp)
  752. checkStatus(flNeedVpp(vol.socket));
  753. #endif
  754. for (iBlock = 0; iBlock < numOfErasableBlocks && status == flOK; iBlock++) {
  755. LONG j;
  756. FLBoolean finished;
  757. FlashWPTR flashPtr = (FlashWPTR)
  758. flMap(vol.socket, (firstErasableBlock + iBlock) * vol.erasableBlockSize);
  759. for (j = 0; j * 2 < vol.interleaving; j++) { /* access chips in pairs */
  760. LONG i;
  761. for (i = 0; i < (vol.interleaving == 1 ? 1 : 2); i++) { /* write to each chip seperately */
  762. if (thisCFI->optionalCommands & QUEUED_ERASE_SUPPORT) {
  763. do {
  764. tffsWriteWordFlash(flashPtr+j, makeCommand(&vol, SETUP_QUEUE_ERASE, i));
  765. } while (!(getData(&vol, tffsReadWordFlash(flashPtr+j), i) & SR_READY) &&
  766. (flMsecCounter < writeTimeout));
  767. if (!(getData(&vol, tffsReadWordFlash(flashPtr+j), i) & SR_READY)) {
  768. DEBUG_PRINT(("Debug: timeout error in CFISCS erase.\n"));
  769. status = flWriteFault;
  770. }
  771. else
  772. tffsWriteWordFlash(flashPtr+j, makeCommand(&vol, CONFIRM_ERASE, i));
  773. }
  774. else {
  775. tffsWriteWordFlash(flashPtr+j, makeCommand(&vol, SETUP_BLOCK_ERASE, i));
  776. tffsWriteWordFlash(flashPtr+j, makeCommand(&vol, CONFIRM_ERASE, i));
  777. }
  778. }
  779. }
  780. do {
  781. #ifdef FL_BACKGROUND
  782. if (thisCFI->optionalCommands & SUSPEND_ERASE_SUPPORT) {
  783. while (flForeground(1) == BG_SUSPEND) { /* suspend */
  784. for (j = 0; j < vol.interleaving; j += 2, flashPtr++) {
  785. LONG i;
  786. for (i = 0; i < (vol.interleaving == 1 ? 1 : 2); i++) {
  787. tffsWriteWordFlash(flashPtr+j, makeCommand(&vol, READ_STATUS, i));
  788. if (!(getData(&vol, tffsReadWordFlash(flashPtr+j), i) & SR_READY)) {
  789. tffsWriteWordFlash(flashPtr+j, makeCommand(&vol, SUSPEND_ERASE, i));
  790. tffsWriteWordFlash(flashPtr+j, makeCommand(&vol, READ_STATUS, i));
  791. while (!(getData(&vol, tffsReadWordFlash(flashPtr+j), i) & SR_READY))
  792. ;
  793. }
  794. tffsWriteWordFlash(flashPtr+j, makeCommand(&vol, READ_ARRAY, i));
  795. }
  796. }
  797. }
  798. }
  799. #endif
  800. finished = TRUE;
  801. for (j = 0; j * 2 < vol.interleaving; j++) {
  802. LONG i;
  803. for (i = 0; i < (vol.interleaving == 1 ? 1 : 2); i++) {
  804. tffsWriteWordFlash(flashPtr+j, makeCommand(&vol, READ_STATUS, i));
  805. if (!(getData(&vol, tffsReadWordFlash(flashPtr+j), i) & SR_READY))
  806. finished = FALSE;
  807. else if (getData(&vol, tffsReadWordFlash(flashPtr+j), i) & SR_ERASE_SUSPEND) {
  808. tffsWriteWordFlash(flashPtr+j, makeCommand(&vol, RESUME_ERASE, i));
  809. finished = FALSE;
  810. }
  811. else {
  812. if (getData(&vol, tffsReadWordFlash(flashPtr+j), i) & WSM_ERROR) {
  813. DEBUG_PRINT(("Debug: CFISCS erase error.\n"));
  814. status = (getData(&vol, tffsReadWordFlash(flashPtr+j), i) & SR_VPP_ERROR) ?
  815. flVppFailure : flWriteFault;
  816. tffsWriteWordFlash(flashPtr+j, makeCommand(&vol, CLEAR_STATUS, i));
  817. }
  818. tffsWriteWordFlash(flashPtr+j, makeCommand(&vol, READ_ARRAY, i));
  819. }
  820. }
  821. }
  822. flDelayMsecs(1);
  823. } while (!finished);
  824. }
  825. #ifdef SOCKET_12_VOLTS
  826. if (thisCFI->vpp)
  827. flDontNeedVpp(vol.socket);
  828. #endif
  829. return status;
  830. }
  831. /*----------------------------------------------------------------------*/
  832. /* c f i s c s W o r d E r a s e */
  833. /* */
  834. /* Erase one or more contiguous Flash erasable blocks in a word-mode */
  835. /* */
  836. /* This routine will be registered as the MTD flash.erase routine */
  837. /* */
  838. /* Parameters: */
  839. /* vol : Pointer identifying drive */
  840. /* firstErasableBlock : Number of first block to erase */
  841. /* numOfErasableBlocks: Number of blocks to erase */
  842. /* */
  843. /* Returns: */
  844. /* FLStatus : 0 on success, failed otherwise */
  845. /*----------------------------------------------------------------------*/
  846. FLStatus cfiscsWordErase(FLFlash vol,
  847. word firstErasableBlock,
  848. word numOfErasableBlocks)
  849. {
  850. FLStatus status = flOK; /* unless proven otherwise */
  851. LONG iBlock;
  852. /* Set timeout to 5 seconds from now */
  853. ULONG writeTimeout = flMsecCounter + 5000;
  854. if (flWriteProtected(vol.socket))
  855. return flWriteProtect;
  856. #ifdef SOCKET_12_VOLTS
  857. if (thisCFI->vpp)
  858. checkStatus(flNeedVpp(vol.socket));
  859. #endif
  860. for (iBlock = 0; iBlock < numOfErasableBlocks && status == flOK; iBlock++) {
  861. FLBoolean finished;
  862. FlashWPTR flashPtr = (FlashWPTR)
  863. flMap(vol.socket,(firstErasableBlock + iBlock) * vol.erasableBlockSize);
  864. if (thisCFI->optionalCommands & QUEUED_ERASE_SUPPORT) {
  865. do {
  866. tffsWriteWordFlash(flashPtr, SETUP_QUEUE_ERASE);
  867. } while (!(tffsReadByteFlash(flashPtr) & SR_READY) && (flMsecCounter < writeTimeout));
  868. if (!(tffsReadByteFlash(flashPtr) & SR_READY)) {
  869. DEBUG_PRINT(("Debug: timeout error in CFISCS erase.\n"));
  870. status = flWriteFault;
  871. }
  872. else
  873. tffsWriteWordFlash(flashPtr, CONFIRM_ERASE);
  874. }
  875. else {
  876. tffsWriteWordFlash(flashPtr, SETUP_BLOCK_ERASE);
  877. tffsWriteWordFlash(flashPtr, CONFIRM_ERASE);
  878. }
  879. do {
  880. #ifdef FL_BACKGROUND
  881. if (thisCFI->optionalCommands & SUSPEND_ERASE_SUPPORT) {
  882. while (flForeground(1) == BG_SUSPEND) { /* suspend */
  883. if (!(tffsReadByteFlash(flashPtr) & SR_READY)) {
  884. tffsWriteWordFlash(flashPtr, SUSPEND_ERASE);
  885. tffsWriteWordFlash(flashPtr, READ_STATUS);
  886. while (!(tffsReadByteFlash(flashPtr) & SR_READY))
  887. ;
  888. }
  889. tffsWriteWordFlash(flashPtr, READ_ARRAY);
  890. }
  891. }
  892. #endif
  893. finished = TRUE;
  894. if (!(tffsReadByteFlash(flashPtr) & SR_READY))
  895. finished = FALSE;
  896. else if (tffsReadByteFlash(flashPtr) & SR_ERASE_SUSPEND) {
  897. tffsWriteWordFlash(flashPtr, RESUME_ERASE);
  898. finished = FALSE;
  899. }
  900. else {
  901. if (tffsReadByteFlash(flashPtr) & WSM_ERROR) {
  902. DEBUG_PRINT(("Debug: CFISCS erase error.\n"));
  903. status = (tffsReadByteFlash(flashPtr) & SR_VPP_ERROR) ? flVppFailure : flWriteFault;
  904. tffsWriteWordFlash(flashPtr, CLEAR_STATUS);
  905. }
  906. tffsWriteWordFlash(flashPtr, READ_ARRAY);
  907. }
  908. flDelayMsecs(1);
  909. } while (!finished);
  910. }
  911. #ifdef SOCKET_12_VOLTS
  912. if (thisCFI->vpp)
  913. flDontNeedVpp(vol.socket);
  914. #endif
  915. return status;
  916. }
  917. /*----------------------------------------------------------------------*/
  918. /* c f i s c s M a p */
  919. /* */
  920. /* Map through buffer. This routine will be registered as the map */
  921. /* routine for this MTD. */
  922. /* */
  923. /* Parameters: */
  924. /* vol : Pointer identifying drive */
  925. /* address : Flash address to be mapped. */
  926. /* length : number of bytes to map. */
  927. /* */
  928. /* Returns: */
  929. /* Pointer to the buffer data was mapped to. */
  930. /* */
  931. /*----------------------------------------------------------------------*/
  932. VOID FAR0 *cfiscsMap (FLFlash vol, CardAddress address, int length)
  933. {
  934. vol.socket->remapped = TRUE;
  935. return mapThroughBuffer(&vol,address,length);
  936. }
  937. /*----------------------------------------------------------------------*/
  938. /* c f i s c s R e a d */
  939. /* */
  940. /* Read some data from the flash. This routine will be registered as */
  941. /* the read routine for this MTD. */
  942. /* */
  943. /* Parameters: */
  944. /* vol : Pointer identifying drive */
  945. /* address : Address to read from. */
  946. /* buffer : buffer to read to. */
  947. /* length : number of bytes to read (up to sector size). */
  948. /* modes : EDC flag etc. */
  949. /* */
  950. /* Returns: */
  951. /* FLStatus : 0 on success, otherwise failed. */
  952. /* */
  953. /*----------------------------------------------------------------------*/
  954. FLStatus cfiscsRead(FLFlash vol,
  955. CardAddress address,
  956. VOID FAR1 *buffer,
  957. dword length,
  958. word modes)
  959. {
  960. ULONG i;
  961. UCHAR * byteBuffer;
  962. FlashPTR byteFlashPtr;
  963. ULONG * doubleWordBuffer = (ULONG *)buffer;
  964. FlashDPTR doubleWordFlashPtr = (FlashDPTR)flMap(vol.socket, address);
  965. for (i = 0; i < length - 4; i += 4, doubleWordBuffer++, doubleWordFlashPtr++) {
  966. *doubleWordBuffer = tffsReadDwordFlash(doubleWordFlashPtr);
  967. }
  968. byteBuffer = (UCHAR *)doubleWordBuffer;
  969. byteFlashPtr = (FlashPTR)doubleWordFlashPtr;
  970. for(; i < length; i++, byteBuffer++, byteFlashPtr++) {
  971. *byteBuffer = tffsReadByteFlash(byteFlashPtr);
  972. }
  973. return flOK ;
  974. }
  975. /*----------------------------------------------------------------------*/
  976. /* c f i s c s I d e n t i f y */
  977. /* */
  978. /* Identifies media based on SCS/CFI and registers as an MTD for */
  979. /* such. */
  980. /* */
  981. /* This routine will be placed on the MTD list in custom.h. It must be */
  982. /* an extern routine. */
  983. /* */
  984. /* On successful identification, the Flash structure is filled out and */
  985. /* the write and erase routines registered. */
  986. /* */
  987. /* Parameters: */
  988. /* vol : Pointer identifying drive */
  989. /* */
  990. /* Returns: */
  991. /* FLStatus : 0 on positive identificaion, failed otherwise */
  992. /*----------------------------------------------------------------------*/
  993. FLStatus cfiscsIdentify(FLFlash vol)
  994. {
  995. FlashWPTR flashPtr;
  996. CHAR queryIdStr[ID_STR_LENGTH + 1] = QUERY_ID_STR;
  997. DEBUG_PRINT(("Debug: entering CFISCS identification routine.\n"));
  998. flSetWindowBusWidth(vol.socket, 16);/* use 16-bits */
  999. flSetWindowSpeed(vol.socket, 150); /* 120 nsec. */
  1000. flSetWindowSize(vol.socket, 2); /* 8 KBytes */
  1001. vol.mtdVars = &mtdVars_cfiscs[flSocketNoOf(vol.socket)];
  1002. /* try word mode first */
  1003. flashPtr = (FlashWPTR)flMap(vol.socket, 0);
  1004. tffsWriteWordFlash(flashPtr+0x55, QUERY);
  1005. if ((tffsReadWordFlash(flashPtr+0x10) == (USHORT)queryIdStr[0]) &&
  1006. (tffsReadWordFlash(flashPtr+0x11) == (USHORT)queryIdStr[1]) &&
  1007. (tffsReadWordFlash(flashPtr+0x12) == (USHORT)queryIdStr[2])) {
  1008. vol.type = (tffsReadWordFlash(flashPtr) << 8) |
  1009. tffsReadWordFlash(flashPtr+1);
  1010. vol.interleaving = 1;
  1011. thisCFI->wordMode = TRUE;
  1012. vol.write = cfiscsWordWrite;
  1013. vol.erase = cfiscsWordErase;
  1014. checkStatus(getWordCFI(&vol));
  1015. DEBUG_PRINT(("Debug: identified 16-bit CFISCS.\n"));
  1016. }
  1017. else { /* Use standard identification routine to detect byte-mode */
  1018. checkStatus(cfiscsByteIdentify(&vol));
  1019. thisCFI->wordMode = FALSE;
  1020. vol.write = cfiscsByteWrite;
  1021. vol.erase = cfiscsByteErase;
  1022. checkStatus(getByteCFI(&vol));
  1023. DEBUG_PRINT(("Debug: identified 8-bit CFISCS.\n"));
  1024. }
  1025. checkStatus(thisCFI->wordMode ? cfiscsWordSize(&vol) : cfiscsByteSize(&vol));
  1026. vol.map = cfiscsMap;
  1027. vol.read = cfiscsRead;
  1028. return flOK;
  1029. }
  1030. /*----------------------------------------------------------------------*/
  1031. /* f l R e g i s t e r C F I S C S */
  1032. /* */
  1033. /* Registers this MTD for use */
  1034. /* */
  1035. /* Parameters: */
  1036. /* None */
  1037. /* */
  1038. /* Returns: */
  1039. /* FLStatus : 0 on success, otherwise failure */
  1040. /*----------------------------------------------------------------------*/
  1041. FLStatus flRegisterCFISCS(VOID)
  1042. {
  1043. if (noOfMTDs >= MTDS)
  1044. return flTooManyComponents;
  1045. mtdTable[noOfMTDs++] = cfiscsIdentify;
  1046. return flOK;
  1047. }