Commit | Line | Data |
---|---|---|
8477437c MM |
1 | /* This file is part of the program psim. |
2 | ||
3 | Copyright (C) 1994-1996, Andrew Cagney <cagney@highland.com.au> | |
4 | ||
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. | |
9 | ||
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. | |
14 | ||
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. | |
18 | ||
19 | */ | |
20 | ||
21 | ||
22 | #ifndef _HW_DISK_C_ | |
23 | #define _HW_DISK_C_ | |
24 | ||
25 | #include "device_table.h" | |
26 | ||
27 | #include "pk.h" | |
28 | ||
29 | #include <stdio.h> | |
30 | ||
31 | ||
32 | /* DEVICE | |
33 | ||
34 | cdrom - readable block device | |
35 | ||
36 | disk - readable block device that should be writeable | |
37 | ||
38 | floppy - readable block device that should be writeable | |
39 | ||
40 | DESCRIPTION | |
41 | ||
42 | Block I/O devices that model the behavour of a fixed or removable | |
43 | disk device. | |
44 | ||
45 | Creating an instance of this device with no arguments will provide | |
46 | access to primative read/write operators. If arguments are | |
47 | specified then the disk-label package is used to perform abstract | |
48 | disk I/O. The disk-label package will then use this devices | |
49 | primatives. | |
50 | ||
51 | For hardware I/O, this device would normally be attached to a | |
52 | parent `bus' and that bus would use the I/O methods to read and | |
53 | write raw data. The bus might actually be a SCSI or IDE device. | |
54 | It is assumed that the parent bus can take care of DMA. | |
55 | ||
56 | PROPERTIES | |
57 | ||
58 | reg = <address> (required) | |
59 | ||
60 | <address> is parent bus dependant. | |
61 | ||
62 | device_type = "block" | |
63 | ||
64 | name = "disk" | "cdrom" | "fd" | |
65 | ||
66 | file = <file-name> (required) | |
67 | ||
68 | The name of the file that contains the disk image. | |
69 | ||
70 | */ | |
71 | ||
72 | typedef struct _hw_disk_device { | |
73 | const char *name; | |
74 | int read_only; | |
75 | unsigned_word size; | |
76 | FILE *image; | |
77 | } hw_disk_device; | |
78 | ||
79 | typedef struct _hw_disk_instance { | |
80 | long pos; | |
81 | hw_disk_device *disk; | |
82 | } hw_disk_instance; | |
83 | ||
84 | ||
85 | static void | |
86 | hw_disk_init_address(device *me) | |
87 | { | |
88 | hw_disk_device *disk = device_data(me); | |
89 | generic_device_init_address(me); | |
90 | if (disk->image != NULL) | |
91 | fclose(disk->image); | |
92 | disk->name = device_find_string_property(me, "file"); | |
93 | if (strcmp(device_name(me), "disk") == 0) { | |
94 | disk->read_only = 0; | |
95 | disk->image = fopen(disk->name, "r+"); | |
96 | } | |
97 | else { | |
98 | disk->read_only = 1; | |
99 | disk->image = fopen(disk->name, "r"); | |
100 | } | |
101 | if (disk->image == NULL) { | |
102 | perror(device_name(me)); | |
103 | device_error(me, "open %s failed\n", disk->name); | |
104 | } | |
105 | } | |
106 | ||
107 | static unsigned | |
108 | hw_disk_io_read_buffer(device *me, | |
109 | void *dest, | |
110 | int space, | |
111 | unsigned_word addr, | |
112 | unsigned nr_bytes, | |
113 | cpu *processor, | |
114 | unsigned_word cia) | |
115 | { | |
116 | hw_disk_device *disk = device_data(me); | |
117 | if (nr_bytes == 0) | |
118 | return 0; | |
119 | if (addr + nr_bytes > disk->size) | |
120 | return 0; | |
121 | if (fseek(disk->image, addr, SEEK_SET) < 0) | |
122 | return 0; | |
123 | if (fread(dest, nr_bytes, 1, disk->image) != 1) | |
124 | return 0; | |
125 | return nr_bytes; | |
126 | } | |
127 | ||
128 | ||
129 | static unsigned | |
130 | hw_disk_io_write_buffer(device *me, | |
131 | const void *source, | |
132 | int space, | |
133 | unsigned_word addr, | |
134 | unsigned nr_bytes, | |
135 | cpu *processor, | |
136 | unsigned_word cia) | |
137 | { | |
138 | hw_disk_device *disk = device_data(me); | |
139 | if (disk->read_only) | |
140 | return 0; | |
141 | if (nr_bytes == 0) | |
142 | return 0; | |
143 | if (addr + nr_bytes > disk->size) | |
144 | return 0; | |
145 | if (fseek(disk->image, addr, SEEK_SET) < 0) | |
146 | return 0; | |
147 | if (fwrite(source, nr_bytes, 1, disk->image) != 1) | |
148 | return 0; | |
149 | return nr_bytes; | |
150 | } | |
151 | ||
152 | ||
153 | /* instances of the hw_disk device */ | |
154 | ||
155 | static void | |
156 | hw_disk_instance_delete(device_instance *instance) | |
157 | { | |
158 | hw_disk_instance *data = device_instance_data(instance); | |
159 | zfree(data); | |
160 | } | |
161 | ||
162 | static int | |
163 | hw_disk_instance_read(device_instance *instance, | |
164 | void *buf, | |
165 | unsigned_word len) | |
166 | { | |
167 | hw_disk_instance *data = device_instance_data(instance); | |
168 | if (fseek(data->disk->image, data->pos, SEEK_SET) < 0) | |
169 | return -1; | |
170 | if (fread(buf, len, 1, data->disk->image) != 1) | |
171 | return -1; | |
172 | data->pos = ftell(data->disk->image); | |
173 | return len; | |
174 | } | |
175 | ||
176 | static int | |
177 | hw_disk_instance_write(device_instance *instance, | |
178 | const void *buf, | |
179 | unsigned_word len) | |
180 | { | |
181 | hw_disk_instance *data = device_instance_data(instance); | |
182 | if (data->disk->read_only) | |
183 | return -1; | |
184 | if (fseek(data->disk->image, data->pos, SEEK_SET) < 0) | |
185 | return -1; | |
186 | if (fwrite(buf, len, 1, data->disk->image) != 1) | |
187 | return -1; | |
188 | data->pos = ftell(data->disk->image); | |
189 | return len; | |
190 | } | |
191 | ||
192 | static int | |
193 | hw_disk_instance_seek(device_instance *instance, | |
194 | unsigned_word pos_hi, | |
195 | unsigned_word pos_lo) | |
196 | { | |
197 | hw_disk_instance *data = device_instance_data(instance); | |
198 | data->pos = pos_lo; | |
199 | return 0; | |
200 | } | |
201 | ||
202 | static const device_instance_callbacks hw_disk_instance_callbacks = { | |
203 | hw_disk_instance_delete, | |
204 | hw_disk_instance_read, | |
205 | hw_disk_instance_write, | |
206 | hw_disk_instance_seek, | |
207 | }; | |
208 | ||
209 | static device_instance * | |
210 | hw_disk_create_instance(device *me, | |
211 | const char *path, | |
212 | const char *args) | |
213 | { | |
214 | device_instance *disk_instance; | |
215 | hw_disk_device *disk = device_data(me); | |
216 | hw_disk_instance *data = ZALLOC(hw_disk_instance); | |
217 | data->disk = disk; | |
218 | data->pos = 0; | |
219 | disk_instance = device_create_instance_from(me, NULL, | |
220 | data, | |
221 | path, args, | |
222 | &hw_disk_instance_callbacks); | |
223 | return pk_disklabel_create_instance(disk_instance, args); | |
224 | } | |
225 | ||
226 | static device_callbacks const hw_disk_callbacks = { | |
227 | { hw_disk_init_address, NULL }, | |
228 | { NULL, }, /* address */ | |
229 | { hw_disk_io_read_buffer, | |
230 | hw_disk_io_write_buffer, }, | |
231 | { NULL, }, /* DMA */ | |
232 | { NULL, }, /* interrupt */ | |
233 | { NULL, }, /* unit */ | |
234 | hw_disk_create_instance, | |
235 | }; | |
236 | ||
237 | ||
238 | static void * | |
239 | hw_disk_create(const char *name, | |
240 | const device_unit *unit_address, | |
241 | const char *args, | |
242 | device *parent) | |
243 | { | |
244 | /* create the descriptor */ | |
245 | hw_disk_device *hw_disk = ZALLOC(hw_disk_device); | |
246 | return hw_disk; | |
247 | } | |
248 | ||
249 | ||
250 | const device_descriptor hw_disk_device_descriptor[] = { | |
251 | { "disk", hw_disk_create, &hw_disk_callbacks }, | |
252 | { NULL }, | |
253 | }; | |
254 | ||
255 | #endif /* _HW_DISK_C_ */ |