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; }
/* read first dir buffer into Dir_buffer */ void vdrive_dir_find_first_slot(vdrive_t *vdrive, const char *name, int length, unsigned int type, vdrive_dir_context_t *dir) { if (length > 0) { BYTE *nslot; nslot = cbmdos_dir_slot_create(name, length); memcpy(dir->find_nslot, nslot, CBMDOS_SLOT_NAME_LENGTH); lib_free(nslot); } dir->vdrive = vdrive; dir->find_length = length; dir->find_type = type; dir->track = vdrive->Header_Track; dir->sector = vdrive->Header_Sector; dir->slot = 7; vdrive_read_sector(vdrive, dir->buffer, dir->track, dir->sector); dir->buffer[0] = vdrive->Dir_Track; dir->buffer[1] = vdrive->Dir_Sector; #ifdef DEBUG_DRIVE log_debug("DIR: vdrive_dir_find_first_slot (curr t:%d/s:%d dir t:%d/s:%d)", dir->track, dir->sector, vdrive->Dir_Track, vdrive->Dir_Sector); #endif }
/* 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; }
static int iec_read_sequential(vdrive_t *vdrive, BYTE *data, unsigned int secondary) { bufferinfo_t *p = &(vdrive->buffers[secondary]); int status; unsigned int track, sector; if (p->readmode != CBMDOS_FAM_READ) { *data = 0xc7; return SERIAL_ERROR; } *data = p->buffer[p->bufptr]; if (p->length != 0) { if (p->bufptr == p->length) { p->bufptr = 0xff; } } p->bufptr = (p->bufptr + 1) & 0xff; if (p->bufptr) { return SERIAL_OK; } if (p->length) { p->readmode = CBMDOS_FAM_EOF; return SERIAL_EOF; } switch (p->mode) { case BUFFER_SEQUENTIAL: track = (unsigned int)p->buffer[0]; sector = (unsigned int)p->buffer[1]; status = vdrive_read_sector(vdrive, p->buffer, track, sector); p->length = p->buffer[0] ? 0 : p->buffer[1]; vdrive_set_last_read(track, sector, p->buffer); if (status == 0) { p->bufptr = 2; } else { p->readmode = CBMDOS_FAM_EOF; } break; case BUFFER_DIRECTORY_READ: p->length = vdrive_dir_next_directory(vdrive, p); p->bufptr = 0; break; } return SERIAL_OK; }
int vdrive_iec_update_dirent(vdrive_t *vdrive, unsigned int channel) { bufferinfo_t *p = &(vdrive->buffers[channel]); /* Read in the track/sector where the directory entry lies. */ vdrive_read_sector(vdrive, p->dir.buffer, p->dir.track, p->dir.sector); /* Copy over our new slot. */ memcpy(&(p->dir.buffer[p->dir.slot * 32 + 2]), p->slot + 2, 30); /* Write it back. */ vdrive_write_sector(vdrive, p->dir.buffer, p->dir.track, p->dir.sector); return 0; }
static int iec_open_read_sequential(vdrive_t *vdrive, unsigned int secondary, unsigned int track, unsigned int sector) { int status; bufferinfo_t *p = &(vdrive->buffers[secondary]); vdrive_alloc_buffer(p, BUFFER_SEQUENTIAL); p->bufptr = 2; status = vdrive_read_sector(vdrive, p->buffer, track, sector); p->length = p->buffer[0] ? 0 : p->buffer[1]; vdrive_set_last_read(track, sector, p->buffer); if (status != 0) { vdrive_iec_close(vdrive, secondary); return SERIAL_ERROR; } return SERIAL_OK; }
void vdrive_dir_free_chain(vdrive_t *vdrive, int t, int s) { BYTE buf[256]; while (t) { /* Check for illegal track or sector. */ if (disk_image_check_sector(vdrive->image, t, s) < 0) { break; } /* Check if this sector is really allocated. */ if (!vdrive_bam_free_sector(vdrive, t, s)) { break; } /* FIXME: This seems to be redundant. AB19981124 */ vdrive_bam_free_sector(vdrive, t, s); vdrive_read_sector(vdrive, buf, t, s); t = (int)buf[0]; s = (int)buf[1]; } }
BYTE *vdrive_dir_find_next_slot(vdrive_dir_context_t *dir) { static BYTE return_slot[32]; vdrive_t *vdrive = dir->vdrive; #ifdef DEBUG_DRIVE log_debug("DIR: vdrive_dir_find_next_slot start (t:%d/s:%d) #%d", dir->track, dir->sector, dir->slot); #endif /* * Loop all directory blocks starting from track 18, sector 1 (1541). */ do { /* * Load next(first) directory block ? */ dir->slot++; if (dir->slot >= 8) { int status; /* end of current directory? */ if (dir->buffer[0] == 0) { break; } dir->slot = 0; dir->track = (unsigned int)dir->buffer[0]; dir->sector = (unsigned int)dir->buffer[1]; status = vdrive_read_sector(vdrive, dir->buffer, dir->track, dir->sector); if (status != 0) { return NULL; /* error */ } } if (vdrive_dir_name_match(&dir->buffer[dir->slot * 32], dir->find_nslot, dir->find_length, dir->find_type)) { memcpy(return_slot, &dir->buffer[dir->slot * 32], 32); return return_slot; } } while (1); #ifdef DEBUG_DRIVE log_debug("DIR: vdrive_dir_find_next_slot (t:%d/s:%d) #%d", dir->track, dir->sector, dir->slot); #endif /* * If length < 0, create new directory-entry if possible */ if (dir->find_length < 0) { int i, sector; BYTE *dirbuf; sector = dir->sector + vdrive_dir_get_interleave(vdrive->image_format); for (i = 0; i < vdrive_get_max_sectors(vdrive, dir->track); i++) { dirbuf = find_next_directory_sector(dir, dir->track, sector); if (dirbuf != NULL) { return dirbuf; } sector++; if (sector >= vdrive_get_max_sectors(vdrive, dir->track)) { sector = 0; } } } return NULL; }
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; }
void mon_drive_block_cmd(int op, int track, int sector, MON_ADDR addr) { vdrive_t *vdrive; mon_evaluate_default_addr(&addr); vdrive = file_system_get_vdrive(8); if (!vdrive || vdrive->image == NULL) { mon_out("No disk attached\n"); return; } if (!op) { BYTE readdata[256]; int i, j, dst; MEMSPACE dest_mem; /* We ignore disk error codes here. */ if (vdrive_read_sector(vdrive, readdata, track, sector) < 0) { mon_out("Error reading track %d sector %d\n", track, sector); return; } if (mon_is_valid_addr(addr)) { dst = addr_location(addr); dest_mem = addr_memspace(addr); for (i = 0; i < 256; i++) { mon_set_mem_val(dest_mem, ADDR_LIMIT(dst + i), readdata[i]); } mon_out("Read track %d sector %d into address $%04x\n", track, sector, dst); } else { for (i = 0; i < 16; i++) { mon_out(">%04x", i * 16); for (j = 0; j < 16; j++) { if ((j & 3) == 0) { mon_out(" "); } mon_out(" %02x", readdata[i * 16 + j]); } mon_out("\n"); } } } else { BYTE writedata[256]; int i, src; MEMSPACE src_mem; src = addr_location(addr); src_mem = addr_memspace(addr); for (i = 0; i < 256; i++) { writedata[i] = mon_get_mem_val(src_mem, ADDR_LIMIT(src + i)); } if (vdrive_write_sector(vdrive, writedata, track, sector)) { mon_out("Error writing track %d sector %d\n", track, sector); return; } mon_out("Write data from address $%04x to track %d sector %d\n", src, track, sector); } }
image_contents_t *diskcontents_block_read(vdrive_t *vdrive) { image_contents_t *contents; BYTE buffer[256]; int retval; image_contents_file_list_t *lp; machine_drive_flush(); if (vdrive == NULL) return NULL; retval = vdrive_bam_read_bam(vdrive); if (retval < 0) { vdrive_internal_close_disk_image(vdrive); return NULL; } contents = image_contents_new(); memcpy(contents->name, vdrive->bam + vdrive->bam_name, IMAGE_CONTENTS_NAME_LEN); contents->name[IMAGE_CONTENTS_NAME_LEN] = 0; memcpy(contents->id, vdrive->bam + vdrive->bam_id, IMAGE_CONTENTS_ID_LEN); contents->id[IMAGE_CONTENTS_ID_LEN] = 0; contents->blocks_free = (int)vdrive_bam_free_block_count(vdrive); vdrive->Curr_track = vdrive->Dir_Track; vdrive->Curr_sector = vdrive->Dir_Sector; lp = NULL; contents->file_list = NULL; circular_check_init(); while (1) { BYTE *p; int j; retval = vdrive_read_sector(vdrive, buffer, vdrive->Curr_track, vdrive->Curr_sector); if (retval != 0 || circular_check(vdrive->Curr_track, vdrive->Curr_sector)) { /*image_contents_destroy(contents);*/ vdrive_internal_close_disk_image(vdrive); circular_check_free(); return contents/*NULL*/; } for (p = buffer, j = 0; j < 8; j++, p += 32) if (p[SLOT_TYPE_OFFSET] != 0) { image_contents_file_list_t *new_list; int i; new_list = lib_malloc(sizeof(image_contents_file_list_t)); new_list->size = ((int)p[SLOT_NR_BLOCKS] + ((int)p[SLOT_NR_BLOCKS + 1] << 8)); for (i = 0; i < IMAGE_CONTENTS_FILE_NAME_LEN; i++) new_list->name[i] = p[SLOT_NAME_OFFSET + i]; new_list->name[IMAGE_CONTENTS_FILE_NAME_LEN] = 0; new_list->name[i] = 0; sprintf((char *)new_list->type, "%c%s%c", (p[SLOT_TYPE_OFFSET] & CBMDOS_FT_CLOSED ? ' ' : '*'), cbmdos_filetype_get(p[SLOT_TYPE_OFFSET] & 0x07), (p[SLOT_TYPE_OFFSET] & CBMDOS_FT_LOCKED ? '<' : ' ')); new_list->next = NULL; if (lp == NULL) { new_list->prev = NULL; contents->file_list = new_list; lp = contents->file_list; } else { new_list->prev = lp; lp->next = new_list; lp = new_list; } } if (buffer[0] == 0) break; vdrive->Curr_track = (int)buffer[0]; vdrive->Curr_sector = (int)buffer[1]; } vdrive_internal_close_disk_image(vdrive); circular_check_free(); return contents; }
/* probably we should make a list with BAM blocks for each drive type... (AF)*/ int vdrive_bam_read_bam(vdrive_t *vdrive) { int err = -1, i; switch (vdrive->image_format) { case VDRIVE_IMAGE_FORMAT_2040: case VDRIVE_IMAGE_FORMAT_1541: err = vdrive_read_sector(vdrive, vdrive->bam, BAM_TRACK_1541, BAM_SECTOR_1541); break; case VDRIVE_IMAGE_FORMAT_1571: err = vdrive_read_sector(vdrive, vdrive->bam, BAM_TRACK_1571, BAM_SECTOR_1571); if (err != 0) { break; } err = vdrive_read_sector(vdrive, vdrive->bam + 256, BAM_TRACK_1571 + 35, BAM_SECTOR_1571); break; case VDRIVE_IMAGE_FORMAT_1581: err = vdrive_read_sector(vdrive, vdrive->bam, BAM_TRACK_1581, BAM_SECTOR_1581); if (err != 0) { break; } err = vdrive_read_sector(vdrive, vdrive->bam + 256, BAM_TRACK_1581, BAM_SECTOR_1581 + 1); if (err != 0) { break; } err = vdrive_read_sector(vdrive, vdrive->bam + 512, BAM_TRACK_1581, BAM_SECTOR_1581 + 2); break; case VDRIVE_IMAGE_FORMAT_8050: case VDRIVE_IMAGE_FORMAT_8250: err = vdrive_read_sector(vdrive, vdrive->bam, BAM_TRACK_8050, BAM_SECTOR_8050); if (err != 0) { break; } err = vdrive_read_sector(vdrive, vdrive->bam + 256, BAM_TRACK_8050 - 1, BAM_SECTOR_8050); if (err != 0) { break; } err = vdrive_read_sector(vdrive, vdrive->bam + 512, BAM_TRACK_8050 - 1, BAM_SECTOR_8050 + 3); if (err != 0) { break; } if (vdrive->image_format == VDRIVE_IMAGE_FORMAT_8050) { break; } err = vdrive_read_sector(vdrive, vdrive->bam + 768, BAM_TRACK_8050 - 1, BAM_SECTOR_8050 + 6); if (err != 0) { break; } err = vdrive_read_sector(vdrive, vdrive->bam + 1024, BAM_TRACK_8050 - 1, BAM_SECTOR_8050 + 9); break; case VDRIVE_IMAGE_FORMAT_4000: for (i = 0; i < 33; i++) { err = vdrive_read_sector(vdrive, vdrive->bam + i * 256, BAM_TRACK_4000, BAM_SECTOR_4000 + i); if (err != 0) { break; } } break; default: log_error(LOG_ERR, "Unknown disk type %i. Cannot read BAM.", vdrive->image_format); } if (err < 0) { return CBMDOS_IPE_NOT_READY; } return err; }
/* 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; }
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, §or); 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, §or); 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, §or, &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 *)§or) >= 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, §or); 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, §or); 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; }