コード例 #1
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;
}
コード例 #2
0
int vdrive_iec_close(vdrive_t *vdrive, unsigned int secondary)
{
    bufferinfo_t *p = &(vdrive->buffers[secondary]);
    int status = SERIAL_OK;

    switch (p->mode) {
        case BUFFER_NOT_IN_USE:
            return SERIAL_OK; /* FIXME: Is this correct? */

        case BUFFER_MEMORY_BUFFER:
        case BUFFER_DIRECTORY_READ:
            vdrive_free_buffer(p);
            p->slot = NULL;
            break;
        case BUFFER_SEQUENTIAL:
            status = iec_close_sequential(vdrive, secondary);
            break;
        case BUFFER_RELATIVE:
            status = vdrive_rel_close(vdrive, secondary);
            break;
        case BUFFER_COMMAND_CHANNEL:
            /* I'm not sure if this is correct, but really closing the buffer
               should reset the read pointer to the beginning for the next
               write! */
            vdrive_command_set_error(vdrive, CBMDOS_IPE_OK, 0, 0);
            /* this breaks any rel file access if the command channel is closed
                when the record is changed. Removed for now.*/
/*        vdrive_close_all_channels(vdrive); */
            break;
        default:
            log_error(vdrive_iec_log, "Fatal: unknown floppy-close-mode: %i.", p->mode);
    }

    return status;
}
コード例 #3
0
ファイル: vdrive-command.c プロジェクト: bobsummerwill/VICE
static int vdrive_command_scratch(vdrive_t *vdrive, BYTE *name, int length)
{
    int status, rc;
    BYTE *slot;
    cbmdos_cmd_parse_t cmd_parse;

    /* XXX
     * Wrong name parser -- s0:file1,0:file2 means scratch
     * those 2 files.  (It's similar to the copy command.)
     */

    cmd_parse.cmd = name;
    cmd_parse.cmdlength = length;
    cmd_parse.readmode = 0;

    rc = cbmdos_command_parse(&cmd_parse);

    if (rc != SERIAL_OK) {
        status = CBMDOS_IPE_NO_NAME;
    } else if (vdrive->image->read_only || VDRIVE_IMAGE_FORMAT_4000_TEST) {
        status = CBMDOS_IPE_WRITE_PROTECT_ON;
    } else {
/*#ifdef DEBUG_DRIVE*/
        log_debug("remove name='%s', len=%d (%d), type= %d.",
                  cmd_parse.parsecmd, cmd_parse.parselength,
                  length, cmd_parse.filetype);
/*#endif*/
        vdrive->deleted_files = 0;

        /* Since vdrive_dir_remove_slot() uses
         * vdrive_dir_find_first_slot() too, we cannot find the
         * matching files by simply repeating
         * vdrive_dir find_next_slot() calls alone; we have to re-call
         * vdrive_dir_find_first_slot() each time... EP 1996/04/07
         */

        vdrive_dir_find_first_slot(vdrive, cmd_parse.parsecmd,
                                   cmd_parse.parselength, 0);

        while ((slot = vdrive_dir_find_next_slot(vdrive))) {
            vdrive_dir_remove_slot(vdrive, slot);
            vdrive->deleted_files++;
            vdrive_dir_find_first_slot(vdrive, cmd_parse.parsecmd,
                                       cmd_parse.parselength, 0);
        }

        if (vdrive->deleted_files)
            status = CBMDOS_IPE_DELETED;
        else
            status = CBMDOS_IPE_NOT_FOUND;

        vdrive_command_set_error(vdrive, status, 1, 0);
    }

    lib_free(cmd_parse.parsecmd);

    return status;
}
コード例 #4
0
static int iec_close_sequential(vdrive_t *vdrive, unsigned int secondary)
{
    bufferinfo_t *p = &(vdrive->buffers[secondary]);
    unsigned int track = 0, sector = 0;

    if (p->readmode & (CBMDOS_FAM_WRITE | CBMDOS_FAM_APPEND)) {
        /*
         * Flush bytes and write slot to directory
         */

        if (vdrive->image->read_only || VDRIVE_IMAGE_FORMAT_4000_TEST) {
            vdrive_command_set_error(vdrive, CBMDOS_IPE_WRITE_PROTECT_ON, 0, 0);
            return SERIAL_ERROR;
        }

#ifdef DEBUG_DRIVE
        log_debug("DEBUG: flush.");
#endif
        /* Flush remained of file */
        iec_write_sequential(vdrive, p, p->bufptr);

        /* Set the file as closed */
        p->slot[SLOT_TYPE_OFFSET] |= 0x80; /* Closed */

        /* is this a save and replace? */
        if (p->needsupdate) {
            /* remember the original track and sector */
            track = p->slot[SLOT_FIRST_TRACK];
            sector = p->slot[SLOT_FIRST_SECTOR];
            /* move over the replacement track and sector */
            p->slot[SLOT_FIRST_TRACK] = p->slot[SLOT_REPLACE_TRACK];
            p->slot[SLOT_FIRST_SECTOR] = p->slot[SLOT_REPLACE_SECTOR];
            /* set replacement track and sector to 0 */
            p->slot[SLOT_REPLACE_TRACK] = 0;
            p->slot[SLOT_REPLACE_SECTOR] = 0;
        }

        /* Update the directory entry (block count, closed) */
        vdrive_iec_update_dirent(vdrive, secondary);

        /* if we have a track and sector saved */
        if (track) {
            /* remove the original file */
            vdrive_dir_free_chain(vdrive, track, sector);
        }

        /* Update BAM */
        vdrive_bam_write_bam(vdrive);

        /* Free up the slot */
        lib_free(p->slot);
    }
    /* Release buffers */
    vdrive_free_buffer(p);

    return SERIAL_OK;
}
コード例 #5
0
ファイル: vdrive-rel.c プロジェクト: twinaphex/vice-next
int vdrive_rel_open(vdrive_t *vdrive, unsigned int secondary,
                    cbmdos_cmd_parse_t *cmd_parse, const BYTE *name)
{
	bufferinfo_t *p = &(vdrive->buffers[secondary]);
	int newrelfile = 0;

	if (p->slot)
	{
		//log_debug("Open existing REL file '%s' with record length %i on channel %d.", name, cmd_parse->recordlength, secondary);
		/* Follow through to function. */
		vdrive_rel_open_existing(vdrive, secondary);
	}
	else
	{
		//log_debug("Open new REL file '%s' with record length %i on channel %d.", name, cmd_parse->recordlength, secondary);

		/* abort if we are in read only mode */
		if (vdrive->image->read_only) {
			vdrive_command_set_error(vdrive, CBMDOS_IPE_WRITE_PROTECT_ON, 0, 0);
			return SERIAL_ERROR;
		}

		/* Call function to open a new REL file, leave if error exists. */
		if (vdrive_rel_open_new(vdrive, secondary, cmd_parse, name)) {
			return SERIAL_ERROR;
		}
		/* set a flag so we can expand the rel file to 1 record later. */
		newrelfile++;
	}

	/* Allocate dual buffers to improve performance */
	p->mode = BUFFER_RELATIVE;
	p->bufptr = 0;
	p->buffer = lib_malloc(256);
	p->record = 0;
	p->track = 0;
	p->sector = 0;
	p->buffer_next = lib_malloc(256);
	p->track_next = 0;
	p->sector_next = 0;

	/* Determine maximum record */
	p->record_max = vdrive_rel_record_max(vdrive, secondary);

	/* If this is a new REL file, have atleast 1 record. */
	if (newrelfile) {
		vdrive_rel_grow(vdrive, secondary, 0);
	}

	/* Move to first record, no offset */
	vdrive_rel_position(vdrive, secondary, 1, 0, 1);

	return SERIAL_OK;
}
コード例 #6
0
ファイル: vdrive-command.c プロジェクト: bobsummerwill/VICE
/*
    CMD style subdir support (using DIR filetype)
*/
static int vdrive_command_chdir(vdrive_t *vdrive, BYTE *name, int length)
{
    int status, rc;
    BYTE *slot, buffer[256];
    cbmdos_cmd_parse_t cmd_parse;

    cmd_parse.cmd = name;
    cmd_parse.cmdlength = length;
    cmd_parse.readmode = 0;

    rc = cbmdos_command_parse(&cmd_parse);

    if (rc != SERIAL_OK) {
        status = CBMDOS_IPE_NO_NAME;
    } else {
/*#ifdef DEBUG_DRIVE*/
        log_debug("chdir name='%s', len=%d (%d), type= %d.",
                  cmd_parse.parsecmd, cmd_parse.parselength,
                  length, cmd_parse.filetype);
/*#endif*/

        vdrive_dir_find_first_slot(vdrive, cmd_parse.parsecmd,
                                   cmd_parse.parselength, CBMDOS_FT_DIR);

        slot = vdrive_dir_find_next_slot(vdrive);

        if (slot) {
            slot = &vdrive->Dir_buffer[vdrive->SlotNumber * 32];
            rc = vdrive_read_sector(vdrive, buffer,
                                        slot[SLOT_FIRST_TRACK],
                                        slot[SLOT_FIRST_SECTOR]);
            if (rc > 0) {
                return rc;
            }
            if (rc < 0) {
                return CBMDOS_IPE_NOT_READY;
            }

            vdrive->Header_Track = slot[SLOT_FIRST_TRACK];
            vdrive->Header_Sector = slot[SLOT_FIRST_SECTOR];
            vdrive->Dir_Track = buffer[0];
            vdrive->Dir_Sector = buffer[1];
            status = CBMDOS_IPE_OK;
        } else {
            status = CBMDOS_IPE_PATH_NOT_FOUND;
        }

        vdrive_command_set_error(vdrive, status, 0, 0);
    }

    lib_free(cmd_parse.parsecmd);

    return status;
}
コード例 #7
0
ファイル: vdrive.c プロジェクト: twinaphex/vice-next
int vdrive_device_setup(vdrive_t *vdrive, unsigned int unit)
{
    unsigned int i;

    vdrive->unit = unit;

    for (i = 0; i < 15; i++)
        vdrive->buffers[i].mode = BUFFER_NOT_IN_USE;

    vdrive->buffers[15].mode = BUFFER_COMMAND_CHANNEL;

    if (vdrive->buffers[15].buffer == NULL)
        vdrive->buffers[15].buffer = lib_malloc(256);
    memset(vdrive->buffers[15].buffer, 0, 256);

    vdrive_command_set_error(vdrive, CBMDOS_IPE_DOS_VERSION, 0, 0);
    return 0;
}
コード例 #8
0
ファイル: vdrive.c プロジェクト: EdCornejo/emu-ex-plus-alpha
int vdrive_device_setup(vdrive_t *vdrive, unsigned int unit)
{
    unsigned int i;

    vdrive->unit = unit;

    /* init buffers */
    for (i = 0; i < 15; i++) {
        vdrive->buffers[i].mode = BUFFER_NOT_IN_USE;
        vdrive->buffers[i].buffer = NULL;
    }

    /* init command channel */
    vdrive_alloc_buffer(&(vdrive->buffers[15]), BUFFER_COMMAND_CHANNEL);
    vdrive_command_set_error(vdrive, CBMDOS_IPE_DOS_VERSION, 0, 0);

    return 0;
}
コード例 #9
0
static int iec_open_read(vdrive_t *vdrive, unsigned int secondary)
{
    int type;
    unsigned int track, sector;
    bufferinfo_t *p = &(vdrive->buffers[secondary]);
    BYTE *slot = p->slot;

    if (!slot) {
        vdrive_iec_close(vdrive, secondary);
        vdrive_command_set_error(vdrive, CBMDOS_IPE_NOT_FOUND, 0, 0);
        return SERIAL_ERROR;
    }

    type = slot[SLOT_TYPE_OFFSET] & 0x07;
    track = (unsigned int)slot[SLOT_FIRST_TRACK];
    sector = (unsigned int)slot[SLOT_FIRST_SECTOR];

    /* Del, Seq, Prg, Usr (Rel not supported here).  */
    if (type != CBMDOS_FT_REL)
        return iec_open_read_sequential(vdrive, secondary, track, sector);

    return SERIAL_ERROR;
}
コード例 #10
0
ファイル: vdrive-rel.c プロジェクト: twinaphex/vice-next
static int vdrive_rel_add_sector(vdrive_t *vdrive, unsigned int secondary,
                                  unsigned int *track, unsigned int *sector)
{
    bufferinfo_t *p = &(vdrive->buffers[secondary]);
    unsigned int i, j, k, l, m, side, o;
    unsigned int t_new, s_new, t_super, s_super, current;
    int retval;
    BYTE *slot = p->slot;

    /* Find the total blocks this REL file uses. */
    i = slot[SLOT_NR_BLOCKS] + (slot[SLOT_NR_BLOCKS + 1] << 8);

    /* Compare it with the maximum for the particular disk image. */
    if (i >= vdrive_rel_blocks_max(vdrive))
    {
        /* If we are equal or over, report error 52 */
        vdrive_command_set_error(vdrive, CBMDOS_IPE_TOOLARGE, 0, 0);
        return 1;
    }

    /* find the number of side sector groups */
    o = OFFSET_SUPER_POINTER;
    for (side = 0; side < SIDE_SUPER_MAX && p->super_side_sector[o] != 0 ; side++, o+=2 );

    /* If the file isn't new, find the last record */
    if ( side )
    {
        side--;

        /* Find last side sector; guaranteed find. */
        o = 256 * ( side * SIDE_SECTORS_MAX ) + OFFSET_NEXT_TRACK;
        for (i = 0; i < SIDE_SECTORS_MAX; i++, o+=256 ) {
            if (p->side_sector[o] == 0)
                break;
        }

        /* obtain the last byte of the sector according to the index */
        j = ( p->side_sector[256 * ( i + side * SIDE_SECTORS_MAX) + OFFSET_NEXT_SECTOR ]
             + 1 - OFFSET_POINTER ) / 2;

        /* Get the track and sector of the last REL block */
        o = 256 * ( i + side * SIDE_SECTORS_MAX) + OFFSET_POINTER + 2 * (j-1);
        *track = p->side_sector[o];
        *sector = p->side_sector[o + 1];

        /* Find a new sector */
        retval = vdrive_bam_alloc_next_free_sector(vdrive, vdrive->bam, track,
                                                   sector);
    } else {
        /* New REL file, get ready to create... */
        i = 0;
        j = 0;

        *track = 0;
        *sector = 0;

        /* Find the first new sector */
        retval = vdrive_bam_alloc_first_free_sector(vdrive, vdrive->bam, track,
                                                    sector);
    }

    /* Leave if no space left */
    if (retval < 0) {
        vdrive_command_set_error(vdrive, CBMDOS_IPE_DISK_FULL, 0, 0);
        return 1;
    }
    /* Check if this side sector is full or if we need on in general. */
    if ( j == SIDE_INDEX_MAX || j == 0 ) {
        /* Allocate a new sector for the new side sector. */
        t_new = *track;
        s_new = *sector;
        retval = vdrive_bam_alloc_next_free_sector(vdrive, vdrive->bam, &t_new,
                                                   &s_new);
        /* If no space, leave with no changes */
        if (retval < 0) {
            vdrive_command_set_error(vdrive, CBMDOS_IPE_DISK_FULL, 0, 0);
            return 1;
        }
        /* We will adjust the side sector later, but atleast we know
            we have a place to make adjustments. */
    }

    /* setup for later */
    k = 0;
    m = p->slot[SLOT_RECORD_LENGTH];

    /* remember old current record, we will need it for later. */
    current = p->record + 1;

    /* If this is a unallocated file... */
    if ( j == 0 ) {
        /* Update slot information if this is our first side sector. */
        p->slot[SLOT_FIRST_TRACK] = *track;
        p->slot[SLOT_FIRST_SECTOR] = *sector;

        /* Update the super side sector */
        p->super_side_sector[OFFSET_NEXT_TRACK] = t_new;
        p->super_side_sector[OFFSET_NEXT_SECTOR] = s_new;
        p->super_side_sector[OFFSET_SUPER_254] = 254;
        p->super_side_sector[OFFSET_SUPER_POINTER] = t_new;
        p->super_side_sector[OFFSET_SUPER_POINTER+1] = s_new;
        p->super_side_sector_needsupdate = 1;

        t_super = t_new;
        s_super = s_new;

        /* Does this image require a real super side sector? */
        if (vdrive_rel_has_super(vdrive)) {
            retval = vdrive_bam_alloc_next_free_sector(vdrive, vdrive->bam, &t_super,
                                                       &s_super);
            /* If no space, leave with no changes */
            if (retval < 0) {
                vdrive_command_set_error(vdrive, CBMDOS_IPE_DISK_FULL, 0, 0);
                return 1;
            }
            p->super_side_sector_track = t_super;
            p->super_side_sector_sector = s_super;
        } else {
            /* No super side sector required for this image */
            p->super_side_sector_track = 0;
            p->super_side_sector_sector = 0;
        }

        p->slot[SLOT_SIDE_TRACK] = t_super;
        p->slot[SLOT_SIDE_SECTOR] = s_super;

        /* set up first data block */
        p->track_next = *track;
        p->sector_next = *sector;

        /* Update the directory entry */
        vdrive_iec_update_dirent(vdrive, secondary);
    } else {
        /* Existing... */
        /* Move to last sector, use position command - this will flush
            any dirty buffers too. */
        vdrive_rel_position(vdrive, secondary, p->record_max & 255,
                            p->record_max >> 8, 1);

        /* Modify this sector to connect to the next one. */
        /* We won't use the pointer in this sector for the last used
            byte as it could very well be wrong.  The 1541/71/81 had a
            tendency to mess the last sector when making REL files
            by expanding in small chunks.  This generally would happen
            when a new side sector was created.  I can generate a case
            where this bug happens, but I can't seem to figure out why
            - yet. */
        p->buffer[OFFSET_NEXT_TRACK] = p->track_next = *track;
        p->buffer[OFFSET_NEXT_SECTOR] = p->sector_next = *sector;

        /* Fill the new records up with the default 0xff 0x00 ... */
        o = p->bufptr + m;
        while (o < 256)
        {
            if (k==0) p->buffer[o] = 0xff;
            else p->buffer[o] = 0x00;
            k = ( k + 1 ) % m;
            /* increment the maximum records each time we complete a full
                record. */
            if (k==0) p->record_max++;
            o++;
        }

        /* flag the current sector as dirty - the other functions will
            update it. */
        p->needsupdate = DIRTY_SECTOR;

    }

    /* Fill new sector with maximum records */
    o = 2;
    while (o < 256)
    {
        if (k==0) p->buffer_next[o] = 0xff;
        else p->buffer_next[o] = 0x00;
        k = ( k + 1 ) % m;
        /* increment the maximum records each time we complete a full
            record. */
        if (k==0) p->record_max++;
        o++;
    }

    /* set as last sector in REL file */
    p->buffer_next[OFFSET_NEXT_TRACK] = 0;

    /* Update the last byte based on how much of the last record we
        filled. */
    p->buffer_next[OFFSET_NEXT_SECTOR] = 255 - k;

    /* update the "next" buffer to disk, we don't have a dirty flag for
        it. */
    disk_image_write_sector(vdrive->image, p->buffer_next,
                            p->track_next, p->sector_next);

    /* If this is the first side sector being made */
    if ( j == 0 )
    {
        /* Build some of the structure */
        p->side_sector[OFFSET_NEXT_TRACK] = 0;
        p->side_sector[OFFSET_RECORD_LEN] = m;
        p->side_sector[OFFSET_SIDE_SECTOR] = t_new;
        p->side_sector[OFFSET_SIDE_SECTOR + 1] = s_new;
        p->side_sector_track[0] = t_new;
        p->side_sector_sector[0] = s_new;
        /* Follow through with the "else" of the next if */
    }

    /* If this side sector is full... */
    if ( j == SIDE_INDEX_MAX ) {
        /* Update previous side sector */
        o = ( i + side * SIDE_SECTORS_MAX);
        /* dirty the side sector. */
        p->side_sector_needsupdate[ o ] = 1;
        o *= 256;
        /* Update the link. */
        p->side_sector[o + OFFSET_NEXT_TRACK] = t_new;
        p->side_sector[o + OFFSET_NEXT_SECTOR] = s_new;

        /* Is this the last side sector of a group in a super side sector? */
        if ( i == SIDE_SECTORS_MAX - 1 ) {
            /* Yes, create a new group. */
            /* correct side reference. */
            side++;

            /* reallocate memory for another side sector group */
            o = SIDE_SECTORS_MAX * 256;
            p->side_sector = lib_realloc(p->side_sector, ( side + 1 ) * o );
            /* clear out new portion, the function may not do this */
            memset(&(p->side_sector[side * o]), 0, o);

            /* Also reallocate and clear out new sections of track and
                sectors locations and dirty flag of    each side sector */
            o = ( side + 1 ) * SIDE_SECTORS_MAX;
            p->side_sector_track = lib_realloc(p->side_sector_track, o);
            p->side_sector_sector = lib_realloc(p->side_sector_sector, o);
            p->side_sector_needsupdate = lib_realloc(p->side_sector_needsupdate, o);
            o = side * SIDE_SECTORS_MAX;
            memset(&(p->side_sector_track[o]), 0, SIDE_SECTORS_MAX);
            memset(&(p->side_sector_sector[o]), 0, SIDE_SECTORS_MAX);
            memset(&(p->side_sector_needsupdate[o]), 0, SIDE_SECTORS_MAX);

            /* Create first side sector of new group */
            o *=256;
            p->side_sector[o + OFFSET_SIDE_SECTOR ] = t_new;
            p->side_sector[o + OFFSET_SIDE_SECTOR + 1] = s_new;
            p->side_sector[o + OFFSET_SECTOR_NUM] = 0;

            /* Adjust the super side sector */
            o = OFFSET_SUPER_POINTER + side * 2;
            p->super_side_sector[o] = t_new;
            p->super_side_sector[o+1] = s_new;
            p->super_side_sector_needsupdate = 1;

            /* Set up reference to the first side sector. */
            o = ( side * SIDE_SECTORS_MAX);
        } else {
            /* Nope, update old group. */
            /* Update side sector indices. */
            l = o = 256 * ( side * SIDE_SECTORS_MAX );
            for (k=0; k<=i; k++, o+=256) {
                p->side_sector[o + OFFSET_SIDE_SECTOR + ( i + 1 ) * 2 ] = t_new;
                p->side_sector[o + OFFSET_SIDE_SECTOR + ( i + 1 ) * 2 + 1] = s_new;
            }
            /* Update the new sector */
            p->side_sector[o + OFFSET_SECTOR_NUM] = i+1;
            /* Copy side sector track and sectors from first side sector. */
            for ( k=0;k<SIDE_SECTORS_MAX * 2;k++ ) {
                p->side_sector[o + OFFSET_SIDE_SECTOR + k ] =
                    p->side_sector[l + OFFSET_SIDE_SECTOR + k ];
            }
            o = ( side * SIDE_SECTORS_MAX );
            /* Mark all of other side sectors as dirty. */
            for ( k=0; k<=i; k++, o++) {
                p->side_sector_needsupdate[o] = 1;
            }
            /* Set up the reference to the new side sector. */
            o = ( (i+1) + side * SIDE_SECTORS_MAX);
        }

        /* dirty the side sector. */
        p->side_sector_needsupdate[ o ] = 1;
        /* update the internal references. */
        p->side_sector_track[ o ] = t_new;
        p->side_sector_sector[ o ] = s_new;
        /* Update the side sector contents. */
        o *= 256;
        p->side_sector[o + OFFSET_NEXT_TRACK] = 0;
        p->side_sector[o + OFFSET_NEXT_SECTOR] = OFFSET_POINTER + 1;
        p->side_sector[o + OFFSET_RECORD_LEN] = m;
        p->side_sector[o + OFFSET_POINTER] = *track;
        p->side_sector[o + OFFSET_POINTER + 1] = *sector;

    } else {
        /* Update last side sector with new data. */
        o = ( i + side * SIDE_SECTORS_MAX );
        /* set sector dirty. */
        p->side_sector_needsupdate[ o ] = 1;
        /* update last byte used. */
        o *= 256;
        p->side_sector[ o + OFFSET_NEXT_SECTOR ] = OFFSET_POINTER + 2 * j + 1;
        o+= OFFSET_POINTER + 2 * j;
        /* update track and sector of data. */
        p->side_sector[o] = *track;
        p->side_sector[o + 1] = *sector;
    }

    /* Move back to original record - it may not even exist. */
    vdrive_rel_position(vdrive, secondary, current & 255,
                        current >> 8, 1);

    /* everything is okay. */
    return 0;
}
コード例 #11
0
ファイル: vdrive-command.c プロジェクト: bobsummerwill/VICE
/*
    CBM style sub partition support (using CBM filetype)

    on 1581 dos command "/dirname" enters a partition, "i" will go back to root

    FIXME: this works only for .d81
*/
static int vdrive_command_chpart(vdrive_t *vdrive, BYTE *name, int length)
{
    int status, rc;
    int ts,ss,te,len;
    BYTE *slot, buffer[256];
    cbmdos_cmd_parse_t cmd_parse;

    cmd_parse.cmd = name;
    cmd_parse.cmdlength = length;
    cmd_parse.readmode = 0;

    rc = cbmdos_command_parse(&cmd_parse);

    if (rc != SERIAL_OK) {
        status = CBMDOS_IPE_NO_NAME;
    } else {
/*#ifdef DEBUG_DRIVE*/
        log_debug("chpart name='%s', len=%d (%d), type= %d.",
                  cmd_parse.parsecmd, cmd_parse.parselength,
                  length, cmd_parse.filetype);
/*#endif*/

        vdrive_dir_find_first_slot(vdrive, cmd_parse.parsecmd,
                                   cmd_parse.parselength, CBMDOS_FT_CBM);

        slot = vdrive_dir_find_next_slot(vdrive);

        status = CBMDOS_IPE_BAD_PARTN; /* FIXME: is this correct ? */
        if (slot) {
            slot = &vdrive->Dir_buffer[vdrive->SlotNumber * 32];
            /*
            In order to use a partition as a sub-directory, it  must  adhere  to  
            the following four rules:

            1. It must start on sector 0
            2. It's size must be in multiples of 40 sectors (which means the 
               last sector is 39)
            3. It must be a minimum of 120 sectors long (3 tracks)
            4. It must not start on or cross  track 40
            */
            ts = slot[SLOT_FIRST_TRACK];
            ss = slot[SLOT_FIRST_SECTOR];
            len = slot[SLOT_NR_BLOCKS] + (slot[SLOT_NR_BLOCKS + 1] * 256);

            if ((ss == 0) && ((len % 40) == 0) && (len >= 120) && (ts != 40)) {
                te = ts + (len / 40);
                if (((ts < 40) && (te >= 40)) || (te >= (int)vdrive->num_tracks)) {
                    return CBMDOS_IPE_BAD_PARTN; /* FIXME: is this correct ? */
                }

                /* read the first BAM sector to get the DIR start 
                   The BAM track for the sub-directory exists on  the  first  
                   track  of  the partition, and has the same layout as the disk 
                   BAM on track 40.
                 */
                rc = vdrive_read_sector(vdrive, buffer, ts, 0);

                if (rc > 0) {
                    return rc;
                }
                if (rc < 0) {
                    return CBMDOS_IPE_NOT_READY;
                }

                /* more sanity checks */
                if ((buffer[0] < ts) || (buffer[1] > 39)) {
                    return CBMDOS_IPE_BAD_PARTN; /* FIXME: is this correct ? */
                }

/*#ifdef DEBUG_DRIVE*/
                log_debug("Partition Trk %d Sec %d - Trk %d len: %d", ts, ss, te, len);
/*#endif*/
                /* setup BAM location */
                vdrive->Header_Track = ts;
                vdrive->Header_Sector = 0;
                vdrive->Bam_Track = ts;
                vdrive->Bam_Sector = 0;
                /* set area for active partition */
                vdrive->Part_Start = ts;
                vdrive->Part_End = te;
                /* start of directory */
                vdrive->Dir_Track = buffer[0];
                vdrive->Dir_Sector = buffer[1];

                status = CBMDOS_IPE_OK;
            }
        }
    }

    vdrive_command_set_error(vdrive, status, 0, 0);
    lib_free(cmd_parse.parsecmd);

    return status;
}
コード例 #12
0
static int iec_write_sequential(vdrive_t *vdrive, bufferinfo_t *bi, int length)
{
    unsigned int t_new, s_new;
    int retval;
    BYTE *buf = bi->buffer;
    BYTE *slot = bi->slot;

    /*
     * First block of a file ?
     */
    if (bi->track == 0) {
        /* allocate the first sector */
        retval = vdrive_bam_alloc_first_free_sector(vdrive, &t_new, &s_new);
        if (retval < 0) {
            vdrive_command_set_error(vdrive, CBMDOS_IPE_DISK_FULL, 0, 0);
            return -1;
        }
        /* remember track and sector */
        bi->track = t_new;
        bi->sector = s_new;
        /* use update flag to indicate replace mode */
        if (bi->needsupdate) {
            /* save and replace */
            slot[SLOT_REPLACE_TRACK] = t_new;
            slot[SLOT_REPLACE_SECTOR] = s_new;
        } else {
            /* new file */
            slot[SLOT_FIRST_TRACK] = t_new;
            slot[SLOT_FIRST_SECTOR] = s_new;
        }
        /* reset block counter */
        slot[SLOT_NR_BLOCKS] = 0;
        slot[SLOT_NR_BLOCKS + 1] = 0;
    }

    if (length == WRITE_BLOCK) {
        /*
         * Write current sector and allocate next
         */
        t_new = bi->track;
        s_new = bi->sector;
        retval = vdrive_bam_alloc_next_free_sector(vdrive, &t_new, &s_new);
        if (retval < 0) {
            vdrive_command_set_error(vdrive, CBMDOS_IPE_DISK_FULL, 0, 0);
            return -1;
        }
        buf[0] = t_new;
        buf[1] = s_new;

        vdrive_write_sector(vdrive, buf, bi->track, bi->sector);

        bi->track = t_new;
        bi->sector = s_new;
    } else {
        /*
         * Write last block
         */
        buf[0] = 0;
        buf[1] = length - 1;

        vdrive_write_sector(vdrive, buf, bi->track, bi->sector);
    }

    /* Increment block count. */
    if (!(++slot[SLOT_NR_BLOCKS])) {
        ++slot[SLOT_NR_BLOCKS + 1];
    }

    return 0;
}
コード例 #13
0
int vdrive_iec_open(vdrive_t *vdrive, const BYTE *name, unsigned int length,
                    unsigned int secondary, cbmdos_cmd_parse_t *cmd_parse_ext)
{
    bufferinfo_t *p = &(vdrive->buffers[secondary]);
    BYTE *slot; /* Current directory entry */
    int rc, status = SERIAL_OK;
    /* FIXME: This should probably be set to zero */
    cbmdos_cmd_parse_t cmd_parse_stat;
    cbmdos_cmd_parse_t *cmd_parse;
    BYTE name_stat[17];
    unsigned int opentype;

    if (cmd_parse_ext != NULL) {
        cmd_parse = cmd_parse_ext;
        memset(name_stat, 0, sizeof(name_stat));
        strncpy((char *)name_stat, cmd_parse->parsecmd, sizeof(name_stat) - 1);
        name = name_stat;
        length = (unsigned int)strlen((char *)name);
        secondary = cmd_parse->secondary;
    } else {
        cmd_parse = &cmd_parse_stat;
    }

    if (cmd_parse_ext == NULL
        && (!name || !*name) && p->mode != BUFFER_COMMAND_CHANNEL) {
        return SERIAL_NO_DEVICE;
    }

    /* No floppy in drive?   */
    if (vdrive->image == NULL
        && p->mode != BUFFER_COMMAND_CHANNEL
        && secondary != 15
        && *name != '#') {
        vdrive_command_set_error(vdrive, CBMDOS_IPE_NOT_READY, 18, 0);
        log_message(vdrive_iec_log, "Drive not ready.");
        return SERIAL_ERROR;
    }

#ifdef DEBUG_DRIVE
    log_debug("VDRIVE#%i: OPEN: Name '%s' (%d) on ch %d.",
              vdrive->unit, name, length, secondary);
#endif

    /*
     * If channel is command channel, name will be used as write. Return only
     * status of last write ...
     */
    if (p->mode == BUFFER_COMMAND_CHANNEL) {
        unsigned int n;

        for (n = 0; n < length; n++) {
            status = vdrive_iec_write(vdrive, name[n], secondary);
        }

        if (length) {
            p->readmode = CBMDOS_FAM_WRITE;
        } else {
            p->readmode = CBMDOS_FAM_READ;
        }
        return status;
    }

    /*
     * Clear error flag
     */
    vdrive_command_set_error(vdrive, CBMDOS_IPE_OK, 0, 0);

    /*
     * In use ?
     */
    if (p->mode != BUFFER_NOT_IN_USE) {
#ifdef DEBUG_DRIVE
        log_debug("Cannot open channel %d. Mode is %d.", secondary, p->mode);
#endif
        vdrive_command_set_error(vdrive, CBMDOS_IPE_NO_CHANNEL, 0, 0);
        return SERIAL_ERROR;
    }

    if (cmd_parse_ext == NULL) {
        cmd_parse->cmd = name;
        cmd_parse->cmdlength = length;
        cmd_parse->secondary = secondary;
        /* make sure this is zero, since it isn't set below */
        cmd_parse->recordlength = 0;
        cmd_parse->drive = -1;

        rc = cbmdos_command_parse(cmd_parse);

        if (rc != CBMDOS_IPE_OK) {
            status = SERIAL_ERROR;
            goto out;
        }
#ifdef DEBUG_DRIVE
        log_debug("Raw file name: `%s', length: %i.", name, length);
        log_debug("Parsed file name: `%s', reallength: %i. drive: %i",
                  cmd_parse->parsecmd, cmd_parse->parselength, cmd_parse->drive);
#endif
        if (cmd_parse->drive != -1) {
            /* a drive number was specified in the filename */
            if ((vdrive->image_format == VDRIVE_IMAGE_FORMAT_8050) ||
                (vdrive->image_format == VDRIVE_IMAGE_FORMAT_8250) ||
                (vdrive->image_format == VDRIVE_IMAGE_FORMAT_2040)) {
                /* FIXME: dual disk drives not supported */
                if (cmd_parse->drive == 0) {
                    /* FIXME: use drive 0 */
                } else if (cmd_parse->drive == 1) {
                    /* FIXME: use drive 1 */
                    /*
                        since some software gets confused when it sees the same disk in
                        both drives, we bail out with an error instead.
                    */
                    log_warning(LOG_DEFAULT, "second drive of dual disk drive is not supported");
                    vdrive_command_set_error(vdrive, CBMDOS_IPE_NOT_READY, 18, 0);
                    status = SERIAL_ERROR;
                    goto out;
                } else {
                    /* FIXME: what exactly does the drive do if drivenumber is > 1, look
                              up the file on both drives perhaps ?
                    */
                }
            } else {
                /* single disk drives seem to ignore the drive number, *except* if it
                   is 1, which will result in an error. */
                if (cmd_parse->drive == 1) {
                    vdrive_command_set_error(vdrive, CBMDOS_IPE_NOT_READY, 18, 0);
                    status = SERIAL_ERROR;
                    goto out;
                }
            }
        }
    }

    /* Limit file name to 16 chars.  */
    if (cmd_parse->parselength > 16) {
        cmd_parse->parselength = 16;
    }

    /*
     * Internal buffer ?
     */
    if (*name == '#') {
        vdrive_alloc_buffer(p, BUFFER_MEMORY_BUFFER);

        /* the pointer is actually 1 on the real drives. */
        /* this probably relates to the B-R and B-W commands. */
        /* 1541 firmware: $cb84 - open channel, $cc0f bp = 1 */
        p->bufptr = 1;
        /* we need a length to support the original B-R and B-W
           commands. */
        p->length = 256;
        status = SERIAL_OK;
        goto out;
    }

    /* Clear update flag */
    p->needsupdate = 0;

    /*
     * Directory read
     * A little-known feature of the 1541: open 1,8,2,"$" (or even 1,8,1).
     * It gives you the BAM+DIR as a sequential file, containing the data
     * just as it appears on disk.  -Olaf Seibert
     */

    if (*name == '$') {
        p->readmode = CBMDOS_FAM_READ;
        status = iec_open_read_directory(vdrive, secondary, cmd_parse);
        goto out;
    }

    /*
     * Check that there is room on directory.
     */
    if (cmd_parse->readmode == CBMDOS_FAM_READ || cmd_parse->readmode == CBMDOS_FAM_APPEND) {
        opentype = cmd_parse->filetype;
    } else {
        opentype = CBMDOS_FT_DEL;
    }

    vdrive_dir_find_first_slot(vdrive, cmd_parse->parsecmd, cmd_parse->parselength, opentype, &p->dir);

    /*
     * Find the first non-DEL entry in the directory (if it exists).
     */
    do {
        slot = vdrive_dir_find_next_slot(&p->dir);
    } while (slot && ((slot[SLOT_TYPE_OFFSET] & 0x07) == CBMDOS_FT_DEL));

    p->readmode = cmd_parse->readmode;
    p->slot = slot;

    /* Call REL function if we are creating OR opening one */
    if (cmd_parse->filetype == CBMDOS_FT_REL ||
        ( slot && (slot[SLOT_TYPE_OFFSET] & 0x07) == CBMDOS_FT_REL)) {
        /* Make sure the record length of the opening command is the same as
           the record length in the directory slot, if not DOS ERROR 50 */
        if (slot && cmd_parse->recordlength > 0 &&
            slot[SLOT_RECORD_LENGTH] != cmd_parse->recordlength) {
            vdrive_command_set_error(vdrive, CBMDOS_IPE_NO_RECORD, 0, 0);
            status = SERIAL_ERROR;
            goto out;
        }
        /* At this point the record lengths are the same (or will be), so set
            them equal. */
        if (slot) {
            cmd_parse->recordlength = slot[SLOT_RECORD_LENGTH];
        }
        status = vdrive_rel_open(vdrive, secondary, cmd_parse, name);
        goto out;
    }

    if (cmd_parse->readmode == CBMDOS_FAM_READ) {
        status = iec_open_read(vdrive, secondary);
    } else {
        status = iec_open_write(vdrive, secondary, cmd_parse, name);
    }

out:
    lib_free(cmd_parse->parsecmd);
    return status;
}
コード例 #14
0
static int iec_open_write(vdrive_t *vdrive, unsigned int secondary,
                          cbmdos_cmd_parse_t *cmd_parse, const BYTE *name)
{
    bufferinfo_t *p = &(vdrive->buffers[secondary]);
    unsigned int track, sector;
    BYTE *slot = p->slot, *e;

    if (vdrive->image->read_only || VDRIVE_IMAGE_FORMAT_4000_TEST) {
        vdrive_command_set_error(vdrive, CBMDOS_IPE_WRITE_PROTECT_ON, 0, 0);
        return SERIAL_ERROR;
    }

    /* set flag for overwrite mode */
    p->needsupdate = 0;

    if (slot) {
        /* file exists */
        if (*name == '@') {
            /* replace mode: we don't want the dirent updated at all until
                close */
            /* allocate buffers */
            vdrive_alloc_buffer(p, BUFFER_SEQUENTIAL);
            p->bufptr = 2;

            /* Create our own slot, since the one passed is static */
            p->slot = lib_calloc(1, 32);

            /* Copy the static on to the new one. */
            memcpy(p->slot, slot, 32);
            slot = p->slot;

            /* set flag for replace mode */
            p->needsupdate = 1;

            /* find a new track and sector when writing */
            p->track = p->sector = 0;
        } else {
            if (p->readmode == CBMDOS_FAM_APPEND) {
                /* append mode */
                /* allocate buffers */
                vdrive_alloc_buffer(p, BUFFER_SEQUENTIAL);

                /* Create our own slot, since the one passed is static */
                p->slot = lib_calloc(1, 32);

                /* Copy the static on to the new one. */
                memcpy(p->slot, slot, 32);
                slot = p->slot;

                /* set file unclosed */
                p->slot[SLOT_TYPE_OFFSET] &= 0x7f;

                /* get the starting track and sector */
                p->track = track = slot[SLOT_FIRST_TRACK];
                p->sector = sector = slot[SLOT_FIRST_SECTOR];

                /* update block count as we find the end of the file */
                /* the real drives actually don't do this, so each time you
                    append to a file, the block count increases by 1.  I think it
                    is safer to correct the block count. */
                slot[SLOT_NR_BLOCKS] = 255;
                slot[SLOT_NR_BLOCKS + 1] = 255;

                /* scan to the end of the file */
                while (track) {
                    p->track = track;
                    p->sector = sector;
                    if (vdrive_read_sector(vdrive, p->buffer, p->track, p->sector)) {
                        /* couldn't read sector, report error and leave */
                        vdrive_free_buffer(p);
                        vdrive_command_set_error(vdrive, CBMDOS_IPE_ILLEGAL_TRACK_OR_SECTOR, p->track, p->sector);
                        return SERIAL_ERROR;
                    }
                    /* setup next link */
                    track = p->buffer[0];
                    sector = p->buffer[1];

                    /* Increment block count. */
                    if (!(++slot[SLOT_NR_BLOCKS])) {
                        ++slot[SLOT_NR_BLOCKS + 1];
                    }
                }
                /* compensate if the dir link is 0 (rare possibility) */
                if (!p->track) {
                    /* Our loop didn't even execute once, set the block
                       size to 0 */
                    slot[SLOT_NR_BLOCKS] = 0;
                    slot[SLOT_NR_BLOCKS + 1] = 0;
                    /* set buffer pointer to 2 */
                    sector = 1;
                }
                /* set the buffer pointer */
                p->bufptr = sector + 1;
            } else {
                /* can't overwrite an existing file */
                vdrive_iec_close(vdrive, secondary);
                vdrive_command_set_error(vdrive, CBMDOS_IPE_FILE_EXISTS, 0, 0);
                return SERIAL_ERROR;
            }
        }
    } else {
        /* new file... */
        /* create a slot based on the opening name */
        vdrive_dir_create_slot(p, cmd_parse->parsecmd, cmd_parse->parselength,
                               cmd_parse->filetype);

        /* Write the directory entry to disk as an UNCLOSED file. */

        vdrive_dir_find_first_slot(vdrive, NULL, -1, 0, &p->dir);
        e = vdrive_dir_find_next_slot(&p->dir);

        /* If there is not space for the slot, disk is full */
        if (!e) {
            vdrive_free_buffer(p);
            vdrive_command_set_error(vdrive, CBMDOS_IPE_DISK_FULL, 0, 0);
            return SERIAL_ERROR;
        }

        /* find a new track and sector when writing */
        p->track = p->sector = 0;
    }

    if (!p->needsupdate) {
        /* copy the slot information into the sector. */
        memcpy(&p->dir.buffer[p->dir.slot * 32 + 2],
               p->slot + 2, 30);

        /* Write the sector. */
        vdrive_write_sector(vdrive, p->dir.buffer, p->dir.track, p->dir.sector);
    }

    return SERIAL_OK;
}
コード例 #15
0
ファイル: vdrive-rel.c プロジェクト: twinaphex/vice-next
static unsigned int vdrive_rel_record_max(vdrive_t *vdrive, unsigned int secondary)
{
	bufferinfo_t *p = &(vdrive->buffers[secondary]);

	unsigned int i, j, k, l, side, o;
	unsigned int track, sector;

	/* The original 1541 documentation states that there can only be 720
	   (6*120) records in a REL file - this is incorrect.  It is actually
	   blocks.  The side sectors point to each block in the REL file.  It is
	   up to the drive to determine the where the buffer pointer should be
	   when the record changes. */

	/* To find the maximum records we have to check the last block of the REL
	   file.  The last block is referenced in the last side sector group by
	   the OFFSET_NEXT_SECTOR byte.  The next sector pointer after this one
	   should be zero - we will check anyways to make sure.  Once the last
	   block is found, we can move to that sector and check the used bytes
	   there. */

	/* The maximum REL file size for a 1541/1571 is 700 blocks, although it
	   is documented to be 720.  The 1581 is limited to 3000 blocks,
	   although it is documented to be 90720 (126*6*120).  You think they
	   would have allowed it to be atleast the maximum amount of disk
	   space. */

	/* find the number of side sector groups */
	o = OFFSET_SUPER_POINTER;
	for (side = 0; side < SIDE_SUPER_MAX && p->super_side_sector[o] != 0 ; side++, o+=2 );

	/* check if this is a NEW rel file - no data in super side sector. */
	if (!side) {
		/* return a maximum of 0. */
		return 0;
	}

	side--;

	/* Find last side sector; guaranteed find. */
	o = 256 * ( side * SIDE_SECTORS_MAX ) + OFFSET_NEXT_TRACK;
	for (i = 0; i < SIDE_SECTORS_MAX; i++, o+=256 ) {
		if (p->side_sector[o] == 0)
			break;
	}

	/* obtain the last byte of the sector according to the index */
	j = ( p->side_sector[256 * ( i + side * SIDE_SECTORS_MAX) + OFFSET_NEXT_SECTOR ] + 1 - OFFSET_POINTER ) / 2;

	/* Get the track and sector of the last block */
	j--;
	o = 256 * ( i + side * SIDE_SECTORS_MAX ) + OFFSET_POINTER + 2 * j;
	track = p->side_sector[o];
	sector = p->side_sector[o + 1];

	/* read it in */
	if (disk_image_read_sector(vdrive->image, p->buffer, track, sector) != 0)
	{
		#ifdef CELL_DEBUG
		printf("ERROR: Cannot read relative file data sector.\n");
		#endif
		vdrive_command_set_error(vdrive,  CBMDOS_IPE_ILLEGAL_TRACK_OR_SECTOR, track, sector);
		return 0;
	}

	/* calculate the total bytes based on the number of super side, side
	   sectors, and last byte index */
	k = ( ( side * SIDE_SECTORS_MAX + i ) * SIDE_INDEX_MAX + j )
		* 254 + p->buffer[OFFSET_NEXT_SECTOR] - 1;

	/* divide by the record length, and get the maximum records */
	l = k / p->slot[SLOT_RECORD_LENGTH];

	return l;
}
コード例 #16
0
ファイル: vdrive-command.c プロジェクト: bobsummerwill/VICE
int vdrive_command_execute(vdrive_t *vdrive, const BYTE *buf,
                           unsigned int length)
{
    int status = CBMDOS_IPE_INVAL;
    BYTE *p, *minus;
    char *name;

    if (!length)
        return CBMDOS_IPE_OK;
    if (length > IP_MAX_COMMAND_LEN) {
        vdrive_command_set_error(vdrive, CBMDOS_IPE_LONG_LINE, 0, 0);
        return CBMDOS_IPE_LONG_LINE;
    }

    if (buf[length - 1] == 0x0d) {
        --length; /* chop CR character */
    }

    p = lib_malloc(length + 1);
    memcpy(p, buf, length);
    p[length] = 0;

    minus = (BYTE *)memchr(p, '-', length);
    name = (char *)memchr(p, ':', length);

#ifdef DEBUG_DRIVE
    log_debug("Command '%c' (%s).", *p, p);
#endif

    switch (*p) {
      case 'M':
      case 'P':
        break;          /* In binary commands, colons are data */
      default:
        if (name) {     /* Fix name length */
            length -= (BYTE *)name - p;
        }
    }

    switch (*p) {
      case 'C':         /* Copy */
        if (p[1] == 'D' && vdrive->image_format == VDRIVE_IMAGE_FORMAT_4000) {
            if (!name) { /* CD_ doesn't allow a : */
                name = (char *)(p + 1);
            }
            status = vdrive_command_chdir(vdrive, (BYTE *)name, length);
        } else {
            status = vdrive_command_copy(vdrive, (char *)name, length);
        }
        break;

      case '/':         /* change partition */
        if ((vdrive->image_format == VDRIVE_IMAGE_FORMAT_1581) ||
            (vdrive->image_format == VDRIVE_IMAGE_FORMAT_4000)) {
            if (!name) { /* handle "/dir" */
                name = (char *)(p + 1);
                --length;
            }
            status = vdrive_command_chpart(vdrive, (BYTE *)name, length);
        }
        break;

#if 0
      case 'D':         /* Duplicate is unused */
        break;
#endif

      case 'R':         /* Rename */
        status = vdrive_command_rename(vdrive, (BYTE *)name, length);
        break;

      case 'S':         /* Scratch */
        status = vdrive_command_scratch(vdrive, (BYTE *)name, length);
        break;

      case 'I':
        status = vdrive_command_initialize(vdrive);
        break;

      case 'N':
        /* Skip ":" at the start of the name.  */
        status = vdrive_command_format(vdrive,
                                       (name == NULL) ? NULL : name + 1);
        break;

      case 'V':
        status = vdrive_command_validate(vdrive);
        break;

      case 'B': /* Block, Buffer */
        if (!name)      /* B-x does not require a : */
            name = (char *)(p + 2);
        if (minus) {
            status = vdrive_command_block(vdrive, minus[1], name + 1);
        }
        break;

      case 'M': /* Memory */
        if (minus) {
            status = vdrive_command_memory(vdrive, minus + 1, length);
        }
        break;

      case 'P': /* Position */
        status = vdrive_command_position(vdrive, p, length);
        break;

      case 'U': /* User */
        if (!name) {    /* Colons are optional */
            name = (char *)(p + 1);
        }
        switch (p[1] & 0x0f) {
          case 1: /* UA */
            if (name)
                status = vdrive_command_block(vdrive, (unsigned char)0xd2, name + 1);
            break;

          case 2: /* UB */
            if (name)
                status = vdrive_command_block(vdrive, (unsigned char)0xd7, name + 1);
            break;

          case 3: /* Jumps */
          case 4:
          case 5:
          case 6:
          case 7:
          case 8:
            status = CBMDOS_IPE_NOT_READY;
            break;

          case 9: /* UI */
            if (p[2] == '-' || p[2] == '+') {
                status = CBMDOS_IPE_OK; /* Set IEC bus speed */
                break;
            }
            /* Fall through. */
          case 10: /* U:, UJ */
            vdrive_close_all_channels(vdrive); /* Warm/Cold reset */
            status = CBMDOS_IPE_DOS_VERSION;
            break;

          default: /* U0, UK..UO */
            if (p[1] == '0') {
                status = CBMDOS_IPE_OK;
                break;
            }
            status = CBMDOS_IPE_NOT_READY;
            break;
        } /* Un */
        break;

      default:
        break;
    } /* commands */

    if (status == CBMDOS_IPE_INVAL) {
        log_error(vdrive_command_log, "Wrong command `%s'.", p);
    }

    vdrive_command_set_error(vdrive, status, 0, 0);

    lib_free((char *)p);
    return status;
}
コード例 #17
0
ファイル: vdrive-command.c プロジェクト: bobsummerwill/VICE
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;
}
コード例 #18
0
int vdrive_iec_read(vdrive_t *vdrive, BYTE *data, unsigned int secondary)
{
    bufferinfo_t *p = &(vdrive->buffers[secondary]);
    int status = SERIAL_OK;

    switch (p->mode) {
        case BUFFER_NOT_IN_USE:
            vdrive_command_set_error(vdrive, CBMDOS_IPE_NOT_OPEN, 0, 0);
            return SERIAL_ERROR;

        case BUFFER_MEMORY_BUFFER:
            *data = p->buffer[p->bufptr];
            p->bufptr++;
            if (p->bufptr >= p->length) {
                /* Buffer pointer resets to 1, not 0. */
                p->bufptr = 1;
                status = SERIAL_EOF;
            }
            break;

        case BUFFER_DIRECTORY_READ:
        case BUFFER_SEQUENTIAL:
            status = iec_read_sequential(vdrive, data, secondary);
            break;

        case BUFFER_COMMAND_CHANNEL:
            if (p->bufptr > p->length) {
                vdrive_command_set_error(vdrive, CBMDOS_IPE_OK, 0, 0);
#if 0
#ifdef DEBUG_DRIVE
                log_debug("End of buffer in command channel.");
#endif
                *data = 0xc7;
#ifdef DEBUG_DRIVE
                if (p->mode == BUFFER_COMMAND_CHANNEL) {
                    log_debug("Disk read  %d [%02d %02d] data %02x (%c).",
                              p->mode, 0, 0, *data, (isprint(*data) ? *data : '.'));
                }
#endif
                return SERIAL_EOF;
#endif
            }
            *data = p->buffer[p->bufptr];
            p->bufptr++;
            if (p->bufptr > p->length) {
                status = SERIAL_EOF;
            }
            break;

        case BUFFER_RELATIVE:
            status = vdrive_rel_read(vdrive, data, secondary);
            break;

        default:
            log_error(vdrive_iec_log, "Fatal: unknown buffermode on floppy-read.");
    }

#ifdef DEBUG_DRIVE
    if (p->mode == BUFFER_COMMAND_CHANNEL) {
        log_debug("Disk read  %d [%02d %02d] data %02x (%c).",
                  p->mode, 0, 0, *data, (isprint(*data) ? *data : '.'));
    }
#endif
    return status;
}
コード例 #19
0
ファイル: vdrive-rel.c プロジェクト: twinaphex/vice-next
int vdrive_rel_write(vdrive_t *vdrive, BYTE data, unsigned int secondary)
{
	bufferinfo_t *p = &(vdrive->buffers[secondary]);

	if (vdrive->image->read_only)
	{
		vdrive_command_set_error(vdrive, CBMDOS_IPE_WRITE_PROTECT_ON, 0, 0);
		return SERIAL_ERROR;
	}

	/* Check if we need to grow the REL file. */
	if (p->record >= p->record_max)
	{
		if (vdrive_rel_grow(vdrive, secondary, p->record) < 0)
			return SERIAL_OK; /* Couldn't grow it, error generated in function. */
	}

	/*
	 * Read next block if needed
	 */
	if (p->buffer[0]) {
		if (p->bufptr >= 256) {
			int status = 0;
			unsigned int track, sector;

			track = (unsigned int)p->buffer[0];
			sector = (unsigned int)p->buffer[1];

			/* Commit the buffers. */
			vdrive_rel_commit(vdrive, p);

			/* Check to see if the next record is in the buffered sector */
			if (p->track_next == track && p->sector_next == sector) {
				/* Swap the two buffers */
				BYTE *tmp;
				tmp = p->buffer;
				p->buffer = p->buffer_next;
				p->buffer_next = tmp;
				p->track_next = p->track;
				p->sector_next = p->sector;
				p->track = track;
				p->sector = sector;
				status = 0;
			} else if (p->track!=track || p->sector != sector ) {
				/* load in the sector to memory */
				status = disk_image_read_sector(vdrive->image, p->buffer, track, sector);
			}

			if (status == 0) {
				p->track = track;
				p->sector = sector;
				p->bufptr = p->bufptr - 254;
				p->length = p->length - 254;
				p->record_next = p->record_next - 254;
				/* keep buffered sector where ever it is */
				/* we won't read in the next sector unless we have to */
			}
			else
			{
#ifdef CELL_DEBUG
				printf("ERROR: Cannot read track %i sector %i.\n", track, sector);
#endif
				return SERIAL_EOF;
			}
		}
	} else {
		if (p->bufptr >= (unsigned int)( p->buffer[1] + 2 ) ) {
#ifdef DEBUG_DRIVE
			if (p->mode == BUFFER_COMMAND_CHANNEL)
				log_error(vdrive_rel_log,
						"Disk read  %d [%02d %02d] data %02x (%c).",
						p->mode, 0, 0, data, (isprint(data)
							? data : '.'));
#endif
			if (vdrive_rel_grow(vdrive, secondary, p->record) < 0)
			{
				/* Couldn't grow it, error generated in function. */
				return SERIAL_OK;
			}
		}
	}

	if (p->bufptr >= p->record_next) {
		/* We CANNOT write into the next record under any
		   circumstances, unlike the reads. */
		vdrive_command_set_error(vdrive, CBMDOS_IPE_OVERFLOW, 0, 0);

		/* But if we try, we still say it is okay, but with a DOS
		   error. */
		return SERIAL_OK;
	}

	/* write the data to the buffer */
	p->buffer[p->bufptr] = data;
	/* increment the pointer */
	p->bufptr++;
	/* flag this sector as dirty and written */
	p->needsupdate |= ( DIRTY_SECTOR | WRITTEN_RECORD ); 

	/* Mark this record as dirty only if we are still in it */
	if (p->bufptr!=p->record_next) {
		p->needsupdate |= DIRTY_RECORD;
	} else {
		p->needsupdate &= (~DIRTY_RECORD);
	}

	/* Any pointer overflow gets handled at the beginning of this
	   function. */

	return SERIAL_OK;
}
コード例 #20
0
ファイル: vdrive-rel.c プロジェクト: twinaphex/vice-next
int vdrive_rel_read(vdrive_t *vdrive, BYTE *data, unsigned int secondary)
{
	bufferinfo_t *p = &(vdrive->buffers[secondary]);

	/* Check if we are past the end of the REL file. */
	if (p->record >= p->record_max)
	{
		*data = 0x0d;
		vdrive_command_set_error(vdrive, CBMDOS_IPE_NO_RECORD, 0, 0);
		return SERIAL_EOF;
	}

	/*
	 * Read next block if needed
	 */
	if (p->buffer[0]) {
		if (p->bufptr >= 256) {
			int status = 0;
			unsigned int track, sector;

			track = (unsigned int)p->buffer[0];
			sector = (unsigned int)p->buffer[1];

			/* Commit the buffers. */
			vdrive_rel_commit(vdrive, p);

			/* Check to see if the next record is in the buffered sector */
			if (p->track_next == track && p->sector_next == sector) {
				/* Swap the two buffers */
				BYTE *tmp;
				tmp = p->buffer;
				p->buffer = p->buffer_next;
				p->buffer_next = tmp;
				p->track_next = p->track;
				p->sector_next = p->sector;
				p->track = track;
				p->sector = sector;
				status = 0;
			} else if (p->track!=track || p->sector != sector ) {
				/* load in the sector to memory */
				status = disk_image_read_sector(vdrive->image, p->buffer, track, sector);
			}

			if (status == 0)
			{
				p->track = track;
				p->sector = sector;
				p->bufptr = p->bufptr - 254;
				p->length = p->length - 254;
				p->record_next = p->record_next - 254;
				/* keep buffered sector where ever it is */
				/* we won't read in the next sector unless we have to */
			}
			else
			{
				#ifdef CELL_DEBUG
				printf("ERROR: Cannot read track %i sector %i.\n", track, sector);
				#endif
				*data = 0xc7;
				return SERIAL_EOF;
			}
		}
	} else {
		if (p->bufptr >= (unsigned int)( p->buffer[1] + 2 ))
		{
			/* check to see if we have the pointer overflow problem here. */
			if (p->record_next > p->length)
			{
				*data = 0x0d;
#ifdef DEBUG_DRIVE
				if (p->mode == BUFFER_COMMAND_CHANNEL)
					log_error(vdrive_rel_log,
							"Disk read  %d [%02d %02d] data %02x (%c).",
							p->mode, 0, 0, *data, (isprint(*data)
								? *data : '.'));
#endif
				vdrive_command_set_error(vdrive, CBMDOS_IPE_NO_RECORD, 0, 0);
				return SERIAL_EOF;
			}
			else {
				/* Yes, just rotate though to this buffer. */
				if (p->bufptr>=256) {
					p->bufptr = p->bufptr - 254;
					p->length = p->length - 254;
					p->record_next = p->record_next - 254;
				}
			}
		}
	}

	*data = p->buffer[p->bufptr];
	p->bufptr++;

	if (p->bufptr > p->length) {
		/* set up the buffer pointer to the next record */
		p->bufptr = p->record_next;
		/* add the record length to the next record pointer */
		p->record_next += p->side_sector[OFFSET_RECORD_LEN];
		/* calculate the maximum length (for read, for write we should use
		   record_next - 1 */
		p->length = p->record_next - 1;
		/* increment the record reference */
		p->record++;
		/* Exit if we have hit the end of the REL data. */
		if (p->record >= p->record_max) {
			return SERIAL_EOF;
		}
		/* Find the length of the record starting from the end until no zeros
		   are found */
		if ( p->length < 256) {
			/* If the maximum length of the record is in this sector, just
			   check for where the zeros end */
			for (;p->length >= p->bufptr && p->buffer[p->length] == 0 ; p->length-- );
		}
		else {
			int status=1;

			/* Get the next sector */
			/* If it doesn't exist, we will use the max length calculated above */
			if (p->buffer[0] != 0) {
				/* Read in the sector if it has not been buffered */
				if (p->buffer[0] != p->track_next || p->buffer[1] != p->sector_next) {
					status = disk_image_read_sector(vdrive->image, p->buffer_next, p->buffer[0],
							p->buffer[1]);
				}
				else {
					status = 0;
				}
			}
			/* If all is good, calculate the length now */
			if (!status) {
				/* update references, if the sector read in */
				p->track_next = p->buffer[0];
				p->sector_next = p->buffer[1];
				/* Start looking in the buffered sector */
				for (;p->length >= 256 && p->buffer_next[p->length-256+2] == 0 ; p->length-- );
				/* If we crossed into the current sector, look there too */
				if (p->length<256) {
					for (;p->length >= p->bufptr && p->buffer[p->length] == 0 ; p->length-- );
				}
			}

		}
		//log_debug("Forced from read to position %d, 0 on channel %d.", p->record, secondary);

		return SERIAL_EOF;
	}

	return SERIAL_OK;
}
コード例 #21
0
int vdrive_iec_write(vdrive_t *vdrive, BYTE data, unsigned int secondary)
{
    bufferinfo_t *p = &(vdrive->buffers[secondary]);

    if ((vdrive->image->read_only || VDRIVE_IMAGE_FORMAT_4000_TEST) && p->mode != BUFFER_COMMAND_CHANNEL) {
        vdrive_command_set_error(vdrive, CBMDOS_IPE_WRITE_PROTECT_ON, 0, 0);
        return SERIAL_ERROR;
    }

#ifdef DEBUG_DRIVE
    if (p->mode == BUFFER_COMMAND_CHANNEL) {
        log_debug("Disk write %d [%02d %02d] data %02x (%c).",
                  p->mode, 0, 0, data, (isprint(data) ? data : '.'));
    }
#endif

    switch (p->mode) {
        case BUFFER_NOT_IN_USE:
            vdrive_command_set_error(vdrive, CBMDOS_IPE_NOT_OPEN, 0, 0);
            return SERIAL_ERROR;
        case BUFFER_DIRECTORY_READ:
            vdrive_command_set_error(vdrive, CBMDOS_IPE_NOT_WRITE, 0, 0);
            return SERIAL_ERROR;
        case BUFFER_MEMORY_BUFFER:
            p->buffer[p->bufptr] = data;
            p->bufptr++;
            if (p->bufptr >= p->length) {
                /* On writes, buffer pointer resets to 0. */
                p->bufptr = 0;
            }
            return SERIAL_OK;
        case BUFFER_SEQUENTIAL:
            if (p->readmode == CBMDOS_FAM_READ) {
                return SERIAL_ERROR;
            }

            if (p->bufptr >= 256) {
                p->bufptr = 2;
                if (iec_write_sequential(vdrive, p, WRITE_BLOCK) < 0) {
                    return SERIAL_ERROR;
                }
            }
            p->buffer[p->bufptr] = data;
            p->bufptr++;
            break;
        case BUFFER_COMMAND_CHANNEL:
            if (p->readmode == CBMDOS_FAM_READ) {
                p->bufptr = 0;
                p->readmode = CBMDOS_FAM_WRITE;
            }
            if (p->bufptr >= 256) { /* Limits checked later */
                return SERIAL_ERROR;
            }
            p->buffer[p->bufptr] = data;
            p->bufptr++;
            break;
        case BUFFER_RELATIVE:
            return vdrive_rel_write(vdrive, data, secondary);
            break;
        default:
            log_error(vdrive_iec_log, "Fatal: Unknown write mode.");
            exit(-1);
    }
    return SERIAL_OK;
}
コード例 #22
0
ファイル: vdrive-rel.c プロジェクト: twinaphex/vice-next
static int vdrive_rel_open_new(vdrive_t *vdrive, unsigned int secondary,
                               cbmdos_cmd_parse_t *cmd_parse, const BYTE *name)
{
    bufferinfo_t *p = &(vdrive->buffers[secondary]);
    BYTE *slot;

    /* Allocate a directory slot */
    vdrive_dir_find_first_slot(vdrive, NULL, -1, 0);
    slot = vdrive_dir_find_next_slot(vdrive);

    /* If we can't get one the directory is full - disk full */
    if (!slot) {
        vdrive_command_set_error(vdrive, CBMDOS_IPE_DISK_FULL, 0, 0);
        return 1;
    }

    /* Create our own slot */
    p->slot = lib_calloc(1, 32);

    /* Populate it */
    memset(p->slot + SLOT_NAME_OFFSET, 0xa0, 16);
    memcpy(p->slot + SLOT_NAME_OFFSET, cmd_parse->parsecmd, cmd_parse->parselength);
#ifdef DEBUG_DRIVE
    log_debug("DIR: Created dir slot. Name (%d) '%s'\n",
              cmd_parse->parsecmd, cmd_parse->parselength);
#endif
    p->slot[SLOT_TYPE_OFFSET] = cmd_parse->filetype | 0x80;       /* closed */

    p->slot[SLOT_RECORD_LENGTH] = cmd_parse->recordlength;

    /* Store in buffer */
    memcpy(&(vdrive->Dir_buffer[vdrive->SlotNumber * 32 + 2]),
           p->slot + 2, 30);

#ifdef DEBUG_DRIVE
    log_debug("DEBUG: write DIR slot (%d %d).",
              vdrive->Curr_track, vdrive->Curr_sector);
#endif
    /* Write the sector */
    disk_image_write_sector(vdrive->image, vdrive->Dir_buffer,
                            vdrive->Curr_track, vdrive->Curr_sector);

    /* Allocate memory for super side sector */
    p->super_side_sector = lib_malloc(256);

    /* clear out block */
    memset(p->super_side_sector, 0, 256);
    /* build valid super side sector block */
    p->super_side_sector[OFFSET_SUPER_254] = 254;
    p->super_side_sector_track = 0;
    p->super_side_sector_sector = 0;
    /* Clear dirty flag */
    p->super_side_sector_needsupdate = 0;

     /* allocate memory for side sectors */
    p->side_sector = lib_malloc(SIDE_SECTORS_MAX * 256);
    memset(p->side_sector, 0, SIDE_SECTORS_MAX * 256);

    /* Also clear out track and sectors locations and dirty flag of
        each side sector */
    p->side_sector_track = lib_malloc(SIDE_SECTORS_MAX);
    p->side_sector_sector = lib_malloc(SIDE_SECTORS_MAX);
    p->side_sector_needsupdate = lib_malloc(SIDE_SECTORS_MAX);
    memset(p->side_sector_track, 0, SIDE_SECTORS_MAX);
    memset(p->side_sector_sector, 0, SIDE_SECTORS_MAX);
    memset(p->side_sector_needsupdate, 0, SIDE_SECTORS_MAX);

    /* Remember the directory information incase our REL file grows. */
    p->dir_track = vdrive->Curr_track;
    p->dir_sector = vdrive->Curr_sector;
    p->dir_slot = vdrive->SlotNumber;

    /* Everything okay */
    return 0;
}