1 /*
2 * Copyright (c) 2006-2023, RT-Thread Development Team
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 *
6 * Change Logs:
7 * Date Author Notes
8 * 2023-02-25 GuEe-GUI first version
9 */
10
11 #include "blk_dev.h"
12 #include "blk_dfs.h"
13
14 #define DBG_TAG "blk.dm"
15 #define DBG_LVL DBG_INFO
16 #include <rtdbg.h>
17
18 #ifdef RT_USING_DFS
19 #include <dfs_fs.h>
20 #endif
21
blk_dev_open(rt_device_t dev,rt_uint16_t oflag)22 static rt_err_t blk_dev_open(rt_device_t dev, rt_uint16_t oflag)
23 {
24 struct rt_blk_device *blk = to_blk(dev);
25
26 return rt_device_open(&blk->disk->parent, oflag);
27 }
28
blk_dev_close(rt_device_t dev)29 static rt_err_t blk_dev_close(rt_device_t dev)
30 {
31 struct rt_blk_device *blk = to_blk(dev);
32
33 return rt_device_close(&blk->disk->parent);
34 }
35
blk_dev_read(rt_device_t dev,rt_off_t sector,void * buffer,rt_size_t sector_count)36 static rt_ssize_t blk_dev_read(rt_device_t dev, rt_off_t sector,
37 void *buffer, rt_size_t sector_count)
38 {
39 struct rt_blk_device *blk = to_blk(dev);
40
41 if (sector <= blk->sector_start + blk->sector_count &&
42 sector_count <= blk->sector_count)
43 {
44 return rt_device_read(&blk->disk->parent,
45 blk->sector_start + sector, buffer, sector_count);
46 }
47
48 return -RT_EINVAL;
49 }
50
blk_dev_write(rt_device_t dev,rt_off_t sector,const void * buffer,rt_size_t sector_count)51 static rt_ssize_t blk_dev_write(rt_device_t dev, rt_off_t sector,
52 const void *buffer, rt_size_t sector_count)
53 {
54 struct rt_blk_device *blk = to_blk(dev);
55
56 if (sector <= blk->sector_start + blk->sector_count &&
57 sector_count <= blk->sector_count)
58 {
59 return rt_device_write(&blk->disk->parent,
60 blk->sector_start + sector, buffer, sector_count);
61 }
62
63 return -RT_EINVAL;
64 }
65
blk_dev_control(rt_device_t dev,int cmd,void * args)66 static rt_err_t blk_dev_control(rt_device_t dev, int cmd, void *args)
67 {
68 rt_err_t err = -RT_EINVAL;
69 struct rt_blk_device *blk = to_blk(dev);
70 struct rt_blk_disk *disk = blk->disk;
71 struct rt_device_blk_geometry disk_geometry, *geometry;
72
73 switch (cmd)
74 {
75 case RT_DEVICE_CTRL_BLK_GETGEOME:
76 if ((geometry = args))
77 {
78 if (!(err = disk->ops->getgeome(disk, &disk_geometry)))
79 {
80 geometry->bytes_per_sector = disk_geometry.bytes_per_sector;
81 geometry->block_size = disk_geometry.block_size;
82 geometry->sector_count = blk->sector_count;
83 }
84 }
85 else
86 {
87 err = -RT_EINVAL;
88 }
89
90 break;
91
92 case RT_DEVICE_CTRL_BLK_SYNC:
93 rt_device_control(&disk->parent, cmd, args);
94 break;
95
96 case RT_DEVICE_CTRL_BLK_ERASE:
97 case RT_DEVICE_CTRL_BLK_AUTOREFRESH:
98 if (disk->partitions <= 1)
99 {
100 rt_device_control(&disk->parent, cmd, args);
101 }
102 else
103 {
104 err = -RT_EIO;
105 }
106 break;
107
108 case RT_DEVICE_CTRL_BLK_PARTITION:
109 if (args)
110 {
111 rt_memcpy(args, &blk->partition, sizeof(blk->partition));
112 }
113 else
114 {
115 err = -RT_EINVAL;
116 }
117
118 break;
119
120 case RT_DEVICE_CTRL_BLK_SSIZEGET:
121 device_get_blk_ssize(dev, args);
122 err = RT_EOK;
123 break;
124
125 case RT_DEVICE_CTRL_ALL_BLK_SSIZEGET:
126 device_get_all_blk_ssize(dev, args);
127 err = RT_EOK;
128 break;
129
130 default:
131 if (disk->ops->control)
132 {
133 err = disk->ops->control(disk, blk, cmd, args);
134 }
135 break;
136 }
137
138 return err;
139 }
140
141 #ifdef RT_USING_DEVICE_OPS
142 const static struct rt_device_ops blk_dev_ops =
143 {
144 .open = blk_dev_open,
145 .close = blk_dev_close,
146 .read = blk_dev_read,
147 .write = blk_dev_write,
148 .control = blk_dev_control,
149 };
150 #endif
151
blk_dev_initialize(struct rt_blk_device * blk)152 rt_err_t blk_dev_initialize(struct rt_blk_device *blk)
153 {
154 struct rt_device *dev;
155
156 if (!blk)
157 {
158 return -RT_EINVAL;
159 }
160
161 dev = &blk->parent;
162 dev->type = RT_Device_Class_Block;
163 #ifdef RT_USING_DEVICE_OPS
164 dev->ops = &blk_dev_ops;
165 #else
166 dev->open = blk_dev_open;
167 dev->close = blk_dev_close;
168 dev->read = blk_dev_read;
169 dev->write = blk_dev_write;
170 dev->control = blk_dev_control;
171 #endif
172
173 return RT_EOK;
174 }
175
disk_add_blk_dev(struct rt_blk_disk * disk,struct rt_blk_device * blk)176 rt_err_t disk_add_blk_dev(struct rt_blk_disk *disk, struct rt_blk_device *blk)
177 {
178 rt_err_t err;
179 #ifdef RT_USING_DM
180 int device_id;
181 #endif
182 const char *disk_name, *name_fmt;
183
184 if (!disk || !blk)
185 {
186 return -RT_EINVAL;
187 }
188
189 #ifdef RT_USING_DM
190 if ((device_id = rt_dm_ida_alloc(disk->ida)) < 0)
191 {
192 return -RT_EFULL;
193 }
194 #endif
195
196 blk->disk = disk;
197 rt_list_init(&blk->list);
198
199 disk_name = to_disk_name(disk);
200
201 /* End is [a-zA-Z] or [0-9] */
202 if (disk_name[rt_strlen(disk_name) - 1] < 'a')
203 {
204 name_fmt = "%sp%d";
205 }
206 else
207 {
208 name_fmt = "%s%d";
209 }
210
211 #ifdef RT_USING_DM
212 rt_dm_dev_set_name(&blk->parent, name_fmt, disk_name, blk->partno);
213 blk->parent.master_id = disk->ida->master_id;
214 blk->parent.device_id = device_id;
215 #else
216 rt_snprintf(blk->parent.parent.name, RT_NAME_MAX, name_fmt, disk_name, blk->partno);
217 #endif
218 device_set_blk_fops(&blk->parent);
219
220 err = rt_device_register(&blk->parent, to_blk_name(blk),
221 disk->parent.flag & RT_DEVICE_FLAG_RDWR);
222
223 if (err)
224 {
225 #ifdef RT_USING_DM
226 rt_dm_ida_free(disk->ida, device_id);
227 #endif
228 return err;
229 }
230
231 spin_lock(&disk->lock);
232
233 rt_list_insert_before(&disk->part_nodes, &blk->list);
234
235 spin_unlock(&disk->lock);
236
237 return RT_EOK;
238 }
239
disk_remove_blk_dev(struct rt_blk_device * blk,rt_bool_t lockless)240 rt_err_t disk_remove_blk_dev(struct rt_blk_device *blk, rt_bool_t lockless)
241 {
242 struct rt_blk_disk *disk;
243
244 if (!blk)
245 {
246 return -RT_EINVAL;
247 }
248
249 disk = blk->disk;
250
251 if (!disk)
252 {
253 return -RT_EINVAL;
254 }
255 else
256 {
257 #ifdef RT_USING_DFS
258 const char *mountpath;
259
260 if ((mountpath = dfs_filesystem_get_mounted_path(&blk->parent)))
261 {
262 dfs_unmount(mountpath);
263 LOG_D("%s: Unmount file system on %s",
264 to_blk_name(blk), mountpath);
265 }
266 #endif
267 }
268
269 #ifdef RT_USING_DM
270 rt_dm_ida_free(disk->ida, blk->parent.device_id);
271 #endif
272
273 rt_device_unregister(&blk->parent);
274
275 if (!lockless)
276 {
277 spin_lock(&disk->lock);
278 }
279
280 rt_list_remove(&blk->list);
281
282 if (!lockless)
283 {
284 spin_unlock(&disk->lock);
285 }
286
287 --disk->partitions;
288
289 return RT_EOK;
290 }
291
blk_request_ioprio(void)292 rt_uint32_t blk_request_ioprio(void)
293 {
294 struct rt_thread *task = rt_thread_self();
295
296 return task ? RT_SCHED_PRIV(task).current_priority : 0;
297 }
298