1 /* disk.h: Routines for handling disk images
2 Copyright (c) 2007-2015 Gergely Szasz
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License along
15 with this program; if not, write to the Free Software Foundation, Inc.,
16 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 Author contact information:
20 Philip: philip-fuse@shadowmagic.org.uk
30 static const unsigned int DISK_FLAG_NONE
= 0x00;
31 static const unsigned int DISK_FLAG_PLUS3_CPC
= 0x01; /* try to fix some CPC issue */
32 static const unsigned int DISK_FLAG_OPEN_DS
= 0x02; /* try to open the other side too */
35 typedef enum disk_error_t
{
47 // for sector reading API
59 typedef enum disk_type_t
{
61 DISK_UDI
, /* raw track disk image (our format :-) */
62 DISK_FDI
, /* Full Disk Image ALT */
65 /* DISCiPLE / +D / SAM Coupe */
67 DISK_IMG
, /* OUT-OUT */
68 DISK_SAD
, /* OUT-OUT with geometry header */
73 /* Beta disk interface (TR-DOS) */
84 /* Log disk structure (.log) */
91 typedef enum disk_dens_t
{
93 DISK_8_SD
, /* 8" SD floppy 5208 MF */
94 DISK_8_DD
, /* 8" DD floppy 10416 */
95 DISK_SD
, /* 3125 bpt MF */
96 DISK_DD
, /* 6250 bpt */
97 DISK_DD_PLUS
, /* 6500 bpt e.g. Coin Op Hits */
98 DISK_HD
, /* 12500 bpt*/
102 typedef struct disk_t
{
103 char *filename
; /* original filename */
104 int sides
; /* 1 or 2 */
105 int cylinders
; /* tracks per side */
106 int bpt
; /* bytes per track */
107 int wrprot
; /* disk write protect */
108 int dirty
; /* disk changed */
109 int have_weak
; /* disk contain weak sectors */
111 disk_error_t status
; /* last error code */
112 uint8_t *data
; /* disk data */
114 int tlen
; /* length of a track with clock and other marks (bpt + 3/8bpt) */
115 uint8_t *track
; /* current track data bytes */
116 uint8_t *clocks
; /* clock marks bits */
117 uint8_t *fm
; /* FM/MFM marks bits */
118 uint8_t *weak
; /* weak marks bits/weak data */
119 int i
; /* index for track and clocks */
120 disk_type_t type
; /* DISK_UDI, ... */
121 disk_dens_t density
; /* DISK_SD DISK_DD, or DISK_HD */
126 TRACK_LEN TYPE TRACK......DATA CLOCK..MARKS MF..MARKS WEAK..MARKS
128 |__ track |__ clocks |__ mf |__ weak
130 TLEN = track[-3] + tarck 256 * track[-2]
131 TYPE is Track type as in UDI spec (0x00, 0x01, 0x02, 0x80, 0x81, 0x82) after update_tracks_mode() !!!
134 #define DISK_CLEN(bpt) ((bpt)/8+((bpt)%8 ? 1 : 0))
136 #define DISK_SET_TRACK_IDX(d, idx) do { \
137 d->track = d->data+3+(idx)*d->tlen; \
138 d->clocks = d->track+d->bpt; \
139 d->fm = d->clocks+DISK_CLEN(d->bpt); \
140 d->weak = d->fm+DISK_CLEN(d->bpt); \
143 #define DISK_SET_TRACK(d, head, cyl) do { \
144 DISK_SET_TRACK_IDX((d), (d)->sides*cyl+head); \
148 // you need to save and restore disk position when manipulating disk data
149 // this is because FDC is using the position too, and if you will break it,
150 // disk i/o operations will read/write invalid data
152 uint8_t *track
; /* current track data bytes */
153 uint8_t *clocks
; /* clock marks bits */
154 uint8_t *fm
; /* FM/MFM marks bits */
155 uint8_t *weak
; /* weak marks bits/weak data */
156 int i
; /* index for track and clocks */
160 static inline __attribute__((unused
))
161 void disk_position_save (const disk_t
*d
, disk_position_t
*c
) {
163 c
->clocks
= d
->clocks
;
169 static inline __attribute__((unused
))
170 void disk_position_restore (disk_t
*d
, const disk_position_t
*c
) {
172 d
->clocks
= c
->clocks
;
179 /* insert simple TR-DOS autoloader? */
180 extern int opt_beta_autoload
; /* default is 1 */
183 const char *disk_strerror (int error
);
185 /* create an unformatted disk sides -> (1/2) cylinders -> track/side,
186 dens -> 'density' related to unformatted length of a track (SD = 3125,
187 DD = 6250, HD = 12500, type -> if write this disk we want to convert
188 into this type of image file
190 int disk_new (disk_t
*d
, int sides
, int cylinders
, disk_dens_t dens
, disk_type_t type
);
192 /* detects some common disk image formats */
193 disk_type_t
disk_detect_format (const void *data
, int size
);
195 /* open a disk image file. if preindex = 1 and the image file not UDI then
196 pre-index gap generated with index mark (0xfc)
197 this time only .mgt(.dsk)/.img/.udi and CPC/extended CPC file format
200 int disk_open (disk_t
*d
, const char *filename
, int preindex
);
202 // returns error code
203 int disk_open_buf_udi (disk_t
*d
, const void *data
, int size
);
204 int disk_open_buf_fdi (disk_t
*d
, const void *data
, int size
);
205 int disk_open_buf_trd (disk_t
*d
, const void *data
, int size
);
206 int disk_open_buf_scl (disk_t
*d
, const void *data
, int size
);
207 int disk_open_buf_td0 (disk_t
*d
, const void *data
, int size
);
208 int disk_open_buf_dsk (disk_t
*d
, const void *data
, int size
);
211 /* merge two one sided disk (d1, d2) to a two sided one (d),
212 after merge closes d1 and d2
214 int disk_merge_sides (disk_t
*d
, disk_t
*d1
, disk_t
*d2
, int autofill
);
216 /* write a disk image file (from the disk buffer). the d->type
217 gives the format of file. if it DISK_TYPE_AUTO, disk_write
218 try to guess from the file name (extension). if fail save as
221 int disk_write (disk_t
*d
, const char *filename
);
223 /* format disk to plus3 accept for formatting
225 int disk_preformat (disk_t
*d
);
227 /* close a disk and free buffers
229 void disk_close (disk_t
*d
);
233 // returns error code (DISK_xxx)
234 // automatically saves and restores disk position
235 // doesn't change `d->status`
236 int disk_read_sector (disk_t
*d
, int head
, int cylinder
, int sector
,
237 void *buf
, size_t bufsize
, int *sectorsize
);
245 // returns error code (DISK_xxx)
246 // automatically saves and restores disk position
247 // doesn't change `d->status`
248 int disk_write_sector (disk_t
*d
, int head
, int cylinder
, int sector
,
249 const void *buf
, size_t bufsize
, int type
/*DISK_WR_xxx*/);
251 // frees old disk data, creates new, sets `d->status`
252 // doesn't write TR-DOS directory, the disk is filled with zeroes
253 int disk_format_beta (disk_t
*d
, int cylinders
, int interleave
);