blob: 6460d968c23f7a039e36fdef86d6765eecb34405 [file] [log] [blame]
Simon Glass9bd1aa82022-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
12#include <common.h>
13#include <blk.h>
14#include <dm.h>
15#include <malloc.h>
16#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
32int host_create_device(const char *label, bool removable, struct udevice **devp)
33{
34 char dev_name[30], *str, *label_new;
35 struct host_sb_plat *plat;
36 struct udevice *dev, *blk;
37 int ret;
38
39 /* unbind any existing device with this label */
40 dev = host_find_by_label(label);
41 if (dev) {
42 ret = host_detach_file(dev);
43 if (ret)
44 return log_msg_ret("det", ret);
45
46 ret = device_unbind(dev);
47 if (ret)
48 return log_msg_ret("unb", ret);
49 }
50
51 snprintf(dev_name, sizeof(dev_name), "host-%s", label);
52 str = strdup(dev_name);
53 if (!str)
54 return -ENOMEM;
55
56 label_new = strdup(label);
57 if (!label_new) {
58 ret = -ENOMEM;
59 goto no_label;
60 }
61
62 ret = device_bind_driver(gd->dm_root, "host_sb_drv", str, &dev);
63 if (ret)
64 goto no_dev;
65 device_set_name_alloced(dev);
66
67 if (!blk_find_from_parent(dev, &blk)) {
68 struct blk_desc *desc = dev_get_uclass_plat(blk);
69
70 desc->removable = removable;
71 }
72
73 plat = dev_get_plat(dev);
74 plat->label = label_new;
75 *devp = dev;
76
77 return 0;
78
79no_dev:
80 free(label_new);
81no_label:
82 free(str);
83
84 return ret;
85}
86
87int host_attach_file(struct udevice *dev, const char *filename)
88{
89 struct host_ops *ops = host_get_ops(dev);
90
91 if (!ops->attach_file)
92 return -ENOSYS;
93
94 return ops->attach_file(dev, filename);
95}
96
97int host_create_attach_file(const char *label, const char *filename,
98 bool removable, struct udevice **devp)
99{
100 struct udevice *dev;
101 int ret;
102
103 ret = host_create_device(label, removable, &dev);
104 if (ret)
105 return log_msg_ret("cre", ret);
106
107 ret = host_attach_file(dev, filename);
108 if (ret) {
109 device_unbind(dev);
110 return log_msg_ret("att", ret);
111 }
112 *devp = dev;
113
114 return 0;
115}
116
117int host_detach_file(struct udevice *dev)
118{
119 struct host_ops *ops = host_get_ops(dev);
120
121 if (!ops->detach_file)
122 return -ENOSYS;
123
124 if (dev == host_get_cur_dev())
125 host_set_cur_dev(NULL);
126
127 return ops->detach_file(dev);
128}
129
130struct udevice *host_find_by_label(const char *label)
131{
132 struct udevice *dev;
133 struct uclass *uc;
134
135 uclass_id_foreach_dev(UCLASS_HOST, dev, uc) {
136 struct host_sb_plat *plat = dev_get_plat(dev);
137
138 if (plat->label && !strcmp(label, plat->label))
139 return dev;
140 }
141
142 return NULL;
143}
144
145struct udevice *host_get_cur_dev(void)
146{
147 struct uclass *uc = uclass_find(UCLASS_HOST);
148
149 if (uc) {
150 struct host_priv *priv = uclass_get_priv(uc);
151
152 return priv->cur_dev;
153 }
154
155 return NULL;
156}
157
158void host_set_cur_dev(struct udevice *dev)
159{
160 struct uclass *uc = uclass_find(UCLASS_HOST);
161
162 if (uc) {
163 struct host_priv *priv = uclass_get_priv(uc);
164
165 priv->cur_dev = dev;
166 }
167}
168
169UCLASS_DRIVER(host) = {
170 .id = UCLASS_HOST,
171 .name = "host",
172#if CONFIG_IS_ENABLED(OF_REAL)
173 .post_bind = dm_scan_fdt_dev,
174#endif
175 .priv_auto = sizeof(struct host_priv),
176};