summaryrefslogtreecommitdiffstatshomepage
path: root/trunk/src/lib/formats/imd_dsk.c
diff options
context:
space:
mode:
Diffstat (limited to 'trunk/src/lib/formats/imd_dsk.c')
-rw-r--r--trunk/src/lib/formats/imd_dsk.c275
1 files changed, 275 insertions, 0 deletions
diff --git a/trunk/src/lib/formats/imd_dsk.c b/trunk/src/lib/formats/imd_dsk.c
new file mode 100644
index 00000000000..5ae14faad92
--- /dev/null
+++ b/trunk/src/lib/formats/imd_dsk.c
@@ -0,0 +1,275 @@
+/*********************************************************************
+
+ formats/imd_dsk.c
+
+ IMD disk images
+
+*********************************************************************/
+
+#include <string.h>
+#include "flopimg.h"
+
+struct imddsk_tag
+{
+ int heads;
+ int tracks;
+ int sector_size;
+ UINT64 track_offsets[84*2]; /* offset within data for each track */
+};
+
+
+static struct imddsk_tag *get_tag(floppy_image_legacy *floppy)
+{
+ struct imddsk_tag *tag;
+ tag = (imddsk_tag *)floppy_tag(floppy);
+ return tag;
+}
+
+
+
+FLOPPY_IDENTIFY( imd_dsk_identify )
+{
+ UINT8 header[3];
+
+ floppy_image_read(floppy, header, 0, 3);
+ if (header[0]=='I' && header[1]=='M' && header[2]=='D') {
+ *vote = 100;
+ } else {
+ *vote = 0;
+ }
+ return FLOPPY_ERROR_SUCCESS;
+}
+
+static int imd_get_heads_per_disk(floppy_image_legacy *floppy)
+{
+ return get_tag(floppy)->heads;
+}
+
+static int imd_get_tracks_per_disk(floppy_image_legacy *floppy)
+{
+ return get_tag(floppy)->tracks;
+}
+
+static UINT64 imd_get_track_offset(floppy_image_legacy *floppy, int head, int track)
+{
+ return get_tag(floppy)->track_offsets[(track<<1) + head];
+}
+
+static floperr_t get_offset(floppy_image_legacy *floppy, int head, int track, int sector, int sector_is_index, UINT64 *offset)
+{
+ UINT64 offs = 0;
+ UINT8 header[5];
+ UINT8 sector_num;
+ int i;
+
+
+ if ((head < 0) || (head >= get_tag(floppy)->heads) || (track < 0) || (track >= get_tag(floppy)->tracks)
+ || (sector < 0) )
+ return FLOPPY_ERROR_SEEKERROR;
+
+ offs = imd_get_track_offset(floppy,head,track);
+ floppy_image_read(floppy, header, offs, 5);
+
+ sector_num = header[3];
+ offs += 5 + sector_num; // skip header and sector numbering map
+ if(header[2] & 0x80) offs += sector_num; // skip cylinder numbering map
+ if(header[2] & 0x40) offs += sector_num; // skip head numbering map
+ get_tag(floppy)->sector_size = 1 << (header[4] + 7);
+ for(i=0;i<sector;i++) {
+ floppy_image_read(floppy, header, offs, 1); // take sector data type
+ switch(header[0]) {
+ case 0: offs++; break;
+ case 1:
+ case 3:
+ case 5:
+ case 7: offs += get_tag(floppy)->sector_size + 1; break;
+ default: offs += 2;
+ }
+ }
+ if (offset)
+ *offset = offs;
+ return FLOPPY_ERROR_SUCCESS;
+}
+
+
+
+static floperr_t internal_imd_read_sector(floppy_image_legacy *floppy, int head, int track, int sector, int sector_is_index, void *buffer, size_t buflen)
+{
+ UINT64 offset;
+ floperr_t err;
+ UINT8 header[1];
+
+ // take sector offset
+ err = get_offset(floppy, head, track, sector, sector_is_index, &offset);
+ if (err)
+ return err;
+
+ floppy_image_read(floppy, header, offset, 1);
+ switch(header[0]) {
+ case 0: break;
+ case 1:
+ case 3:
+ case 5:
+ case 7:
+ floppy_image_read(floppy, buffer, offset+1, buflen);
+ break;
+
+ default: // all data same
+ floppy_image_read(floppy, header, offset+1, 1);
+ memset(buffer,header[0],buflen);
+ break;
+ }
+
+ return FLOPPY_ERROR_SUCCESS;
+}
+
+
+static floperr_t imd_read_sector(floppy_image_legacy *floppy, int head, int track, int sector, void *buffer, size_t buflen)
+{
+ return internal_imd_read_sector(floppy, head, track, sector, FALSE, buffer, buflen);
+}
+
+static floperr_t imd_read_indexed_sector(floppy_image_legacy *floppy, int head, int track, int sector, void *buffer, size_t buflen)
+{
+ return internal_imd_read_sector(floppy, head, track, sector, TRUE, buffer, buflen);
+}
+
+static floperr_t imd_get_sector_length(floppy_image_legacy *floppy, int head, int track, int sector, UINT32 *sector_length)
+{
+ floperr_t err;
+ err = get_offset(floppy, head, track, sector, FALSE, NULL);
+ if (err)
+ return err;
+
+ if (sector_length) {
+ *sector_length = get_tag(floppy)->sector_size;
+ }
+ return FLOPPY_ERROR_SUCCESS;
+}
+
+static floperr_t imd_get_indexed_sector_info(floppy_image_legacy *floppy, int head, int track, int sector_index, int *cylinder, int *side, int *sector, UINT32 *sector_length, unsigned long *flags)
+{
+ UINT64 offset;
+ UINT8 header[5];
+ UINT8 hd;
+ UINT8 tr;
+ UINT32 sector_size;
+ UINT8 sector_num;
+
+ offset = imd_get_track_offset(floppy,head,track);
+ floppy_image_read(floppy, header, offset, 5);
+ tr = header[1];
+ hd = header[2];
+ sector_num = header[3];
+ sector_size = 1 << (header[4] + 7);
+ if (sector_index >= sector_num) return FLOPPY_ERROR_SEEKERROR;
+ if (cylinder) {
+ if (head & 0x80) {
+ floppy_image_read(floppy, header, offset + 5 + sector_num+ sector_index, 1);
+ *cylinder = header[0];
+ } else {
+ *cylinder = tr;
+ }
+ }
+ if (side) {
+ if (head & 0x40) {
+ if (head & 0x80) {
+ floppy_image_read(floppy, header, offset + 5 + 2 * sector_num+sector_index, 1);
+ } else {
+ floppy_image_read(floppy, header, offset + 5 + sector_num+sector_index, 1);
+ }
+ *side = header[0];
+ } else {
+ *side = hd & 1;
+ }
+ }
+ if (sector) {
+ floppy_image_read(floppy, header, offset + 5 + sector_index, 1);
+ *sector = header[0];
+ }
+ if (sector_length) {
+ *sector_length = sector_size;
+ }
+ if (flags) {
+ UINT8 skip;
+ if (head & 0x40) {
+ if (head & 0x80) {
+ skip = 3;
+ } else {
+ skip = 2;
+ }
+ } else {
+ skip = 1;
+ }
+ floppy_image_read(floppy, header, offset + 5 + skip * sector_num, 1);
+ *flags = 0;
+ if ((header[0]-1) & 0x02) *flags |= ID_FLAG_DELETED_DATA;
+ if ((header[0]-1) & 0x04) *flags |= ID_FLAG_CRC_ERROR_IN_DATA_FIELD;
+ }
+ return FLOPPY_ERROR_SUCCESS;
+}
+
+
+FLOPPY_CONSTRUCT( imd_dsk_construct )
+{
+ struct FloppyCallbacks *callbacks;
+ struct imddsk_tag *tag;
+ UINT8 header[0x100];
+ UINT64 pos = 0;
+ int sector_size = 0;
+ int sector_num;
+ int i;
+ if(params)
+ {
+ // create
+ return FLOPPY_ERROR_UNSUPPORTED;
+ }
+
+ tag = (struct imddsk_tag *) floppy_create_tag(floppy, sizeof(struct imddsk_tag));
+ if (!tag)
+ return FLOPPY_ERROR_OUTOFMEMORY;
+
+ floppy_image_read(floppy, header, pos, 1);
+ while(header[0]!=0x1a) {
+ pos++;
+ floppy_image_read(floppy, header, pos, 1);
+ }
+ pos++;
+ tag->tracks = 0;
+ tag->heads = 1;
+ do {
+ floppy_image_read(floppy, header, pos, 5);
+ if ((header[2] & 1)==1) tag->heads = 2;
+ tag->track_offsets[(header[1]<<1) + (header[2] & 1)] = pos;
+ sector_num = header[3];
+ pos += 5 + sector_num; // skip header and sector numbering map
+ if(header[2] & 0x80) pos += sector_num; // skip cylinder numbering map
+ if(header[2] & 0x40) pos += sector_num; // skip head numbering map
+ sector_size = 1 << (header[4] + 7);
+ for(i=0;i<sector_num;i++) {
+ floppy_image_read(floppy, header, pos, 1); // take sector data type
+ switch(header[0]) {
+ case 0: pos++; break;
+ case 1:
+ case 3:
+ case 5:
+ case 7: pos += sector_size + 1; break;
+ default: pos += 2;break;
+ }
+ }
+ tag->tracks += 1;
+ } while(pos < floppy_image_size(floppy));
+ if (tag->heads==2) {
+ tag->tracks = tag->tracks / 2;
+ }
+ callbacks = floppy_callbacks(floppy);
+ callbacks->read_sector = imd_read_sector;
+ callbacks->read_indexed_sector = imd_read_indexed_sector;
+ callbacks->get_sector_length = imd_get_sector_length;
+ callbacks->get_heads_per_disk = imd_get_heads_per_disk;
+ callbacks->get_tracks_per_disk = imd_get_tracks_per_disk;
+ callbacks->get_indexed_sector_info = imd_get_indexed_sector_info;
+
+ return FLOPPY_ERROR_SUCCESS;
+}
+