SdDisks.Mod 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268
  1. MODULE SdDisks;
  2. (**
  3. AUTHOR Timothée Martiel
  4. PURPOSE Disk driver for SD cards.
  5. *)
  6. IMPORT
  7. SYSTEM,
  8. Objects, Kernel, Plugins, Disks, DiskCaches, Strings,
  9. Sd, SdEnvironment, KernelLog;
  10. CONST
  11. NameBase = "SD";
  12. BlockSize = 512; (** Size of a SD block *)
  13. EnableCache* = TRUE;
  14. TYPE
  15. (**
  16. SD Card Disk Device
  17. *)
  18. Device * = OBJECT (Disks.Device)
  19. VAR
  20. card: Sd.Card;
  21. next: Device;
  22. cache: DiskCaches.Cache;
  23. PROCEDURE & InitSdDevice (card: Sd.Card);
  24. VAR
  25. bufferSize: LONGINT;
  26. BEGIN
  27. SELF.card := card;
  28. blockSize := BlockSize;
  29. (* CASE card.sdStatus.speedClass OF
  30. 2, 4:
  31. IF card.csd.capacity > 1024*1024*1024 THEN
  32. bufferSize := 32 * 1024 DIV BlockSize
  33. ELSE
  34. bufferSize := 16 * 1024 DIV BlockSize
  35. END
  36. |6: bufferSize := 64 * 1024 DIV BlockSize
  37. |10: bufferSize := 512 * 1024 DIV BlockSize
  38. END;*)
  39. bufferSize := 16 * 1024 DIV BlockSize;
  40. INCL(flags, Disks.Removable);
  41. IF EnableCache THEN
  42. NEW(cache,Transfer0,bufferSize);
  43. END;
  44. END InitSdDevice;
  45. PROCEDURE Transfer0 * (op, block, num: LONGINT; VAR data: ARRAY OF CHAR; ofs: LONGINT; VAR res: LONGINT);
  46. VAR ok: BOOLEAN;
  47. BEGIN
  48. CASE op OF
  49. Disks.Write:
  50. ok := Sd.Write(card, block, num*blockSize, data, ofs, res)
  51. |Disks.Read:
  52. ok := Sd.Read(card, block, num*blockSize, data, ofs, res);
  53. END
  54. END Transfer0;
  55. PROCEDURE Transfer * (op, block, num: LONGINT; VAR data: ARRAY OF CHAR; offs: LONGINT; VAR res: LONGINT);
  56. VAR
  57. t: SdEnvironment.Time;
  58. BEGIN{EXCLUSIVE}
  59. t := SdEnvironment.GetTimeCounter();
  60. IF EnableCache THEN
  61. cache.Transfer(op, block, num, data, offs, res);
  62. ELSE
  63. Transfer0(op, block, num, data, offs, res);
  64. END;
  65. t := SdEnvironment.GetTimeCounter() - t;
  66. IF op = Disks.Read THEN
  67. INC(rdTime,t);
  68. ELSE
  69. INC(wrTime,t);
  70. END;
  71. (* TRACE(block,num,t);*)
  72. END Transfer;
  73. PROCEDURE GetSize * (VAR size, res: LONGINT);
  74. BEGIN
  75. size := LONGINT(card.csd.capacity);
  76. IF size < 0 THEN size := MAX(LONGINT) END;
  77. res := Disks.Ok
  78. END GetSize;
  79. PROCEDURE Handle * (VAR msg: Disks.Message; VAR res: LONGINT);
  80. BEGIN
  81. res := 0;
  82. IF msg IS Disks.LockMsg THEN
  83. Sd.SetLedState(card.hc, TRUE)
  84. ELSIF msg IS Disks.UnlockMsg THEN
  85. Sd.SetLedState(card.hc, FALSE);
  86. Sync;
  87. ELSIF (msg IS Disks.EjectMsg) OR (msg IS Disks.SyncMsg) THEN
  88. Sync;
  89. END
  90. END Handle;
  91. (*
  92. (** Make sure that the RU ru is in cache entry idx *)
  93. PROCEDURE UpdateCacheEntry (ru, idx: LONGINT; VAR res: LONGINT): BOOLEAN;
  94. VAR entry: POINTER {UNSAFE} TO CacheEntry;
  95. BEGIN
  96. entry := ADDRESSOF(cache[idx]);
  97. IF ~entry.active OR (entry.ru # ru) THEN
  98. INC(NcacheMiss);
  99. IF entry.active THEN INC(NcacheEvict) END;
  100. (*IF entry.active & entry.mod THEN
  101. INC(NcacheWriteback);
  102. IF ~Sd.Write(card, entry.ru * bufferSize, bufferSize * BlockSize, entry.buffer^, 0, res) THEN RETURN FALSE END
  103. END;*)
  104. entry.active := TRUE;
  105. (*entry.mod := FALSE;*)
  106. entry.ru := ru;
  107. IF ~Sd.Read(card, ru * bufferSize, bufferSize * BlockSize, entry.buffer^, 0, res) THEN RETURN FALSE END
  108. ELSE
  109. INC(NcacheHits)
  110. END;
  111. RETURN TRUE
  112. END UpdateCacheEntry;
  113. *)
  114. (** Write back all modified cache entries to disk and invalidate all entries *)
  115. PROCEDURE Sync;
  116. (*VAR
  117. i, len, res, ofs: LONGINT;
  118. wbentry, wbnext: POINTER {UNSAFE} TO WriteBufferEntry;
  119. ignore: BOOLEAN;*)
  120. BEGIN {EXCLUSIVE}
  121. (* wbentry := ADDRESSOF(wbuffer[head MOD WBSize]);
  122. i := 1;
  123. len := wbentry.len;
  124. LOOP
  125. IF i = size THEN EXIT END;
  126. wbnext := ADDRESSOF(wbuffer[(head + i) MOD WBSize]);
  127. IF wbentry.block + len DIV BlockSize # wbnext.block THEN EXIT END;
  128. ofs := wbnext.block MOD bufferSize;
  129. SYSTEM.MOVE(ADDRESSOF(wbnext.buffer[ofs]), ADDRESSOF(wbentry.buffer[ofs]), wbnext.len);
  130. INC(len, wbnext.len);
  131. INC(i)
  132. END;
  133. ignore := Sd.Write(card, wbentry.block, len, wbentry.buffer^, 0, res);
  134. INC(head, i);
  135. DEC(size, i);
  136. INC(NbufferWrites);
  137. INC(NbufferSize, len)*)
  138. END Sync;
  139. PROCEDURE Stop;
  140. BEGIN {EXCLUSIVE}
  141. (* stop := TRUE*)
  142. END Stop;
  143. (*BEGIN {ACTIVE, PRIORITY(Objects.Normal)}
  144. LOOP
  145. BEGIN {EXCLUSIVE}
  146. AWAIT(stop OR (size > 0));
  147. IF stop THEN EXIT END;
  148. END;
  149. IF EnableCache THEN Sync; END;
  150. END;
  151. IF EnableCache THEN Sync; END;*)
  152. END Device;
  153. (** Handle SD Controller Events: create & register a new disk on card insertion, remove disk on card removal *)
  154. PROCEDURE HandleSdEvent * (card: Sd.Card; event: LONGINT);
  155. VAR
  156. disk, prev: Device;
  157. name, id: ARRAY 32 OF CHAR;
  158. result: LONGINT;
  159. BEGIN
  160. CASE event OF
  161. Sd.OnInitialization:
  162. NEW(disk, card);
  163. Strings.IntToStr(diskId, id);
  164. name := NameBase;
  165. Strings.Append(name, id);
  166. disk.SetName(name);
  167. disk.desc := "SD";
  168. CASE card.scr.security OF
  169. Sd.TypeNone, Sd.TypeSDSC:
  170. |Sd.TypeSDHC: Strings.Append(disk.desc, "HC")
  171. |Sd.TypeSDXC: Strings.Append(disk.desc, "XC")
  172. ELSE
  173. Strings.Append(disk.desc, "??");
  174. KernelLog.String("[SD] unknown card type: "); KernelLog.Int(card.scr.security, 0); KernelLog.Ln;
  175. END;
  176. Strings.Append(disk.desc, " card, v");
  177. CASE card.scr.version OF
  178. Sd.Version1: Strings.Append(disk.desc, "1")
  179. |Sd.Version1p1: Strings.Append(disk.desc, "1.10")
  180. |Sd.Version2: Strings.Append(disk.desc, "2")
  181. |Sd.Version3: Strings.Append(disk.desc, "3")
  182. |Sd.Version4: Strings.Append(disk.desc, "4")
  183. |Sd.Version5: Strings.Append(disk.desc, "5")
  184. |Sd.Version6: Strings.Append(disk.desc, "6")
  185. ELSE
  186. Strings.Append(disk.desc, "?");
  187. KernelLog.String("[SD] unknown card version: "); KernelLog.Int(card.scr.version, 0); KernelLog.Ln;
  188. END;
  189. Disks.registry.Add(disk, result);
  190. IF result # Plugins.Ok THEN
  191. SdEnvironment.String("Error registering disk");
  192. SdEnvironment.Ln
  193. ELSE
  194. INC(diskId);
  195. disk.next := devices;
  196. devices := disk;
  197. SdEnvironment.String("Disk ");
  198. SdEnvironment.String(name);
  199. SdEnvironment.String(" is now available");
  200. SdEnvironment.Ln
  201. END
  202. |Sd.OnRemoval:
  203. ASSERT(devices # NIL);
  204. IF devices.card = card THEN
  205. devices.Stop;
  206. SdEnvironment.String("Removed disk ");
  207. SdEnvironment.String(devices.name);
  208. SdEnvironment.Ln;
  209. devices := devices.next
  210. ELSE
  211. disk := devices;
  212. WHILE (disk # NIL) & (disk.card # card) DO
  213. prev := disk;
  214. disk := disk.next
  215. END;
  216. ASSERT(disk # NIL);
  217. disk.Stop;
  218. SdEnvironment.String("Removed disk ");
  219. SdEnvironment.String(disk.name);
  220. SdEnvironment.Ln;
  221. prev.next := disk.next
  222. END;
  223. END
  224. END HandleSdEvent;
  225. VAR
  226. devices: Device;
  227. diskId: LONGINT;
  228. (* Statistics *)
  229. NcacheHits *, NcacheMiss *, NcacheEvict *, NbufferWrites *, NbufferSize *, NbufferQueueSize *, NbufferQueueSamples *: LONGINT;
  230. rdTime, wrTime: SdEnvironment.Time;
  231. PROCEDURE ResetStats *;
  232. BEGIN
  233. TRACE(rdTime, wrTime);
  234. rdTime := 0; wrTime := 0;
  235. NcacheHits := 0;
  236. NcacheMiss := 0;
  237. NcacheEvict := 0;
  238. NbufferWrites := 0;
  239. NbufferSize := 0
  240. END ResetStats;
  241. END SdDisks.