]> Git Repo - u-boot.git/blame - drivers/block/sandbox.c
blk: Switch over to using uclass IDs
[u-boot.git] / drivers / block / sandbox.c
CommitLineData
83d290c5 1// SPDX-License-Identifier: GPL-2.0+
f4d8de48
HN
2/*
3 * Copyright (C) 2013 Henrik Nordstrom <[email protected]>
f4d8de48
HN
4 */
5
f4d8de48 6#include <common.h>
40fd0508
SG
7#include <blk.h>
8#include <dm.h>
9#include <fdtdec.h>
f4d8de48
HN
10#include <part.h>
11#include <os.h>
12#include <malloc.h>
13#include <sandboxblockdev.h>
401d1c4f 14#include <asm/global_data.h>
336d4615 15#include <dm/device_compat.h>
1221ce45 16#include <linux/errno.h>
40fd0508 17#include <dm/device-internal.h>
f4d8de48 18
40fd0508
SG
19DECLARE_GLOBAL_DATA_PTR;
20
e161356b 21#ifndef CONFIG_BLK
32c8566f 22static struct host_block_dev host_devices[SANDBOX_HOST_MAX_DEVICES];
e161356b
SG
23
24static struct host_block_dev *find_host_device(int dev)
25{
32c8566f 26 if (dev >= 0 && dev < SANDBOX_HOST_MAX_DEVICES)
e161356b
SG
27 return &host_devices[dev];
28
29 return NULL;
30}
31#endif
32
33#ifdef CONFIG_BLK
40fd0508
SG
34static unsigned long host_block_read(struct udevice *dev,
35 unsigned long start, lbaint_t blkcnt,
36 void *buffer)
37{
c69cda25 38 struct host_block_dev *host_dev = dev_get_plat(dev);
caa4daa2 39 struct blk_desc *block_dev = dev_get_uclass_plat(dev);
f4d8de48 40
e161356b
SG
41#else
42static unsigned long host_block_read(struct blk_desc *block_dev,
43 unsigned long start, lbaint_t blkcnt,
44 void *buffer)
45{
46 int dev = block_dev->devnum;
47 struct host_block_dev *host_dev = find_host_device(dev);
48
49 if (!host_dev)
50 return -1;
51#endif
52
7ded959e
SG
53 if (os_lseek(host_dev->fd, start * block_dev->blksz, OS_SEEK_SET) ==
54 -1) {
55 printf("ERROR: Invalid block %lx\n", start);
f4d8de48
HN
56 return -1;
57 }
7ded959e 58 ssize_t len = os_read(host_dev->fd, buffer, blkcnt * block_dev->blksz);
f4d8de48 59 if (len >= 0)
7ded959e 60 return len / block_dev->blksz;
f4d8de48
HN
61 return -1;
62}
63
e161356b 64#ifdef CONFIG_BLK
40fd0508
SG
65static unsigned long host_block_write(struct udevice *dev,
66 unsigned long start, lbaint_t blkcnt,
67 const void *buffer)
68{
c69cda25 69 struct host_block_dev *host_dev = dev_get_plat(dev);
caa4daa2 70 struct blk_desc *block_dev = dev_get_uclass_plat(dev);
e161356b
SG
71#else
72static unsigned long host_block_write(struct blk_desc *block_dev,
73 unsigned long start, lbaint_t blkcnt,
74 const void *buffer)
75{
76 int dev = block_dev->devnum;
77 struct host_block_dev *host_dev = find_host_device(dev);
78#endif
7ded959e
SG
79
80 if (os_lseek(host_dev->fd, start * block_dev->blksz, OS_SEEK_SET) ==
81 -1) {
82 printf("ERROR: Invalid block %lx\n", start);
f4d8de48
HN
83 return -1;
84 }
7ded959e 85 ssize_t len = os_write(host_dev->fd, buffer, blkcnt * block_dev->blksz);
f4d8de48 86 if (len >= 0)
7ded959e 87 return len / block_dev->blksz;
f4d8de48
HN
88 return -1;
89}
90
e161356b 91#ifdef CONFIG_BLK
1758551e 92int host_dev_bind(int devnum, char *filename, bool removable)
40fd0508
SG
93{
94 struct host_block_dev *host_dev;
95 struct udevice *dev;
168e313b 96 struct blk_desc *desc;
40fd0508
SG
97 char dev_name[20], *str, *fname;
98 int ret, fd;
99
100 /* Remove and unbind the old device, if any */
e33a5c6b 101 ret = blk_get_device(UCLASS_ROOT, devnum, &dev);
40fd0508 102 if (ret == 0) {
706865af 103 ret = device_remove(dev, DM_REMOVE_NORMAL);
40fd0508
SG
104 if (ret)
105 return ret;
106 ret = device_unbind(dev);
107 if (ret)
108 return ret;
109 } else if (ret != -ENODEV) {
110 return ret;
111 }
112
113 if (!filename)
114 return 0;
115
116 snprintf(dev_name, sizeof(dev_name), "host%d", devnum);
117 str = strdup(dev_name);
118 if (!str)
119 return -ENOMEM;
120 fname = strdup(filename);
121 if (!fname) {
122 free(str);
123 return -ENOMEM;
124 }
125
126 fd = os_open(filename, OS_O_RDWR);
127 if (fd == -1) {
7aa9dbd0
SG
128 printf("Failed to access host backing file '%s', trying read-only\n",
129 filename);
130 fd = os_open(filename, OS_O_RDONLY);
131 if (fd == -1) {
132 printf("- still failed\n");
133 ret = -ENOENT;
134 goto err;
135 }
40fd0508
SG
136 }
137 ret = blk_create_device(gd->dm_root, "sandbox_host_blk", str,
e33a5c6b 138 UCLASS_ROOT, devnum, 512,
5fe7702e 139 os_lseek(fd, 0, OS_SEEK_END) / 512, &dev);
40fd0508
SG
140 if (ret)
141 goto err_file;
8f994c86 142
c69cda25 143 host_dev = dev_get_plat(dev);
8f994c86
BM
144 host_dev->fd = fd;
145 host_dev->filename = fname;
146
40fd0508
SG
147 ret = device_probe(dev);
148 if (ret) {
149 device_unbind(dev);
150 goto err_file;
151 }
152
e33a5c6b 153 desc = blk_get_devnum_by_type(UCLASS_ROOT, devnum);
1758551e 154 desc->removable = removable;
168e313b
HS
155 snprintf(desc->vendor, BLK_VEN_SIZE, "U-Boot");
156 snprintf(desc->product, BLK_PRD_SIZE, "hostfile");
157 snprintf(desc->revision, BLK_REV_SIZE, "1.0");
158
d0851c89 159 return 0;
40fd0508
SG
160err_file:
161 os_close(fd);
162err:
163 free(fname);
164 free(str);
165 return ret;
166}
e161356b 167#else
1758551e 168int host_dev_bind(int dev, char *filename, bool removable)
e161356b
SG
169{
170 struct host_block_dev *host_dev = find_host_device(dev);
171
172 if (!host_dev)
173 return -1;
174 if (host_dev->blk_dev.priv) {
175 os_close(host_dev->fd);
176 host_dev->blk_dev.priv = NULL;
177 }
178 if (host_dev->filename)
179 free(host_dev->filename);
180 if (filename && *filename) {
181 host_dev->filename = strdup(filename);
182 } else {
183 host_dev->filename = NULL;
184 return 0;
185 }
186
187 host_dev->fd = os_open(host_dev->filename, OS_O_RDWR);
188 if (host_dev->fd == -1) {
189 printf("Failed to access host backing file '%s'\n",
190 host_dev->filename);
191 return 1;
192 }
193
194 struct blk_desc *blk_dev = &host_dev->blk_dev;
e33a5c6b 195 blk_dev->if_type = UCLASS_ROOT;
e161356b
SG
196 blk_dev->priv = host_dev;
197 blk_dev->blksz = 512;
198 blk_dev->lba = os_lseek(host_dev->fd, 0, OS_SEEK_END) / blk_dev->blksz;
199 blk_dev->block_read = host_block_read;
200 blk_dev->block_write = host_block_write;
201 blk_dev->devnum = dev;
202 blk_dev->part_type = PART_TYPE_UNKNOWN;
1758551e 203 blk_dev->removable = removable;
168e313b
HS
204 snprintf(blk_dev->vendor, BLK_VEN_SIZE, "U-Boot");
205 snprintf(blk_dev->product, BLK_PRD_SIZE, "hostfile");
206 snprintf(blk_dev->revision, BLK_REV_SIZE, "1.0");
e161356b
SG
207 part_init(blk_dev);
208
209 return 0;
210}
211#endif
f4d8de48 212
7ded959e 213int host_get_dev_err(int devnum, struct blk_desc **blk_devp)
f4d8de48 214{
e161356b 215#ifdef CONFIG_BLK
40fd0508
SG
216 struct udevice *dev;
217 int ret;
218
e33a5c6b 219 ret = blk_get_device(UCLASS_ROOT, devnum, &dev);
40fd0508
SG
220 if (ret)
221 return ret;
caa4daa2 222 *blk_devp = dev_get_uclass_plat(dev);
e161356b
SG
223#else
224 struct host_block_dev *host_dev = find_host_device(devnum);
225
226 if (!host_dev)
227 return -ENODEV;
228
229 if (!host_dev->blk_dev.priv)
230 return -ENOENT;
231
232 *blk_devp = &host_dev->blk_dev;
233#endif
40fd0508 234
f4d8de48
HN
235 return 0;
236}
237
e161356b 238#ifdef CONFIG_BLK
297b8b3e
HS
239
240int sandbox_host_unbind(struct udevice *dev)
241{
242 struct host_block_dev *host_dev;
243
244 /* Data validity is checked in host_dev_bind() */
245 host_dev = dev_get_plat(dev);
246 os_close(host_dev->fd);
247
248 return 0;
249}
250
40fd0508
SG
251static const struct blk_ops sandbox_host_blk_ops = {
252 .read = host_block_read,
253 .write = host_block_write,
254};
255
256U_BOOT_DRIVER(sandbox_host_blk) = {
257 .name = "sandbox_host_blk",
258 .id = UCLASS_BLK,
259 .ops = &sandbox_host_blk_ops,
297b8b3e 260 .unbind = sandbox_host_unbind,
caa4daa2 261 .plat_auto = sizeof(struct host_block_dev),
40fd0508 262};
0cc65a7c
SG
263#else
264U_BOOT_LEGACY_BLK(sandbox_host) = {
265 .if_typename = "host",
e33a5c6b 266 .if_type = UCLASS_ROOT,
32c8566f 267 .max_devs = SANDBOX_HOST_MAX_DEVICES,
0cc65a7c
SG
268 .get_dev = host_get_dev_err,
269};
e161356b 270#endif
This page took 0.289107 seconds and 4 git commands to generate.