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