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, &sectors, &sectorbytes) != 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