1 /*
2 * Copyright (c) 2006-2022, RT-Thread Development Team
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 *
6 * Change Logs:
7 * Date Author Notes
8 * 2016-09-20 Bernard the first version
9 */
10
11 #include <stdint.h>
12 #include <stdio.h>
13 #include <stdlib.h>
14
15 #include <rtthread.h>
16 #include <rtdevice.h>
17
18 #include "partition.h"
19
20 // #define PARTITION_DEBUG
21
22 #ifdef PARTITION_DEBUG
23 #define DEBUG_TRACE rt_kprintf("[part] "); rt_kprintf
24 #else
25 #define DEBUG_TRACE(...)
26 #endif
27
28 struct partition_device
29 {
30 struct rt_device parent; /* parent block device */
31
32 int sector_size;
33 int block_size;
34
35 struct rt_device *block_device;
36 const struct rt_partition *partition;
37 };
38
39 /* RT-Thread device interface */
partition_init(rt_device_t dev)40 static rt_err_t partition_init(rt_device_t dev)
41 {
42 return RT_EOK;
43 }
44
partition_open(rt_device_t dev,rt_uint16_t oflag)45 static rt_err_t partition_open(rt_device_t dev, rt_uint16_t oflag)
46 {
47 return RT_EOK;
48 }
49
partition_close(rt_device_t dev)50 static rt_err_t partition_close(rt_device_t dev)
51 {
52 return RT_EOK;
53 }
54
55 #if RTTHREAD_VERSION >= 30000
partition_control(rt_device_t dev,int cmd,void * args)56 static rt_err_t partition_control(rt_device_t dev, int cmd, void *args)
57 #else
58 static rt_err_t partition_control(rt_device_t dev, rt_uint8_t cmd, void *args)
59 #endif
60 {
61 struct partition_device *part;
62
63 part = (struct partition_device*) dev;
64 RT_ASSERT(part != RT_NULL);
65
66 if (cmd == RT_DEVICE_CTRL_BLK_GETGEOME)
67 {
68 struct rt_device_blk_geometry *geometry;
69
70 geometry = (struct rt_device_blk_geometry *)args;
71 if (geometry == RT_NULL) return -RT_ERROR;
72
73 geometry->bytes_per_sector = part->sector_size;
74 geometry->sector_count = part->partition->size / part->sector_size;
75 geometry->block_size = part->block_size;
76 }
77
78 return RT_EOK;
79 }
80
partition_read(rt_device_t dev,rt_off_t pos,void * buffer,rt_size_t size)81 static rt_ssize_t partition_read(rt_device_t dev,
82 rt_off_t pos,
83 void* buffer,
84 rt_size_t size)
85 {
86 struct partition_device *part;
87
88 part = (struct partition_device*) dev;
89 RT_ASSERT(part != RT_NULL);
90
91 DEBUG_TRACE("read block: %d, size=%d\n", pos + part->partition->offset/part->sector_size, size);
92
93 return rt_device_read(part->block_device, pos + part->partition->offset/part->sector_size, buffer, size);
94 }
95
partition_write(rt_device_t dev,rt_off_t pos,const void * buffer,rt_size_t size)96 static rt_ssize_t partition_write(rt_device_t dev,
97 rt_off_t pos,
98 const void* buffer,
99 rt_size_t size)
100 {
101 struct partition_device *part;
102
103 part = (struct partition_device*) dev;
104 RT_ASSERT(part != RT_NULL);
105
106 if (part->partition->flags & PARTITION_WRITEABLE)
107 {
108 DEBUG_TRACE("write block: %d, size=%d\n", pos + part->partition->offset/part->sector_size, size);
109
110 return rt_device_write(part->block_device, pos + part->partition->offset/part->sector_size,
111 buffer, size);
112 }
113
114 DEBUG_TRACE("read-only partition!\n");
115 return 0;
116 }
117
118 #ifdef RT_USING_DEVICE_OPS
119 const static struct rt_device_ops _partition_ops =
120 {
121 .init = partition_init,
122 .open = partition_open,
123 .close = partition_close,
124 .read = partition_read,
125 .write = partition_write,
126 .control = partition_control,
127 };
128 #endif /* RT_USING_DEVICE_OPS */
129
rt_partition_init(const char * flash_device,const struct rt_partition * parts,rt_size_t num)130 int rt_partition_init(const char* flash_device, const struct rt_partition* parts, rt_size_t num)
131 {
132 struct rt_device *device;
133 struct partition_device *part_dev;
134 const struct rt_partition* part;
135 struct rt_device_blk_geometry geometry;
136
137 device = (struct rt_device *)rt_device_find(flash_device);
138 if(device == RT_NULL)
139 {
140 DEBUG_TRACE("block device %s not found!\r\n", flash_device);
141 return -RT_ENOSYS;
142 }
143
144 /* open the block device */
145 rt_device_open(device, RT_DEVICE_OFLAG_RDWR);
146 /* get block device geometry */
147 rt_device_control(device, RT_DEVICE_CTRL_BLK_GETGEOME, &geometry);
148
149 /* create each partition device */
150 while(num --)
151 {
152 part = parts ++;
153 part_dev = (struct partition_device*)rt_malloc (sizeof(struct partition_device));
154 if (part_dev)
155 {
156 part_dev->block_device = device;
157 part_dev->partition = part;
158 part_dev->sector_size = geometry.bytes_per_sector;
159 part_dev->block_size = geometry.block_size;
160
161 /* register device */
162 part_dev->parent.type = RT_Device_Class_Block;
163 #ifndef RT_USING_DEVICE_OPS
164 part_dev->parent.init = partition_init;
165 part_dev->parent.open = partition_open;
166 part_dev->parent.close = partition_close;
167 part_dev->parent.read = partition_read;
168 part_dev->parent.write = partition_write;
169 part_dev->parent.control = partition_control;
170 #else
171 part_dev->parent.ops = &_partition_ops;
172 #endif /* RT_USING_DEVICE_OPS */
173 /* no private */
174 part_dev->parent.user_data = RT_NULL;
175
176 DEBUG_TRACE("add partition: %s\n", part->name);
177 rt_device_register(RT_DEVICE(part_dev), part->name,
178 RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_STANDALONE);
179 }
180 }
181
182 return RT_EOK;
183 }
184