bankmem.c 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320
  1. /*
  2. * Copyright (C) 2004 by egnite Software GmbH. All rights reserved.
  3. *
  4. * Redistribution and use in source and binary forms, with or without
  5. * modification, are permitted provided that the following conditions
  6. * are met:
  7. *
  8. * 1. Redistributions of source code must retain the above copyright
  9. * notice, this list of conditions and the following disclaimer.
  10. * 2. Redistributions in binary form must reproduce the above copyright
  11. * notice, this list of conditions and the following disclaimer in the
  12. * documentation and/or other materials provided with the distribution.
  13. * 3. Neither the name of the copyright holders nor the names of
  14. * contributors may be used to endorse or promote products derived
  15. * from this software without specific prior written permission.
  16. *
  17. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  18. * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  19. * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
  20. * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
  21. * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
  22. * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
  23. * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
  24. * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
  25. * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
  26. * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
  27. * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  28. * SUCH DAMAGE.
  29. *
  30. * For additional information see http://www.ethernut.de/
  31. *
  32. */
  33. /*!
  34. * $Log$
  35. * Revision 1.7 2009/02/06 15:40:29 haraldkipp
  36. * Using newly available strdup() and calloc().
  37. * Replaced NutHeap routines by standard malloc/free.
  38. * Replaced pointer value 0 by NULL.
  39. *
  40. * Revision 1.6 2008/08/11 07:00:33 haraldkipp
  41. * BSD types replaced by stdint types (feature request #1282721).
  42. *
  43. * Revision 1.5 2008/02/15 17:08:05 haraldkipp
  44. * Calling the initialization routine more than once is now possible.
  45. * By default, half of the available memory will be allocated. Previous
  46. * versions eat all free memory but 8k.
  47. *
  48. * Revision 1.4 2007/04/12 09:08:57 haraldkipp
  49. * Segmented buffer routines ported to ARM.
  50. *
  51. * Revision 1.3 2004/12/17 15:28:33 haraldkipp
  52. * Bugfix. Comparison of the read and write pointers now includes the segments.
  53. * Thanks to Pete Allinson and Johan van der Stoel.
  54. *
  55. * Revision 1.2 2004/08/18 18:51:56 haraldkipp
  56. * Made banked memory configurable.
  57. *
  58. * Revision 1.1 2003/07/21 18:19:48 haraldkipp
  59. * First check in
  60. *
  61. */
  62. #include <sys/heap.h>
  63. #include <stdint.h>
  64. /*!
  65. * \addtogroup xgBankMem
  66. */
  67. /*@{*/
  68. #include <sys/bankmem.h>
  69. static char segbuf_empty;
  70. static uint32_t segbuf_total;
  71. static uint32_t segbuf_used;
  72. static char *segbuf_start;
  73. static char *segbuf_end;
  74. static char *segbuf_wp;
  75. static char segbuf_ws;
  76. static char *segbuf_rp;
  77. static char segbuf_rs;
  78. /*!
  79. * \brief Reset the segmented buffer.
  80. *
  81. * \return Pointer to the first buffer segment.
  82. */
  83. char *NutSegBufReset(void)
  84. {
  85. segbuf_rp = segbuf_wp = segbuf_start;
  86. segbuf_rs = segbuf_ws = 0;
  87. NutSegBufEnable(0);
  88. segbuf_empty = 1;
  89. segbuf_used = 0;
  90. return segbuf_start;
  91. }
  92. /*!
  93. * \brief Initialize the segmented buffer.
  94. *
  95. * \param size Number of bytes to allocate for the global buffer.
  96. * In systems with banked memory this parameter is
  97. * ignored and all banked memory is occupied for the
  98. * global buffer. In systems without banked memory,
  99. * the specified number of bytes is taken from heap
  100. * memory.
  101. *
  102. * \return Pointer to the first buffer segment or null on failures.
  103. */
  104. char *NutSegBufInit(size_t size)
  105. {
  106. #if NUTBANK_COUNT
  107. segbuf_start = (char *)(NUTBANK_START);
  108. segbuf_end = (char *)(NUTBANK_START) + NUTBANK_SIZE;
  109. segbuf_total = (uint32_t) NUTBANK_COUNT *(uint32_t) NUTBANK_SIZE;
  110. #else
  111. if (size == 0)
  112. size = NutHeapAvailable() / 2;
  113. if (segbuf_start) {
  114. NutHeapFree(segbuf_start);
  115. }
  116. if ((segbuf_start = NutHeapAlloc(size)) != NULL)
  117. segbuf_end = segbuf_start + size;
  118. segbuf_total = size;
  119. #endif
  120. return NutSegBufReset();
  121. }
  122. /*!
  123. * \brief Request segmented buffer space for writing.
  124. *
  125. * This call will also enable the current write segment and
  126. * may disable the current read segment.
  127. *
  128. * \param bcp Pointer to a variable, which receives the
  129. * number of consecutive bytes available for
  130. * writing.
  131. *
  132. * \return Pointer to the next write position.
  133. */
  134. char *NutSegBufWriteRequest(size_t * bcp)
  135. {
  136. if (segbuf_empty || segbuf_ws != segbuf_rs || segbuf_wp > segbuf_rp)
  137. *bcp = segbuf_end - segbuf_wp;
  138. else
  139. *bcp = segbuf_rp - segbuf_wp;
  140. NutSegBufEnable(segbuf_ws);
  141. return segbuf_wp;
  142. }
  143. /*!
  144. * \brief Request segmented buffer space for reading.
  145. *
  146. * This call will also enable the current read segment and
  147. * may disable the current write segment.
  148. *
  149. * \param bcp Pointer to a variable, which receives the
  150. * number of consecutive bytes available for
  151. * reading.
  152. *
  153. * \return Pointer to the next read position.
  154. */
  155. char *NutSegBufReadRequest(size_t * bcp)
  156. {
  157. if (segbuf_empty)
  158. *bcp = 0;
  159. else if (segbuf_ws != segbuf_rs || segbuf_rp >= segbuf_wp)
  160. *bcp = segbuf_end - segbuf_rp;
  161. else if ((*bcp = segbuf_wp - segbuf_rp) == 0 && segbuf_ws == segbuf_rs)
  162. segbuf_empty = 1;
  163. NutSegBufEnable(segbuf_rs);
  164. return segbuf_rp;
  165. }
  166. /*!
  167. * \brief Commit written buffer space.
  168. *
  169. * The write pointer will be incremented by the specified number of bytes.
  170. * If the pointer reaches the end of a segment, the next segment will be
  171. * enabled and the pointer will point to the start of the new segement.
  172. *
  173. * \param bc Number of bytes to commit.
  174. *
  175. * \return Pointer to the next write position.
  176. */
  177. char *NutSegBufWriteCommit(size_t bc)
  178. {
  179. if (bc) {
  180. segbuf_wp += bc;
  181. segbuf_empty = 0;
  182. segbuf_used += bc;
  183. if (segbuf_wp == segbuf_end) {
  184. segbuf_wp = segbuf_start;
  185. #if NUTBANK_COUNT > 0
  186. if (++segbuf_ws >= NUTBANK_COUNT)
  187. segbuf_ws = 0;
  188. #endif
  189. NutSegBufEnable(segbuf_ws);
  190. }
  191. }
  192. return segbuf_wp;
  193. }
  194. /*!
  195. * \brief Commit read buffer space.
  196. *
  197. * The read pointer will be incremented by the specified number of bytes.
  198. * If the pointer reaches the end of a segment, the next segment will be
  199. * enabled and the pointer will point to the start of the new segement.
  200. *
  201. * \param bc Number of bytes to commit.
  202. *
  203. * \return Pointer to the next read position.
  204. */
  205. char *NutSegBufReadCommit(size_t bc)
  206. {
  207. if (bc) {
  208. segbuf_rp += bc;
  209. segbuf_used -= bc;
  210. if (segbuf_rp == segbuf_end) {
  211. segbuf_rp = segbuf_start;
  212. #if NUTBANK_COUNT > 0
  213. if (++segbuf_rs >= NUTBANK_COUNT)
  214. segbuf_rs = 0;
  215. #endif
  216. NutSegBufEnable(segbuf_rs);
  217. }
  218. if (segbuf_rp == segbuf_wp && segbuf_rs == segbuf_ws)
  219. segbuf_empty = 1;
  220. }
  221. return segbuf_rp;
  222. }
  223. /*!
  224. * \brief Commit written buffer space and finish write access.
  225. *
  226. * The write pointer will be incremented by the specified number of bytes.
  227. * This call will also enable the current read segment and may disable the
  228. * current write segment.
  229. *
  230. * \param bc Number of bytes to commit.
  231. */
  232. void NutSegBufWriteLast(size_t bc)
  233. {
  234. if (bc) {
  235. segbuf_wp += bc;
  236. segbuf_used += bc;
  237. segbuf_empty = 0;
  238. if (segbuf_wp == segbuf_end) {
  239. segbuf_wp = segbuf_start;
  240. #if NUTBANK_COUNT > 0
  241. if (++segbuf_ws >= NUTBANK_COUNT)
  242. segbuf_ws = 0;
  243. #endif
  244. }
  245. }
  246. NutSegBufEnable(segbuf_rs);
  247. }
  248. /*!
  249. * \brief Commit written buffer space and finish read access.
  250. *
  251. * The write pointer will be incremented by the specified number of bytes.
  252. * This call will also enable the current read segment and may disable the
  253. * current write segment.
  254. *
  255. * \param bc Number of bytes to commit.
  256. */
  257. void NutSegBufReadLast(size_t bc)
  258. {
  259. if (bc) {
  260. segbuf_rp += bc;
  261. segbuf_used -= bc;
  262. if (segbuf_rp == segbuf_end) {
  263. segbuf_rp = segbuf_start;
  264. #if NUTBANK_COUNT > 0
  265. if (++segbuf_rs >= NUTBANK_COUNT)
  266. segbuf_rs = 0;
  267. #endif
  268. }
  269. if (segbuf_rp == segbuf_wp && segbuf_rs == segbuf_ws)
  270. segbuf_empty = 1;
  271. }
  272. NutSegBufEnable(segbuf_ws);
  273. }
  274. /*!
  275. * \brief Return the available buffer space.
  276. *
  277. * \return Total number of free bytes in the buffer.
  278. */
  279. uint32_t NutSegBufAvailable(void)
  280. {
  281. return segbuf_total - segbuf_used;
  282. }
  283. /*!
  284. * \brief Return the used buffer space.
  285. *
  286. * \return Total number of used bytes in the buffer.
  287. */
  288. uint32_t NutSegBufUsed(void)
  289. {
  290. return segbuf_used;
  291. }
  292. /*@}*/