1 // license:BSD-3-Clause
2 // copyright-holders:Aaron Giles
3 /***************************************************************************
4
5 hardisk.c
6
7 Generic MAME hard disk implementation, with differencing files
8
9 ***************************************************************************/
10
11 #include <cassert>
12 #include "harddisk.h"
13 #include "osdcore.h"
14 #include <cstdlib>
15
16 /***************************************************************************
17 TYPE DEFINITIONS
18 ***************************************************************************/
19
20 struct hard_disk_file
21 {
22 chd_file * chd; /* CHD file */
23 util::core_file *fhandle; /* core_file if not a CHD */
24 hard_disk_info info; /* hard disk info */
25 };
26
27
28
29 /***************************************************************************
30 CORE IMPLEMENTATION
31 ***************************************************************************/
32
33 /*-------------------------------------------------
34 hard_disk_open - open a hard disk handle,
35 given a chd_file
36 -------------------------------------------------*/
37
hard_disk_open(chd_file * chd)38 hard_disk_file *hard_disk_open(chd_file *chd)
39 {
40 int cylinders, heads, sectors, sectorbytes;
41 hard_disk_file *file;
42 std::string metadata;
43 chd_error err;
44
45 /* punt if no CHD */
46 if (chd == nullptr)
47 return nullptr;
48
49 /* read the hard disk metadata */
50 err = chd->read_metadata(HARD_DISK_METADATA_TAG, 0, metadata);
51 if (err != CHDERR_NONE)
52 return nullptr;
53
54 /* parse the metadata */
55 if (sscanf(metadata.c_str(), HARD_DISK_METADATA_FORMAT, &cylinders, &heads, §ors, §orbytes) != 4)
56 return nullptr;
57
58 /* allocate memory for the hard disk file */
59 file = (hard_disk_file *)malloc(sizeof(hard_disk_file));
60 if (file == nullptr)
61 return nullptr;
62
63 /* fill in the data */
64 file->chd = chd;
65 file->fhandle = nullptr;
66 file->info.cylinders = cylinders;
67 file->info.heads = heads;
68 file->info.sectors = sectors;
69 file->info.sectorbytes = sectorbytes;
70 file->info.fileoffset = 0;
71 return file;
72 }
73
hard_disk_open(util::core_file & corefile,uint32_t skipoffs)74 hard_disk_file *hard_disk_open(util::core_file &corefile, uint32_t skipoffs)
75 {
76 hard_disk_file *file;
77
78 /* allocate memory for the hard disk file */
79 file = (hard_disk_file *)malloc(sizeof(hard_disk_file));
80 if (file == nullptr)
81 return nullptr;
82
83 file->chd = nullptr;
84 file->fhandle = &corefile;
85 file->info.sectorbytes = 512;
86 file->info.cylinders = 0;
87 file->info.heads = 0;
88 file->info.sectors = 0;
89 file->info.fileoffset = skipoffs;
90
91 // attempt to guess geometry in case this is an ATA situation
92 for (uint32_t totalsectors = (corefile.size() - skipoffs) / file->info.sectorbytes; ; totalsectors++)
93 for (uint32_t cursectors = 63; cursectors > 1; cursectors--)
94 if (totalsectors % cursectors == 0)
95 {
96 uint32_t totalheads = totalsectors / cursectors;
97 for (uint32_t curheads = 16; curheads > 1; curheads--)
98 if (totalheads % curheads == 0)
99 {
100 file->info.cylinders = totalheads / curheads;
101 file->info.heads = curheads;
102 file->info.sectors = cursectors;
103 osd_printf_verbose("Guessed CHS of %d/%d/%d\n", file->info.cylinders, file->info.heads, file->info.sectors);
104 return file;
105 }
106 }
107
108 return file;
109 }
110
111
112 /*-------------------------------------------------
113 hard_disk_close - close a hard disk handle
114 -------------------------------------------------*/
115
hard_disk_close(hard_disk_file * file)116 void hard_disk_close(hard_disk_file *file)
117 {
118 if (file->fhandle)
119 {
120 file->fhandle->flush();
121 }
122
123 free(file);
124 }
125
126
127 /*-------------------------------------------------
128 hard_disk_get_chd - get a handle to a CHD
129 from a hard disk
130 -------------------------------------------------*/
131
hard_disk_get_chd(hard_disk_file * file)132 chd_file *hard_disk_get_chd(hard_disk_file *file)
133 {
134 return file->chd;
135 }
136
137
138 /*-------------------------------------------------
139 hard_disk_get_info - return information about
140 a hard disk
141 -------------------------------------------------*/
142
143 /**
144 * @fn hard_disk_info *hard_disk_get_info(hard_disk_file *file)
145 *
146 * @brief Hard disk get information.
147 *
148 * @param [in,out] file If non-null, the file.
149 *
150 * @return null if it fails, else a hard_disk_info*.
151 */
152
hard_disk_get_info(hard_disk_file * file)153 hard_disk_info *hard_disk_get_info(hard_disk_file *file)
154 {
155 return &file->info;
156 }
157
158
159 /*-------------------------------------------------
160 hard_disk_read - read sectors from a hard
161 disk
162 -------------------------------------------------*/
163
164 /**
165 * @fn uint32_t hard_disk_read(hard_disk_file *file, uint32_t lbasector, void *buffer)
166 *
167 * @brief Hard disk read.
168 *
169 * @param [in,out] file If non-null, the file.
170 * @param lbasector The lbasector.
171 * @param [in,out] buffer If non-null, the buffer.
172 *
173 * @return An uint32_t.
174 */
175
hard_disk_read(hard_disk_file * file,uint32_t lbasector,void * buffer)176 uint32_t hard_disk_read(hard_disk_file *file, uint32_t lbasector, void *buffer)
177 {
178 if (file->chd)
179 {
180 chd_error err = file->chd->read_units(lbasector, buffer);
181 return (err == CHDERR_NONE);
182 }
183 else
184 {
185 uint32_t actual = 0;
186 file->fhandle->seek(file->info.fileoffset + (lbasector * file->info.sectorbytes), SEEK_SET);
187 actual = file->fhandle->read(buffer, file->info.sectorbytes);
188 return (actual == file->info.sectorbytes);
189 }
190 }
191
192
193 /*-------------------------------------------------
194 hard_disk_write - write sectors to a hard
195 disk
196 -------------------------------------------------*/
197
198 /**
199 * @fn uint32_t hard_disk_write(hard_disk_file *file, uint32_t lbasector, const void *buffer)
200 *
201 * @brief Hard disk write.
202 *
203 * @param [in,out] file If non-null, the file.
204 * @param lbasector The lbasector.
205 * @param buffer The buffer.
206 *
207 * @return An uint32_t.
208 */
209
hard_disk_write(hard_disk_file * file,uint32_t lbasector,const void * buffer)210 uint32_t hard_disk_write(hard_disk_file *file, uint32_t lbasector, const void *buffer)
211 {
212 if (file->chd)
213 {
214 chd_error err = file->chd->write_units(lbasector, buffer);
215 return (err == CHDERR_NONE);
216 }
217 else
218 {
219 uint32_t actual = 0;
220 file->fhandle->seek(file->info.fileoffset + (lbasector * file->info.sectorbytes), SEEK_SET);
221 actual = file->fhandle->write(buffer, file->info.sectorbytes);
222 return (actual == file->info.sectorbytes);
223 }
224 }
225