fs_blockpartition.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366
  1. /****************************************************************************
  2. * fs/driver/fs_blockpartition.c
  3. *
  4. * Copyright (C) 2018 Pinecone Inc. All rights reserved.
  5. * Author: Xiang Xiao <xiaoxiang@pinecone.net>
  6. *
  7. * Redistribution and use in source and binary forms, with or without
  8. * modification, are permitted provided that the following conditions
  9. * are met:
  10. *
  11. * 1. Redistributions of source code must retain the above copyright
  12. * notice, this list of conditions and the following disclaimer.
  13. * 2. Redistributions in binary form must reproduce the above copyright
  14. * notice, this list of conditions and the following disclaimer in
  15. * the documentation and/or other materials provided with the
  16. * distribution.
  17. * 3. Neither the name NuttX nor the names of its contributors may be
  18. * used to endorse or promote products derived from this software
  19. * without specific prior written permission.
  20. *
  21. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  22. * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  23. * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
  24. * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
  25. * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
  26. * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
  27. * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
  28. * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
  29. * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  30. * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
  31. * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  32. * POSSIBILITY OF SUCH DAMAGE.
  33. *
  34. ****************************************************************************/
  35. /****************************************************************************
  36. * Included Files
  37. ****************************************************************************/
  38. #include <nuttx/config.h>
  39. #include <errno.h>
  40. #include <sys/mount.h>
  41. #include <sys/stat.h>
  42. #include <nuttx/fs/fs.h>
  43. #include <nuttx/fs/ioctl.h>
  44. #include <nuttx/mtd/mtd.h>
  45. #include <nuttx/kmalloc.h>
  46. #include "driver/driver.h"
  47. #include "inode/inode.h"
  48. /****************************************************************************
  49. * Private Types
  50. ****************************************************************************/
  51. struct part_struct_s
  52. {
  53. FAR struct inode *parent;
  54. size_t firstsector;
  55. size_t nsectors;
  56. };
  57. /****************************************************************************
  58. * Private Function Prototypes
  59. ****************************************************************************/
  60. static int part_open(FAR struct inode *inode);
  61. static int part_close(FAR struct inode *inode);
  62. static ssize_t part_read(FAR struct inode *inode, unsigned char *buffer,
  63. size_t start_sector, unsigned int nsectors);
  64. #ifdef CONFIG_FS_WRITABLE
  65. static ssize_t part_write(FAR struct inode *inode, const unsigned char *buffer,
  66. size_t start_sector, unsigned int nsectors);
  67. #endif
  68. static int part_geometry(FAR struct inode *inode, struct geometry *geometry);
  69. static int part_ioctl(FAR struct inode *inode, int cmd, unsigned long arg);
  70. #ifndef CONFIG_DISABLE_PSEUDOFS_OPERATIONS
  71. static int part_unlink(FAR struct inode *inode);
  72. #endif
  73. /****************************************************************************
  74. * Private Data
  75. ****************************************************************************/
  76. static const struct block_operations g_part_bops =
  77. {
  78. part_open, /* open */
  79. part_close, /* close */
  80. part_read, /* read */
  81. #ifdef CONFIG_FS_WRITABLE
  82. part_write, /* write */
  83. #else
  84. NULL, /* write */
  85. #endif
  86. part_geometry, /* geometry */
  87. part_ioctl /* ioctl */
  88. #ifndef CONFIG_DISABLE_PSEUDOFS_OPERATIONS
  89. , part_unlink /* unlink */
  90. #endif
  91. };
  92. /****************************************************************************
  93. * Private Functions
  94. ****************************************************************************/
  95. /****************************************************************************
  96. * Name: part_open
  97. *
  98. * Description: Open the block device
  99. *
  100. ****************************************************************************/
  101. static int part_open(FAR struct inode *inode)
  102. {
  103. FAR struct part_struct_s *dev = inode->i_private;
  104. FAR struct inode *parent = dev->parent;
  105. int ret = OK;
  106. /* Open the parent block device */
  107. if (parent->u.i_bops->open)
  108. {
  109. ret = parent->u.i_bops->open(parent);
  110. }
  111. return ret;
  112. }
  113. /****************************************************************************
  114. * Name: part_close
  115. *
  116. * Description: close the block device
  117. *
  118. ****************************************************************************/
  119. static int part_close(FAR struct inode *inode)
  120. {
  121. FAR struct part_struct_s *dev = inode->i_private;
  122. FAR struct inode *parent = dev->parent;
  123. int ret = OK;
  124. if (parent->u.i_bops->close)
  125. {
  126. ret = parent->u.i_bops->close(parent);
  127. }
  128. return ret;
  129. }
  130. /****************************************************************************
  131. * Name: part_read
  132. *
  133. * Description: Read the specified number of sectors
  134. *
  135. ****************************************************************************/
  136. static ssize_t part_read(FAR struct inode *inode, unsigned char *buffer,
  137. size_t start_sector, unsigned int nsectors)
  138. {
  139. FAR struct part_struct_s *dev = inode->i_private;
  140. FAR struct inode *parent = dev->parent;
  141. if (start_sector + nsectors > dev->nsectors)
  142. {
  143. nsectors = dev->nsectors - start_sector;
  144. }
  145. start_sector += dev->firstsector;
  146. return parent->u.i_bops->read(parent, buffer, start_sector, nsectors);
  147. }
  148. /****************************************************************************
  149. * Name: part_write
  150. *
  151. * Description: Write (or buffer) the specified number of sectors
  152. *
  153. ****************************************************************************/
  154. #ifdef CONFIG_FS_WRITABLE
  155. static ssize_t part_write(FAR struct inode *inode, const unsigned char *buffer,
  156. size_t start_sector, unsigned int nsectors)
  157. {
  158. FAR struct part_struct_s *dev = inode->i_private;
  159. FAR struct inode *parent = dev->parent;
  160. if (start_sector + nsectors > dev->nsectors)
  161. {
  162. nsectors = dev->nsectors - start_sector;
  163. }
  164. start_sector += dev->firstsector;
  165. return parent->u.i_bops->write(parent, buffer, start_sector, nsectors);
  166. }
  167. #endif
  168. /****************************************************************************
  169. * Name: part_geometry
  170. *
  171. * Description: Return device geometry
  172. *
  173. ****************************************************************************/
  174. static int part_geometry(FAR struct inode *inode, struct geometry *geometry)
  175. {
  176. FAR struct part_struct_s *dev = inode->i_private;
  177. FAR struct inode *parent = dev->parent;
  178. int ret;
  179. ret = parent->u.i_bops->geometry(parent, geometry);
  180. if (ret >= 0)
  181. {
  182. geometry->geo_nsectors = dev->nsectors;
  183. }
  184. return ret;
  185. }
  186. /****************************************************************************
  187. * Name: part_ioctl
  188. *
  189. * Description: Return device geometry
  190. *
  191. ****************************************************************************/
  192. static int part_ioctl(FAR struct inode *inode, int cmd, unsigned long arg)
  193. {
  194. FAR struct part_struct_s *dev = inode->i_private;
  195. FAR struct inode *parent = dev->parent;
  196. int ret = -ENOTTY;
  197. if (parent->u.i_bops->ioctl)
  198. {
  199. if (cmd == MTDIOC_PROTECT || cmd == MTDIOC_UNPROTECT)
  200. {
  201. FAR struct mtd_protect_s *prot = (FAR struct mtd_protect_s *)arg;
  202. prot->startblock += dev->firstsector;
  203. }
  204. ret = parent->u.i_bops->ioctl(parent, cmd, arg);
  205. if (ret >= 0)
  206. {
  207. if (cmd == BIOC_XIPBASE || cmd == MTDIOC_XIPBASE)
  208. {
  209. FAR void **base = (FAR void **)arg;
  210. struct geometry geo;
  211. ret = parent->u.i_bops->geometry(parent, &geo);
  212. if (ret >= 0)
  213. {
  214. *(FAR uint8_t *)base += dev->firstsector * geo.geo_sectorsize;
  215. }
  216. }
  217. else if (cmd == MTDIOC_GEOMETRY)
  218. {
  219. FAR struct mtd_geometry_s *mgeo = (FAR struct mtd_geometry_s *)arg;
  220. uint32_t blkper = mgeo->erasesize / mgeo->blocksize;
  221. mgeo->neraseblocks = dev->nsectors / blkper;
  222. }
  223. }
  224. }
  225. return ret;
  226. }
  227. /****************************************************************************
  228. * Name: part_unlink
  229. ****************************************************************************/
  230. #ifndef CONFIG_DISABLE_PSEUDOFS_OPERATIONS
  231. static int part_unlink(FAR struct inode *inode)
  232. {
  233. FAR struct part_struct_s *dev = inode->i_private;
  234. FAR struct inode *parent = dev->parent;
  235. inode_release(parent);
  236. kmm_free(dev);
  237. return OK;
  238. }
  239. #endif
  240. /****************************************************************************
  241. * Public Functions
  242. ****************************************************************************/
  243. /****************************************************************************
  244. * Name: register_blockpartition
  245. *
  246. * Description:
  247. * Register a block partition driver inode the pseudo file system.
  248. *
  249. * Input Parameters:
  250. * partition - The path to the partition inode
  251. * parent - The path to the parent inode
  252. * firstsector - The offset in sectors to the partition
  253. * nsectors - The number of sectors in the partition
  254. *
  255. * Returned Value:
  256. * Zero on success (with the inode point in 'inode'); A negated errno
  257. * value is returned on a failure (all error values returned by
  258. * inode_reserve):
  259. *
  260. * EINVAL - 'path' is invalid for this operation
  261. * EEXIST - An inode already exists at 'path'
  262. * ENOMEM - Failed to allocate in-memory resources for the operation
  263. *
  264. ****************************************************************************/
  265. int register_blockpartition(FAR const char *partition,
  266. mode_t mode, FAR const char *parent,
  267. size_t firstsector, size_t nsectors)
  268. {
  269. FAR struct part_struct_s *dev;
  270. int ret;
  271. /* Allocate a partition device structure */
  272. dev = kmm_zalloc(sizeof(*dev));
  273. if (!dev)
  274. {
  275. return -ENOMEM;
  276. }
  277. dev->firstsector = firstsector;
  278. dev->nsectors = nsectors;
  279. /* Find the block driver */
  280. if (mode & (S_IWOTH | S_IWGRP | S_IWUSR))
  281. {
  282. ret = find_blockdriver(parent, 0, &dev->parent);
  283. }
  284. else
  285. {
  286. ret = find_blockdriver(parent, MS_RDONLY, &dev->parent);
  287. }
  288. if (ret < 0)
  289. {
  290. goto errout_free;
  291. }
  292. /* Inode private data is a reference to the partition device structure */
  293. ret = register_blockdriver(partition, &g_part_bops, mode, dev);
  294. if (ret < 0)
  295. {
  296. goto errout_release;
  297. }
  298. return OK;
  299. errout_release:
  300. inode_release(dev->parent);
  301. errout_free:
  302. kmm_free(dev);
  303. return ret;
  304. }