blob: cf42bd1e07acd3b9d723993b2c018b48c46fd849 [file] [log] [blame]
Simon Glass884c2f82022-10-29 19:47:15 -06001// SPDX-License-Identifier: GPL-2.0+
2/*
3 * Uclass 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
Simon Glass884c2f82022-10-29 19:47:15 -060012#include <blk.h>
13#include <dm.h>
14#include <malloc.h>
Bin Meng881e4752023-09-26 16:43:33 +080015#include <part.h>
Simon Glass884c2f82022-10-29 19:47:15 -060016#include <sandbox_host.h>
17#include <dm/device-internal.h>
18#include <dm/lists.h>
19#include <dm/uclass-internal.h>
20
21DECLARE_GLOBAL_DATA_PTR;
22
23/**
24 * struct host_priv - information kept by the host uclass
25 *
26 * @cur_dev: Currently selected host device, or NULL if none
27 */
28struct host_priv {
29 struct udevice *cur_dev;
30};
31
Bin Meng881e4752023-09-26 16:43:33 +080032int host_create_device(const char *label, bool removable, unsigned long blksz,
33 struct udevice **devp)
Simon Glass884c2f82022-10-29 19:47:15 -060034{
35 char dev_name[30], *str, *label_new;
36 struct host_sb_plat *plat;
37 struct udevice *dev, *blk;
38 int ret;
39
40 /* unbind any existing device with this label */
41 dev = host_find_by_label(label);
42 if (dev) {
43 ret = host_detach_file(dev);
44 if (ret)
45 return log_msg_ret("det", ret);
46
47 ret = device_unbind(dev);
48 if (ret)
49 return log_msg_ret("unb", ret);
50 }
51
52 snprintf(dev_name, sizeof(dev_name), "host-%s", label);
53 str = strdup(dev_name);
54 if (!str)
55 return -ENOMEM;
56
57 label_new = strdup(label);
58 if (!label_new) {
59 ret = -ENOMEM;
60 goto no_label;
61 }
62
63 ret = device_bind_driver(gd->dm_root, "host_sb_drv", str, &dev);
64 if (ret)
65 goto no_dev;
66 device_set_name_alloced(dev);
67
68 if (!blk_find_from_parent(dev, &blk)) {
69 struct blk_desc *desc = dev_get_uclass_plat(blk);
70
71 desc->removable = removable;
Bin Meng881e4752023-09-26 16:43:33 +080072
73 /* update blk device's block size with the provided one */
74 if (blksz != desc->blksz) {
75 desc->blksz = blksz;
76 desc->log2blksz = LOG2(desc->blksz);
77 }
Simon Glass884c2f82022-10-29 19:47:15 -060078 }
79
80 plat = dev_get_plat(dev);
81 plat->label = label_new;
82 *devp = dev;
83
84 return 0;
85
86no_dev:
87 free(label_new);
88no_label:
89 free(str);
90
91 return ret;
92}
93
94int host_attach_file(struct udevice *dev, const char *filename)
95{
96 struct host_ops *ops = host_get_ops(dev);
97
98 if (!ops->attach_file)
99 return -ENOSYS;
100
101 return ops->attach_file(dev, filename);
102}
103
104int host_create_attach_file(const char *label, const char *filename,
Bin Meng881e4752023-09-26 16:43:33 +0800105 bool removable, unsigned long blksz,
106 struct udevice **devp)
Simon Glass884c2f82022-10-29 19:47:15 -0600107{
108 struct udevice *dev;
109 int ret;
110
Bin Meng881e4752023-09-26 16:43:33 +0800111 ret = host_create_device(label, removable, blksz, &dev);
Simon Glass884c2f82022-10-29 19:47:15 -0600112 if (ret)
113 return log_msg_ret("cre", ret);
114
115 ret = host_attach_file(dev, filename);
116 if (ret) {
117 device_unbind(dev);
118 return log_msg_ret("att", ret);
119 }
120 *devp = dev;
121
122 return 0;
123}
124
125int host_detach_file(struct udevice *dev)
126{
127 struct host_ops *ops = host_get_ops(dev);
128
129 if (!ops->detach_file)
130 return -ENOSYS;
131
132 if (dev == host_get_cur_dev())
133 host_set_cur_dev(NULL);
134
135 return ops->detach_file(dev);
136}
137
138struct udevice *host_find_by_label(const char *label)
139{
140 struct udevice *dev;
141 struct uclass *uc;
142
143 uclass_id_foreach_dev(UCLASS_HOST, dev, uc) {
144 struct host_sb_plat *plat = dev_get_plat(dev);
145
146 if (plat->label && !strcmp(label, plat->label))
147 return dev;
148 }
149
150 return NULL;
151}
152
153struct udevice *host_get_cur_dev(void)
154{
155 struct uclass *uc = uclass_find(UCLASS_HOST);
156
157 if (uc) {
158 struct host_priv *priv = uclass_get_priv(uc);
159
160 return priv->cur_dev;
161 }
162
163 return NULL;
164}
165
166void host_set_cur_dev(struct udevice *dev)
167{
168 struct uclass *uc = uclass_find(UCLASS_HOST);
169
170 if (uc) {
171 struct host_priv *priv = uclass_get_priv(uc);
172
173 priv->cur_dev = dev;
174 }
175}
176
177UCLASS_DRIVER(host) = {
178 .id = UCLASS_HOST,
179 .name = "host",
180#if CONFIG_IS_ENABLED(OF_REAL)
181 .post_bind = dm_scan_fdt_dev,
182#endif
183 .priv_auto = sizeof(struct host_priv),
184};