1 /* This file is part of the program psim.
3 Copyright (C) 1994-1997, Andrew Cagney <cagney@highland.com.au>
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
25 #include "device_table.h"
42 cdrom - read-only removable mass storage device
44 disk - mass storage device
46 floppy - removable mass storage device
52 Mass storage devices such as a hard-disk or cdrom-drive are not
53 normally directly connected to the processor. Instead, these
54 devices are attached to a logical bus, such as SCSI or IDE, and
55 then a controller of that bus is made accessible to the processor.
57 Reflecting this, within a device tree, mass storage devices such as
58 a <<cdrom>>, <<disk>> or <<floppy>> are created as children of of a
59 logical bus controller node (such as a SCSI or IDE interface).
60 That controller, in turn, would be made the child of a physical bus
61 node that is directly accessible to the processor.
63 The above mass storage devices provide two interfaces - a logical
66 At the physical level the <<device_io_...>> functions can be used
67 perform reads and writes of the raw media. The address being
68 interpreted as an offset from the start of the disk.
70 At the logical level, it is possible to create an instance of the
71 disk that provides access to any of the physical media, a disk
72 partition, or even a file within a partition. The <<disk-label>>
73 package, which implements this functionality, is described
74 elsewhere. Both the Open Firmware and Moto BUG rom emulations
75 support this interface.
77 Block devices such as the <<floppy>> and <<cdrom>> have removable
78 media. At the programmer level, the media can be changed using the
79 <<change_media>> ioctl. From within GDB, a <<change-media>>
80 operation can be initated by using the command.
88 file = <file-name> (required)
90 The name of the file that contains an image of the disk. For
91 <<disk>> and <<floppy>> devices, the image will be opened for both
92 reading and writing. Multiple image files may be specified, the
93 second and later files being opened when <<change-media>> (with a
94 NULL file name) being specified.
97 block-size = <nr-bytes> (optional)
99 The value is returned by the block-size method. The default value
103 max-transfer = <nr-bytes> (optional)
105 The value is returned by the max-transfer method. The default value
109 #blocks = <nr-blocks> (optional)
111 The value is returned by the #blocks method. If no value is
112 present then -1 is returned.
115 read-only = <anything> (optional)
117 If this property is present, the disk file image is always opened
125 | $ psim -t 'disk-device' \
128 Add a CDROM and disk to an IDE bus. Specify the host operating
129 system's cd drive as the CD-ROM image.
131 | -o '/pci/ide/disk@0/file "disk-image' \
132 | -o '/pci/ide/cdrom@1/file "/dev/cd0a' \
135 As part of the code implementing a logical bus device (for instance
136 the IDE controller), locate the CDROM device and then read block
139 | device *cdrom = device_tree_find_device(me, "cdrom");
141 | device_io_read_buffer(cdrom, buf, 0,
142 0, 47 * sizeof(block), // space, address
143 sizeof(block), NULL, 0);
146 Use the device instance interface to read block 47 of the file
147 called <<netbsd.elf>> on the disks default partition. Similar code
148 would be used in an operating systems pre-boot loader.
150 | device_instance *netbsd =
151 | device_create_instance(root, "/pci/ide/disk:,\netbsd.elf");
153 | device_instance_seek(netbsd, 0, 47 * sizeof(block));
154 | device_instance_read(netbsd, block, sizeof(block));
160 The block device specification includes mechanisms for determining
161 the physical device characteristics - such as the disks size.
162 Currently this mechanism is not implemented.
164 The functionality of this device (in particular the device instance
165 interface) depends on the implementation of <<disk-label>> package.
166 That package may not be fully implemented.
168 The disk does not know its size. Hence it relies on the failure of
169 fread(), fwrite() and fseek() calls to detect errors.
171 The disk size is limited by the addressable range covered by
172 unsigned_word (addr). An extension would be to instead use the
173 concatenated value space:addr.
175 The method #blocks should `stat' the disk to determine the number
176 of blocks if there is no #blocks property.
178 It would appear that OpenFirmware does not define a client call for
179 changing (ejecting) the media of a device.
183 typedef struct _hw_disk_device {
188 /* unsigned_word size; */
192 typedef struct _hw_disk_instance {
194 hw_disk_device *disk;
199 open_disk_image(device *me,
200 hw_disk_device *disk,
203 if (disk->image != NULL)
205 if (disk->name != NULL)
207 disk->name = strdup(name);
208 disk->image = fopen(disk->name, disk->read_only ? "r" : "r+");
209 if (disk->image == NULL) {
210 perror(device_name(me));
211 device_error(me, "open %s failed\n", disk->name);
214 DTRACE(disk, ("image %s (%s)\n",
216 (disk->read_only ? "read-only" : "read-write")));
220 hw_disk_init_address(device *me)
222 hw_disk_device *disk = device_data(me);
223 unsigned_word address;
227 /* attach to the parent. Since the bus is logical, attach using just
228 the unit-address (size must be zero) */
229 device_address_to_attach_address(device_parent(me), device_unit_address(me),
230 &space, &address, me);
231 device_attach_address(device_parent(me), attach_callback,
232 space, address, 0/*size*/, access_read_write_exec,
235 /* Tell the world we are a disk. */
236 device_add_string_property(me, "device_type", "block");
238 /* get the name of the file specifying the disk image */
239 disk->name_index = 0;
240 disk->nr_names = device_find_string_array_property(me, "file",
241 disk->name_index, &name);
243 device_error(me, "invalid file property");
245 /* is it a RO device? */
247 (strcmp(device_name(me), "disk") != 0
248 && strcmp(device_name(me), "floppy") != 0
249 && device_find_property(me, "read-only") == NULL);
252 open_disk_image(me, disk, name);
256 hw_disk_ioctl(device *me,
259 device_ioctl_request request,
263 case device_ioctl_change_media:
265 hw_disk_device *disk = device_data(me);
266 const char *name = va_arg(ap, const char *);
268 disk->name_index = -1;
271 disk->name_index = (disk->name_index + 1) % disk->nr_names;
272 if (!device_find_string_array_property(me, "file",
273 disk->name_index, &name))
274 device_error(me, "invalid file property");
276 open_disk_image(me, disk, name);
280 device_error(me, "insupported ioctl request");
291 hw_disk_io_read_buffer(device *me,
299 hw_disk_device *disk = device_data(me);
300 unsigned nr_bytes_read;
302 device_error(me, "read - extended disk addressing unimplemented");
305 else if (fseek(disk->image, addr, SEEK_SET) < 0)
307 else if (fread(dest, nr_bytes, 1, disk->image) != 1)
310 nr_bytes_read = nr_bytes;
311 DTRACE(disk, ("io-read - address 0x%lx, nr-bytes-read %d, requested %d\n",
312 (unsigned long) addr, (int)nr_bytes_read, (int)nr_bytes));
313 return nr_bytes_read;
318 hw_disk_io_write_buffer(device *me,
326 hw_disk_device *disk = device_data(me);
327 unsigned nr_bytes_written;
329 device_error(me, "write - extended disk addressing unimplemented");
331 nr_bytes_written = 0;
332 else if (nr_bytes == 0)
333 nr_bytes_written = 0;
334 else if (fseek(disk->image, addr, SEEK_SET) < 0)
335 nr_bytes_written = 0;
336 else if (fwrite(source, nr_bytes, 1, disk->image) != 1)
337 nr_bytes_written = 0;
339 nr_bytes_written = nr_bytes;
340 DTRACE(disk, ("io-write - address 0x%lx, nr-bytes-written %d, requested %d\n",
341 (unsigned long) addr, (int)nr_bytes_written, (int)nr_bytes));
342 return nr_bytes_written;
346 /* instances of the hw_disk device */
349 hw_disk_instance_delete(device_instance *instance)
351 hw_disk_instance *data = device_instance_data(instance);
352 DITRACE(disk, ("delete - instance=%ld\n",
353 (unsigned long)device_instance_to_external(instance)));
358 hw_disk_instance_read(device_instance *instance,
362 hw_disk_instance *data = device_instance_data(instance);
363 DITRACE(disk, ("read - instance=%ld len=%ld\n",
364 (unsigned long)device_instance_to_external(instance),
366 if ((data->pos + len) < data->pos)
367 return -1; /* overflow */
368 if (fseek(data->disk->image, data->pos, SEEK_SET) < 0)
370 if (fread(buf, len, 1, data->disk->image) != 1)
372 data->pos = ftell(data->disk->image);
377 hw_disk_instance_write(device_instance *instance,
381 hw_disk_instance *data = device_instance_data(instance);
382 DITRACE(disk, ("write - instance=%ld len=%ld\n",
383 (unsigned long)device_instance_to_external(instance),
385 if ((data->pos + len) < data->pos)
386 return -1; /* overflow */
387 if (data->disk->read_only)
389 if (fseek(data->disk->image, data->pos, SEEK_SET) < 0)
391 if (fwrite(buf, len, 1, data->disk->image) != 1)
393 data->pos = ftell(data->disk->image);
398 hw_disk_instance_seek(device_instance *instance,
399 unsigned_word pos_hi,
400 unsigned_word pos_lo)
402 hw_disk_instance *data = device_instance_data(instance);
404 device_error(device_instance_device(instance),
405 "seek - extended addressing unimplemented");
406 DITRACE(disk, ("seek - instance=%ld pos_hi=%ld pos_lo=%ld\n",
407 (unsigned long)device_instance_to_external(instance),
408 (long)pos_hi, (long)pos_lo));
414 hw_disk_max_transfer(device_instance *instance,
416 unsigned32 stack_args[/*n_stack_args*/],
418 unsigned32 stack_returns[/*n_stack_returns*/])
420 device *me = device_instance_device(instance);
421 if ((n_stack_args != 0)
422 || (n_stack_returns != 1)) {
423 device_error(me, "Incorrect number of arguments for max-transfer method\n");
427 unsigned_cell max_transfer;
428 if (device_find_property(me, "max-transfer"))
429 max_transfer = device_find_integer_property(me, "max-transfer");
432 DITRACE(disk, ("max-transfer - instance=%ld max-transfer=%ld\n",
433 (unsigned long)device_instance_to_external(instance),
434 (long int)max_transfer));
435 stack_returns[0] = max_transfer;
441 hw_disk_block_size(device_instance *instance,
443 unsigned32 stack_args[/*n_stack_args*/],
445 unsigned32 stack_returns[/*n_stack_returns*/])
447 device *me = device_instance_device(instance);
448 if ((n_stack_args != 0)
449 || (n_stack_returns != 1)) {
450 device_error(me, "Incorrect number of arguments for block-size method\n");
454 unsigned_cell block_size;
455 if (device_find_property(me, "block-size"))
456 block_size = device_find_integer_property(me, "block-size");
459 DITRACE(disk, ("block-size - instance=%ld block-size=%ld\n",
460 (unsigned long)device_instance_to_external(instance),
461 (long int)block_size));
462 stack_returns[0] = block_size;
468 hw_disk_nr_blocks(device_instance *instance,
470 unsigned32 stack_args[/*n_stack_args*/],
472 unsigned32 stack_returns[/*n_stack_returns*/])
474 device *me = device_instance_device(instance);
475 if ((n_stack_args != 0)
476 || (n_stack_returns != 1)) {
477 device_error(me, "Incorrect number of arguments for block-size method\n");
481 unsigned_word nr_blocks;
482 if (device_find_property(me, "#blocks"))
483 nr_blocks = device_find_integer_property(me, "#blocks");
486 DITRACE(disk, ("#blocks - instance=%ld #blocks=%ld\n",
487 (unsigned long)device_instance_to_external(instance),
488 (long int)nr_blocks));
489 stack_returns[0] = nr_blocks;
494 static device_instance_methods hw_disk_instance_methods[] = {
495 { "max-transfer", hw_disk_max_transfer },
496 { "block-size", hw_disk_block_size },
497 { "#blocks", hw_disk_nr_blocks },
501 static const device_instance_callbacks hw_disk_instance_callbacks = {
502 hw_disk_instance_delete,
503 hw_disk_instance_read,
504 hw_disk_instance_write,
505 hw_disk_instance_seek,
506 hw_disk_instance_methods,
509 static device_instance *
510 hw_disk_create_instance(device *me,
514 device_instance *instance;
515 hw_disk_device *disk = device_data(me);
516 hw_disk_instance *data = ZALLOC(hw_disk_instance);
519 instance = device_create_instance_from(me, NULL,
522 &hw_disk_instance_callbacks);
523 DITRACE(disk, ("create - path=%s(%s) instance=%ld\n",
525 (unsigned long)device_instance_to_external(instance)));
526 return pk_disklabel_create_instance(instance, args);
529 static device_callbacks const hw_disk_callbacks = {
530 { hw_disk_init_address, NULL },
531 { NULL, }, /* address */
532 { hw_disk_io_read_buffer,
533 hw_disk_io_write_buffer, },
535 { NULL, }, /* interrupt */
536 { NULL, }, /* unit */
537 hw_disk_create_instance,
543 hw_disk_create(const char *name,
544 const device_unit *unit_address,
547 /* create the descriptor */
548 hw_disk_device *hw_disk = ZALLOC(hw_disk_device);
553 const device_descriptor hw_disk_device_descriptor[] = {
554 { "disk", hw_disk_create, &hw_disk_callbacks },
555 { "cdrom", hw_disk_create, &hw_disk_callbacks },
556 { "floppy", hw_disk_create, &hw_disk_callbacks },
560 #endif /* _HW_DISK_C_ */