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 3 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, see <http://www.gnu.org/licenses/>.
24 #include "device_table.h"
41 cdrom - read-only removable mass storage device
43 disk - mass storage device
45 floppy - removable mass storage device
51 Mass storage devices such as a hard-disk or cdrom-drive are not
52 normally directly connected to the processor. Instead, these
53 devices are attached to a logical bus, such as SCSI or IDE, and
54 then a controller of that bus is made accessible to the processor.
56 Reflecting this, within a device tree, mass storage devices such as
57 a <<cdrom>>, <<disk>> or <<floppy>> are created as children of of a
58 logical bus controller node (such as a SCSI or IDE interface).
59 That controller, in turn, would be made the child of a physical bus
60 node that is directly accessible to the processor.
62 The above mass storage devices provide two interfaces - a logical
65 At the physical level the <<device_io_...>> functions can be used
66 perform reads and writes of the raw media. The address being
67 interpreted as an offset from the start of the disk.
69 At the logical level, it is possible to create an instance of the
70 disk that provides access to any of the physical media, a disk
71 partition, or even a file within a partition. The <<disk-label>>
72 package, which implements this functionality, is described
73 elsewhere. Both the Open Firmware and Moto BUG rom emulations
74 support this interface.
76 Block devices such as the <<floppy>> and <<cdrom>> have removable
77 media. At the programmer level, the media can be changed using the
78 <<change_media>> ioctl. From within GDB, a <<change-media>>
79 operation can be initated by using the command.
87 file = <file-name> (required)
89 The name of the file that contains an image of the disk. For
90 <<disk>> and <<floppy>> devices, the image will be opened for both
91 reading and writing. Multiple image files may be specified, the
92 second and later files being opened when <<change-media>> (with a
93 NULL file name) being specified.
96 block-size = <nr-bytes> (optional)
98 The value is returned by the block-size method. The default value
102 max-transfer = <nr-bytes> (optional)
104 The value is returned by the max-transfer method. The default value
108 #blocks = <nr-blocks> (optional)
110 The value is returned by the #blocks method. If no value is
111 present then -1 is returned.
114 read-only = <anything> (optional)
116 If this property is present, the disk file image is always opened
124 | $ psim -t 'disk-device' \
127 Add a CDROM and disk to an IDE bus. Specify the host operating
128 system's cd drive as the CD-ROM image.
130 | -o '/pci/ide/disk@0/file "disk-image' \
131 | -o '/pci/ide/cdrom@1/file "/dev/cd0a' \
134 As part of the code implementing a logical bus device (for instance
135 the IDE controller), locate the CDROM device and then read block
138 | device *cdrom = device_tree_find_device(me, "cdrom");
140 | device_io_read_buffer(cdrom, buf, 0,
141 0, 47 * sizeof(block), // space, address
142 sizeof(block), NULL, 0);
145 Use the device instance interface to read block 47 of the file
146 called <<netbsd.elf>> on the disks default partition. Similar code
147 would be used in an operating systems pre-boot loader.
149 | device_instance *netbsd =
150 | device_create_instance(root, "/pci/ide/disk:,\netbsd.elf");
152 | device_instance_seek(netbsd, 0, 47 * sizeof(block));
153 | device_instance_read(netbsd, block, sizeof(block));
159 The block device specification includes mechanisms for determining
160 the physical device characteristics - such as the disks size.
161 Currently this mechanism is not implemented.
163 The functionality of this device (in particular the device instance
164 interface) depends on the implementation of <<disk-label>> package.
165 That package may not be fully implemented.
167 The disk does not know its size. Hence it relies on the failure of
168 fread(), fwrite() and fseek() calls to detect errors.
170 The disk size is limited by the addressable range covered by
171 unsigned_word (addr). An extension would be to instead use the
172 concatenated value space:addr.
174 The method #blocks should `stat' the disk to determine the number
175 of blocks if there is no #blocks property.
177 It would appear that OpenFirmware does not define a client call for
178 changing (ejecting) the media of a device.
182 typedef struct _hw_disk_device
{
187 /* unsigned_word size; */
191 typedef struct _hw_disk_instance
{
193 hw_disk_device
*disk
;
198 open_disk_image(device
*me
,
199 hw_disk_device
*disk
,
202 if (disk
->image
!= NULL
)
204 if (disk
->name
!= NULL
)
206 disk
->name
= strdup(name
);
207 disk
->image
= fopen(disk
->name
, disk
->read_only
? "r" : "r+");
208 if (disk
->image
== NULL
) {
209 perror(device_name(me
));
210 device_error(me
, "open %s failed\n", disk
->name
);
213 DTRACE(disk
, ("image %s (%s)\n",
215 (disk
->read_only
? "read-only" : "read-write")));
219 hw_disk_init_address(device
*me
)
221 hw_disk_device
*disk
= device_data(me
);
222 unsigned_word address
;
226 /* attach to the parent. Since the bus is logical, attach using just
227 the unit-address (size must be zero) */
228 device_address_to_attach_address(device_parent(me
), device_unit_address(me
),
229 &space
, &address
, me
);
230 device_attach_address(device_parent(me
), attach_callback
,
231 space
, address
, 0/*size*/, access_read_write_exec
,
234 /* Tell the world we are a disk. */
235 device_add_string_property(me
, "device_type", "block");
237 /* get the name of the file specifying the disk image */
238 disk
->name_index
= 0;
239 disk
->nr_names
= device_find_string_array_property(me
, "file",
240 disk
->name_index
, &name
);
242 device_error(me
, "invalid file property");
244 /* is it a RO device? */
246 (strcmp(device_name(me
), "disk") != 0
247 && strcmp(device_name(me
), "floppy") != 0
248 && device_find_property(me
, "read-only") == NULL
);
251 open_disk_image(me
, disk
, name
);
255 hw_disk_ioctl(device
*me
,
258 device_ioctl_request request
,
262 case device_ioctl_change_media
:
264 hw_disk_device
*disk
= device_data(me
);
265 const char *name
= va_arg(ap
, const char *);
267 disk
->name_index
= -1;
270 disk
->name_index
= (disk
->name_index
+ 1) % disk
->nr_names
;
271 if (!device_find_string_array_property(me
, "file",
272 disk
->name_index
, &name
))
273 device_error(me
, "invalid file property");
275 open_disk_image(me
, disk
, name
);
279 device_error(me
, "insupported ioctl request");
290 hw_disk_io_read_buffer(device
*me
,
298 hw_disk_device
*disk
= device_data(me
);
299 unsigned nr_bytes_read
;
301 device_error(me
, "read - extended disk addressing unimplemented");
304 else if (fseek(disk
->image
, addr
, SEEK_SET
) < 0)
306 else if (fread(dest
, nr_bytes
, 1, disk
->image
) != 1)
309 nr_bytes_read
= nr_bytes
;
310 DTRACE(disk
, ("io-read - address 0x%lx, nr-bytes-read %d, requested %d\n",
311 (unsigned long) addr
, (int)nr_bytes_read
, (int)nr_bytes
));
312 return nr_bytes_read
;
317 hw_disk_io_write_buffer(device
*me
,
325 hw_disk_device
*disk
= device_data(me
);
326 unsigned nr_bytes_written
;
328 device_error(me
, "write - extended disk addressing unimplemented");
330 nr_bytes_written
= 0;
331 else if (nr_bytes
== 0)
332 nr_bytes_written
= 0;
333 else if (fseek(disk
->image
, addr
, SEEK_SET
) < 0)
334 nr_bytes_written
= 0;
335 else if (fwrite(source
, nr_bytes
, 1, disk
->image
) != 1)
336 nr_bytes_written
= 0;
338 nr_bytes_written
= nr_bytes
;
339 DTRACE(disk
, ("io-write - address 0x%lx, nr-bytes-written %d, requested %d\n",
340 (unsigned long) addr
, (int)nr_bytes_written
, (int)nr_bytes
));
341 return nr_bytes_written
;
345 /* instances of the hw_disk device */
348 hw_disk_instance_delete(device_instance
*instance
)
350 hw_disk_instance
*data
= device_instance_data(instance
);
351 DITRACE(disk
, ("delete - instance=%ld\n",
352 (unsigned long)device_instance_to_external(instance
)));
357 hw_disk_instance_read(device_instance
*instance
,
361 hw_disk_instance
*data
= device_instance_data(instance
);
362 DITRACE(disk
, ("read - instance=%ld len=%ld\n",
363 (unsigned long)device_instance_to_external(instance
),
365 if ((data
->pos
+ len
) < data
->pos
)
366 return -1; /* overflow */
367 if (fseek(data
->disk
->image
, data
->pos
, SEEK_SET
) < 0)
369 if (fread(buf
, len
, 1, data
->disk
->image
) != 1)
371 data
->pos
= ftell(data
->disk
->image
);
376 hw_disk_instance_write(device_instance
*instance
,
380 hw_disk_instance
*data
= device_instance_data(instance
);
381 DITRACE(disk
, ("write - instance=%ld len=%ld\n",
382 (unsigned long)device_instance_to_external(instance
),
384 if ((data
->pos
+ len
) < data
->pos
)
385 return -1; /* overflow */
386 if (data
->disk
->read_only
)
388 if (fseek(data
->disk
->image
, data
->pos
, SEEK_SET
) < 0)
390 if (fwrite(buf
, len
, 1, data
->disk
->image
) != 1)
392 data
->pos
= ftell(data
->disk
->image
);
397 hw_disk_instance_seek(device_instance
*instance
,
398 unsigned_word pos_hi
,
399 unsigned_word pos_lo
)
401 hw_disk_instance
*data
= device_instance_data(instance
);
403 device_error(device_instance_device(instance
),
404 "seek - extended addressing unimplemented");
405 DITRACE(disk
, ("seek - instance=%ld pos_hi=%ld pos_lo=%ld\n",
406 (unsigned long)device_instance_to_external(instance
),
407 (long)pos_hi
, (long)pos_lo
));
413 hw_disk_max_transfer(device_instance
*instance
,
415 unsigned32 stack_args
[/*n_stack_args*/],
417 unsigned32 stack_returns
[/*n_stack_returns*/])
419 device
*me
= device_instance_device(instance
);
420 if ((n_stack_args
!= 0)
421 || (n_stack_returns
!= 1)) {
422 device_error(me
, "Incorrect number of arguments for max-transfer method\n");
426 unsigned_cell max_transfer
;
427 if (device_find_property(me
, "max-transfer"))
428 max_transfer
= device_find_integer_property(me
, "max-transfer");
431 DITRACE(disk
, ("max-transfer - instance=%ld max-transfer=%ld\n",
432 (unsigned long)device_instance_to_external(instance
),
433 (long int)max_transfer
));
434 stack_returns
[0] = max_transfer
;
440 hw_disk_block_size(device_instance
*instance
,
442 unsigned32 stack_args
[/*n_stack_args*/],
444 unsigned32 stack_returns
[/*n_stack_returns*/])
446 device
*me
= device_instance_device(instance
);
447 if ((n_stack_args
!= 0)
448 || (n_stack_returns
!= 1)) {
449 device_error(me
, "Incorrect number of arguments for block-size method\n");
453 unsigned_cell block_size
;
454 if (device_find_property(me
, "block-size"))
455 block_size
= device_find_integer_property(me
, "block-size");
458 DITRACE(disk
, ("block-size - instance=%ld block-size=%ld\n",
459 (unsigned long)device_instance_to_external(instance
),
460 (long int)block_size
));
461 stack_returns
[0] = block_size
;
467 hw_disk_nr_blocks(device_instance
*instance
,
469 unsigned32 stack_args
[/*n_stack_args*/],
471 unsigned32 stack_returns
[/*n_stack_returns*/])
473 device
*me
= device_instance_device(instance
);
474 if ((n_stack_args
!= 0)
475 || (n_stack_returns
!= 1)) {
476 device_error(me
, "Incorrect number of arguments for block-size method\n");
480 unsigned_word nr_blocks
;
481 if (device_find_property(me
, "#blocks"))
482 nr_blocks
= device_find_integer_property(me
, "#blocks");
485 DITRACE(disk
, ("#blocks - instance=%ld #blocks=%ld\n",
486 (unsigned long)device_instance_to_external(instance
),
487 (long int)nr_blocks
));
488 stack_returns
[0] = nr_blocks
;
493 static device_instance_methods hw_disk_instance_methods
[] = {
494 { "max-transfer", hw_disk_max_transfer
},
495 { "block-size", hw_disk_block_size
},
496 { "#blocks", hw_disk_nr_blocks
},
500 static const device_instance_callbacks hw_disk_instance_callbacks
= {
501 hw_disk_instance_delete
,
502 hw_disk_instance_read
,
503 hw_disk_instance_write
,
504 hw_disk_instance_seek
,
505 hw_disk_instance_methods
,
508 static device_instance
*
509 hw_disk_create_instance(device
*me
,
513 device_instance
*instance
;
514 hw_disk_device
*disk
= device_data(me
);
515 hw_disk_instance
*data
= ZALLOC(hw_disk_instance
);
518 instance
= device_create_instance_from(me
, NULL
,
521 &hw_disk_instance_callbacks
);
522 DITRACE(disk
, ("create - path=%s(%s) instance=%ld\n",
524 (unsigned long)device_instance_to_external(instance
)));
525 return pk_disklabel_create_instance(instance
, args
);
528 static device_callbacks
const hw_disk_callbacks
= {
529 { hw_disk_init_address
, NULL
},
530 { NULL
, }, /* address */
531 { hw_disk_io_read_buffer
,
532 hw_disk_io_write_buffer
, },
534 { NULL
, }, /* interrupt */
535 { NULL
, }, /* unit */
536 hw_disk_create_instance
,
542 hw_disk_create(const char *name
,
543 const device_unit
*unit_address
,
546 /* create the descriptor */
547 hw_disk_device
*hw_disk
= ZALLOC(hw_disk_device
);
552 const device_descriptor hw_disk_device_descriptor
[] = {
553 { "disk", hw_disk_create
, &hw_disk_callbacks
},
554 { "cdrom", hw_disk_create
, &hw_disk_callbacks
},
555 { "floppy", hw_disk_create
, &hw_disk_callbacks
},
559 #endif /* _HW_DISK_C_ */