2009-07-01 Pavel Roskin <proski@gnu.org>
[grub2/jjazz.git] / disk / ieee1275 / ofdisk.c
blobca257d6d125fae2c04c29553530331eff48a10e5
1 /* ofdisk.c - Open Firmware disk access. */
2 /*
3 * GRUB -- GRand Unified Bootloader
4 * Copyright (C) 2004,2006,2007,2008 Free Software Foundation, Inc.
6 * GRUB is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
11 * GRUB is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
20 #include <grub/misc.h>
21 #include <grub/disk.h>
22 #include <grub/mm.h>
23 #include <grub/ieee1275/ieee1275.h>
24 #include <grub/ieee1275/ofdisk.h>
26 struct ofdisk_hash_ent
28 char *devpath;
29 struct ofdisk_hash_ent *next;
32 #define OFDISK_HASH_SZ 8
33 static struct ofdisk_hash_ent *ofdisk_hash[OFDISK_HASH_SZ];
35 static int
36 ofdisk_hash_fn (const char *devpath)
38 int hash = 0;
39 while (*devpath)
40 hash ^= *devpath++;
41 return (hash & (OFDISK_HASH_SZ - 1));
44 static struct ofdisk_hash_ent *
45 ofdisk_hash_find (const char *devpath)
47 struct ofdisk_hash_ent *p = ofdisk_hash[ofdisk_hash_fn(devpath)];
49 while (p)
51 if (!grub_strcmp (p->devpath, devpath))
52 break;
53 p = p->next;
55 return p;
58 static struct ofdisk_hash_ent *
59 ofdisk_hash_add (char *devpath)
61 struct ofdisk_hash_ent **head = &ofdisk_hash[ofdisk_hash_fn(devpath)];
62 struct ofdisk_hash_ent *p = grub_malloc(sizeof (*p));
64 if (p)
66 p->devpath = devpath;
67 p->next = *head;
68 *head = p;
70 return p;
73 static int
74 grub_ofdisk_iterate (int (*hook) (const char *name))
76 auto int dev_iterate (struct grub_ieee1275_devalias *alias);
78 int dev_iterate (struct grub_ieee1275_devalias *alias)
80 int ret = 0;
82 grub_dprintf ("disk", "disk name = %s\n", alias->name);
84 if (grub_ieee1275_test_flag (GRUB_IEEE1275_FLAG_OFDISK_SDCARD_ONLY))
86 grub_ieee1275_phandle_t dev;
87 char tmp[8];
89 if (grub_ieee1275_finddevice (alias->path, &dev))
91 grub_dprintf ("disk", "finddevice (%s) failed\n", alias->path);
92 return 0;
95 if (grub_ieee1275_get_property (dev, "iconname", tmp,
96 sizeof tmp, 0))
98 grub_dprintf ("disk", "get iconname failed\n");
99 return 0;
102 if (grub_strcmp (tmp, "sdmmc"))
104 grub_dprintf ("disk", "device is not an SD card\n");
105 return 0;
109 if (! grub_strcmp (alias->type, "block") &&
110 grub_strcmp (alias->name, "cdrom"))
111 ret = hook (alias->name);
112 return ret;
115 return grub_devalias_iterate (dev_iterate);
118 static char *
119 compute_dev_path (const char *name)
121 char *devpath = grub_malloc (grub_strlen (name) + 2);
122 char *p, c;
124 if (!devpath)
125 return NULL;
127 /* Un-escape commas. */
128 p = devpath;
129 while ((c = *name++) != '\0')
131 if (c == '\\' && *name == ',')
133 *p++ = ',';
134 name++;
136 else
137 *p++ = c;
140 if (! grub_ieee1275_test_flag (GRUB_IEEE1275_FLAG_NO_PARTITION_0))
142 *p++ = ':';
143 *p++ = '0';
145 *p++ = '\0';
147 return devpath;
150 static grub_err_t
151 grub_ofdisk_open (const char *name, grub_disk_t disk)
153 grub_ieee1275_phandle_t dev;
154 grub_ieee1275_ihandle_t dev_ihandle = 0;
155 struct ofdisk_hash_ent *op;
156 char *devpath;
157 /* XXX: This should be large enough for any possible case. */
158 char prop[64];
159 grub_ssize_t actual;
161 devpath = compute_dev_path (name);
162 if (! devpath)
163 return grub_errno;
165 op = ofdisk_hash_find (devpath);
166 if (!op)
167 op = ofdisk_hash_add (devpath);
169 grub_free (devpath);
170 if (!op)
171 return grub_errno;
173 grub_dprintf ("disk", "Opening `%s'.\n", op->devpath);
175 grub_ieee1275_open (op->devpath, &dev_ihandle);
176 if (! dev_ihandle)
178 grub_error (GRUB_ERR_UNKNOWN_DEVICE, "Can't open device");
179 goto fail;
182 grub_dprintf ("disk", "Opened `%s' as handle %p.\n", op->devpath,
183 (void *) (unsigned long) dev_ihandle);
185 if (grub_ieee1275_finddevice (op->devpath, &dev))
187 grub_error (GRUB_ERR_UNKNOWN_DEVICE, "Can't read device properties");
188 goto fail;
191 if (grub_ieee1275_get_property (dev, "device_type", prop, sizeof (prop),
192 &actual))
194 grub_error (GRUB_ERR_UNKNOWN_DEVICE, "Can't read the device type");
195 goto fail;
198 if (grub_strcmp (prop, "block"))
200 grub_error (GRUB_ERR_BAD_DEVICE, "Not a block device");
201 goto fail;
204 /* XXX: There is no property to read the number of blocks. There
205 should be a property `#blocks', but it is not there. Perhaps it
206 is possible to use seek for this. */
207 disk->total_sectors = 0xFFFFFFFFUL;
209 disk->id = (unsigned long) op;
211 /* XXX: Read this, somehow. */
212 disk->has_partitions = 1;
213 disk->data = (void *) (unsigned long) dev_ihandle;
214 return 0;
216 fail:
217 if (dev_ihandle)
218 grub_ieee1275_close (dev_ihandle);
219 return grub_errno;
222 static void
223 grub_ofdisk_close (grub_disk_t disk)
225 grub_dprintf ("disk", "Closing handle %p.\n",
226 (void *) disk->data);
227 grub_ieee1275_close ((grub_ieee1275_ihandle_t) (unsigned long) disk->data);
230 static grub_err_t
231 grub_ofdisk_read (grub_disk_t disk, grub_disk_addr_t sector,
232 grub_size_t size, char *buf)
234 grub_ssize_t status, actual;
235 unsigned long long pos;
237 grub_dprintf ("disk",
238 "Reading handle %p: sector 0x%llx, size 0x%lx, buf %p.\n",
239 (void *) disk->data, (long long) sector, (long) size, buf);
241 pos = sector * 512UL;
243 grub_ieee1275_seek ((grub_ieee1275_ihandle_t) (unsigned long) disk->data,
244 (int) (pos >> 32), (int) pos & 0xFFFFFFFFUL, &status);
245 if (status < 0)
246 return grub_error (GRUB_ERR_READ_ERROR,
247 "Seek error, can't seek block %llu",
248 (long long) sector);
249 grub_ieee1275_read ((grub_ieee1275_ihandle_t) (unsigned long) disk->data,
250 buf, size * 512UL, &actual);
251 if (actual != actual)
252 return grub_error (GRUB_ERR_READ_ERROR, "Read error on block: %llu",
253 (long long) sector);
255 return 0;
258 static grub_err_t
259 grub_ofdisk_write (grub_disk_t disk __attribute ((unused)),
260 grub_disk_addr_t sector __attribute ((unused)),
261 grub_size_t size __attribute ((unused)),
262 const char *buf __attribute ((unused)))
264 return GRUB_ERR_NOT_IMPLEMENTED_YET;
267 static struct grub_disk_dev grub_ofdisk_dev =
269 .name = "ofdisk",
270 .id = GRUB_DISK_DEVICE_OFDISK_ID,
271 .iterate = grub_ofdisk_iterate,
272 .open = grub_ofdisk_open,
273 .close = grub_ofdisk_close,
274 .read = grub_ofdisk_read,
275 .write = grub_ofdisk_write,
276 .next = 0
279 void
280 grub_ofdisk_init (void)
282 grub_disk_dev_register (&grub_ofdisk_dev);
285 void
286 grub_ofdisk_fini (void)
288 grub_disk_dev_unregister (&grub_ofdisk_dev);