]> git.kernelconcepts.de Git - karo-tx-uboot.git/blob - api/api_storage.c
Merge branch 'master' of git://www.denx.de/git/u-boot-mpc85xx
[karo-tx-uboot.git] / api / api_storage.c
1 /*
2  * (C) Copyright 2007 Semihalf
3  *
4  * Written by: Rafal Jaworowski <raj@semihalf.com>
5  *
6  * See file CREDITS for list of people who contributed to this
7  * project.
8  *
9  * This program is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU General Public License as
11  * published by the Free Software Foundation; either version 2 of
12  * the License, or (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
22  * MA 02111-1307 USA
23  *
24  */
25
26 #include <config.h>
27
28 #if defined(CONFIG_API)
29
30 #include <common.h>
31 #include <api_public.h>
32
33 #define DEBUG
34 #undef DEBUG
35
36 #ifdef DEBUG
37 #define debugf(fmt, args...) do { printf("%s(): ", __func__); printf(fmt, ##args); } while (0)
38 #else
39 #define debugf(fmt, args...)
40 #endif
41
42 #define errf(fmt, args...) do { printf("ERROR @ %s(): ", __func__); printf(fmt, ##args); } while (0)
43
44
45 #define ENUM_IDE        0
46 #define ENUM_USB        1
47 #define ENUM_SCSI       2
48 #define ENUM_MMC        3
49 #define ENUM_MAX        4
50
51 struct stor_spec {
52         int             max_dev;
53         int             enum_started;
54         int             enum_ended;
55         int             type;           /* "external" type: DT_STOR_{IDE,USB,etc} */
56         char            name[4];
57 };
58
59 static struct stor_spec specs[ENUM_MAX] = { { 0, 0, 0, 0, "" }, };
60
61
62 void dev_stor_init(void)
63 {
64 #if (CONFIG_COMMANDS & CFG_CMD_IDE)
65         specs[ENUM_IDE].max_dev = CFG_IDE_MAXDEVICE;
66         specs[ENUM_IDE].enum_started = 0;
67         specs[ENUM_IDE].enum_ended = 0;
68         specs[ENUM_IDE].type = DEV_TYP_STOR | DT_STOR_IDE;
69         specs[ENUM_IDE].name = "ide";
70 #endif
71 #if (CONFIG_COMMANDS & CFG_CMD_USB)
72         specs[ENUM_USB].max_dev = USB_MAX_STOR_DEV;
73         specs[ENUM_USB].enum_started = 0;
74         specs[ENUM_USB].enum_ended = 0;
75         specs[ENUM_USB].type = DEV_TYP_STOR | DT_STOR_USB;
76         specs[ENUM_USB].name = "usb";
77 #endif
78 #if (CONFIG_COMMANDS & CFG_CMD_SCSI)
79         specs[ENUM_SCSI].max_dev = CFG_SCSI_MAX_DEVICE;
80         specs[ENUM_SCSI].enum_started = 0;
81         specs[ENUM_SCSI].enum_ended = 0;
82         specs[ENUM_SCSI].type = DEV_TYP_STOR | DT_STOR_SCSI;
83         specs[ENUM_SCSI].name = "scsi";
84 #endif
85 }
86
87 /*
88  * Finds next available device in the storage group
89  *
90  * type:        storage group type - ENUM_IDE, ENUM_SCSI etc.
91  *
92  * first:       if 1 the first device in the storage group is returned (if
93  *              exists), if 0 the next available device is searched
94  *
95  * more:        returns 0/1 depending if there are more devices in this group
96  *              available (for future iterations)
97  *
98  * returns:     0/1 depending if device found in this iteration
99  */
100 static int dev_stor_get(int type, int first, int *more, struct device_info *di)
101 {
102         int found = 0;
103         *more = 0;
104
105         int i;
106
107         block_dev_desc_t *dd;
108
109         if (first) {
110                 di->cookie = (void *)get_dev(specs[type].name, 0);
111                 found = 1;
112
113         } else {
114                 for (i = 0; i < specs[type].max_dev; i++)
115                         if (di->cookie == (void *)get_dev(specs[type].name, i)) {
116                                 /* previous cookie found -- advance to the
117                                  * next device, if possible */
118
119                                 if (++i >= specs[type].max_dev) {
120                                         /* out of range, no more to enum */
121                                         di->cookie = NULL;
122                                         break;
123                                 }
124
125                                 di->cookie = (void *)get_dev(specs[type].name, i);
126                                 found = 1;
127
128                                 /* provide hint if there are more devices in
129                                  * this group to enumerate */
130                                 if ((i + 1) < specs[type].max_dev)
131                                         *more = 1;
132
133                                 break;
134                         }
135         }
136
137         if (found) {
138                 di->type = specs[type].type;
139
140                 if (di->cookie != NULL) {
141                         dd = (block_dev_desc_t *)di->cookie;
142                         if (dd->type == DEV_TYPE_UNKNOWN) {
143                                 debugf("device instance exists, but is not active..");
144                                 found = 0;
145                         } else {
146                                 di->di_stor.block_count = dd->lba;
147                                 di->di_stor.block_size = dd->blksz;
148                         }
149                 }
150
151         } else
152                 di->cookie = NULL;
153
154         return found;
155 }
156
157
158 /*
159  * returns:     ENUM_IDE, ENUM_USB etc. based on block_dev_desc_t
160  */
161 static int dev_stor_type(block_dev_desc_t *dd)
162 {
163         int i, j;
164
165         for (i = ENUM_IDE; i < ENUM_MAX; i++)
166                 for (j = 0; j < specs[i].max_dev; j++)
167                         if (dd == get_dev(specs[i].name, j))
168                                 return i;
169
170         return ENUM_MAX;
171 }
172
173
174 /*
175  * returns:     0/1 whether cookie points to some device in this group
176  */
177 static int dev_is_stor(int type, struct device_info *di)
178 {
179         return (dev_stor_type(di->cookie) == type) ? 1 : 0;
180 }
181
182
183 static int dev_enum_stor(int type, struct device_info *di)
184 {
185         int found = 0, more = 0;
186
187         debugf("called, type %d\n", type);
188
189         /*
190          * Formulae for enumerating storage devices:
191          * 1. if cookie (hint from previous enum call) is NULL we start again
192          *    with enumeration, so return the first available device, done.
193          *
194          * 2. if cookie is not NULL, check if it identifies some device in
195          *    this group:
196          *
197          * 2a. if cookie is a storage device from our group (IDE, USB etc.),
198          *     return next available (if exists) in this group
199          *
200          * 2b. if it isn't device from our group, check if such devices were
201          *     ever enumerated before:
202          *     - if not, return the first available device from this group
203          *     - else return 0
204          */
205
206         if (di->cookie == NULL) {
207
208                 debugf("group%d - enum restart\n", type);
209
210                 /*
211                  * 1. Enumeration (re-)started: take the first available
212                  * device, if exists
213                  */
214                 found = dev_stor_get(type, 1, &more, di);
215                 specs[type].enum_started = 1;
216
217         } else if (dev_is_stor(type, di)) {
218
219                 debugf("group%d - enum continued for the next device\n", type);
220
221                 if (specs[type].enum_ended) {
222                         debugf("group%d - nothing more to enum!\n", type);
223                         return 0;
224                 }
225
226                 /* 2a. Attempt to take a next available device in the group */
227                 found = dev_stor_get(type, 0, &more, di);
228
229         } else {
230
231                 if (specs[type].enum_ended) {
232                         debugf("group %d - already enumerated, skipping\n", type);
233                         return 0;
234                 }
235
236                 debugf("group%d - first time enum\n", type);
237
238                 if (specs[type].enum_started == 0) {
239                         /*
240                          * 2b.  If enumerating devices in this group did not
241                          * happen before, it means the cookie pointed to a
242                          * device frome some other group (another storage
243                          * group, or network); in this case try to take the
244                          * first available device from our group
245                          */
246                         specs[type].enum_started = 1;
247
248                         /*
249                          * Attempt to take the first device in this group:
250                          *'first element' flag is set
251                          */
252                         found = dev_stor_get(type, 1, &more, di);
253
254                 } else {
255                         errf("group%d - out of order iteration\n", type);
256                         found = 0;
257                         more = 0;
258                 }
259         }
260
261         /*
262          * If there are no more devices in this group, consider its
263          * enumeration finished
264          */
265         specs[type].enum_ended = (!more) ? 1 : 0;
266
267         if (found)
268                 debugf("device found, returning cookie 0x%08x\n",
269                         (u_int32_t)di->cookie);
270         else
271                 debugf("no device found\n");
272
273         return found;
274 }
275
276 void dev_enum_reset(void)
277 {
278         int i;
279
280         for (i = 0; i < ENUM_MAX; i ++) {
281                 specs[i].enum_started = 0;
282                 specs[i].enum_ended = 0;
283         }
284 }
285
286 int dev_enum_storage(struct device_info *di)
287 {
288         int i;
289
290         /*
291          * check: ide, usb, scsi, mmc
292          */
293         for (i = ENUM_IDE; i < ENUM_MAX; i ++) {
294                 if (dev_enum_stor(i, di))
295                         return 1;
296         }
297
298         return 0;
299 }
300
301 static int dev_stor_is_valid(int type, block_dev_desc_t *dd)
302 {
303         int i;
304
305         for (i = 0; i < specs[type].max_dev; i++)
306                 if (dd == get_dev(specs[type].name, i))
307                         if (dd->type != DEV_TYPE_UNKNOWN)
308                                 return 1;
309
310         return 0;
311 }
312
313
314 int dev_open_stor(void *cookie)
315 {
316         int type = dev_stor_type(cookie);
317
318         if (type == ENUM_MAX)
319                 return API_ENODEV;
320
321         if (dev_stor_is_valid(type, (block_dev_desc_t *)cookie))
322                 return 0;
323
324         return API_ENODEV;
325 }
326
327
328 int dev_close_stor(void *cookie)
329 {
330         /*
331          * Not much to do as we actually do not alter storage devices upon
332          * close
333          */
334         return 0;
335 }
336
337
338 static int dev_stor_index(block_dev_desc_t *dd)
339 {
340         int i, type;
341
342         type = dev_stor_type(dd);
343         for (i = 0; i < specs[type].max_dev; i++)
344                 if (dd == get_dev(specs[type].name, i))
345                         return i;
346
347         return (specs[type].max_dev);
348 }
349
350
351 lbasize_t dev_read_stor(void *cookie, void *buf, lbasize_t len, lbastart_t start)
352 {
353         int type;
354         block_dev_desc_t *dd = (block_dev_desc_t *)cookie;
355
356         if ((type = dev_stor_type(dd)) == ENUM_MAX)
357                 return 0;
358
359         if (!dev_stor_is_valid(type, dd))
360                 return 0;
361
362         if ((dd->block_read) == NULL) {
363                 debugf("no block_read() for device 0x%08x\n");
364                 return 0;
365         }
366
367         return (dd->block_read(dev_stor_index(dd), start, len, buf));
368 }
369
370 #endif /* CONFIG_API */