ramdisk.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458
  1. /****************************************************************************
  2. * drivers/ramdisk.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 <sys/types.h>
  25. #include <sys/ioctl.h>
  26. #include <inttypes.h>
  27. #include <stdint.h>
  28. #include <stdbool.h>
  29. #include <stdio.h>
  30. #include <stdlib.h>
  31. #include <string.h>
  32. #include <assert.h>
  33. #include <debug.h>
  34. #include <errno.h>
  35. #include <nuttx/kmalloc.h>
  36. #include <nuttx/fs/fs.h>
  37. #include <nuttx/drivers/ramdisk.h>
  38. /****************************************************************************
  39. * Pre-processor Definitions
  40. ****************************************************************************/
  41. /* Helpers for rdflags */
  42. /* User input flags */
  43. #define RDFLAG_USER (RDFLAG_WRENABLED | RDFLAG_FUNLINK)
  44. #define RDFLAG_IS_WRENABLED(f) (((f) & RDFLAG_WRENABLED) != 0)
  45. #define RDFLAG_IS_FUNLINK(f) (((f) & RDFLAG_WRENABLED) != 0)
  46. /* Flag set when the RAM disk block driver is unlink */
  47. #define RDFLAG_UNLINK(f) do { (f) |= RDFLAG_UNLINKED; } while (0)
  48. #define RDFLAG_IS_UNLINKED(f) (((f) & RDFLAG_UNLINKED) != 0)
  49. /****************************************************************************
  50. * Private Types
  51. ****************************************************************************/
  52. struct rd_struct_s
  53. {
  54. uint32_t rd_nsectors; /* Number of sectors on device */
  55. uint16_t rd_sectsize; /* The size of one sector */
  56. #ifndef CONFIG_DISABLE_PSEUDOFS_OPERATIONS
  57. uint8_t rd_crefs; /* Open reference count */
  58. #endif
  59. uint8_t rd_flags; /* See RDFLAG_* definitions */
  60. FAR uint8_t *rd_buffer; /* RAM disk backup memory */
  61. };
  62. /****************************************************************************
  63. * Private Function Prototypes
  64. ****************************************************************************/
  65. #ifndef CONFIG_DISABLE_PSEUDOFS_OPERATIONS
  66. static void rd_destroy(FAR struct rd_struct_s *dev);
  67. static int rd_open(FAR struct inode *inode);
  68. static int rd_close(FAR struct inode *inode);
  69. #endif
  70. static ssize_t rd_read(FAR struct inode *inode, FAR unsigned char *buffer,
  71. blkcnt_t start_sector, unsigned int nsectors);
  72. static ssize_t rd_write(FAR struct inode *inode,
  73. FAR const unsigned char *buffer, blkcnt_t start_sector,
  74. unsigned int nsectors);
  75. static int rd_geometry(FAR struct inode *inode,
  76. FAR struct geometry *geometry);
  77. static int rd_ioctl(FAR struct inode *inode, int cmd,
  78. unsigned long arg);
  79. #ifndef CONFIG_DISABLE_PSEUDOFS_OPERATIONS
  80. static int rd_unlink(FAR struct inode *inode);
  81. #endif
  82. /****************************************************************************
  83. * Private Data
  84. ****************************************************************************/
  85. static const struct block_operations g_bops =
  86. {
  87. #ifndef CONFIG_DISABLE_PSEUDOFS_OPERATIONS
  88. rd_open, /* open */
  89. rd_close, /* close */
  90. #else
  91. 0, /* open */
  92. 0, /* close */
  93. #endif
  94. rd_read, /* read */
  95. rd_write, /* write */
  96. rd_geometry, /* geometry */
  97. rd_ioctl, /* ioctl */
  98. #ifndef CONFIG_DISABLE_PSEUDOFS_OPERATIONS
  99. rd_unlink /* unlink */
  100. #endif
  101. };
  102. /****************************************************************************
  103. * Private Functions
  104. ****************************************************************************/
  105. /****************************************************************************
  106. * Name: rd_destroy
  107. *
  108. * Description:
  109. * Free all resources used by the RAM disk
  110. *
  111. ****************************************************************************/
  112. #ifndef CONFIG_DISABLE_PSEUDOFS_OPERATIONS
  113. static void rd_destroy(FAR struct rd_struct_s *dev)
  114. {
  115. finfo("Destroying RAM disk\n");
  116. /* We we configured to free the RAM disk memory when unlinked? */
  117. if (RDFLAG_IS_UNLINKED(dev->rd_flags))
  118. {
  119. /* Yes.. do it */
  120. kmm_free(dev->rd_buffer);
  121. }
  122. /* And free the block driver itself */
  123. kmm_free(dev);
  124. }
  125. #endif
  126. /****************************************************************************
  127. * Name: rd_open
  128. *
  129. * Description: Open the block device
  130. *
  131. ****************************************************************************/
  132. #ifndef CONFIG_DISABLE_PSEUDOFS_OPERATIONS
  133. static int rd_open(FAR struct inode *inode)
  134. {
  135. FAR struct rd_struct_s *dev;
  136. DEBUGASSERT(inode && inode->i_private);
  137. dev = (FAR struct rd_struct_s *)inode->i_private;
  138. /* Increment the open reference count */
  139. dev->rd_crefs++;
  140. DEBUGASSERT(dev->rd_crefs > 0);
  141. finfo("rd_crefs: %d\n", dev->rd_crefs);
  142. return OK;
  143. }
  144. #endif
  145. /****************************************************************************
  146. * Name: rd_close
  147. *
  148. * Description: close the block device
  149. *
  150. ****************************************************************************/
  151. #ifndef CONFIG_DISABLE_PSEUDOFS_OPERATIONS
  152. static int rd_close(FAR struct inode *inode)
  153. {
  154. FAR struct rd_struct_s *dev;
  155. DEBUGASSERT(inode && inode->i_private);
  156. dev = (FAR struct rd_struct_s *)inode->i_private;
  157. /* Increment the open reference count */
  158. DEBUGASSERT(dev->rd_crefs > 0);
  159. dev->rd_crefs--;
  160. finfo("rd_crefs: %d\n", dev->rd_crefs);
  161. #ifndef CONFIG_DISABLE_PSEUDOFS_OPERATIONS
  162. /* Was that the last open reference to the RAM disk? */
  163. if (dev->rd_crefs == 0)
  164. {
  165. /* Yes.. Have we been unlinked? */
  166. if (RDFLAG_IS_UNLINKED(dev->rd_flags))
  167. {
  168. /* Yes.. Release all of the RAM disk resources */
  169. rd_destroy(dev);
  170. }
  171. }
  172. #endif
  173. return OK;
  174. }
  175. #endif
  176. /****************************************************************************
  177. * Name: rd_read
  178. *
  179. * Description: Read the specified number of sectors
  180. *
  181. ****************************************************************************/
  182. static ssize_t rd_read(FAR struct inode *inode, unsigned char *buffer,
  183. blkcnt_t start_sector, unsigned int nsectors)
  184. {
  185. FAR struct rd_struct_s *dev;
  186. DEBUGASSERT(inode && inode->i_private);
  187. dev = (FAR struct rd_struct_s *)inode->i_private;
  188. finfo("sector: %" PRIu32 " nsectors: %u sectorsize: %d\n",
  189. start_sector, nsectors, dev->rd_sectsize);
  190. if (start_sector < dev->rd_nsectors &&
  191. start_sector + nsectors <= dev->rd_nsectors)
  192. {
  193. finfo("Transfer %d bytes from %p\n",
  194. nsectors * dev->rd_sectsize,
  195. &dev->rd_buffer[start_sector * dev->rd_sectsize]);
  196. memcpy(buffer,
  197. &dev->rd_buffer[start_sector * dev->rd_sectsize],
  198. nsectors * dev->rd_sectsize);
  199. return nsectors;
  200. }
  201. return -EINVAL;
  202. }
  203. /****************************************************************************
  204. * Name: rd_write
  205. *
  206. * Description: Write the specified number of sectors
  207. *
  208. ****************************************************************************/
  209. static ssize_t rd_write(FAR struct inode *inode, const unsigned char *buffer,
  210. blkcnt_t start_sector, unsigned int nsectors)
  211. {
  212. struct rd_struct_s *dev;
  213. DEBUGASSERT(inode && inode->i_private);
  214. dev = (struct rd_struct_s *)inode->i_private;
  215. finfo("sector: %" PRIu32 " nsectors: %u sectorsize: %d\n",
  216. start_sector, nsectors, dev->rd_sectsize);
  217. if (!RDFLAG_IS_WRENABLED(dev->rd_flags))
  218. {
  219. return -EACCES;
  220. }
  221. else if (start_sector < dev->rd_nsectors &&
  222. start_sector + nsectors <= dev->rd_nsectors)
  223. {
  224. finfo("Transfer %d bytes to %p\n",
  225. nsectors * dev->rd_sectsize,
  226. &dev->rd_buffer[start_sector * dev->rd_sectsize]);
  227. memcpy(&dev->rd_buffer[start_sector * dev->rd_sectsize],
  228. buffer,
  229. nsectors * dev->rd_sectsize);
  230. return nsectors;
  231. }
  232. return -EFBIG;
  233. }
  234. /****************************************************************************
  235. * Name: rd_geometry
  236. *
  237. * Description: Return device geometry
  238. *
  239. ****************************************************************************/
  240. static int rd_geometry(FAR struct inode *inode, struct geometry *geometry)
  241. {
  242. struct rd_struct_s *dev;
  243. finfo("Entry\n");
  244. DEBUGASSERT(inode);
  245. if (geometry)
  246. {
  247. dev = (struct rd_struct_s *)inode->i_private;
  248. geometry->geo_available = true;
  249. geometry->geo_mediachanged = false;
  250. geometry->geo_writeenabled = RDFLAG_IS_WRENABLED(dev->rd_flags);
  251. geometry->geo_nsectors = dev->rd_nsectors;
  252. geometry->geo_sectorsize = dev->rd_sectsize;
  253. finfo("available: true mediachanged: false writeenabled: %s\n",
  254. geometry->geo_writeenabled ? "true" : "false");
  255. finfo("nsectors: %" PRIu32 " sectorsize: %" PRIi16 "\n",
  256. geometry->geo_nsectors, geometry->geo_sectorsize);
  257. return OK;
  258. }
  259. return -EINVAL;
  260. }
  261. /****************************************************************************
  262. * Name: rd_ioctl
  263. *
  264. * Description:
  265. * Return device geometry
  266. *
  267. ****************************************************************************/
  268. static int rd_ioctl(FAR struct inode *inode, int cmd, unsigned long arg)
  269. {
  270. FAR struct rd_struct_s *dev;
  271. FAR void **ppv = (void**)((uintptr_t)arg);
  272. finfo("Entry\n");
  273. /* Only one ioctl command is supported */
  274. DEBUGASSERT(inode && inode->i_private);
  275. if (cmd == BIOC_XIPBASE && ppv)
  276. {
  277. dev = (FAR struct rd_struct_s *)inode->i_private;
  278. *ppv = (FAR void *)dev->rd_buffer;
  279. finfo("ppv: %p\n", *ppv);
  280. return OK;
  281. }
  282. return -ENOTTY;
  283. }
  284. /****************************************************************************
  285. * Name: rd_unlink
  286. *
  287. * Description:
  288. * The block driver has been unlinked.
  289. *
  290. ****************************************************************************/
  291. #ifndef CONFIG_DISABLE_PSEUDOFS_OPERATIONS
  292. static int rd_unlink(FAR struct inode *inode)
  293. {
  294. FAR struct rd_struct_s *dev;
  295. DEBUGASSERT(inode && inode->i_private);
  296. dev = (FAR struct rd_struct_s *)inode->i_private;
  297. /* Mark the pipe unlinked */
  298. RDFLAG_UNLINK(dev->rd_flags);
  299. /* Are the any open references to the driver? */
  300. if (dev->rd_crefs == 0)
  301. {
  302. /* No... release all resources held by the block driver */
  303. rd_destroy(dev);
  304. }
  305. return OK;
  306. }
  307. #endif
  308. /****************************************************************************
  309. * Public Functions
  310. ****************************************************************************/
  311. /****************************************************************************
  312. * Name: ramdisk_register or romdisk_register
  313. *
  314. * Description:
  315. * Non-standard function to register a ramdisk or a romdisk
  316. *
  317. * Input Parameters:
  318. * minor: Selects suffix of device named /dev/ramN, N={1,2,3...}
  319. * nsectors: Number of sectors on device
  320. * sectize: The size of one sector
  321. * rdflags: See RDFLAG_* definitions
  322. * buffer: RAM disk backup memory
  323. *
  324. * Returned Value:
  325. * Zero on success; a negated errno value on failure.
  326. *
  327. ****************************************************************************/
  328. int ramdisk_register(int minor, FAR uint8_t *buffer, uint32_t nsectors,
  329. uint16_t sectsize, uint8_t rdflags)
  330. {
  331. struct rd_struct_s *dev;
  332. char devname[16];
  333. int ret = -ENOMEM;
  334. finfo("buffer: %p nsectors: %" PRIu32 " sectsize: %" PRIu16 "\n",
  335. buffer, nsectors, sectsize);
  336. /* Sanity check */
  337. #ifdef CONFIG_DEBUG_FEATURES
  338. if (minor < 0 || minor > 255 || !buffer || !nsectors || !sectsize)
  339. {
  340. return -EINVAL;
  341. }
  342. #endif
  343. /* Allocate a ramdisk device structure */
  344. dev = (struct rd_struct_s *)kmm_zalloc(sizeof(struct rd_struct_s));
  345. if (dev)
  346. {
  347. /* Initialize the ramdisk device structure */
  348. dev->rd_nsectors = nsectors; /* Number of sectors on device */
  349. dev->rd_sectsize = sectsize; /* The size of one sector */
  350. dev->rd_buffer = buffer; /* RAM disk backup memory */
  351. dev->rd_flags = rdflags & RDFLAG_USER;
  352. /* Create a ramdisk device name */
  353. snprintf(devname, 16, "/dev/ram%d", minor);
  354. /* Inode private data is a reference to the ramdisk device structure */
  355. ret = register_blockdriver(devname, &g_bops, 0, dev);
  356. if (ret < 0)
  357. {
  358. ferr("register_blockdriver failed: %d\n", -ret);
  359. kmm_free(dev);
  360. }
  361. }
  362. return ret;
  363. }