/********************************************************************* formats/imd_dsk.c IMD disk images *********************************************************************/ #include #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;isector_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;itracks += 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; }