ide: Avoid preprocessor for CONFIG_LBA48
[platform/kernel/u-boot.git] / drivers / block / host_dev.c
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * Driver for sandbox host interface, used to access files on the host which
4  * contain partitions and filesystem
5  *
6  * Copyright 2022 Google LLC
7  * Written by Simon Glass <sjg@chromium.org>
8  */
9
10 #define LOG_CATEGORY UCLASS_HOST
11
12 #include <common.h>
13 #include <blk.h>
14 #include <bootdev.h>
15 #include <dm.h>
16 #include <log.h>
17 #include <malloc.h>
18 #include <os.h>
19 #include <sandbox_host.h>
20 #include <dm/device-internal.h>
21
22 static int host_sb_attach_file(struct udevice *dev, const char *filename)
23 {
24         struct host_sb_plat *plat = dev_get_plat(dev);
25         struct blk_desc *desc;
26         struct udevice *blk;
27         int ret, fd, size;
28         char *fname;
29
30         if (!filename)
31                 return -EINVAL;
32
33         if (plat->fd)
34                 return log_msg_ret("fd", -EEXIST);
35
36         /* Sanity check that host_sb_bind() has been used */
37         ret = blk_find_from_parent(dev, &blk);
38         if (ret)
39                 return ret;
40
41         fd = os_open(filename, OS_O_RDWR);
42         if (fd == -1) {
43                 printf("Failed to access host backing file '%s', trying read-only\n",
44                        filename);
45                 fd = os_open(filename, OS_O_RDONLY);
46                 if (fd == -1) {
47                         printf("- still failed\n");
48                         return log_msg_ret("open", -ENOENT);
49                 }
50         }
51
52         fname = strdup(filename);
53         if (!fname) {
54                 ret = -ENOMEM;
55                 goto err_fname;
56         }
57
58         size = os_filesize(fd);
59         desc = dev_get_uclass_plat(blk);
60         desc->lba = size / desc->blksz;
61
62         /* write this in last, when nothing can go wrong */
63         plat = dev_get_plat(dev);
64         plat->fd = fd;
65         plat->filename = fname;
66
67         return 0;
68
69 err_fname:
70         os_close(fd);
71
72         return ret;
73 }
74
75 int host_sb_detach_file(struct udevice *dev)
76 {
77         struct host_sb_plat *plat = dev_get_plat(dev);
78         int ret;
79
80         if (!plat->fd)
81                 return log_msg_ret("fd", -ENOENT);
82
83         ret = device_remove(dev, DM_REMOVE_NORMAL);
84         if (ret)
85                 return log_msg_ret("rem", ret);
86
87         /* Unbind all children */
88         ret = device_chld_unbind(dev, NULL);
89         if (ret)
90                 return log_msg_ret("unb", ret);
91
92         os_close(plat->fd);
93         plat->fd = 0;
94         free(plat->filename);
95         free(plat->label);
96
97         return 0;
98 }
99
100 static int host_sb_bind(struct udevice *dev)
101 {
102         struct udevice *blk, *bdev;
103         struct blk_desc *desc;
104         int ret;
105
106         ret = blk_create_devicef(dev, "sandbox_host_blk", "blk", UCLASS_HOST,
107                                  dev_seq(dev), 512, 0, &blk);
108         if (ret)
109                 return log_msg_ret("blk", ret);
110
111         desc = dev_get_uclass_plat(blk);
112         snprintf(desc->vendor, BLK_VEN_SIZE, "U-Boot");
113         snprintf(desc->product, BLK_PRD_SIZE, "hostfile");
114         snprintf(desc->revision, BLK_REV_SIZE, "1.0");
115
116         if (CONFIG_IS_ENABLED(BOOTSTD)) {
117                 ret = bootdev_bind(dev, "host_bootdev", "bootdev", &bdev);
118                 if (ret)
119                         return log_msg_ret("bd", ret);
120         }
121
122         return 0;
123 }
124
125 struct host_ops host_sb_ops = {
126         .attach_file    = host_sb_attach_file,
127         .detach_file    = host_sb_detach_file,
128 };
129
130 static const struct udevice_id host_ids[] = {
131         { .compatible = "sandbox,host" },
132         { }
133 };
134
135 U_BOOT_DRIVER(host_sb_drv) = {
136         .name           = "host_sb_drv",
137         .id             = UCLASS_HOST,
138         .of_match       = host_ids,
139         .ops            = &host_sb_ops,
140         .bind           = host_sb_bind,
141         .plat_auto      = sizeof(struct host_sb_plat),
142 };