Ejemplo n.º 1
0
/*
    FIXME: partition support
*/
int vdrive_bam_alloc_first_free_sector(vdrive_t *vdrive,
                                       unsigned int *track,
                                       unsigned int *sector)
{
    unsigned int s, d, max_tracks;
    int t;

    max_tracks = vdrive_calculate_disk_half(vdrive);

    for (d = 0; d <= max_tracks; d++) {
        int max_sector;
        t = vdrive->Bam_Track - d;
#ifdef DEBUG_DRIVE
        log_error(LOG_ERR, "Allocate first free sector on track %d.", t);
#endif
        if (d && t >= 1) {
            max_sector = vdrive_get_max_sectors(vdrive, t);
            for (s = 0; s < (unsigned int)max_sector; s++) {
                if (vdrive_bam_allocate_sector(vdrive, t, s)) {
                    *track = t;
                    *sector = s;
#ifdef DEBUG_DRIVE
                    log_error(LOG_ERR,
                              "Allocate first free sector: %d,%d.", t, s);
#endif
                    return 0;
                }
            }
        }
        t = vdrive->Bam_Track + d;
#ifdef DEBUG_DRIVE
        log_error(LOG_ERR, "Allocate first free sector on track %d.", t);
#endif
        if (t <= (int)(vdrive->num_tracks)) {
            max_sector = vdrive_get_max_sectors(vdrive, t);
            if (d) {
                s = 0;
            } else if (vdrive->image_format == VDRIVE_IMAGE_FORMAT_4000) {
                s = 64; /* after root directory */
            } else {
                s = max_sector; /* skip bam track */
            }
            for (; s < (unsigned int)max_sector; s++) {
                if (vdrive_bam_allocate_sector(vdrive, t, s)) {
                    *track = t;
                    *sector = s;
#ifdef DEBUG_DRIVE
                    log_error(LOG_ERR,
                              "Allocate first free sector: %d,%d.", t, s);
#endif
                    return 0;
                }
            }
        }
    }
    return -1;
}
Ejemplo n.º 2
0
int vdrive_bam_allocate_chain(vdrive_t *vdrive, unsigned int t, unsigned int s)
{
    BYTE tmp[256];
    int rc;

    while (t) {
        /* Check for illegal track or sector.  */
        if (disk_image_check_sector(vdrive->image, t, s) < 0) {
            vdrive_command_set_error(vdrive, CBMDOS_IPE_ILLEGAL_TRACK_OR_SECTOR,
                                     s, t);
            return CBMDOS_IPE_ILLEGAL_TRACK_OR_SECTOR;
        }
        if (!vdrive_bam_allocate_sector(vdrive, t, s)) {
            /* The real drive does not seem to catch this error.  */
            vdrive_command_set_error(vdrive, CBMDOS_IPE_NO_BLOCK, s, t);
            return CBMDOS_IPE_NO_BLOCK;
        }
        rc = vdrive_read_sector(vdrive, tmp, t, s);
        if (rc > 0) {
            return rc;
        }
        if (rc < 0) {
            return CBMDOS_IPE_NOT_READY;
        }

        t = (int)tmp[0];
        s = (int)tmp[1];
    }
    return CBMDOS_IPE_OK;
}
Ejemplo n.º 3
0
static int vdrive_bam_alloc_up(vdrive_t *vdrive,
                               unsigned int *track, unsigned int *sector)
{
    unsigned int max_sector, t, s;

    for (t = *track; t <= vdrive->num_tracks; t++) {
        max_sector = vdrive_get_max_sectors(vdrive, t);
        for (s = 0; s < max_sector; s++) {
            if (vdrive_bam_allocate_sector(vdrive, t, s)) {
                *track = t;
                *sector = s;
                return 0;
            }
        }
    }
    return -1;
}
Ejemplo n.º 4
0
/* Returns NULL if the allocation failed.               */
static BYTE *find_next_directory_sector(vdrive_t *vdrive, unsigned int track,
                                        unsigned int sector)
{
    if (vdrive_bam_allocate_sector(vdrive->image_format, vdrive->bam, track,
        sector)) {
        vdrive->Dir_buffer[0] = track;
        vdrive->Dir_buffer[1] = sector;
        disk_image_write_sector(vdrive->image, vdrive->Dir_buffer,
                                vdrive->Curr_track, vdrive->Curr_sector);
#ifdef DEBUG_DRIVE
        log_debug("Found (%d %d) TR = %d SE = %d.",
                  track, sector, vdrive->Curr_track, vdrive->Curr_sector);
#endif
        vdrive->SlotNumber = 0;
        memset(vdrive->Dir_buffer, 0, 256);
        vdrive->Dir_buffer[1] = 0xff;
        vdrive->Curr_sector = sector;
        return vdrive->Dir_buffer;
    }
    return NULL;
}
Ejemplo n.º 5
0
/* Returns NULL if the allocation failed.               */
static BYTE *find_next_directory_sector(vdrive_dir_context_t *dir, unsigned int track,
                                        unsigned int sector)
{
    vdrive_t *vdrive = dir->vdrive;

    if (vdrive_bam_allocate_sector(vdrive, track, sector)) {
        dir->buffer[0] = track;
        dir->buffer[1] = sector;
        vdrive_write_sector(vdrive, dir->buffer, dir->track, dir->sector);
#ifdef DEBUG_DRIVE
        log_debug("Found (%d %d) TR = %d SE = %d.",
                  track, sector, dir->track, dir->sector);
#endif
        dir->slot = 0;
        memset(dir->buffer, 0, 256);
        dir->buffer[1] = 0xff;
        dir->track = track;
        dir->sector = sector;
        return dir->buffer;
    }
    return NULL;
}
Ejemplo n.º 6
0
/*
    FIXME: partition support
*/
int vdrive_bam_alloc_next_free_sector(vdrive_t *vdrive,
                                      unsigned int *track,
                                      unsigned int *sector)
{
    unsigned int max_sector, i, t, s;

    if (*track == vdrive->Bam_Track) {
        if (vdrive->image_format != VDRIVE_IMAGE_FORMAT_4000 || *sector < 64) {
            return -1;
        }
    }

    /* Calculate the next sector for the current interleave */
    s = *sector + vdrive_bam_get_interleave(vdrive->image_format);
    t = *track;
    max_sector = vdrive_get_max_sectors(vdrive, t);
    if (s >= max_sector) {
        s -= max_sector;
        if (s != 0) {
            s--;
        }
    }
    /* Look for a sector on the same track */
    for (i = 0; i < max_sector; i++) {
        if (vdrive->image_format == VDRIVE_IMAGE_FORMAT_4000 && *track == vdrive->Bam_Track && s < 64) {
            s = 64;
        }
        if (vdrive_bam_allocate_sector(vdrive, t, s)) {
            *track = t;
            *sector = s;
            return 0;
        }
        s++;
        if (s >= max_sector) {
            s = 0;
        }
    }
    if (vdrive->image_format == VDRIVE_IMAGE_FORMAT_4000 && *track == vdrive->Bam_Track) {
        (*track)++;
    }

    /* Look for a sector on a close track */
    *sector = 0;
    if (*track < vdrive->Dir_Track) {
        if (vdrive_bam_alloc_down(vdrive, track, sector) == 0) {
            return 0;
        }
        *track = vdrive->Dir_Track - 1;
        if (vdrive_bam_alloc_down(vdrive, track, sector) == 0) {
            return 0;
        }
        *track = vdrive->Dir_Track + 1;
        if (vdrive_bam_alloc_up(vdrive, track, sector) == 0) {
            return 0;
        }
    } else {
        if (vdrive_bam_alloc_up(vdrive, track, sector) == 0) {
            return 0;
        }
        *track = vdrive->Dir_Track + 1;
        if (vdrive_bam_alloc_up(vdrive, track, sector) == 0) {
            return 0;
        }
        *track = vdrive->Dir_Track - 1;
        if (vdrive_bam_alloc_down(vdrive, track, sector) == 0) {
            return 0;
        }
    }
    return -1;
}
Ejemplo n.º 7
0
/*
    FIXME: partition support
 */
