fs_blockpartition.c 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349
  1. /****************************************************************************
  2. * fs/driver/fs_blockpartition.c
  3. *
  4. * Licensed to the Apache Software Foundation (ASF) under one or more
  5. * contributor license agreements. See the NOTICE file distributed with
  6. * this work for additional information regarding copyright ownership. The
  7. * ASF licenses this file to you under the Apache License, Version 2.0 (the
  8. * "License"); you may not use this file except in compliance with the
  9. * License. You may obtain a copy of the License at
  10. *
  11. * http://www.apache.org/licenses/LICENSE-2.0
  12. *
  13. * Unless required by applicable law or agreed to in writing, software
  14. * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
  15. * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
  16. * License for the specific language governing permissions and limitations
  17. * under the License.
  18. *
  19. ****************************************************************************/
  20. /****************************************************************************
  21. * Included Files
  22. ****************************************************************************/
  23. #include <nuttx/config.h>
  24. #include <errno.h>
  25. #include <sys/mount.h>
  26. #include <sys/stat.h>
  27. #include <nuttx/fs/fs.h>
  28. #include <nuttx/fs/ioctl.h>
  29. #include <nuttx/mtd/mtd.h>
  30. #include <nuttx/kmalloc.h>
  31. #include "driver/driver.h"
  32. #include "inode/inode.h"
  33. /****************************************************************************
  34. * Private Types
  35. ****************************************************************************/
  36. struct part_struct_s
  37. {
  38. FAR struct inode *parent;
  39. size_t firstsector;
  40. size_t nsectors;
  41. };
  42. /****************************************************************************
  43. * Private Function Prototypes
  44. ****************************************************************************/
  45. static int part_open(FAR struct inode *inode);
  46. static int part_close(FAR struct inode *inode);
  47. static ssize_t part_read(FAR struct inode *inode, FAR unsigned char *buffer,
  48. size_t start_sector, unsigned int nsectors);
  49. static ssize_t part_write(FAR struct inode *inode,
  50. FAR const unsigned char *buffer, size_t start_sector,
  51. unsigned int nsectors);
  52. static int part_geometry(FAR struct inode *inode,
  53. FAR struct geometry *geometry);
  54. static int part_ioctl(FAR struct inode *inode, int cmd,
  55. unsigned long arg);
  56. #ifndef CONFIG_DISABLE_PSEUDOFS_OPERATIONS
  57. static int part_unlink(FAR struct inode *inode);
  58. #endif
  59. /****************************************************************************
  60. * Private Data
  61. ****************************************************************************/
  62. static const struct block_operations g_part_bops =
  63. {
  64. part_open, /* open */
  65. part_close, /* close */
  66. part_read, /* read */
  67. part_write, /* write */
  68. part_geometry, /* geometry */
  69. part_ioctl /* ioctl */
  70. #ifndef CONFIG_DISABLE_PSEUDOFS_OPERATIONS
  71. , part_unlink /* unlink */
  72. #endif
  73. };
  74. /****************************************************************************
  75. * Private Functions
  76. ****************************************************************************/
  77. /****************************************************************************
  78. * Name: part_open
  79. *
  80. * Description: Open the block device
  81. *
  82. ****************************************************************************/
  83. static int part_open(FAR struct inode *inode)
  84. {
  85. FAR struct part_struct_s *dev = inode->i_private;
  86. FAR struct inode *parent = dev->parent;
  87. int ret = OK;
  88. /* Open the parent block device */
  89. if (parent->u.i_bops->open)
  90. {
  91. ret = parent->u.i_bops->open(parent);
  92. }
  93. return ret;
  94. }
  95. /****************************************************************************
  96. * Name: part_close
  97. *
  98. * Description: close the block device
  99. *
  100. ****************************************************************************/
  101. static int part_close(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. if (parent->u.i_bops->close)
  107. {
  108. ret = parent->u.i_bops->close(parent);
  109. }
  110. return ret;
  111. }
  112. /****************************************************************************
  113. * Name: part_read
  114. *
  115. * Description: Read the specified number of sectors
  116. *
  117. ****************************************************************************/
  118. static ssize_t part_read(FAR struct inode *inode, unsigned char *buffer,
  119. size_t start_sector, unsigned int nsectors)
  120. {
  121. FAR struct part_struct_s *dev = inode->i_private;
  122. FAR struct inode *parent = dev->parent;
  123. if (start_sector + nsectors > dev->nsectors)
  124. {
  125. nsectors = dev->nsectors - start_sector;
  126. }
  127. start_sector += dev->firstsector;
  128. return parent->u.i_bops->read(parent, buffer, start_sector, nsectors);
  129. }
  130. /****************************************************************************
  131. * Name: part_write
  132. *
  133. * Description: Write (or buffer) the specified number of sectors
  134. *
  135. ****************************************************************************/
  136. static ssize_t part_write(FAR struct inode *inode,
  137. FAR const unsigned char *buffer,
  138. size_t start_sector, unsigned int nsectors)
  139. {
  140. FAR struct part_struct_s *dev = inode->i_private;
  141. FAR struct inode *parent = dev->parent;
  142. if (start_sector + nsectors > dev->nsectors)
  143. {
  144. nsectors = dev->nsectors - start_sector;
  145. }
  146. start_sector += dev->firstsector;
  147. return parent->u.i_bops->write(parent, buffer, start_sector, nsectors);
  148. }
  149. /****************************************************************************
  150. * Name: part_geometry
  151. *
  152. * Description: Return device geometry
  153. *
  154. ****************************************************************************/
  155. static int part_geometry(FAR struct inode *inode, struct geometry *geometry)
  156. {
  157. FAR struct part_struct_s *dev = inode->i_private;
  158. FAR struct inode *parent = dev->parent;
  159. int ret;
  160. ret = parent->u.i_bops->geometry(parent, geometry);
  161. if (ret >= 0)
  162. {
  163. geometry->geo_nsectors = dev->nsectors;
  164. }
  165. return ret;
  166. }
  167. /****************************************************************************
  168. * Name: part_ioctl
  169. *
  170. * Description: Return device geometry
  171. *
  172. ****************************************************************************/
  173. static int part_ioctl(FAR struct inode *inode, int cmd, unsigned long arg)
  174. {
  175. FAR uintptr_t ptr_arg = (uintptr_t)arg;
  176. FAR struct part_struct_s *dev = inode->i_private;
  177. FAR struct inode *parent = dev->parent;
  178. int ret = -ENOTTY;
  179. if (parent->u.i_bops->ioctl)
  180. {
  181. if (cmd == MTDIOC_PROTECT || cmd == MTDIOC_UNPROTECT)
  182. {
  183. FAR struct mtd_protect_s *prot =
  184. (FAR struct mtd_protect_s *)ptr_arg;
  185. prot->startblock += dev->firstsector;
  186. }
  187. ret = parent->u.i_bops->ioctl(parent, cmd, arg);
  188. if (ret >= 0)
  189. {
  190. if (cmd == BIOC_XIPBASE || cmd == MTDIOC_XIPBASE)
  191. {
  192. FAR void **base = (FAR void **)ptr_arg;
  193. struct geometry geo;
  194. ret = parent->u.i_bops->geometry(parent, &geo);
  195. if (ret >= 0)
  196. {
  197. *(FAR uint8_t *)base +=
  198. dev->firstsector * geo.geo_sectorsize;
  199. }
  200. }
  201. else if (cmd == MTDIOC_GEOMETRY)
  202. {
  203. FAR struct mtd_geometry_s *mgeo =
  204. (FAR struct mtd_geometry_s *)ptr_arg;
  205. uint32_t blkper = mgeo->erasesize / mgeo->blocksize;
  206. mgeo->neraseblocks = dev->nsectors / blkper;
  207. }
  208. }
  209. }
  210. return ret;
  211. }
  212. /****************************************************************************
  213. * Name: part_unlink
  214. ****************************************************************************/
  215. #ifndef CONFIG_DISABLE_PSEUDOFS_OPERATIONS
  216. static int part_unlink(FAR struct inode *inode)
  217. {
  218. FAR struct part_struct_s *dev = inode->i_private;
  219. FAR struct inode *parent = dev->parent;
  220. inode_release(parent);
  221. kmm_free(dev);
  222. return OK;
  223. }
  224. #endif
  225. /****************************************************************************
  226. * Public Functions
  227. ****************************************************************************/
  228. /****************************************************************************
  229. * Name: register_blockpartition
  230. *
  231. * Description:
  232. * Register a block partition driver inode the pseudo file system.
  233. *
  234. * Input Parameters:
  235. * partition - The path to the partition inode
  236. * parent - The path to the parent inode
  237. * firstsector - The offset in sectors to the partition
  238. * nsectors - The number of sectors in the partition
  239. *
  240. * Returned Value:
  241. * Zero on success (with the inode point in 'inode'); A negated errno
  242. * value is returned on a failure (all error values returned by
  243. * inode_reserve):
  244. *
  245. * EINVAL - 'path' is invalid for this operation
  246. * EEXIST - An inode already exists at 'path'
  247. * ENOMEM - Failed to allocate in-memory resources for the operation
  248. *
  249. ****************************************************************************/
  250. int register_blockpartition(FAR const char *partition,
  251. mode_t mode, FAR const char *parent,
  252. size_t firstsector, size_t nsectors)
  253. {
  254. FAR struct part_struct_s *dev;
  255. int ret;
  256. /* Allocate a partition device structure */
  257. dev = kmm_zalloc(sizeof(*dev));
  258. if (!dev)
  259. {
  260. return -ENOMEM;
  261. }
  262. dev->firstsector = firstsector;
  263. dev->nsectors = nsectors;
  264. /* Find the block driver */
  265. if (mode & (S_IWOTH | S_IWGRP | S_IWUSR))
  266. {
  267. ret = find_blockdriver(parent, 0, &dev->parent);
  268. }
  269. else
  270. {
  271. ret = find_blockdriver(parent, MS_RDONLY, &dev->parent);
  272. }
  273. if (ret < 0)
  274. {
  275. goto errout_free;
  276. }
  277. /* Inode private data is a reference to the partition device structure */
  278. ret = register_blockdriver(partition, &g_part_bops, mode, dev);
  279. if (ret < 0)
  280. {
  281. goto errout_release;
  282. }
  283. return OK;
  284. errout_release:
  285. inode_release(dev->parent);
  286. errout_free:
  287. kmm_free(dev);
  288. return ret;
  289. }