phatio.c 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324
  1. /*
  2. * Copyright (C) 2005 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. * \file fs/phatio.c
  34. * \brief PHAT File System.
  35. *
  36. * \verbatim
  37. *
  38. * $Log$
  39. * Revision 1.5 2008/08/11 06:59:42 haraldkipp
  40. * BSD types replaced by stdint types (feature request #1282721).
  41. *
  42. * Revision 1.4 2006/07/11 12:20:19 haraldkipp
  43. * PHAT file system failed when accessed from multiple threads. A mutual
  44. * exclusion semaphore fixes this.
  45. *
  46. * Revision 1.3 2006/02/23 15:45:22 haraldkipp
  47. * PHAT file system now supports configurable number of sector buffers.
  48. * This dramatically increased write rates of no-name cards.
  49. * AVR compile errors corrected.
  50. *
  51. * Revision 1.2 2006/01/22 17:38:43 haraldkipp
  52. * *** empty log message ***
  53. *
  54. * Revision 1.1 2006/01/05 16:31:45 haraldkipp
  55. * First check-in.
  56. *
  57. *
  58. * \endverbatim
  59. */
  60. #include <errno.h>
  61. #include <fs/fs.h>
  62. #include <fs/phatfs.h>
  63. #include <fs/phatvol.h>
  64. #include <dev/blockdev.h>
  65. #include <fs/phatio.h>
  66. #include <sys/event.h>
  67. #include <sys/timer.h>
  68. #if 0
  69. /* Use for local debugging. */
  70. #define NUTDEBUG
  71. #include <stdio.h>
  72. #endif
  73. /*!
  74. * \addtogroup xgPhatIo
  75. */
  76. /*@{*/
  77. /*!
  78. * \brief Directly write consecutive sectors.
  79. */
  80. int PhatSectorWrite(NUTDEVICE * dev, uint32_t sect, const void *data, int num)
  81. {
  82. int rc = 0;
  83. BLKPAR_SEEK pars;
  84. PHATVOL *vol = (PHATVOL *) dev->dev_dcb;
  85. NUTFILE *blkmnt = dev->dev_icb;
  86. NUTDEVICE *blkdev = blkmnt->nf_dev;
  87. int written;
  88. uint8_t *dp;
  89. int sbn;
  90. int sbc;
  91. while (num && rc == 0) {
  92. /* Gain mutex access. */
  93. NutEventWait(&vol->vol_iomutex, 0);
  94. /* Check if any of the sectors is locked. */
  95. #if PHAT_SECTOR_BUFFERS
  96. sbc = PHAT_SECTOR_BUFFERS;
  97. #else
  98. sbc = 1;
  99. #endif
  100. for (sbn = 0; sbn < sbc; sbn++) {
  101. if (vol->vol_buf[sbn].sect_num >= sect && vol->vol_buf[sbn].sect_num < sect + num) {
  102. if (vol->vol_buf[sbn].sect_lock) {
  103. break;
  104. } else {
  105. vol->vol_buf[sbn].sect_dirty = 0;
  106. }
  107. }
  108. }
  109. if (sbn == sbc) {
  110. /* Note, that not all drivers may support multi-sector write. */
  111. dp = (uint8_t *) data;
  112. while (num) {
  113. pars.par_nfp = blkmnt;
  114. pars.par_blknum = sect;
  115. rc = (*blkdev->dev_ioctl) (blkdev, NUTBLKDEV_SEEK, &pars);
  116. if (rc) {
  117. errno = EIO;
  118. break;
  119. }
  120. written = (*blkdev->dev_write) (blkmnt, dp, num);
  121. if (written <= 0) {
  122. rc = -1;
  123. errno = EIO;
  124. break;
  125. }
  126. num -= written;
  127. sect += written;
  128. dp += (written * vol->vol_sectsz);
  129. }
  130. }
  131. NutEventPost(&vol->vol_iomutex);
  132. }
  133. return rc;
  134. }
  135. /*!
  136. * \brief Flush sector buffers.
  137. *
  138. * The volume must be locked before calling this function.
  139. *
  140. * \param dev Specifies the file system device.
  141. * \param bufnum The buffer number to flush. If -1, all buffers are flushed.
  142. *
  143. * \return 0 on success, -1 on failures.
  144. */
  145. int PhatSectorFlush(NUTDEVICE * dev, int bufnum)
  146. {
  147. BLKPAR_SEEK pars;
  148. int sbn;
  149. PHATVOL *vol = (PHATVOL *) dev->dev_dcb;
  150. NUTFILE *blkmnt = dev->dev_icb;
  151. NUTDEVICE *blkdev = blkmnt->nf_dev;
  152. if (bufnum < 0) {
  153. sbn = 0;
  154. #if PHAT_SECTOR_BUFFERS
  155. bufnum = PHAT_SECTOR_BUFFERS - 1;
  156. #else
  157. bufnum = 0;
  158. #endif
  159. }
  160. else {
  161. sbn = bufnum;
  162. }
  163. while (sbn <= bufnum) {
  164. if (vol->vol_buf[sbn].sect_dirty) {
  165. pars.par_nfp = blkmnt;
  166. pars.par_blknum = vol->vol_buf[sbn].sect_num;
  167. if ((*blkdev->dev_ioctl) (blkdev, NUTBLKDEV_SEEK, &pars)) {
  168. errno = EIO;
  169. return -1;
  170. }
  171. if ((*blkdev->dev_write) (blkmnt, vol->vol_buf[sbn].sect_data, 1) != 1) {
  172. errno = EIO;
  173. return -1;
  174. }
  175. vol->vol_buf[sbn].sect_dirty = 0;
  176. }
  177. sbn++;
  178. }
  179. return 0;
  180. }
  181. /*!
  182. * \brief Read sector.
  183. *
  184. * The volume must be locked before calling this function.
  185. *
  186. * \param blkmnt Specifies the mounted block device partition.
  187. * \param sect Sector to load.
  188. * \param buf Points to a buffer which will receive the sector data.
  189. *
  190. * \return 0 on success, -1 on failures.
  191. */
  192. int PhatSectorRead(NUTFILE * blkmnt, uint32_t sect, uint8_t * buf)
  193. {
  194. BLKPAR_SEEK pars;
  195. NUTDEVICE *blkdev = blkmnt->nf_dev;
  196. /* Set the block device's sector position. */
  197. pars.par_nfp = blkmnt;
  198. pars.par_blknum = sect;
  199. if ((*blkdev->dev_ioctl) (blkdev, NUTBLKDEV_SEEK, &pars)) {
  200. errno = EIO;
  201. return -1;
  202. }
  203. /* Read a single block from the device. */
  204. if ((*blkdev->dev_read) (blkmnt, buf, 1) != 1) {
  205. errno = EIO;
  206. return -1;
  207. }
  208. return 0;
  209. }
  210. /*
  211. * \param dev Specifies the file system device.
  212. * \return Buffer number on success, -1 on failures.
  213. */
  214. int PhatSectorLoad(NUTDEVICE * dev, uint32_t sect)
  215. {
  216. int sbn;
  217. #if PHAT_SECTOR_BUFFERS
  218. int i;
  219. #endif
  220. PHATVOL *vol = (PHATVOL *) dev->dev_dcb;
  221. /* Search for a buffer. */
  222. for (;;) {
  223. /* Gain mutex access. */
  224. NutEventWait(&vol->vol_iomutex, 0);
  225. #if PHAT_SECTOR_BUFFERS
  226. /* Check if the requested sector is already buffered. */
  227. for (sbn = 0; sbn < PHAT_SECTOR_BUFFERS; sbn++) {
  228. if (vol->vol_buf[sbn].sect_num == sect) {
  229. /* Found, increase the lock and return. */
  230. vol->vol_buf[sbn].sect_lock++;
  231. vol->vol_usenext = sbn;
  232. NutEventPost(&vol->vol_iomutex);
  233. return sbn;
  234. }
  235. }
  236. /* Sector not loaded. Use round robin to select a new buffer. */
  237. for (i = vol->vol_usenext + 1;; i++) {
  238. if (i >= PHAT_SECTOR_BUFFERS) {
  239. i = 0;
  240. }
  241. if (i == vol->vol_usenext) {
  242. break;
  243. }
  244. if (vol->vol_buf[i].sect_num == (uint32_t) -1) {
  245. /* Unused buffer found, stop searching. */
  246. sbn = i;
  247. break;
  248. }
  249. if (vol->vol_buf[i].sect_lock == 0) {
  250. /* Unlocked buffer found, continue searching and hope to
  251. find an unused one. */
  252. sbn = i;
  253. }
  254. }
  255. #else
  256. /* Check if the requested sector is already buffered. */
  257. sbn = 0;
  258. if (vol->vol_buf[sbn].sect_num == sect) {
  259. /* Found, increase the lock and return. */
  260. vol->vol_buf[sbn].sect_lock++;
  261. NutEventPost(&vol->vol_iomutex);
  262. return sbn;
  263. }
  264. #endif
  265. /* If the selected buffer is unlocked, use it. */
  266. if (vol->vol_buf[sbn].sect_lock == 0) {
  267. break;
  268. }
  269. /* All buffers are locked. Allow other threads to try their luck. */
  270. NutEventPost(&vol->vol_iomutex);
  271. NutSleep(1);
  272. }
  273. if (PhatSectorFlush(dev, sbn)) {
  274. sbn = -1;
  275. }
  276. else if (PhatSectorRead(dev->dev_icb, sect, vol->vol_buf[sbn].sect_data)) {
  277. sbn = -1;
  278. }
  279. else {
  280. vol->vol_buf[sbn].sect_num = sect;
  281. vol->vol_buf[sbn].sect_lock++;
  282. #if PHAT_SECTOR_BUFFERS
  283. // TODO: Is this fix correct for non buffered systems?
  284. vol->vol_usenext = sbn;
  285. #endif
  286. }
  287. /* Release mutex access. */
  288. NutEventPost(&vol->vol_iomutex);
  289. return sbn;
  290. }
  291. void PhatSectorBufferRelease(NUTDEVICE * dev, int bufnum)
  292. {
  293. PHATVOL *vol = (PHATVOL *) dev->dev_dcb;
  294. if (vol->vol_buf[bufnum].sect_lock) {
  295. vol->vol_buf[bufnum].sect_lock--;
  296. }
  297. }
  298. /*@}*/