int vdrive_command_validate(vdrive_t *vdrive)
{
    unsigned int t, s;
    int status, max_sector;
    BYTE *b, oldbam[BAM_MAXSIZE];

    status = vdrive_command_initialize(vdrive);

    if (status != CBMDOS_IPE_OK)
        return status;
    if (vdrive->image->read_only || VDRIVE_IMAGE_FORMAT_4000_TEST)
        return CBMDOS_IPE_WRITE_PROTECT_ON;

    memcpy(oldbam, vdrive->bam, vdrive->bam_size);

    vdrive_bam_clear_all(vdrive->image_format, vdrive->bam);

    for (t = 1; t <= vdrive->num_tracks; t++) {
        max_sector = vdrive_get_max_sectors(vdrive, t);
        for (s = 0; s < (unsigned int)max_sector; s++) {
            vdrive_bam_free_sector(vdrive->image_format, vdrive->bam, t, s);
        }
    }

    /* First, map out the header (BAM) and the directory, themselves. */
    status = vdrive_bam_allocate_chain(vdrive, vdrive->Bam_Track,
                                       vdrive->Bam_Sector);

    if (status != CBMDOS_IPE_OK) {
        memcpy(vdrive->bam, oldbam, vdrive->bam_size);
        return status;
    }

    switch (vdrive->image_format) {
    case VDRIVE_IMAGE_FORMAT_1571:
        /* Map the opposite side of the directory cylinder. */
        max_sector = vdrive_get_max_sectors(vdrive, 53);
        for (s = 0; s < (unsigned int)max_sector; s++) {
            vdrive_bam_allocate_sector(vdrive->image_format, vdrive->bam, 53, s);
        }
        break;
    case VDRIVE_IMAGE_FORMAT_1581:
        /* Map the BAM sectors. */
        vdrive_bam_allocate_sector(vdrive->image_format, vdrive->bam,
                                   vdrive->Bam_Track, vdrive->Bam_Sector + 1);
        vdrive_bam_allocate_sector(vdrive->image_format, vdrive->bam,
                                   vdrive->Bam_Track, vdrive->Bam_Sector + 2);
        break;
    case VDRIVE_IMAGE_FORMAT_4000:
        /* Map the boot sector. */
        vdrive_bam_allocate_sector(vdrive->image_format, vdrive->bam, 1, 0);

        /* Map the BAM sectors. */
        for (s = 2; s < 34; s++)
            vdrive_bam_allocate_sector(vdrive->image_format, vdrive->bam, 1, s);
        break;
    }

    vdrive_dir_find_first_slot(vdrive, "*", 1, 0);

    while ((b = vdrive_dir_find_next_slot(vdrive))) {
        char *filetype = (char *)
        &vdrive->Dir_buffer[vdrive->SlotNumber * 32 + SLOT_TYPE_OFFSET];

        if (*filetype & CBMDOS_FT_CLOSED) {
            status = vdrive_bam_allocate_chain(vdrive, b[SLOT_FIRST_TRACK],
                                               b[SLOT_FIRST_SECTOR]);
            if (status != CBMDOS_IPE_OK) {
                memcpy(vdrive->bam, oldbam, vdrive->bam_size);
                return status;
            }
            /* The real drive always validates side sectors even if the file
               type is not REL.  */
            status = vdrive_bam_allocate_chain(vdrive, b[SLOT_SIDE_TRACK],
                                               b[SLOT_SIDE_SECTOR]);
            if (status != CBMDOS_IPE_OK) {
                memcpy(vdrive->bam, oldbam, vdrive->bam_size);
                return status;
            }
        } else {
            /* Delete an unclosed file. */
            *filetype = CBMDOS_FT_DEL;
            if (vdrive_write_sector(vdrive, vdrive->Dir_buffer,
                vdrive->Curr_track, vdrive->Curr_sector) < 0)
                return CBMDOS_IPE_WRITE_ERROR_VER;
        }
    }

    /* Write back BAM only if validate was successful.  */
    vdrive_bam_write_bam(vdrive);
    return status;
}
Ejemplo n.º 8
0
static int vdrive_command_block(vdrive_t *vdrive, unsigned char command,
                                char *buffer)
{
    int channel = 0, drive = 0, track = 0, sector = 0, position = 0;
    int l, rc;

#ifdef DEBUG_DRIVE
    log_debug("vdrive_command_block command:%c.", command);
#endif

    switch (command) {
      /* 1581 has u-R (shifted) and u-W (shifted) for block read/write
         without track/sector checking. */
      /* Use this for U1,UA and U2,UB also */
      case 0xd2:
      case 0xd7:
        l = vdrive_get_block_parameters(buffer, &channel, &drive, &track,
                                        &sector);

        if (l < 0) {
#ifdef DEBUG_DRIVE
            log_debug("b-R/W parsed OK. (l=%d) channel %d mode %d, "
                      "drive=%d, track=%d sector=%d.", l, channel,
                      vdrive->buffers[channel].mode, drive, track, sector);
#endif

            if (vdrive->buffers[channel].mode != BUFFER_MEMORY_BUFFER)
                return CBMDOS_IPE_NO_CHANNEL;

            if (command == 0xd7) {
                /* For write */
                if (vdrive->image->read_only || VDRIVE_IMAGE_FORMAT_4000_TEST)
                    return CBMDOS_IPE_WRITE_PROTECT_ON;
                if (vdrive_write_sector(vdrive, vdrive->buffers[channel].buffer,
                                            track, sector) < 0)
                    return CBMDOS_IPE_NOT_READY;
            } else {
                /* For read */
                rc = vdrive_read_sector(vdrive, vdrive->buffers[channel].buffer,
                                            track, sector);
                if (rc > 0)
                    return rc;
                if (rc < 0)
                    return CBMDOS_IPE_NOT_READY;
            }
            vdrive->buffers[channel].bufptr = 0;
        } else {
            log_error(vdrive_command_log, "b-R/W invalid parameter "
                      "C:%i D:%i T:%i S:%i.", channel, drive, track, sector);
            return l;
        }
        break;
      /* Old-style B-R and B-W */
      case 'R':
      case 'W':
        l = vdrive_get_block_parameters(buffer, &channel, &drive, &track,
                                        &sector);

        if (l < 0) {
#ifdef DEBUG_DRIVE
            log_debug("b-r/w parsed OK. (l=%d) channel %d mode %d, "
                      "drive=%d, track=%d sector=%d.", l, channel,
                      vdrive->buffers[channel].mode, drive, track, sector);
#endif

            if (vdrive->buffers[channel].mode != BUFFER_MEMORY_BUFFER)
                return CBMDOS_IPE_NO_CHANNEL;

            if (command == 'W') {
                /* For write */
                if (vdrive->image->read_only || VDRIVE_IMAGE_FORMAT_4000_TEST)
                    return CBMDOS_IPE_WRITE_PROTECT_ON;
                /* Update length of block based on the buffer pointer. */
                l = vdrive->buffers[channel].bufptr - 1;
                vdrive->buffers[channel].buffer[0] = ( l < 1 ? 1 : l );
                if (vdrive_write_sector(vdrive, vdrive->buffers[channel].buffer,
                                            track, sector) < 0)
                    return CBMDOS_IPE_NOT_READY;
                /* after write, buffer pointer is 1. */
                vdrive->buffers[channel].bufptr = 1;
            } else {
                /* For read */
                rc = vdrive_read_sector(vdrive, vdrive->buffers[channel].buffer,
                                            track, sector);
                /* set buffer length base on first value */
                vdrive->buffers[channel].length =
                    vdrive->buffers[channel].buffer[0] + 1;
                /* buffer pointer is 1, not 0. */
                vdrive->buffers[channel].bufptr = 1;
                if (rc > 0)
                    return rc;
                if (rc < 0)
                    return CBMDOS_IPE_NOT_READY;
            }
        } else {
            log_error(vdrive_command_log, "b-r/w invalid parameter "
                      "C:%i D:%i T:%i S:%i.", channel, drive, track, sector);
            return l;
        }
        break;
      case 'A':
      case 'F':
        l = vdrive_get_block_parameters(buffer, &drive, &track, &sector,
                                        &channel);
        if (l > 0) /* just 3 args used */
            return l;
        if (command == 'A') {
            if (!vdrive_bam_allocate_sector(vdrive->image_format, vdrive->bam,
                track, sector)) {
                /*
                 * Desired sector not free. Suggest another. XXX The 1541
                 * uses an inferior search function that only looks on
                 * higher tracks and can return sectors in the directory
                 * track.
                 */
                if (vdrive_bam_alloc_next_free_sector(vdrive, vdrive->bam,
                    (unsigned int*)&track, (unsigned int *)&sector) >= 0) {
                    /* Deallocate it and merely suggest it */
                    vdrive_bam_free_sector(vdrive->image_format, vdrive->bam,
                                           track, sector);
                } else {
                    /* Found none */
                    track = 0;
                    sector = 0;
                }
                vdrive_command_set_error(vdrive, CBMDOS_IPE_NO_BLOCK, track,
                                         sector);
                return CBMDOS_IPE_NO_BLOCK;
            }
        } else {
            vdrive_bam_free_sector(vdrive->image_format, vdrive->bam,
                                   track, sector);
        }
        break;
      case 'P':
        l = vdrive_get_block_parameters(buffer, &channel, &position, &track,
                                        &sector);
        if (l > 0) /* just 2 args used */
            return l;
        if (vdrive->buffers[channel].mode != BUFFER_MEMORY_BUFFER)
            return CBMDOS_IPE_NO_CHANNEL;
        vdrive->buffers[channel].bufptr = position;
        break;
      case 'E':
        l = vdrive_get_block_parameters(buffer, &channel, &drive, &track, &sector);
        log_warning(vdrive_command_log, "B-E: %d %d %d %d (needs TDE)", channel, drive, track, sector);
        break;
      default:
        return CBMDOS_IPE_INVAL;
    }
    return CBMDOS_IPE_OK;
}