]>
Commit | Line | Data |
---|---|---|
6eef6eac SG |
1 | /* |
2 | * Copyright (C) 2016 Google, Inc | |
3 | * Written by Simon Glass <sjg@chromium.org> | |
4 | * | |
5 | * SPDX-License-Identifier: GPL-2.0+ | |
6 | */ | |
7 | ||
8 | #include <common.h> | |
9 | #include <linux/err.h> | |
10 | ||
11 | struct blk_driver *blk_driver_lookup_type(int if_type) | |
12 | { | |
13 | struct blk_driver *drv = ll_entry_start(struct blk_driver, blk_driver); | |
14 | const int n_ents = ll_entry_count(struct blk_driver, blk_driver); | |
15 | struct blk_driver *entry; | |
16 | ||
17 | for (entry = drv; entry != drv + n_ents; entry++) { | |
18 | if (if_type == entry->if_type) | |
19 | return entry; | |
20 | } | |
21 | ||
22 | /* Not found */ | |
23 | return NULL; | |
24 | } | |
25 | ||
26 | static struct blk_driver *blk_driver_lookup_typename(const char *if_typename) | |
27 | { | |
28 | struct blk_driver *drv = ll_entry_start(struct blk_driver, blk_driver); | |
29 | const int n_ents = ll_entry_count(struct blk_driver, blk_driver); | |
30 | struct blk_driver *entry; | |
31 | ||
32 | for (entry = drv; entry != drv + n_ents; entry++) { | |
33 | if (!strcmp(if_typename, entry->if_typename)) | |
34 | return entry; | |
35 | } | |
36 | ||
37 | /* Not found */ | |
38 | return NULL; | |
39 | } | |
40 | ||
41 | /** | |
42 | * get_desc() - Get the block device descriptor for the given device number | |
43 | * | |
44 | * @drv: Legacy block driver | |
45 | * @devnum: Device number (0 = first) | |
46 | * @descp: Returns block device descriptor on success | |
47 | * @return 0 on success, -ENODEV if there is no such device, -ENOSYS if the | |
48 | * driver does not provide a way to find a device, or other -ve on other | |
49 | * error. | |
50 | */ | |
51 | static int get_desc(struct blk_driver *drv, int devnum, struct blk_desc **descp) | |
52 | { | |
53 | if (drv->desc) { | |
54 | if (devnum < 0 || devnum >= drv->max_devs) | |
55 | return -ENODEV; | |
56 | *descp = &drv->desc[devnum]; | |
57 | return 0; | |
58 | } | |
59 | if (!drv->get_dev) | |
60 | return -ENOSYS; | |
61 | ||
62 | return drv->get_dev(devnum, descp); | |
63 | } | |
64 | ||
65 | #ifdef HAVE_BLOCK_DEVICE | |
66 | int blk_list_part(enum if_type if_type) | |
67 | { | |
68 | struct blk_driver *drv; | |
69 | struct blk_desc *desc; | |
70 | int devnum, ok; | |
71 | bool first = true; | |
72 | ||
73 | drv = blk_driver_lookup_type(if_type); | |
74 | if (!drv) | |
75 | return -ENOSYS; | |
76 | for (ok = 0, devnum = 0; devnum < drv->max_devs; ++devnum) { | |
77 | if (get_desc(drv, devnum, &desc)) | |
78 | continue; | |
79 | if (desc->part_type != PART_TYPE_UNKNOWN) { | |
80 | ++ok; | |
81 | if (!first) | |
82 | putc('\n'); | |
83 | part_print(desc); | |
84 | first = false; | |
85 | } | |
86 | } | |
87 | if (!ok) | |
88 | return -ENODEV; | |
89 | ||
90 | return 0; | |
91 | } | |
92 | ||
93 | int blk_print_part_devnum(enum if_type if_type, int devnum) | |
94 | { | |
95 | struct blk_driver *drv = blk_driver_lookup_type(if_type); | |
96 | struct blk_desc *desc; | |
97 | int ret; | |
98 | ||
99 | if (!drv) | |
100 | return -ENOSYS; | |
101 | ret = get_desc(drv, devnum, &desc); | |
102 | if (ret) | |
103 | return ret; | |
104 | if (desc->type == DEV_TYPE_UNKNOWN) | |
105 | return -ENOENT; | |
106 | part_print(desc); | |
107 | ||
108 | return 0; | |
109 | } | |
110 | ||
111 | void blk_list_devices(enum if_type if_type) | |
112 | { | |
113 | struct blk_driver *drv = blk_driver_lookup_type(if_type); | |
114 | struct blk_desc *desc; | |
115 | int i; | |
116 | ||
117 | if (!drv) | |
118 | return; | |
119 | for (i = 0; i < drv->max_devs; ++i) { | |
120 | if (get_desc(drv, i, &desc)) | |
121 | continue; | |
122 | if (desc->type == DEV_TYPE_UNKNOWN) | |
123 | continue; /* list only known devices */ | |
124 | printf("Device %d: ", i); | |
125 | dev_print(desc); | |
126 | } | |
127 | } | |
128 | ||
129 | int blk_print_device_num(enum if_type if_type, int devnum) | |
130 | { | |
131 | struct blk_driver *drv = blk_driver_lookup_type(if_type); | |
132 | struct blk_desc *desc; | |
133 | int ret; | |
134 | ||
135 | if (!drv) | |
136 | return -ENOSYS; | |
137 | ret = get_desc(drv, devnum, &desc); | |
138 | if (ret) | |
139 | return ret; | |
140 | printf("\n%s device %d: ", drv->if_typename, devnum); | |
141 | dev_print(desc); | |
142 | ||
143 | return 0; | |
144 | } | |
145 | ||
146 | int blk_show_device(enum if_type if_type, int devnum) | |
147 | { | |
148 | struct blk_driver *drv = blk_driver_lookup_type(if_type); | |
149 | struct blk_desc *desc; | |
150 | int ret; | |
151 | ||
152 | if (!drv) | |
153 | return -ENOSYS; | |
154 | printf("\nDevice %d: ", devnum); | |
155 | if (devnum >= drv->max_devs) { | |
156 | puts("unknown device\n"); | |
157 | return -ENODEV; | |
158 | } | |
159 | ret = get_desc(drv, devnum, &desc); | |
160 | if (ret) | |
161 | return ret; | |
162 | dev_print(desc); | |
163 | ||
164 | if (desc->type == DEV_TYPE_UNKNOWN) | |
165 | return -ENOENT; | |
166 | ||
167 | return 0; | |
168 | } | |
169 | #endif /* HAVE_BLOCK_DEVICE */ | |
170 | ||
171 | struct blk_desc *blk_get_devnum_by_type(enum if_type if_type, int devnum) | |
172 | { | |
173 | struct blk_driver *drv = blk_driver_lookup_type(if_type); | |
174 | struct blk_desc *desc; | |
175 | ||
176 | if (!drv) | |
177 | return NULL; | |
178 | ||
179 | if (get_desc(drv, devnum, &desc)) | |
180 | return NULL; | |
181 | ||
182 | return desc; | |
183 | } | |
184 | ||
185 | int blk_dselect_hwpart(struct blk_desc *desc, int hwpart) | |
186 | { | |
187 | struct blk_driver *drv = blk_driver_lookup_type(desc->if_type); | |
188 | ||
189 | if (!drv) | |
190 | return -ENOSYS; | |
191 | if (drv->select_hwpart) | |
192 | return drv->select_hwpart(desc, hwpart); | |
193 | ||
194 | return 0; | |
195 | } | |
196 | ||
197 | struct blk_desc *blk_get_devnum_by_typename(const char *if_typename, int devnum) | |
198 | { | |
199 | struct blk_driver *drv = blk_driver_lookup_typename(if_typename); | |
200 | struct blk_desc *desc; | |
201 | ||
202 | if (!drv) | |
203 | return NULL; | |
204 | ||
205 | if (get_desc(drv, devnum, &desc)) | |
206 | return NULL; | |
207 | ||
208 | return desc; | |
209 | } | |
210 | ||
211 | ulong blk_read_devnum(enum if_type if_type, int devnum, lbaint_t start, | |
212 | lbaint_t blkcnt, void *buffer) | |
213 | { | |
214 | struct blk_driver *drv = blk_driver_lookup_type(if_type); | |
215 | struct blk_desc *desc; | |
216 | ulong n; | |
217 | int ret; | |
218 | ||
219 | if (!drv) | |
220 | return -ENOSYS; | |
221 | ret = get_desc(drv, devnum, &desc); | |
222 | if (ret) | |
223 | return ret; | |
224 | n = desc->block_read(desc, start, blkcnt, buffer); | |
225 | if (IS_ERR_VALUE(n)) | |
226 | return n; | |
227 | ||
228 | /* flush cache after read */ | |
229 | flush_cache((ulong)buffer, blkcnt * desc->blksz); | |
230 | ||
231 | return n; | |
232 | } | |
233 | ||
234 | ulong blk_write_devnum(enum if_type if_type, int devnum, lbaint_t start, | |
235 | lbaint_t blkcnt, const void *buffer) | |
236 | { | |
237 | struct blk_driver *drv = blk_driver_lookup_type(if_type); | |
238 | struct blk_desc *desc; | |
239 | int ret; | |
240 | ||
241 | if (!drv) | |
242 | return -ENOSYS; | |
243 | ret = get_desc(drv, devnum, &desc); | |
244 | if (ret) | |
245 | return ret; | |
246 | return desc->block_write(desc, start, blkcnt, buffer); | |
247 | } | |
248 | ||
249 | int blk_select_hwpart_devnum(enum if_type if_type, int devnum, int hwpart) | |
250 | { | |
251 | struct blk_driver *drv = blk_driver_lookup_type(if_type); | |
252 | struct blk_desc *desc; | |
253 | int ret; | |
254 | ||
255 | if (!drv) | |
256 | return -ENOSYS; | |
257 | ret = get_desc(drv, devnum, &desc); | |
258 | if (ret) | |
259 | return ret; | |
260 | return drv->select_hwpart(desc, hwpart); | |
261 | } |