1 /***************************************************************************
2
3 Generic MAME hard disk implementation, with differencing files
4
5 ***************************************************************************/
6
7 #include "harddisk.h"
8
9
10
11 /*************************************
12 *
13 * Type definitions
14 *
15 *************************************/
16
17 struct hard_disk_file
18 {
19 struct chd_file * chd; /* CHD file */
20 struct hard_disk_info info; /* hard disk info */
21 UINT32 hunksectors; /* sectors per hunk */
22 UINT32 cachehunk; /* which hunk is cached */
23 UINT8 * cache; /* cache of the current hunk */
24 };
25
26
27
28 /*************************************
29 *
30 * Open a hard disk
31 *
32 *************************************/
33
hard_disk_open(struct chd_file * chd)34 struct hard_disk_file *hard_disk_open(struct chd_file *chd)
35 {
36 int cylinders, heads, sectors, sectorbytes;
37 struct hard_disk_file *file;
38 char metadata[256];
39 UINT32 metatag;
40 UINT32 count;
41
42 /* punt if no CHD */
43 if (!chd)
44 return NULL;
45
46 /* read the hard disk metadata */
47 metatag = HARD_DISK_STANDARD_METADATA;
48 count = chd_get_metadata(chd, &metatag, 0, metadata, sizeof(metadata));
49 if (count == 0)
50 return NULL;
51
52 /* parse the metadata */
53 if (sscanf(metadata, HARD_DISK_METADATA_FORMAT, &cylinders, &heads, §ors, §orbytes) != 4)
54 return NULL;
55
56 /* allocate memory for the hard disk file */
57 file = malloc(sizeof(struct hard_disk_file));
58 if (!file)
59 return NULL;
60
61 /* fill in the data */
62 file->chd = chd;
63 file->info.cylinders = cylinders;
64 file->info.heads = heads;
65 file->info.sectors = sectors;
66 file->info.sectorbytes = sectorbytes;
67 file->hunksectors = chd_get_header(chd)->hunkbytes / file->info.sectorbytes;
68 file->cachehunk = -1;
69
70 /* allocate a cache */
71 file->cache = malloc(chd_get_header(chd)->hunkbytes);
72 if (!file->cache)
73 {
74 free(file);
75 return NULL;
76 }
77
78 return file;
79 }
80
81
82
83 /*************************************
84 *
85 * Close a hard disk
86 *
87 *************************************/
88
hard_disk_close(struct hard_disk_file * file)89 void hard_disk_close(struct hard_disk_file *file)
90 {
91 /* free the cache */
92 if (file->cache)
93 free(file->cache);
94 free(file);
95 }
96
97
98
99 /*************************************
100 *
101 * Return the handle to the CHD
102 *
103 *************************************/
104
hard_disk_get_chd(struct hard_disk_file * file)105 struct chd_file *hard_disk_get_chd(struct hard_disk_file *file)
106 {
107 return file->chd;
108 }
109
110
111
112 /*************************************
113 *
114 * Return hard disk specific info
115 *
116 *************************************/
117
hard_disk_get_info(struct hard_disk_file * file)118 struct hard_disk_info *hard_disk_get_info(struct hard_disk_file *file)
119 {
120 return &file->info;
121 }
122
123
124
125 /*************************************
126 *
127 * Read from a hard disk
128 *
129 *************************************/
130
hard_disk_read(struct hard_disk_file * file,UINT32 lbasector,UINT32 numsectors,void * buffer)131 UINT32 hard_disk_read(struct hard_disk_file *file, UINT32 lbasector, UINT32 numsectors, void *buffer)
132 {
133 UINT32 hunknum = lbasector / file->hunksectors;
134 UINT32 sectoroffs = lbasector % file->hunksectors;
135
136 /* for now, just break down multisector reads into single sectors */
137 if (numsectors > 1)
138 {
139 UINT32 total = 0;
140 while (numsectors--)
141 {
142 if (hard_disk_read(file, lbasector++, 1, (UINT8 *)buffer + total * file->info.sectorbytes))
143 total++;
144 else
145 break;
146 }
147 return total;
148 }
149
150 /* if we haven't cached this hunk, read it now */
151 if (file->cachehunk != hunknum)
152 {
153 if (!chd_read(file->chd, hunknum, 1, file->cache))
154 return 0;
155 file->cachehunk = hunknum;
156 }
157
158 /* copy out the requested sector */
159 memcpy(buffer, &file->cache[sectoroffs * file->info.sectorbytes], file->info.sectorbytes);
160 return 1;
161 }
162
163
164
165 /*************************************
166 *
167 * Write to a hard disk
168 *
169 *************************************/
170
hard_disk_write(struct hard_disk_file * file,UINT32 lbasector,UINT32 numsectors,const void * buffer)171 UINT32 hard_disk_write(struct hard_disk_file *file, UINT32 lbasector, UINT32 numsectors, const void *buffer)
172 {
173 UINT32 hunknum = lbasector / file->hunksectors;
174 UINT32 sectoroffs = lbasector % file->hunksectors;
175
176 /* for now, just break down multisector writes into single sectors */
177 if (numsectors > 1)
178 {
179 UINT32 total = 0;
180 while (numsectors--)
181 {
182 if (hard_disk_write(file, lbasector++, 1, (const UINT8 *)buffer + total * file->info.sectorbytes))
183 total++;
184 else
185 break;
186 }
187 return total;
188 }
189
190 /* if we haven't cached this hunk, read it now */
191 if (file->cachehunk != hunknum)
192 {
193 if (!chd_read(file->chd, hunknum, 1, file->cache))
194 return 0;
195 file->cachehunk = hunknum;
196 }
197
198 /* copy in the requested data */
199 memcpy(&file->cache[sectoroffs * file->info.sectorbytes], buffer, file->info.sectorbytes);
200
201 /* write it back out */
202 if (chd_write(file->chd, hunknum, 1, file->cache))
203 return 1;
204 return 0;
205 }
206