--- trunk/src/diskimage.c 2007/10/08 16:17:48 2 +++ trunk/src/diskimage.c 2007/10/08 16:19:56 24 @@ -1,5 +1,5 @@ /* - * Copyright (C) 2003-2005 Anders Gavare. All rights reserved. + * Copyright (C) 2003-2006 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -25,7 +25,7 @@ * SUCH DAMAGE. * * - * $Id: diskimage.c,v 1.81 2005/04/04 21:50:05 debug Exp $ + * $Id: diskimage.c,v 1.109 2006/05/06 08:42:48 debug Exp $ * * Disk image support. * @@ -36,10 +36,8 @@ * that return feof (which results in a filemark). This is probably * trivial to fix, but I don't feel like it right now. * - * TODO: Non-SCSI disk images? - * - * TODO: diskimage_remove() ? - * Actually test diskimage_access() to see that it works. + * TODO: diskimage_remove()? This would be useful for floppies in PC-style + * machines, where disks may need to be swapped during boot etc. */ #include @@ -55,9 +53,11 @@ #include "misc.h" -extern int quiet_mode; +/* #define debug fatal */ + extern int single_step; +static char *diskimage_types[] = DISKIMAGE_TYPES; static struct scsi_transfer *first_free_scsi_transfer_alloc = NULL; @@ -209,14 +209,15 @@ /* * diskimage_exist(): * - * Returns 1 if the specified SCSI id exists, 0 otherwise. + * Returns 1 if the specified disk id (for a specific type) exists, 0 + * otherwise. */ -int diskimage_exist(struct machine *machine, int scsi_id) +int diskimage_exist(struct machine *machine, int id, int type) { struct diskimage *d = machine->first_diskimage; while (d != NULL) { - if (d->type == DISKIMAGE_SCSI && d->id == scsi_id) + if (d->type == type && d->id == id) return 1; d = d->next; } @@ -256,21 +257,24 @@ d->total_size = size; d->ncyls = d->total_size / 1048576; + + /* TODO: There is a mismatch between d->ncyls and d->cylinders, + SCSI-based stuff usually doesn't care. TODO: Fix this. */ } /* * diskimage_getsize(): * - * Returns -1 if the specified SCSI id does not exists, otherwise + * Returns -1 if the specified disk id/type does not exists, otherwise * the size of the disk image is returned. */ -int64_t diskimage_getsize(struct machine *machine, int scsi_id) +int64_t diskimage_getsize(struct machine *machine, int id, int type) { struct diskimage *d = machine->first_diskimage; while (d != NULL) { - if (d->type == DISKIMAGE_SCSI && d->id == scsi_id) + if (d->type == type && d->id == id) return d->total_size; d = d->next; } @@ -279,6 +283,31 @@ /* + * diskimage_getchs(): + * + * Returns the current CHS values of a disk image. + */ +void diskimage_getchs(struct machine *machine, int id, int type, + int *c, int *h, int *s) +{ + struct diskimage *d = machine->first_diskimage; + + while (d != NULL) { + if (d->type == type && d->id == id) { + *c = d->cylinders; + *h = d->heads; + *s = d->sectors_per_track; + return; + } + d = d->next; + } + fatal("diskimage_getchs(): disk id %i (type %i) not found?\n", + id, diskimage_types[type]); + exit(1); +} + + +/* * diskimage__return_default_status_and_message(): * * Set the status and msg_in parts of a scsi_transfer struct @@ -381,7 +410,7 @@ static int diskimage__internal_access(struct diskimage *d, int writeflag, off_t offset, unsigned char *buf, size_t len) { - size_t lendone; + ssize_t lendone; int res; if (buf == NULL) { @@ -447,10 +476,11 @@ * 1 if otherwise ok, * 0 on error. */ -int diskimage_scsicommand(struct cpu *cpu, int scsi_id, +int diskimage_scsicommand(struct cpu *cpu, int id, int type, struct scsi_transfer *xferp) { - int retlen, i; + char namebuf[16]; + int retlen, i, q; uint64_t size; int64_t ofs; int pagecode; @@ -464,13 +494,13 @@ d = machine->first_diskimage; while (d != NULL) { - if (d->type == DISKIMAGE_SCSI && d->id == scsi_id) + if (d->type == type && d->id == id) break; d = d->next; } if (d == NULL) { - fprintf(stderr, "[ diskimage_scsicommand(): SCSI disk" - " with id %i not connected? ]\n", scsi_id); + fprintf(stderr, "[ diskimage_scsicommand(): %s " + " id %i not connected? ]\n", diskimage_types[type], id); } if (xferp->cmd == NULL) { @@ -485,11 +515,11 @@ } debug("[ diskimage_scsicommand(id=%i) cmd=0x%02x: ", - scsi_id, xferp->cmd[0]); + id, xferp->cmd[0]); #if 0 fatal("[ diskimage_scsicommand(id=%i) cmd=0x%02x len=%i:", - scsi_id, xferp->cmd[0], xferp->cmd_len); + id, xferp->cmd[0], xferp->cmd_len); for (i=0; icmd_len; i++) fatal(" %02x", xferp->cmd[i]); fatal("\n"); @@ -504,7 +534,7 @@ f = fopen("scsi_log.txt", "w"); if (f != NULL) { int i; - fprintf(f, "id=%i cmd =", scsi_id); + fprintf(f, "id=%i cmd =", id); for (i=0; icmd_len; i++) fprintf(f, " %02x", xferp->cmd[i]); fprintf(f, "\n"); @@ -560,17 +590,29 @@ xferp->data_in[6] = 0x04; /* ACKREQQ */ xferp->data_in[7] = 0x60; /* WBus32, WBus16 */ - /* These must be padded with spaces: */ - memcpy(xferp->data_in+8, "FAKE ", 8); - memcpy(xferp->data_in+16, "DISK ", 16); - memcpy(xferp->data_in+32, "V0.0", 4); + /* These are padded with spaces: */ + + memcpy(xferp->data_in+8, "GXemul ", 8); + if (diskimage_getname(cpu->machine, id, + type, namebuf, sizeof(namebuf))) { + size_t i; + for (i=0; idata_in+16, namebuf, 16); + } else + memcpy(xferp->data_in+16, "DISK ", 16); + memcpy(xferp->data_in+32, "0 ", 4); /* * Some Ultrix kernels want specific responses from * the drives. */ - if (machine->machine_type == MACHINE_DEC) { + if (machine->machine_type == MACHINE_PMAX) { /* DEC, RZ25 (rev 0900) = 832527 sectors */ /* DEC, RZ58 (rev 2000) = 2698061 sectors */ memcpy(xferp->data_in+8, "DEC ", 8); @@ -582,9 +624,9 @@ if (d->is_a_cdrom) { xferp->data_in[0] = 0x05; /* 0x05 = CD-ROM */ xferp->data_in[1] = 0x80; /* 0x80 = removable */ - memcpy(xferp->data_in+16, "CD-ROM ", 16); + /* memcpy(xferp->data_in+16, "CD-ROM ", 16);*/ - if (machine->machine_type == MACHINE_DEC) { + if (machine->machine_type == MACHINE_PMAX) { /* SONY, CD-ROM: */ memcpy(xferp->data_in+8, "SONY ", 8); memcpy(xferp->data_in+16, @@ -595,7 +637,7 @@ memcpy(xferp->data_in+16, "RRD42 (C) DEC ", 16); memcpy(xferp->data_in+32, "4.5d", 4); - } else { + } else if (machine->machine_type == MACHINE_ARC) { /* NEC, CD-ROM: */ memcpy(xferp->data_in+8, "NEC ", 8); memcpy(xferp->data_in+16, @@ -610,7 +652,7 @@ xferp->data_in[1] = 0x80; /* 0x80 = removable */ memcpy(xferp->data_in+16, "TAPE ", 16); - if (machine->machine_type == MACHINE_DEC) { + if (machine->machine_type == MACHINE_PMAX) { /* * TODO: find out if these are correct. * @@ -665,13 +707,17 @@ break; case SCSICMD_MODE_SENSE: + case SCSICMD_MODE_SENSE10: debug("MODE_SENSE"); - - if (xferp->cmd_len != 6) - fatal(" (unimplemented mode_sense len=%i)", + q = 4; retlen = xferp->cmd[4]; + switch (xferp->cmd_len) { + case 6: break; + case 10:q = 8; + retlen = xferp->cmd[7] * 256 + xferp->cmd[8]; + break; + default:fatal(" (unimplemented mode_sense len=%i)", xferp->cmd_len); - - retlen = xferp->cmd[4]; + } /* * NOTE/TODO: This code doesn't handle too short retlens @@ -694,7 +740,7 @@ pagecode = xferp->cmd[2] & 0x3f; - debug("[ MODE SENSE id %i, pagecode=%i ]\n", scsi_id, pagecode); + debug("[ MODE SENSE id %i, pagecode=%i ]\n", id, pagecode); /* 4 bytes of header for 6-byte command, 8 bytes of header for 10-byte command. */ @@ -706,15 +752,15 @@ xferp->data_in[3] = 8 * 1; /* block descriptor length: 1 page (?) */ - /* TODO: update this when implementing 10-byte commands: */ - xferp->data_in[4] = 0x00; /* density code */ - xferp->data_in[5] = 0; /* nr of blocks, high */ - xferp->data_in[6] = 0; /* nr of blocks, mid */ - xferp->data_in[7] = 0; /* nr of blocks, low */ - xferp->data_in[8] = 0x00; /* reserved */ - xferp->data_in[9] = (d->logical_block_size >> 16) & 255; - xferp->data_in[10] = (d->logical_block_size >> 8) & 255; - xferp->data_in[11] = d->logical_block_size & 255; + xferp->data_in[q+0] = 0x00; /* density code */ + xferp->data_in[q+1] = 0; /* nr of blocks, high */ + xferp->data_in[q+2] = 0; /* nr of blocks, mid */ + xferp->data_in[q+3] = 0; /* nr of blocks, low */ + xferp->data_in[q+4] = 0x00; /* reserved */ + xferp->data_in[q+5] = (d->logical_block_size >> 16) & 255; + xferp->data_in[q+6] = (d->logical_block_size >> 8) & 255; + xferp->data_in[q+7] = d->logical_block_size & 255; + q += 8; diskimage__return_default_status_and_message(xferp); @@ -726,54 +772,54 @@ /* TODO: Nothing here? */ break; case 1: /* read-write error recovery page */ - xferp->data_in[12 + 0] = pagecode; - xferp->data_in[12 + 1] = 10; + xferp->data_in[q + 0] = pagecode; + xferp->data_in[q + 1] = 10; break; case 3: /* format device page */ - xferp->data_in[12 + 0] = pagecode; - xferp->data_in[12 + 1] = 22; + xferp->data_in[q + 0] = pagecode; + xferp->data_in[q + 1] = 22; /* 10,11 = sectors per track */ - xferp->data_in[12 + 10] = 0; - xferp->data_in[12 + 11] = 1; /* TODO */ + xferp->data_in[q + 10] = 0; + xferp->data_in[q + 11] = d->sectors_per_track; /* 12,13 = physical sector size */ - xferp->data_in[12 + 12] = + xferp->data_in[q + 12] = (d->logical_block_size >> 8) & 255; - xferp->data_in[12 + 13] = d->logical_block_size & 255; + xferp->data_in[q + 13] = d->logical_block_size & 255; break; case 4: /* rigid disk geometry page */ - xferp->data_in[12 + 0] = pagecode; - xferp->data_in[12 + 1] = 22; - xferp->data_in[12 + 2] = (d->ncyls >> 16) & 255; - xferp->data_in[12 + 3] = (d->ncyls >> 8) & 255; - xferp->data_in[12 + 4] = d->ncyls & 255; - xferp->data_in[12 + 5] = 15; /* nr of heads */ + xferp->data_in[q + 0] = pagecode; + xferp->data_in[q + 1] = 22; + xferp->data_in[q + 2] = (d->ncyls >> 16) & 255; + xferp->data_in[q + 3] = (d->ncyls >> 8) & 255; + xferp->data_in[q + 4] = d->ncyls & 255; + xferp->data_in[q + 5] = d->heads; - xferp->data_in[12 + 20] = (d->rpms >> 8) & 255; - xferp->data_in[12 + 21] = d->rpms & 255; + xferp->data_in[q + 20] = (d->rpms >> 8) & 255; + xferp->data_in[q + 21] = d->rpms & 255; break; case 5: /* flexible disk page */ - xferp->data_in[12 + 0] = pagecode; - xferp->data_in[12 + 1] = 0x1e; + xferp->data_in[q + 0] = pagecode; + xferp->data_in[q + 1] = 0x1e; /* 2,3 = transfer rate */ - xferp->data_in[12 + 2] = ((5000) >> 8) & 255; - xferp->data_in[12 + 3] = (5000) & 255; + xferp->data_in[q + 2] = ((5000) >> 8) & 255; + xferp->data_in[q + 3] = (5000) & 255; - xferp->data_in[12 + 4] = 2; /* nr of heads */ - xferp->data_in[12 + 5] = 18; /* sectors per track */ + xferp->data_in[q + 4] = d->heads; + xferp->data_in[q + 5] = d->sectors_per_track; /* 6,7 = data bytes per sector */ - xferp->data_in[12 + 6] = (d->logical_block_size >> 8) + xferp->data_in[q + 6] = (d->logical_block_size >> 8) & 255; - xferp->data_in[12 + 7] = d->logical_block_size & 255; + xferp->data_in[q + 7] = d->logical_block_size & 255; - xferp->data_in[12 + 8] = (d->ncyls >> 8) & 255; - xferp->data_in[12 + 9] = d->ncyls & 255; + xferp->data_in[q + 8] = (d->ncyls >> 8) & 255; + xferp->data_in[q + 9] = d->ncyls & 255; - xferp->data_in[12 + 28] = (d->rpms >> 8) & 255; - xferp->data_in[12 + 29] = d->rpms & 255; + xferp->data_in[q + 28] = (d->rpms >> 8) & 255; + xferp->data_in[q + 29] = d->rpms & 255; break; default: fatal("[ MODE_SENSE for page %i is not yet " @@ -819,7 +865,7 @@ ofs = d->tape_offset; fatal("[ READ tape, id=%i file=%i, cmd[1]=%02x size=%i" - ", ofs=%lli ]\n", scsi_id, d->tape_filenr, + ", ofs=%lli ]\n", id, d->tape_filenr, xferp->cmd[1], (int)size, (long long)ofs); } else { if (xferp->cmd[0] == SCSICMD_READ) { @@ -851,9 +897,9 @@ * blocks to transfer. (NOTE: If the value is * 0, this means 0, not 65536. :-) */ - ofs = (xferp->cmd[2] << 24) + (xferp->cmd[3] - << 16) + (xferp->cmd[4] << 8) + - xferp->cmd[5]; + ofs = ((uint64_t)xferp->cmd[2] << 24) + + (xferp->cmd[3] << 16) + (xferp->cmd[4] << 8) + + xferp->cmd[5]; retlen = (xferp->cmd[7] << 8) + xferp->cmd[8]; } @@ -882,7 +928,7 @@ * be set to NO SENSE".. */ if (d->is_a_tape && d->f != NULL && feof(d->f)) { - debug(" feof id=%i\n", scsi_id); + debug(" feof id=%i\n", id); xferp->status[0] = 0x02; /* CHECK CONDITION */ d->filemark = 1; @@ -891,7 +937,7 @@ xferp->data_in, size); if (d->is_a_tape && d->f != NULL) - d->tape_offset = ftell(d->f); + d->tape_offset = ftello(d->f); /* TODO: other errors? */ break; @@ -929,8 +975,9 @@ * transfer. (NOTE: If the value is 0 this means 0, * not 65536.) */ - ofs = (xferp->cmd[2] << 24) + (xferp->cmd[3] << 16) + - (xferp->cmd[4] << 8) + xferp->cmd[5]; + ofs = ((uint64_t)xferp->cmd[2] << 24) + + (xferp->cmd[3] << 16) + (xferp->cmd[4] << 8) + + xferp->cmd[5]; retlen = (xferp->cmd[7] << 8) + xferp->cmd[8]; } @@ -978,7 +1025,7 @@ if (xferp->cmd_len != 6) debug(" (weird len=%i)", xferp->cmd_len); - for (i=0; icmd_len ; i++) + for (i=0; i<(ssize_t)xferp->cmd_len; i++) debug(" %02x", xferp->cmd[i]); /* TODO: actualy care about cmd[] */ @@ -1187,7 +1234,18 @@ scsi_transfer_allocbuf(&xferp->data_in_len, &xferp->data_in, retlen, 1); - /* TODO */ + xferp->data_in[0] = 0; + xferp->data_in[1] = 10; + xferp->data_in[2] = 0; /* First track. */ + xferp->data_in[3] = 0; /* Last track. */ + + /* Track 0 data: */ + xferp->data_in[4] = 0x00; /* Reserved. */ + xferp->data_in[5] = 0x04; /* ADR + CTRL: + Data, not audio */ + xferp->data_in[6] = 0x00; /* Track nr */ + xferp->data_in[7] = 0x00; /* Reserved */ + /* 8..11 = absolute CDROM address */ diskimage__return_default_status_and_message(xferp); break; @@ -1228,10 +1286,10 @@ } else { int i; fatal("[ unknown MODE_SELECT: cmd ="); - for (i=0; icmd_len; i++) + for (i=0; i<(ssize_t)xferp->cmd_len; i++) fatal(" %02x", xferp->cmd[i]); fatal(", data_out ="); - for (i=0; idata_out_len; i++) + for (i=0; i<(ssize_t)xferp->data_out_len; i++) fatal(" %02x", xferp->data_out[i]); fatal(" ]"); } @@ -1240,10 +1298,9 @@ diskimage__return_default_status_and_message(xferp); break; - case 0x1e: - debug("[ SCSI 0x%02x: TODO ]\n", xferp->cmd[0]); - - /* TODO */ + case SCSICMD_PREVENT_ALLOW_REMOVE: + debug("[ SCSI 0x%02x Prevent/allow medium removal: " + "TODO ]\n", xferp->cmd[0]); diskimage__return_default_status_and_message(xferp); break; @@ -1251,7 +1308,7 @@ case 0xbd: fatal("[ SCSI 0x%02x (len %i), TODO: ", xferp->cmd[0], xferp->cmd_len); - for (i=0; icmd_len; i++) + for (i=0; i<(ssize_t)xferp->cmd_len; i++) fatal(" %02x", xferp->cmd[i]); fatal(" ]\n"); @@ -1275,11 +1332,12 @@ &xferp->data_in, retlen, 1); diskimage__return_default_status_and_message(xferp); + break; default: fatal("[ UNIMPLEMENTED SCSI command 0x%02x, disk id=%i ]\n", - xferp->cmd[0], scsi_id); + xferp->cmd[0], id); exit(1); } debug(" ]\n"); @@ -1295,20 +1353,21 @@ * * Returns 1 if the access completed successfully, 0 otherwise. */ -int diskimage_access(struct machine *machine, int scsi_id, int writeflag, +int diskimage_access(struct machine *machine, int id, int type, int writeflag, off_t offset, unsigned char *buf, size_t len) { struct diskimage *d = machine->first_diskimage; while (d != NULL) { - if (d->type == DISKIMAGE_SCSI && d->id == scsi_id) + if (d->type == type && d->id == id) break; d = d->next; } if (d == NULL) { fatal("[ diskimage_access(): ERROR: trying to access a " - "non-existant SCSI disk image (%i)\n", scsi_id); + "non-existant %s disk image (id %i)\n", + diskimage_types[type], id); return 0; } @@ -1323,12 +1382,16 @@ * The filename may be prefixed with one or more modifiers, followed * by a colon. * - * b specifies that this is the boot device - * c CD-ROM (instead of normal SCSI DISK) - * d SCSI DISK (this is the default) + * b specifies that this is a bootable device + * c CD-ROM (instead of a normal DISK) + * d DISK (this is the default) + * f FLOPPY (instead of SCSI) + * gH;S; set geometry (H=heads, S=sectors per track, cylinders are + * automatically calculated). (This is ignored for floppies.) * i IDE (instead of SCSI) * r read-only (don't allow changes to the file) - * t SCSI tape + * s SCSI (this is the default) + * t tape * 0-7 force a specific SCSI ID number * * machine is assumed to be non-NULL. @@ -1337,15 +1400,11 @@ int diskimage_add(struct machine *machine, char *fname) { struct diskimage *d, *d2; - int id = 0; + int id = 0, override_heads=0, override_spt=0; + int64_t bytespercyl; char *cp; - int prefix_b = 0; - int prefix_c = 0; - int prefix_d = 0; - int prefix_i = 0; - int prefix_t = 0; - int prefix_id = -1; - int prefix_r = 0; + int prefix_b=0, prefix_c=0, prefix_d=0, prefix_f=0, prefix_g=0; + int prefix_i=0, prefix_r=0, prefix_s=0, prefix_t=0, prefix_id = -1; if (fname == NULL) { fprintf(stderr, "diskimage_add(): NULL ptr\n"); @@ -1377,15 +1436,42 @@ case 'd': prefix_d = 1; break; + case 'f': + prefix_f = 1; + break; + case 'g': + prefix_g = 1; + override_heads = atoi(fname); + while (*fname != '\0' && *fname != ';') + fname ++; + if (*fname == ';') + fname ++; + override_spt = atoi(fname); + while (*fname != '\0' && *fname != ';' && + *fname != ':') + fname ++; + if (*fname == ';') + fname ++; + if (override_heads < 1 || + override_spt < 1) { + fatal("Bad geometry: heads=%i " + "spt=%i\n", override_heads, + override_spt); + exit(1); + } + break; case 'i': prefix_i = 1; break; - case 't': - prefix_t = 1; - break; case 'r': prefix_r = 1; break; + case 's': + prefix_s = 1; + break; + case 't': + prefix_t = 1; + break; case ':': break; default: @@ -1396,39 +1482,6 @@ } } - /* Calculate which ID to use: */ - if (prefix_id == -1) { - int free = 0, collision = 1; - - while (collision) { - collision = 0; - d = machine->first_diskimage; - while (d != NULL) { - if (d->id == free) { - collision = 1; - break; - } - d = d->next; - } - if (!collision) - id = free; - else - free ++; - } - } else { - id = prefix_id; - - d = machine->first_diskimage; - while (d != NULL) { - if (d->id == id) { - fprintf(stderr, "disk image SCSI id %i " - "already in use\n", id); - exit(1); - } - d = d->next; - } - } - /* Allocate a new diskimage struct: */ d = malloc(sizeof(struct diskimage)); if (d == NULL) { @@ -1446,11 +1499,26 @@ d2->next = d; } - d->type = DISKIMAGE_SCSI; - d->id = id; + /* Default to IDE disks... */ + d->type = DISKIMAGE_IDE; + + /* ... but some machines use SCSI by default: */ + if (machine->machine_type == MACHINE_PMAX || + machine->machine_type == MACHINE_ARC) + d->type = DISKIMAGE_SCSI; + + if (prefix_i + prefix_f + prefix_s > 1) { + fprintf(stderr, "Invalid disk image prefix(es). You can" + "only use one of i, f, and s\nfor each disk image.\n"); + exit(1); + } if (prefix_i) d->type = DISKIMAGE_IDE; + if (prefix_f) + d->type = DISKIMAGE_FLOPPY; + if (prefix_s) + d->type = DISKIMAGE_SCSI; d->fname = strdup(fname); if (d->fname == NULL) { @@ -1464,14 +1532,15 @@ * Is this a tape, CD-ROM or a normal disk? * * An intelligent guess, if no prefixes are used, would be that - * filenames ending with .iso are CD-ROM images. + * filenames ending with .iso or .cdr are CD-ROM images. */ if (prefix_t) { d->is_a_tape = 1; } else { if (prefix_c || ((strlen(d->fname) > 4 && - strcasecmp(d->fname + strlen(d->fname) - 4, ".iso") == 0) + (strcasecmp(d->fname + strlen(d->fname) - 4, ".cdr") == 0 || + strcasecmp(d->fname + strlen(d->fname) - 4, ".iso") == 0)) && !prefix_d) ) { d->is_a_cdrom = 1; @@ -1489,7 +1558,7 @@ */ #if 0 - if (machine->machine_type == MACHINE_DEC) + if (machine->machine_type == MACHINE_PMAX) d->logical_block_size = 512; else d->logical_block_size = 2048; @@ -1500,6 +1569,36 @@ diskimage_recalc_size(d); + if ((d->total_size == 720*1024 || d->total_size == 1474560 + || d->total_size == 2949120 || d->total_size == 1228800) + && !prefix_i && !prefix_s) + d->type = DISKIMAGE_FLOPPY; + + switch (d->type) { + case DISKIMAGE_FLOPPY: + if (d->total_size < 737280) { + fatal("\nTODO: small (non-80-cylinder) floppies?\n\n"); + exit(1); + } + d->cylinders = 80; + d->heads = 2; + d->sectors_per_track = d->total_size / (d->cylinders * + d->heads * 512); + break; + default:/* Non-floppies: */ + d->heads = 16; + d->sectors_per_track = 63; + if (prefix_g) { + d->chs_override = 1; + d->heads = override_heads; + d->sectors_per_track = override_spt; + } + bytespercyl = d->heads * d->sectors_per_track * 512; + d->cylinders = d->total_size / bytespercyl; + if (d->cylinders * bytespercyl < d->total_size) + d->cylinders ++; + } + d->rpms = 3600; if (prefix_b) @@ -1516,6 +1615,50 @@ exit(1); } + /* Calculate which ID to use: */ + if (prefix_id == -1) { + int free = 0, collision = 1; + + while (collision) { + collision = 0; + d2 = machine->first_diskimage; + while (d2 != NULL) { + /* (don't compare against ourselves :) */ + if (d2 == d) { + d2 = d2->next; + continue; + } + if (d2->id == free && d2->type == d->type) { + collision = 1; + break; + } + d2 = d2->next; + } + if (!collision) + id = free; + else + free ++; + } + } else { + id = prefix_id; + d2 = machine->first_diskimage; + while (d2 != NULL) { + /* (don't compare against ourselves :) */ + if (d2 == d) { + d2 = d2->next; + continue; + } + if (d2->id == id && d2->type == d->type) { + fprintf(stderr, "disk image id %i " + "already in use\n", id); + exit(1); + } + d2 = d2->next; + } + } + + d->id = id; + return id; } @@ -1523,39 +1666,77 @@ /* * diskimage_bootdev(): * - * Returns the disk id (0..7) of the device which we're booting from. + * Returns the disk id of the device which we're booting from. If typep is + * non-NULL, the type is returned as well. * * If no disk was used as boot device, then -1 is returned. (In practice, * this is used to fake network (tftp) boot.) */ -int diskimage_bootdev(struct machine *machine) +int diskimage_bootdev(struct machine *machine, int *typep) { - struct diskimage *d = machine->first_diskimage; + struct diskimage *d; + + d = machine->first_diskimage; while (d != NULL) { - if (d->is_boot_device) + if (d->is_boot_device) { + if (typep != NULL) + *typep = d->type; return d->id; + } d = d->next; } d = machine->first_diskimage; - if (d != NULL) + if (d != NULL) { + if (typep != NULL) + *typep = d->type; return d->id; + } return -1; } /* + * diskimage_getname(): + * + * Returns 1 if a valid disk image name was returned, 0 otherwise. + */ +int diskimage_getname(struct machine *machine, int id, int type, + char *buf, size_t bufsize) +{ + struct diskimage *d = machine->first_diskimage; + + if (buf == NULL) + return 0; + + while (d != NULL) { + if (d->type == type && d->id == id) { + char *p = strrchr(d->fname, '/'); + if (p == NULL) + p = d->fname; + else + p ++; + snprintf(buf, bufsize, "%s", p); + return 1; + } + d = d->next; + } + return 0; +} + + +/* * diskimage_is_a_cdrom(): * - * Returns 1 if a disk image is a SCSI CDROM, 0 otherwise. + * Returns 1 if a disk image is a CDROM, 0 otherwise. */ -int diskimage_is_a_cdrom(struct machine *machine, int scsi_id) +int diskimage_is_a_cdrom(struct machine *machine, int id, int type) { struct diskimage *d = machine->first_diskimage; while (d != NULL) { - if (d->type == DISKIMAGE_SCSI && d->id == scsi_id) + if (d->type == type && d->id == id) return d->is_a_cdrom; d = d->next; } @@ -1566,16 +1747,17 @@ /* * diskimage_is_a_tape(): * - * Returns 1 if a disk image is a SCSI tape, 0 otherwise. + * Returns 1 if a disk image is a tape, 0 otherwise. + * * (Used in src/machine.c, to select 'rz' vs 'tz' for DECstation * boot strings.) */ -int diskimage_is_a_tape(struct machine *machine, int scsi_id) +int diskimage_is_a_tape(struct machine *machine, int id, int type) { struct diskimage *d = machine->first_diskimage; while (d != NULL) { - if (d->type == DISKIMAGE_SCSI && d->id == scsi_id) + if (d->type == type && d->id == id) return d->is_a_tape; d = d->next; } @@ -1590,7 +1772,7 @@ */ void diskimage_dump_info(struct machine *machine) { - int iadd=4; + int iadd = DEBUG_INDENTATION; struct diskimage *d = machine->first_diskimage; while (d != NULL) { @@ -1604,6 +1786,9 @@ case DISKIMAGE_IDE: debug("IDE"); break; + case DISKIMAGE_FLOPPY: + debug("FLOPPY"); + break; default: debug("UNKNOWN type %i", d->type); } @@ -1613,10 +1798,21 @@ debug(" id %i, ", d->id); debug("%s, ", d->writable? "read/write" : "read-only"); - debug("%lli MB (%lli sectors)%s\n", - (long long) (d->total_size / 1048576), - (long long) (d->total_size / 512), - d->is_boot_device? " (BOOT)" : ""); + if (d->type == DISKIMAGE_FLOPPY) + debug("%lli KB", (long long) (d->total_size / 1024)); + else + debug("%lli MB", (long long) (d->total_size / 1048576)); + + if (d->type == DISKIMAGE_FLOPPY || d->chs_override) + debug(" (CHS=%i,%i,%i)", d->cylinders, d->heads, + d->sectors_per_track); + else + debug(" (%lli sectors)", (long long) + (d->total_size / 512)); + + if (d->is_boot_device) + debug(" (BOOT)"); + debug("\n"); debug_indentation(-iadd);