1 /*
2  * sio.c - Serial I/O emulation
3  *
4  * Copyright (C) 1995-1998 David Firth
5  * Copyright (C) 1998-2010 Atari800 development team (see DOC/CREDITS)
6  *
7  * This file is part of the Atari800 emulator project which emulates
8  * the Atari 400, 800, 800XL, 130XE, and 5200 8-bit computers.
9  *
10  * Atari800 is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation; either version 2 of the License, or
13  * (at your option) any later version.
14  *
15  * Atari800 is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with Atari800; if not, write to the Free Software
22  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
23 */
24 
25 #define _POSIX_C_SOURCE 200112L /* for snprintf */
26 
27 #include "config.h"
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <string.h>
31 #include <math.h>
32 
33 #include "afile.h"
34 #include "antic.h"  /* ANTIC_ypos */
35 #include "atari.h"
36 #include "binload.h"
37 #include "cassette.h"
38 #include "compfile.h"
39 #include "cpu.h"
40 #include "esc.h"
41 #include "log.h"
42 #include "memory.h"
43 #include "platform.h"
44 #include "pokey.h"
45 #include "pokeysnd.h"
46 #include "sio.h"
47 #include "util.h"
48 #ifndef BASIC
49 #include "statesav.h"
50 #endif
51 
52 #undef DEBUG_PRO
53 #undef DEBUG_VAPI
54 
55 /* If ATR image is in double density (256 bytes per sector),
56    then the boot sectors (sectors 1-3) can be:
57    - logical (as seen by Atari) - 128 bytes in each sector
58    - physical (as stored on the disk) - 256 bytes in each sector.
59      Only the first half of sector is used for storing data, the rest is zero.
60    - SIO2PC (the type used by the SIO2PC program) - 3 * 128 bytes for data
61      of boot sectors, then 3 * 128 unused bytes (zero)
62    The XFD images in double density have either logical or physical
63    boot sectors. */
64 #define BOOT_SECTORS_LOGICAL	0
65 #define BOOT_SECTORS_PHYSICAL	1
66 #define BOOT_SECTORS_SIO2PC		2
67 static int boot_sectors_type[SIO_MAX_DRIVES];
68 
69 static int image_type[SIO_MAX_DRIVES];
70 #define IMAGE_TYPE_XFD  0
71 #define IMAGE_TYPE_ATR  1
72 #define IMAGE_TYPE_PRO  2
73 #define IMAGE_TYPE_VAPI 3
74 static FILE *disk[SIO_MAX_DRIVES] = { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL };
75 static int sectorcount[SIO_MAX_DRIVES];
76 static int sectorsize[SIO_MAX_DRIVES];
77 /* these two are used by the 1450XLD parallel disk device */
78 int SIO_format_sectorcount[SIO_MAX_DRIVES];
79 int SIO_format_sectorsize[SIO_MAX_DRIVES];
80 static int io_success[SIO_MAX_DRIVES];
81 /* stores dup sector counter for PRO images */
82 typedef struct tagpro_additional_info_t {
83 	int max_sector;
84 	unsigned char *count;
85 } pro_additional_info_t;
86 
87 #define MAX_VAPI_PHANTOM_SEC  		40
88 #define VAPI_BYTES_PER_TRACK        26042.0
89 #define VAPI_CYCLES_PER_ROT 		372706
90 #define VAPI_CYCLES_PER_TRACK_STEP 	35780 /*70937*/
91 #define VAPI_CYCLES_HEAD_SETTLE 	70134
92 #define VAPI_CYCLES_TRACK_READ_DELTA 1426
93 #define VAPI_CYCLES_CMD_ACK_TRANS 	3188
94 #define VAPI_CYCLES_SECTOR_READ 	29014
95 #define VAPI_CYCLES_MISSING_SECTOR	(2*VAPI_CYCLES_PER_ROT + 14453)
96 #define VAPI_CYCLES_BAD_SECTOR_NUM	1521
97 
98 /* stores dup sector information for VAPI images */
99 typedef struct tagvapi_sec_info_t {
100 	int sec_count;
101 	unsigned int sec_offset[MAX_VAPI_PHANTOM_SEC];
102 	unsigned char sec_status[MAX_VAPI_PHANTOM_SEC];
103 	unsigned int sec_rot_pos[MAX_VAPI_PHANTOM_SEC];
104 } vapi_sec_info_t;
105 
106 typedef struct tagvapi_additional_info_t {
107 	vapi_sec_info_t *sectors;
108 	int sec_stat_buff[4];
109 	int vapi_delay_time;
110 } vapi_additional_info_t;
111 
112 /* VAPI Format Header */
113 typedef struct tagvapi_file_header_t {
114 	unsigned char signature[4];
115 	unsigned char majorver;
116 	unsigned char minorver;
117 	unsigned char reserved1[22];
118 	unsigned char startdata[4];
119 	unsigned char reserved[16];
120 } vapi_file_header_t;
121 
122 typedef struct tagvapi_track_header_t {
123 	unsigned char  next[4];
124 	unsigned char  type[2];
125 	unsigned char  reserved1[2];
126 	unsigned char  tracknum;
127 	unsigned char  reserved2;
128 	unsigned char  sectorcnt[2];
129 	unsigned char  reserved3[8];
130 	unsigned char  startdata[4];
131 	unsigned char  reserved4[8];
132 } vapi_track_header_t;
133 
134 typedef struct tagvapi_sector_list_header_t {
135 	unsigned char  sizelist[4];
136 	unsigned char  type;
137 	unsigned char  reserved[3];
138 } vapi_sector_list_header_t;
139 
140 typedef struct tagvapi_sector_header_t {
141 	unsigned char  sectornum;
142 	unsigned char  sectorstatus;
143 	unsigned char  sectorpos[2];
144 	unsigned char  startdata[4];
145 } vapi_sector_header_t;
146 
147 #define VAPI_32(x) (x[0] + (x[1] << 8) + (x[2] << 16) + (x[3] << 24))
148 #define VAPI_16(x) (x[0] + (x[1] << 8))
149 
150 /* Additional Info for all copy protected disk types */
151 static void *additional_info[SIO_MAX_DRIVES];
152 
153 SIO_UnitStatus SIO_drive_status[SIO_MAX_DRIVES];
154 char SIO_filename[SIO_MAX_DRIVES][FILENAME_MAX];
155 
156 Util_tmpbufdef(static, sio_tmpbuf[SIO_MAX_DRIVES])
157 
158 int SIO_last_op;
159 int SIO_last_op_time = 0;
160 int SIO_last_drive;
161 int SIO_last_sector;
162 char SIO_status[256];
163 
164 /* Serial I/O emulation support */
165 #define SIO_NoFrame         (0x00)
166 #define SIO_CommandFrame    (0x01)
167 #define SIO_StatusRead      (0x02)
168 #define SIO_ReadFrame       (0x03)
169 #define SIO_WriteFrame      (0x04)
170 #define SIO_FinalStatus     (0x05)
171 #define SIO_FormatFrame     (0x06)
172 #define SIO_CasReadWrite    (0x60)
173 static UBYTE CommandFrame[6];
174 static int CommandIndex = 0;
175 static UBYTE DataBuffer[256 + 3];
176 static int DataIndex = 0;
177 static int TransferStatus = SIO_NoFrame;
178 static int ExpectedBytes = 0;
179 
180 int ignore_header_writeprotect = FALSE;
181 
SIO_Initialise(int * argc,char * argv[])182 int SIO_Initialise(int *argc, char *argv[])
183 {
184 	int i;
185 	for (i = 0; i < SIO_MAX_DRIVES; i++) {
186 		strcpy(SIO_filename[i], "Off");
187 		SIO_drive_status[i] = SIO_OFF;
188 		SIO_format_sectorsize[i] = 128;
189 		SIO_format_sectorcount[i] = 720;
190 	}
191 	TransferStatus = SIO_NoFrame;
192 
193 	return TRUE;
194 }
195 
196 /* umount disks so temporary files are deleted */
SIO_Exit(void)197 void SIO_Exit(void)
198 {
199 	int i;
200 	for (i = 1; i <= SIO_MAX_DRIVES; i++)
201 		SIO_Dismount(i);
202 }
203 
SIO_Mount(int diskno,const char * filename,int b_open_readonly)204 int SIO_Mount(int diskno, const char *filename, int b_open_readonly)
205 {
206 	FILE *f = NULL;
207 	SIO_UnitStatus status = SIO_READ_WRITE;
208 	struct AFILE_ATR_Header header;
209 
210 	/* avoid overruns in SIO_filename[] */
211 	if (strlen(filename) >= FILENAME_MAX)
212 		return FALSE;
213 
214 	/* release previous disk */
215 	SIO_Dismount(diskno);
216 
217 	/* open file */
218 	if (!b_open_readonly)
219 		f = Util_fopen(filename, "rb+", sio_tmpbuf[diskno - 1]);
220 	if (f == NULL) {
221 		f = Util_fopen(filename, "rb", sio_tmpbuf[diskno - 1]);
222 		if (f == NULL)
223 			return FALSE;
224 		status = SIO_READ_ONLY;
225 	}
226 
227 	/* read header */
228 	if (fread(&header, 1, sizeof(struct AFILE_ATR_Header), f) != sizeof(struct AFILE_ATR_Header)) {
229 		fclose(f);
230 		return FALSE;
231 	}
232 
233 	/* detect compressed image and uncompress */
234 	switch (header.magic1) {
235 	case 0xf9:
236 	case 0xfa:
237 		/* DCM */
238 		{
239 			FILE *f2 = Util_tmpopen(sio_tmpbuf[diskno - 1]);
240 			if (f2 == NULL)
241 				return FALSE;
242 			Util_rewind(f);
243 			if (!CompFile_DCMtoATR(f, f2)) {
244 				Util_fclose(f2, sio_tmpbuf[diskno - 1]);
245 				fclose(f);
246 				return FALSE;
247 			}
248 			fclose(f);
249 			f = f2;
250 		}
251 		Util_rewind(f);
252 		if (fread(&header, 1, sizeof(struct AFILE_ATR_Header), f) != sizeof(struct AFILE_ATR_Header)) {
253 			Util_fclose(f, sio_tmpbuf[diskno - 1]);
254 			return FALSE;
255 		}
256 		status = SIO_READ_ONLY;
257 		/* XXX: status = b_open_readonly ? SIO_READ_ONLY : SIO_READ_WRITE; */
258 		break;
259 	case 0x1f:
260 		if (header.magic2 == 0x8b) {
261 			/* ATZ/ATR.GZ, XFZ/XFD.GZ */
262 			fclose(f);
263 			f = Util_tmpopen(sio_tmpbuf[diskno - 1]);
264 			if (f == NULL)
265 				return FALSE;
266 			if (!CompFile_ExtractGZ(filename, f)) {
267 				Util_fclose(f, sio_tmpbuf[diskno - 1]);
268 				return FALSE;
269 			}
270 			Util_rewind(f);
271 			if (fread(&header, 1, sizeof(struct AFILE_ATR_Header), f) != sizeof(struct AFILE_ATR_Header)) {
272 				Util_fclose(f, sio_tmpbuf[diskno - 1]);
273 				return FALSE;
274 			}
275 			status = SIO_READ_ONLY;
276 			/* XXX: status = b_open_readonly ? SIO_READ_ONLY : SIO_READ_WRITE; */
277 		}
278 		break;
279 	default:
280 		break;
281 	}
282 
283 	boot_sectors_type[diskno - 1] = BOOT_SECTORS_LOGICAL;
284 
285 	if (header.magic1 == AFILE_ATR_MAGIC1 && header.magic2 == AFILE_ATR_MAGIC2) {
286 		/* ATR (may be temporary from DCM or ATR/ATR.GZ) */
287 		image_type[diskno - 1] = IMAGE_TYPE_ATR;
288 
289 		sectorsize[diskno - 1] = (header.secsizehi << 8) + header.secsizelo;
290 		if (sectorsize[diskno - 1] != 128 && sectorsize[diskno - 1] != 256) {
291 			Util_fclose(f, sio_tmpbuf[diskno - 1]);
292 			return FALSE;
293 		}
294 
295 		if (header.writeprotect != 0 && !ignore_header_writeprotect)
296 			status = SIO_READ_ONLY;
297 
298 		/* ATR header contains length in 16-byte chunks. */
299 		/* First compute number of 128-byte chunks
300 		   - it's number of sectors on single density disk */
301 		sectorcount[diskno - 1] = ((header.hiseccounthi << 24)
302 			+ (header.hiseccountlo << 16)
303 			+ (header.seccounthi << 8)
304 			+ header.seccountlo) >> 3;
305 
306 		/* Fix number of sectors if double density */
307 		if (sectorsize[diskno - 1] == 256) {
308 			if ((sectorcount[diskno - 1] & 1) != 0)
309 				/* logical (128-byte) boot sectors */
310 				sectorcount[diskno - 1] += 3;
311 			else {
312 				/* 256-byte boot sectors */
313 				/* check if physical or SIO2PC: physical if there's
314 				   a non-zero byte in bytes 0x190-0x30f of the ATR file */
315 				UBYTE buffer[0x180];
316 				int i;
317 				fseek(f, 0x190, SEEK_SET);
318 				if (fread(buffer, 1, 0x180, f) != 0x180) {
319 					Util_fclose(f, sio_tmpbuf[diskno - 1]);
320 					return FALSE;
321 				}
322 				boot_sectors_type[diskno - 1] = BOOT_SECTORS_SIO2PC;
323 				for (i = 0; i < 0x180; i++)
324 					if (buffer[i] != 0) {
325 						boot_sectors_type[diskno - 1] = BOOT_SECTORS_PHYSICAL;
326 						break;
327 					}
328 			}
329 			sectorcount[diskno - 1] >>= 1;
330 		}
331 	}
332 	else if (header.magic1 == 'A' && header.magic2 == 'T' && header.seccountlo == '8' &&
333 		 header.seccounthi == 'X') {
334 		int file_length = Util_flen(f);
335 		vapi_additional_info_t *info;
336 		vapi_file_header_t fileheader;
337 		vapi_track_header_t trackheader;
338 		int trackoffset, totalsectors;
339 
340 		/* .atx is read only for now */
341 #ifndef VAPI_WRITE_ENABLE
342 		if (!b_open_readonly) {
343 			fclose(f);
344 			f = Util_fopen(filename, "rb", sio_tmpbuf[diskno - 1]);
345 			if (f == NULL)
346 				return FALSE;
347 			status = SIO_READ_ONLY;
348 		}
349 #endif
350 
351 		image_type[diskno - 1] = IMAGE_TYPE_VAPI;
352 		sectorsize[diskno - 1] = 128;
353 		sectorcount[diskno - 1] = 720;
354 		fseek(f,0,SEEK_SET);
355 		if (fread(&fileheader,1,sizeof(fileheader),f) != sizeof(fileheader)) {
356 			Util_fclose(f, sio_tmpbuf[diskno - 1]);
357 			Log_print("VAPI: Bad File Header");
358 			return(FALSE);
359 			}
360 		trackoffset = VAPI_32(fileheader.startdata);
361 		if (trackoffset > file_length) {
362 			Util_fclose(f, sio_tmpbuf[diskno - 1]);
363 			Log_print("VAPI: Bad Track Offset");
364 			return(FALSE);
365 			}
366 #ifdef DEBUG_VAPI
367 		Log_print("VAPI File Version %d.%d",fileheader.majorver,fileheader.minorver);
368 #endif
369 		/* Read all of the track headers to get the total sector count */
370 		totalsectors = 0;
371 		while (trackoffset > 0 && trackoffset < file_length) {
372 			ULONG next;
373 			UWORD tracktype;
374 
375 			fseek(f,trackoffset,SEEK_SET);
376 			if (fread(&trackheader,1,sizeof(trackheader),f) != sizeof(trackheader)) {
377 				Util_fclose(f, sio_tmpbuf[diskno - 1]);
378 				Log_print("VAPI: Bad Track Header");
379 				return(FALSE);
380 				}
381 			next = VAPI_32(trackheader.next);
382 			tracktype = VAPI_16(trackheader.type);
383 			if (tracktype == 0) {
384 				totalsectors += VAPI_16(trackheader.sectorcnt);
385 				}
386 			trackoffset += next;
387 		}
388 
389 		info = Util_malloc(sizeof(vapi_additional_info_t));
390 		additional_info[diskno-1] = info;
391 		info->sectors = Util_malloc(sectorcount[diskno - 1] *
392  					    sizeof(vapi_sec_info_t));
393 		memset(info->sectors, 0, sectorcount[diskno - 1] *
394  					 sizeof(vapi_sec_info_t));
395 
396 		/* Now read all the sector data */
397 		trackoffset = VAPI_32(fileheader.startdata);
398 		while (trackoffset > 0 && trackoffset < file_length) {
399 			int sectorcnt, seclistdata,next;
400 			vapi_sector_list_header_t sectorlist;
401 			vapi_sector_header_t sectorheader;
402 			vapi_sec_info_t *sector;
403 			UWORD tracktype;
404 			int j;
405 
406 			fseek(f,trackoffset,SEEK_SET);
407 			if (fread(&trackheader,1,sizeof(trackheader),f) != sizeof(trackheader)) {
408 				free(info->sectors);
409 				free(info);
410 				Util_fclose(f, sio_tmpbuf[diskno - 1]);
411 				Log_print("VAPI: Bad Track Header while reading sectors");
412 				return(FALSE);
413 				}
414 			next = VAPI_32(trackheader.next);
415 			sectorcnt = VAPI_16(trackheader.sectorcnt);
416 			tracktype = VAPI_16(trackheader.type);
417 			seclistdata = VAPI_32(trackheader.startdata) + trackoffset;
418 #ifdef DEBUG_VAPI
419 			Log_print("Track %d: next %x type %d seccnt %d secdata %x",trackheader.tracknum,
420 				trackoffset + next,VAPI_16(trackheader.type),sectorcnt,seclistdata);
421 #endif
422 			if (tracktype == 0) {
423 				if (seclistdata > file_length) {
424 					free(info->sectors);
425 					free(info);
426 					Util_fclose(f, sio_tmpbuf[diskno - 1]);
427 					Log_print("VAPI: Bad Sector List Offset");
428 					return(FALSE);
429 					}
430 				fseek(f,seclistdata,SEEK_SET);
431 				if (fread(&sectorlist,1,sizeof(sectorlist),f) != sizeof(sectorlist)) {
432 					free(info->sectors);
433 					free(info);
434 					Util_fclose(f, sio_tmpbuf[diskno - 1]);
435 					Log_print("VAPI: Bad Sector List");
436 					return(FALSE);
437 					}
438 #ifdef DEBUG_VAPI
439 				Log_print("Size sec list %x type %d",VAPI_32(sectorlist.sizelist),sectorlist.type);
440 #endif
441 				for (j=0;j<sectorcnt;j++) {
442 					double percent_rot;
443 
444 					if (fread(&sectorheader,1,sizeof(sectorheader),f) != sizeof(sectorheader)) {
445 						free(info->sectors);
446 						free(info);
447 						Util_fclose(f, sio_tmpbuf[diskno - 1]);
448 						Log_print("VAPI: Bad Sector Header");
449 						return(FALSE);
450 						}
451 					if (sectorheader.sectornum > 18)  {
452 						Util_fclose(f, sio_tmpbuf[diskno - 1]);
453 						Log_print("VAPI: Bad Sector Index: Track %d Sec Num %d Index %d",
454 								trackheader.tracknum,j,sectorheader.sectornum);
455 						return(FALSE);
456 						}
457 					sector = &info->sectors[trackheader.tracknum * 18 + sectorheader.sectornum - 1];
458 
459 					percent_rot = ((double) VAPI_16(sectorheader.sectorpos))/VAPI_BYTES_PER_TRACK;
460 					sector->sec_rot_pos[sector->sec_count] = (unsigned int) (percent_rot * VAPI_CYCLES_PER_ROT);
461 					sector->sec_offset[sector->sec_count] = VAPI_32(sectorheader.startdata) + trackoffset;
462 					sector->sec_status[sector->sec_count] = ~sectorheader.sectorstatus;
463 					sector->sec_count++;
464 					if (sector->sec_count > MAX_VAPI_PHANTOM_SEC) {
465 						free(info->sectors);
466 						free(info);
467 						Util_fclose(f, sio_tmpbuf[diskno - 1]);
468 						Log_print("VAPI: Too many Phantom Sectors");
469 						return(FALSE);
470 						}
471 #ifdef DEBUG_VAPI
472 					Log_print("Sector %d status %x position %f %d %d data %x",sectorheader.sectornum,
473 						sector->sec_status[sector->sec_count-1],percent_rot,
474 						sector->sec_rot_pos[sector->sec_count-1],
475 						VAPI_16(sectorheader.sectorpos),
476 						sector->sec_offset[sector->sec_count-1]);
477 #endif
478 				}
479 #ifdef DEBUG_VAPI
480 				Log_flushlog();
481 #endif
482 			} else {
483 				Log_print("Unknown VAPI track type Track:%d Type:%d",trackheader.tracknum,tracktype);
484 			}
485 			trackoffset += next;
486 		}
487 	}
488 	else {
489 		int file_length = Util_flen(f);
490 		/* check for PRO */
491 		if ((file_length-16)%(128+12) == 0 &&
492 				(header.magic1*256 + header.magic2 == (file_length-16)/(128+12)) &&
493 				header.seccountlo == 'P') {
494 			pro_additional_info_t *info;
495 			/* .pro is read only for now */
496 			if (!b_open_readonly) {
497 				fclose(f);
498 				f = Util_fopen(filename, "rb", sio_tmpbuf[diskno - 1]);
499 				if (f == NULL)
500 					return FALSE;
501 				status = SIO_READ_ONLY;
502 			}
503 			image_type[diskno - 1] = IMAGE_TYPE_PRO;
504 			sectorsize[diskno - 1] = 128;
505 			if (file_length >= 1040*(128+12)+16) {
506 				/* assume enhanced density */
507 				sectorcount[diskno - 1] = 1040;
508 			}
509 			else {
510 				/* assume single density */
511 				sectorcount[diskno - 1] = 720;
512 			}
513 
514 			info = Util_malloc(sizeof(pro_additional_info_t));
515 			additional_info[diskno-1] = info;
516 			info->count = Util_malloc(sectorcount[diskno - 1]);
517 			memset(info->count, 0, sectorcount[diskno -1]);
518 			info->max_sector = (file_length-16)/(128+12);
519 		}
520 		else {
521 			/* XFD (may be temporary from XFZ/XFD.GZ) */
522 
523 			image_type[diskno - 1] = IMAGE_TYPE_XFD;
524 
525 			if (file_length <= (1040 * 128)) {
526 				/* single density */
527 				sectorsize[diskno - 1] = 128;
528 				sectorcount[diskno - 1] = file_length >> 7;
529 			}
530 			else {
531 				/* double density */
532 				sectorsize[diskno - 1] = 256;
533 				if ((file_length & 0xff) == 0) {
534 					boot_sectors_type[diskno - 1] = BOOT_SECTORS_PHYSICAL;
535 					sectorcount[diskno - 1] = file_length >> 8;
536 				}
537 				else
538 					sectorcount[diskno - 1] = (file_length + 0x180) >> 8;
539 			}
540 		}
541 	}
542 
543 #ifdef DEBUG
544 	Log_print("sectorcount = %d, sectorsize = %d",
545 		   sectorcount[diskno - 1], sectorsize[diskno - 1]);
546 #endif
547 	SIO_format_sectorsize[diskno - 1] = sectorsize[diskno - 1];
548 	SIO_format_sectorcount[diskno - 1] = sectorcount[diskno - 1];
549 	strcpy(SIO_filename[diskno - 1], filename);
550 	SIO_drive_status[diskno - 1] = status;
551 	disk[diskno - 1] = f;
552 	return TRUE;
553 }
554 
SIO_Dismount(int diskno)555 void SIO_Dismount(int diskno)
556 {
557 	if (disk[diskno - 1] != NULL) {
558 		Util_fclose(disk[diskno - 1], sio_tmpbuf[diskno - 1]);
559 		disk[diskno - 1] = NULL;
560 		SIO_drive_status[diskno - 1] = SIO_NO_DISK;
561 		strcpy(SIO_filename[diskno - 1], "Empty");
562 		if (image_type[diskno - 1] == IMAGE_TYPE_PRO) {
563 			free(((pro_additional_info_t *)additional_info[diskno-1])->count);
564 		}
565 		else if (image_type[diskno - 1] == IMAGE_TYPE_VAPI) {
566 			free(((vapi_additional_info_t *)additional_info[diskno-1])->sectors);
567 		}
568 		free(additional_info[diskno - 1]);
569 		additional_info[diskno - 1] = 0;
570 	}
571 }
572 
SIO_DisableDrive(int diskno)573 void SIO_DisableDrive(int diskno)
574 {
575 	SIO_Dismount(diskno);
576 	SIO_drive_status[diskno - 1] = SIO_OFF;
577 	strcpy(SIO_filename[diskno - 1], "Off");
578 }
579 
SIO_SizeOfSector(UBYTE unit,int sector,int * sz,ULONG * ofs)580 void SIO_SizeOfSector(UBYTE unit, int sector, int *sz, ULONG *ofs)
581 {
582 	int size;
583 	ULONG offset;
584 	int header_size = (image_type[unit] == IMAGE_TYPE_ATR ? 16 : 0);
585 
586 	if (BINLOAD_start_binloading) {
587 		if (sz)
588 			*sz = 128;
589 		if (ofs)
590 			*ofs = 0;
591 		return;
592 	}
593 
594 	if (image_type[unit] == IMAGE_TYPE_PRO) {
595 		size = 128;
596 		offset = 16 + (128+12)*(sector -1); /* returns offset of header */
597 	}
598 	else if (image_type[unit] == IMAGE_TYPE_VAPI) {
599 		vapi_additional_info_t *info;
600 		vapi_sec_info_t *secinfo;
601 
602 		size = 128;
603 		info = additional_info[unit];
604 		if (info == NULL)
605 			offset = 0;
606 		else if (sector > sectorcount[unit])
607 			offset = 0;
608 		else {
609 			secinfo = &info->sectors[sector-1];
610 			if (secinfo->sec_count == 0  )
611 				offset = 0;
612 			else
613 				offset = secinfo->sec_offset[0];
614 		}
615 	}
616 	else if (sector < 4) {
617 		/* special case for first three sectors in ATR and XFD image */
618 		size = 128;
619 		offset = header_size + (sector - 1) * (boot_sectors_type[unit] == BOOT_SECTORS_PHYSICAL ? 256 : 128);
620 	}
621 	else {
622 		size = sectorsize[unit];
623 		offset = header_size + (boot_sectors_type[unit] == BOOT_SECTORS_LOGICAL ? 0x180 : 0x300) + (sector - 4) * size;
624 	}
625 
626 	if (sz)
627 		*sz = size;
628 
629 	if (ofs)
630 		*ofs = offset;
631 }
632 
SeekSector(int unit,int sector)633 static int SeekSector(int unit, int sector)
634 {
635 	ULONG offset;
636 	int size;
637 
638 	SIO_last_sector = sector;
639 	snprintf(SIO_status, sizeof(SIO_status), "%d: %d", unit + 1, sector);
640 	SIO_SizeOfSector((UBYTE) unit, sector, &size, &offset);
641 	fseek(disk[unit], offset, SEEK_SET);
642 
643 	return size;
644 }
645 
646 /* Unit counts from zero up */
SIO_ReadSector(int unit,int sector,UBYTE * buffer)647 int SIO_ReadSector(int unit, int sector, UBYTE *buffer)
648 {
649 	int size;
650 	if (BINLOAD_start_binloading)
651 		return BINLOAD_LoaderStart(buffer);
652 
653 	io_success[unit] = -1;
654 	if (SIO_drive_status[unit] == SIO_OFF)
655 		return 0;
656 	if (disk[unit] == NULL)
657 		return 'N';
658 	if (sector <= 0 || sector > sectorcount[unit])
659 		return 'E';
660 	SIO_last_op = SIO_LAST_READ;
661 	SIO_last_op_time = 1;
662 	SIO_last_drive = unit + 1;
663 	/* FIXME: what sector size did the user expect? */
664 	size = SeekSector(unit, sector);
665 	if (image_type[unit] == IMAGE_TYPE_PRO) {
666 		pro_additional_info_t *info;
667 		unsigned char *count;
668 		info = (pro_additional_info_t *)additional_info[unit];
669 		count = info->count;
670 		if (fread(buffer, 1, 12, disk[unit]) < 12) {
671 			Log_print("Error in header of .pro image: sector:%d", sector);
672 			return 'E';
673 		}
674 		/* handle duplicate sectors */
675 		if (buffer[5] != 0) {
676 			int dupnum = count[sector];
677 #ifdef DEBUG_PRO
678 			Log_print("duplicate sector:%d dupnum:%d",sector, dupnum);
679 #endif
680 			count[sector] = (count[sector]+1) % (buffer[5]+1);
681 			if (dupnum != 0)  {
682 				sector = sectorcount[unit] + buffer[6+dupnum];
683 				/* can dupnum be 5? */
684 				if (dupnum > 4 || sector <= 0 || sector > info->max_sector) {
685 					Log_print("Error in .pro image: sector:%d dupnum:%d", sector, dupnum);
686 					return 'E';
687 				}
688 				size = SeekSector(unit, sector);
689 				/* read sector header */
690 				if (fread(buffer, 1, 12, disk[unit]) < 12) {
691 					Log_print("Error in header2 of .pro image: sector:%d dupnum:%d", sector, dupnum);
692 					return 'E';
693 				}
694 			}
695 		}
696 		/* bad sector */
697 		if (buffer[1] != 0xff) {
698 			if (fread(buffer, 1, size, disk[unit]) < size) {
699 				Log_print("Error in bad sector of .pro image: sector:%d", sector);
700 			}
701 			io_success[unit] = sector;
702 #ifdef DEBUG_PRO
703 			Log_print("bad sector:%d", sector);
704 #endif
705 			return 'E';
706 		}
707 	}
708 	else if (image_type[unit] == IMAGE_TYPE_VAPI) {
709 		vapi_additional_info_t *info;
710 		vapi_sec_info_t *secinfo;
711 		ULONG secindex = 0;
712 		static int lasttrack = 0;
713 		unsigned int currpos, time, delay, rotations, bestdelay;
714 /*		unsigned char beststatus;*/
715 		int fromtrack, trackstostep, j;
716 
717 		info = (vapi_additional_info_t *)additional_info[unit];
718 		info->vapi_delay_time = 0;
719 
720 		if (sector > sectorcount[unit]) {
721 #ifdef DEBUG_VAPI
722 			Log_print("bad sector num:%d", sector);
723 #endif
724 			info->sec_stat_buff[0] = 9;
725 			info->sec_stat_buff[1] = 0xFF;
726 			info->sec_stat_buff[2] = 0xe0;
727 			info->sec_stat_buff[3] = 0;
728 			info->vapi_delay_time= VAPI_CYCLES_BAD_SECTOR_NUM;
729 			return 'E';
730 		}
731 
732 		secinfo = &info->sectors[sector-1];
733 		fromtrack = lasttrack;
734 		lasttrack = (sector-1)/18;
735 
736 		if (secinfo->sec_count == 0) {
737 #ifdef DEBUG_VAPI
738 			Log_print("missing sector:%d", sector);
739 #endif
740 			info->sec_stat_buff[0] = 0xC;
741 			info->sec_stat_buff[1] = 0xEF;
742 			info->sec_stat_buff[2] = 0xe0;
743 			info->sec_stat_buff[3] = 0;
744 			info->vapi_delay_time= VAPI_CYCLES_MISSING_SECTOR;
745 			return 'E';
746 		}
747 
748 		trackstostep = abs((sector-1)/18 - fromtrack);
749 		time = (unsigned int) ANTIC_CPU_CLOCK;
750 		if (trackstostep)
751 			time += trackstostep * VAPI_CYCLES_PER_TRACK_STEP + VAPI_CYCLES_HEAD_SETTLE ;
752 		time += VAPI_CYCLES_CMD_ACK_TRANS;
753 		rotations = time/VAPI_CYCLES_PER_ROT;
754 		currpos = time - rotations*VAPI_CYCLES_PER_ROT;
755 
756 #ifdef DEBUG_VAPI
757 		Log_print(" sector:%d sector count :%d time %d", sector,secinfo->sec_count,ANTIC_CPU_CLOCK);
758 #endif
759 
760 		bestdelay = 10 * VAPI_CYCLES_PER_ROT;
761 /*		beststatus = 0;*/
762 		for (j=0;j<secinfo->sec_count;j++) {
763 			if (secinfo->sec_rot_pos[j]  < currpos)
764 				delay = (VAPI_CYCLES_PER_ROT - currpos) + secinfo->sec_rot_pos[j];
765 			else
766 				delay = secinfo->sec_rot_pos[j] - currpos;
767 #ifdef DEBUG_VAPI
768 			Log_print("%d %d %d %d %d %x",j,secinfo->sec_rot_pos[j],
769 					  ((unsigned int) ANTIC_CPU_CLOCK) - ((((unsigned int) ANTIC_CPU_CLOCK)/VAPI_CYCLES_PER_ROT)*VAPI_CYCLES_PER_ROT),
770 					  currpos,delay,secinfo->sec_status[j]);
771 #endif
772 			if (delay < bestdelay) {
773 				bestdelay = delay;
774 /*				beststatus = secinfo->sec_status[j];*/
775 				secindex = j;
776 			}
777 		}
778 		if (trackstostep)
779 			info->vapi_delay_time = bestdelay + trackstostep * VAPI_CYCLES_PER_TRACK_STEP +
780 				     VAPI_CYCLES_HEAD_SETTLE   +  VAPI_CYCLES_TRACK_READ_DELTA +
781 						       VAPI_CYCLES_CMD_ACK_TRANS + VAPI_CYCLES_SECTOR_READ;
782 		else
783 			info->vapi_delay_time = bestdelay +
784 						       VAPI_CYCLES_CMD_ACK_TRANS + VAPI_CYCLES_SECTOR_READ;
785 #ifdef DEBUG_VAPI
786 		Log_print("Bestdelay = %d VapiDelay = %d",bestdelay,info->vapi_delay_time);
787 		if (secinfo->sec_count > 1)
788 			Log_print("duplicate sector:%d dupnum:%d delay:%d",sector, secindex,info->vapi_delay_time);
789 #endif
790 		fseek(disk[unit],secinfo->sec_offset[secindex],SEEK_SET);
791 		info->sec_stat_buff[0] = 0x8 | ((secinfo->sec_status[secindex] == 0xFF) ? 0 : 0x04);
792 		info->sec_stat_buff[1] = secinfo->sec_status[secindex];
793 		info->sec_stat_buff[2] = 0xe0;
794 		info->sec_stat_buff[3] = 0;
795 		if (secinfo->sec_status[secindex] != 0xFF) {
796 			if (fread(buffer, 1, size, disk[unit]) < size) {
797 				Log_print("error reading sector:%d", sector);
798 			}
799 			io_success[unit] = sector;
800 			info->vapi_delay_time += VAPI_CYCLES_PER_ROT + 10000;
801 #ifdef DEBUG_VAPI
802 			Log_print("bad sector:%d 0x%0X delay:%d", sector, secinfo->sec_status[secindex],info->vapi_delay_time );
803 #endif
804 			{
805 			int i;
806 				if (secinfo->sec_status[secindex] == 0xB7) {
807 					for (i=0;i<128;i++) {
808 						Log_print("0x%02x",buffer[i]);
809 						if (buffer[i] == 0x33)
810 							buffer[i] = rand() & 0xFF;
811 					}
812 				}
813 			}
814 			return 'E';
815 		}
816 #ifdef DEBUG_VAPI
817 		Log_flushlog();
818 #endif
819 	}
820 	if (fread(buffer, 1, size, disk[unit]) < size) {
821 		Log_print("incomplete sector num:%d", sector);
822 	}
823 	io_success[unit] = 0;
824 	return 'C';
825 }
826 
SIO_WriteSector(int unit,int sector,const UBYTE * buffer)827 int SIO_WriteSector(int unit, int sector, const UBYTE *buffer)
828 {
829 	int size;
830 	io_success[unit] = -1;
831 	if (SIO_drive_status[unit] == SIO_OFF)
832 		return 0;
833 	if (disk[unit] == NULL)
834 		return 'N';
835 	if (SIO_drive_status[unit] != SIO_READ_WRITE || sector <= 0 || sector > sectorcount[unit])
836 		return 'E';
837 	SIO_last_op = SIO_LAST_WRITE;
838 	SIO_last_op_time = 1;
839 	SIO_last_drive = unit + 1;
840 #ifdef VAPI_WRITE_ENABLE
841  	if (image_type[unit] == IMAGE_TYPE_VAPI) {
842 		vapi_additional_info_t *info;
843 		vapi_sec_info_t *secinfo;
844 
845 		info = (vapi_additional_info_t *)additional_info[unit];
846 		secinfo = &info->sectors[sector-1];
847 
848 		if (secinfo->sec_count != 1) {
849 			/* No writes to sectors with duplicates or missing sectors */
850 			return 'E';
851 		}
852 
853 		if (secinfo->sec_status[0] != 0xFF) {
854 			/* No writes to bad sectors */
855 			return 'E';
856 		}
857 
858 		size = SeekSector(unit, sector);
859 		fseek(disk[unit],secinfo->sec_offset[0],SEEK_SET);
860 		fwrite(buffer, 1, size, disk[unit]);
861 		io_success[unit] = 0;
862 		return 'C';
863 #if 0
864 	} else if (image_type[unit] == IMAGE_TYPE_PRO) {
865 		pro_additional_info_t *info;
866 		pro_phantom_sec_info_t *phantom;
867 
868 		info = (pro_additional_info_t *)additional_info[unit];
869 		phantom = &info->phantom[sector-1];
870 
871 		if (phantom->phantom_count != 0) {
872 			/* No writes to sectors with duplicates */
873 			return 'E';
874 		}
875 
876 		size = SeekSector(unit, sector);
877 		if (buffer[1] != 0xff) {
878 #endif
879 	}
880 #endif
881 	size = SeekSector(unit, sector);
882 	fwrite(buffer, 1, size, disk[unit]);
883 	io_success[unit] = 0;
884 	return 'C';
885 }
886 
887 int SIO_FormatDisk(int unit, UBYTE *buffer, int sectsize, int sectcount)
888 {
889 	char fname[FILENAME_MAX];
890 	int is_atr;
891 	int save_boot_sectors_type;
892 	int bootsectsize;
893 	int bootsectcount;
894 	FILE *f;
895 	int i;
896 	io_success[unit] = -1;
897 	if (SIO_drive_status[unit] == SIO_OFF)
898 		return 0;
899 	if (disk[unit] == NULL)
900 		return 'N';
901 	if (SIO_drive_status[unit] != SIO_READ_WRITE)
902 		return 'E';
903 	/* Note formatting the disk can change size of the file.
904 	   There is no portable way to truncate the file at given position.
905 	   We have to close the "rb+" open file and open it in "wb" mode.
906 	   First get the information about the disk image, because we are going
907 	   to umount it. */
908 	memcpy(fname, SIO_filename[unit], FILENAME_MAX);
909 	is_atr = (image_type[unit] == IMAGE_TYPE_ATR);
910 	save_boot_sectors_type = boot_sectors_type[unit];
911 	bootsectsize = 128;
912 	if (sectsize == 256 && save_boot_sectors_type != BOOT_SECTORS_LOGICAL)
913 		bootsectsize = 256;
914 	bootsectcount = sectcount < 3 ? sectcount : 3;
915 	/* Umount the file and open it in "wb" mode (it will truncate the file) */
916 	SIO_Dismount(unit + 1);
917 	f = fopen(fname, "wb");
918 	if (f == NULL) {
919 		Log_print("SIO_FormatDisk: failed to open %s for writing", fname);
920 		return 'E';
921 	}
922 	/* Write ATR header if necessary */
923 	if (is_atr) {
924 		struct AFILE_ATR_Header header;
925 		ULONG disksize = (bootsectsize * bootsectcount + sectsize * (sectcount - bootsectcount)) >> 4;
926 		memset(&header, 0, sizeof(header));
927 		header.magic1 = AFILE_ATR_MAGIC1;
928 		header.magic2 = AFILE_ATR_MAGIC2;
929 		header.secsizelo = (UBYTE) sectsize;
930 		header.secsizehi = (UBYTE) (sectsize >> 8);
931 		header.seccountlo = (UBYTE) disksize;
932 		header.seccounthi = (UBYTE) (disksize >> 8);
933 		header.hiseccountlo = (UBYTE) (disksize >> 16);
934 		header.hiseccounthi = (UBYTE) (disksize >> 24);
935 		fwrite(&header, 1, sizeof(header), f);
936 	}
937 	/* Write boot sectors */
938 	memset(buffer, 0, sectsize);
939 	for (i = 1; i <= bootsectcount; i++)
940 		fwrite(buffer, 1, bootsectsize, f);
941 	/* Write regular sectors */
942 	for ( ; i <= sectcount; i++)
943 		fwrite(buffer, 1, sectsize, f);
944 	/* Close file and mount the disk back */
945 	fclose(f);
946 	SIO_Mount(unit + 1, fname, FALSE);
947 	/* We want to keep the current PHYSICAL/SIO2PC boot sectors type
948 	   (since the image is blank it can't be figured out by SIO_Mount) */
949 	if (bootsectsize == 256)
950 		boot_sectors_type[unit] = save_boot_sectors_type;
951 	/* Return information for Atari (buffer filled with ff's - no bad sectors) */
952 	memset(buffer, 0xff, sectsize);
953 	io_success[unit] = 0;
954 	return 'C';
955 }
956 
957 /* Set density and number of sectors
958    This function is used before the format (0x21) command
959    to set how the disk will be formatted.
960    Note this function does *not* affect the currently attached disk
961    (previously sectorsize/sectorcount were used which could result in
962    a corrupted image).
963 */
964 int SIO_WriteStatusBlock(int unit, const UBYTE *buffer)
965 {
966 	int size;
967 #ifdef DEBUG
968 	Log_print("Write Status-Block: %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x",
969 		buffer[0], buffer[1], buffer[2], buffer[3],
970 		buffer[4], buffer[5], buffer[6], buffer[7],
971 		buffer[8], buffer[9], buffer[10], buffer[11]);
972 #endif
973 	if (SIO_drive_status[unit] == SIO_OFF)
974 		return 0;
975 	/* We only care about the density and the sector count here.
976 	   Setting everything else right here seems to be non-sense.
977 	   I'm not sure about this density settings, my XF551
978 	   honors only the sector size and ignores the density */
979 	size = buffer[6] * 256 + buffer[7];
980 	if (size == 128 || size == 256)
981 		SIO_format_sectorsize[unit] = size;
982 	/* Note that the number of heads are minus 1 */
983 	SIO_format_sectorcount[unit] = buffer[0] * (buffer[2] * 256 + buffer[3]) * (buffer[4] + 1);
984 	if (SIO_format_sectorcount[unit] < 1 || SIO_format_sectorcount[unit] > 65535)
985 		SIO_format_sectorcount[unit] = 720;
986 	return 'C';
987 }
988 
989 int SIO_ReadStatusBlock(int unit, UBYTE *buffer)
990 {
991 	UBYTE tracks;
992 	UBYTE heads;
993 	int spt;
994 	if (SIO_drive_status[unit] == SIO_OFF)
995 		return 0;
996 	/* default to 1 track, 1 side for non-standard images */
997 	tracks = 1;
998 	heads = 1;
999 	spt = sectorcount[unit];
1000 
1001 	if (spt % 40 == 0) {
1002 		/* standard disk */
1003 		tracks = 40;
1004 		spt /= 40;
1005 		if (spt > 26 && spt % 2 == 0) {
1006 			/* double-sided */
1007 			heads = 2;
1008 			spt >>= 1;
1009 			if (spt > 26 && spt % 2 == 0) {
1010 				/* double-sided, 80 tracks */
1011 				tracks = 80;
1012 				spt >>= 1;
1013 			}
1014 		}
1015 	}
1016 
1017 	buffer[0] = tracks;              /* # of tracks */
1018 	buffer[1] = 1;                   /* step rate */
1019 	buffer[2] = (UBYTE) (spt >> 8);  /* sectors per track. HI byte */
1020 	buffer[3] = (UBYTE) spt;         /* sectors per track. LO byte */
1021 	buffer[4] = (UBYTE) (heads - 1); /* # of heads minus 1 */
1022 	/* FM for single density, MFM otherwise */
1023 	buffer[5] = (sectorsize[unit] == 128 && sectorcount[unit] <= 720) ? 0 : 4;
1024 	buffer[6] = (UBYTE) (sectorsize[unit] >> 8); /* bytes per sector. HI byte */
1025 	buffer[7] = (UBYTE) sectorsize[unit];        /* bytes per sector. LO byte */
1026 	buffer[8] = 1;                   /* drive is online */
1027 	buffer[9] = 192;                 /* transfer speed, whatever this means */
1028 	buffer[10] = 0;
1029 	buffer[11] = 0;
1030 	return 'C';
1031 }
1032 
1033 /*
1034    Status Request from Atari 400/800 Technical Reference Notes
1035 
1036    DVSTAT + 0   Command Status
1037    DVSTAT + 1   Hardware Status
1038    DVSTAT + 2   Timeout
1039    DVSTAT + 3   Unused
1040 
1041    Command Status Bits
1042 
1043    Bit 0 = 1 indicates an invalid command frame was received
1044    Bit 1 = 1 indicates an invalid data frame was received
1045    Bit 2 = 1 indicates that last read/write operation was unsuccessful
1046    Bit 3 = 1 indicates that the diskette is write protected
1047    Bit 4 = 1 indicates active/standby
1048 
1049    plus
1050 
1051    Bit 5 = 1 indicates double density
1052    Bit 7 = 1 indicates dual density disk (1050 format)
1053  */
1054 int SIO_DriveStatus(int unit, UBYTE *buffer)
1055 {
1056 	if (BINLOAD_start_binloading) {
1057 		buffer[0] = 16 + 8;
1058 		buffer[1] = 255;
1059 		buffer[2] = 1;
1060 		buffer[3] = 0 ;
1061 		return 'C';
1062 	}
1063 
1064 	if (SIO_drive_status[unit] == SIO_OFF)
1065 		return 0;
1066 
1067 	/* .PRO contains status information in the sector header */
1068 	if (io_success[unit] != 0  && image_type[unit] == IMAGE_TYPE_PRO) {
1069 		int sector = io_success[unit];
1070 		SeekSector(unit, sector);
1071 		if (fread(buffer, 1, 4, disk[unit]) < 4) {
1072 			Log_print("SIO_DriveStatus: failed to read sector header");
1073 		}
1074 		return 'C';
1075 	}
1076 	else if (io_success[unit] != 0  && image_type[unit] == IMAGE_TYPE_VAPI &&
1077 			 SIO_drive_status[unit] != SIO_NO_DISK) {
1078 		vapi_additional_info_t *info;
1079 		info = (vapi_additional_info_t *)additional_info[unit];
1080 		buffer[0] = info->sec_stat_buff[0];
1081 		buffer[1] = info->sec_stat_buff[1];
1082 		buffer[2] = info->sec_stat_buff[2];
1083 		buffer[3] = info->sec_stat_buff[3];
1084 		Log_print("Drive Status unit %d %x %x %x %x",unit,buffer[0], buffer[1], buffer[2], buffer[3]);
1085 		return 'C';
1086 	}
1087 	buffer[0] = 16;         /* drive active */
1088 	buffer[1] = disk[unit] != NULL ? 255 /* WD 177x OK */ : 127 /* no disk */;
1089 	if (io_success[unit] != 0)
1090 		buffer[0] |= 4;     /* failed RW-operation */
1091 	if (SIO_drive_status[unit] == SIO_READ_ONLY)
1092 		buffer[0] |= 8;     /* write protection */
1093 	if (SIO_format_sectorsize[unit] == 256)
1094 		buffer[0] |= 32;    /* double density */
1095 	if (SIO_format_sectorcount[unit] == 1040)
1096 		buffer[0] |= 128;   /* 1050 enhanced density */
1097 	buffer[2] = 1;
1098 	buffer[3] = 0;
1099 	return 'C';
1100 }
1101 
1102 #ifndef NO_SECTOR_DELAY
1103 /* A hack for the "Overmind" demo.  This demo verifies if sectors aren't read
1104    faster than with a typical disk drive.  We introduce a delay
1105    of SECTOR_DELAY scanlines between successive reads of sector 1. */
1106 #define SECTOR_DELAY 3200
1107 static int delay_counter = 0;
1108 static int last_ypos = 0;
1109 #endif
1110 
1111 /* SIO patch emulation routine */
1112 void SIO_Handler(void)
1113 {
1114 	int sector = MEMORY_dGetWordAligned(0x30a);
1115 	UBYTE unit = (MEMORY_dGetByte(0x300) + MEMORY_dGetByte(0x301) + 0xff ) - 0x31;
1116 	UBYTE result = 0x00;
1117 	UWORD data = MEMORY_dGetWordAligned(0x304);
1118 	int length = MEMORY_dGetWordAligned(0x308);
1119 	int realsize = 0;
1120 	int cmd = MEMORY_dGetByte(0x302);
1121 
1122 	if ((unsigned int)MEMORY_dGetByte(0x300) + (unsigned int)MEMORY_dGetByte(0x301) > 0xff) {
1123 		/* carry */
1124 		unit++;
1125 	}
1126 	/* A real atari just adds the bytes and 0xff. The result could wrap.*/
1127 	/* XL OS: E99D: LDA $0300 ADC $0301 ADC #$FF STA 023A */
1128 	/* Disk 1 is ASCII '1' = 0x31 etc */
1129 	/* Disk 1 -> unit = 0 */
1130 	if (MEMORY_dGetByte(0x300) != 0x60 && unit < SIO_MAX_DRIVES && (SIO_drive_status[unit] != SIO_OFF || BINLOAD_start_binloading)) {	/* UBYTE range ! */
1131 #ifdef DEBUG
1132 		Log_print("SIO disk command is %02x %02x %02x %02x %02x   %02x %02x %02x %02x %02x %02x",
1133 			cmd, MEMORY_dGetByte(0x303), MEMORY_dGetByte(0x304), MEMORY_dGetByte(0x305), MEMORY_dGetByte(0x306),
1134 			MEMORY_dGetByte(0x308), MEMORY_dGetByte(0x309), MEMORY_dGetByte(0x30a), MEMORY_dGetByte(0x30b),
1135 			MEMORY_dGetByte(0x30c), MEMORY_dGetByte(0x30d));
1136 #endif
1137 		switch (cmd) {
1138 		case 0x4e:				/* Read Status Block */
1139 			if (12 == length) {
1140 				result = SIO_ReadStatusBlock(unit, DataBuffer);
1141 				if (result == 'C')
1142 					MEMORY_CopyToMem(DataBuffer, data, 12);
1143 			}
1144 			else
1145 				result = 'E';
1146 			break;
1147 		case 0x4f:				/* Write Status Block */
1148 			if (12 == length) {
1149 				MEMORY_CopyFromMem(data, DataBuffer, 12);
1150 				result = SIO_WriteStatusBlock(unit, DataBuffer);
1151 			}
1152 			else
1153 				result = 'E';
1154 			break;
1155 		case 0x50:				/* Write */
1156 		case 0x57:
1157 		case 0xD0:				/* xf551 hispeed */
1158 		case 0xD7:
1159 			SIO_SizeOfSector(unit, sector, &realsize, NULL);
1160 			if (realsize == length) {
1161 				MEMORY_CopyFromMem(data, DataBuffer, realsize);
1162 				result = SIO_WriteSector(unit, sector, DataBuffer);
1163 			}
1164 			else
1165 				result = 'E';
1166 			break;
1167 		case 0x52:				/* Read */
1168 		case 0xD2:				/* xf551 hispeed */
1169 #ifndef NO_SECTOR_DELAY
1170 			if (sector == 1) {
1171 				if (delay_counter > 0) {
1172 					if (last_ypos != ANTIC_ypos) {
1173 						last_ypos = ANTIC_ypos;
1174 						delay_counter--;
1175 					}
1176 					CPU_regPC = 0xe459;	/* stay at SIO patch */
1177 					return;
1178 				}
1179 				delay_counter = SECTOR_DELAY;
1180 			}
1181 			else {
1182 				delay_counter = 0;
1183 			}
1184 #endif
1185 			SIO_SizeOfSector(unit, sector, &realsize, NULL);
1186 			if (realsize == length) {
1187 				result = SIO_ReadSector(unit, sector, DataBuffer);
1188 				if (result == 'C')
1189 					MEMORY_CopyToMem(DataBuffer, data, realsize);
1190 			}
1191 			else
1192 				result = 'E';
1193 			break;
1194 		case 0x53:				/* Status */
1195 			if (4 == length) {
1196 				result = SIO_DriveStatus(unit, DataBuffer);
1197 				if (result == 'C') {
1198 					MEMORY_CopyToMem(DataBuffer, data, 4);
1199 				}
1200 			}
1201 			else
1202 				result = 'E';
1203 			break;
1204 		/*case 0x66:*/			/* US Doubler Format - I think! */
1205 		case 0x21:				/* Format Disk */
1206 		case 0xA1:				/* xf551 hispeed */
1207 			realsize = SIO_format_sectorsize[unit];
1208 			if (realsize == length) {
1209 				result = SIO_FormatDisk(unit, DataBuffer, realsize, SIO_format_sectorcount[unit]);
1210 				if (result == 'C')
1211 					MEMORY_CopyToMem(DataBuffer, data, realsize);
1212 			}
1213 			else {
1214 				/* there are programs which send the format-command but don't wait for the result (eg xf-tools) */
1215 				SIO_FormatDisk(unit, DataBuffer, realsize, SIO_format_sectorcount[unit]);
1216 				result = 'E';
1217 			}
1218 			break;
1219 		case 0x22:				/* Enhanced Density Format */
1220 		case 0xA2:				/* xf551 hispeed */
1221 			realsize = 128;
1222 			if (realsize == length) {
1223 				result = SIO_FormatDisk(unit, DataBuffer, 128, 1040);
1224 				if (result == 'C')
1225 					MEMORY_CopyToMem(DataBuffer, data, realsize);
1226 			}
1227 			else {
1228 				SIO_FormatDisk(unit, DataBuffer, 128, 1040);
1229 				result = 'E';
1230 			}
1231 			break;
1232 		default:
1233 			result = 'N';
1234 		}
1235 	}
1236 	/* cassette i/o */
1237 	else if (MEMORY_dGetByte(0x300) == 0x60) {
1238 		UBYTE gaps = MEMORY_dGetByte(0x30b);
1239 		switch (cmd){
1240 		case 0x52:	/* read */
1241 			SIO_last_op = SIO_LAST_READ;
1242 			SIO_last_drive = 0x61;
1243 			SIO_last_op_time = 0x10;
1244 			/* set expected Gap */
1245 			CASSETTE_AddGap(gaps == 0 ? 2000 : 160);
1246 			/* get record from storage medium */
1247 			if (CASSETTE_ReadToMemory(data, length))
1248 				result = 'C';
1249 			else
1250 				result = 'E';
1251 			break;
1252 		case 0x57:	/* write */
1253 			SIO_last_op = SIO_LAST_WRITE;
1254 			SIO_last_drive = 0x61;
1255 			SIO_last_op_time = 0x10;
1256 			/* add pregap length */
1257 			CASSETTE_AddGap(gaps == 0 ? 3000 : 260);
1258 			/* write full record to storage medium */
1259 			if (CASSETTE_WriteFromMemory(data, length))
1260 				result = 'C';
1261 			else
1262 				result = 'E';
1263 			break;
1264 		default:
1265 			result = 'N';
1266 		}
1267 	}
1268 
1269 	switch (result) {
1270 	case 0x00:					/* Device disabled, generate timeout */
1271 		CPU_regY = 138;
1272 		CPU_SetN;
1273 		break;
1274 	case 'A':					/* Device acknowledge */
1275 	case 'C':					/* Operation complete */
1276 		CPU_regY = 1;
1277 		CPU_ClrN;
1278 		break;
1279 	case 'N':					/* Device NAK */
1280 		CPU_regY = 144;
1281 		CPU_SetN;
1282 		break;
1283 	case 'E':					/* Device error */
1284 	default:
1285 		CPU_regY = 146;
1286 		CPU_SetN;
1287 		break;
1288 	}
1289 	CPU_regA = 0;	/* MMM */
1290 	MEMORY_dPutByte(0x0303, CPU_regY);
1291 	MEMORY_dPutByte(0x42,0);
1292 	CPU_SetC;
1293 
1294 	/* After each SIO operation a routine called SENDDS ($EC5F in OSB) is
1295 	   invoked, which, among other functions, silences the sound
1296 	   generators. With SIO patch we don't call SIOV and in effect SENDDS
1297 	   is not called either, but this causes a problem with tape saving.
1298 	   During tape saving sound generators are enabled before calling
1299 	   SIOV, but are not disabled later (no call to SENDDS). The effect is
1300 	   that after saving to tape the unwanted SIO sounds are left audible.
1301 	   To avoid the problem, we silence the sound registers by hand. */
1302 	POKEY_PutByte(POKEY_OFFSET_AUDC1, 0);
1303 	POKEY_PutByte(POKEY_OFFSET_AUDC2, 0);
1304 	POKEY_PutByte(POKEY_OFFSET_AUDC3, 0);
1305 	POKEY_PutByte(POKEY_OFFSET_AUDC4, 0);
1306 }
1307 
1308 UBYTE SIO_ChkSum(const UBYTE *buffer, int length)
1309 {
1310 #if 0
1311 	/* old, less efficient version */
1312 	int i;
1313 	int checksum = 0;
1314 	for (i = 0; i < length; i++, buffer++) {
1315 		checksum += *buffer;
1316 		while (checksum > 255)
1317 			checksum -= 255;
1318 	}
1319 #else
1320 	int checksum = 0;
1321 	while (--length >= 0)
1322 		checksum += *buffer++;
1323 	do
1324 		checksum = (checksum & 0xff) + (checksum >> 8);
1325 	while (checksum > 255);
1326 #endif
1327 	return checksum;
1328 }
1329 
1330 static UBYTE Command_Frame(void)
1331 {
1332 	int unit;
1333 	int sector;
1334 	int realsize;
1335 
1336 	sector = CommandFrame[2] | (((UWORD) CommandFrame[3]) << 8);
1337 	unit = CommandFrame[0] - '1';
1338 
1339 	if (unit < 0 || unit >= SIO_MAX_DRIVES) {
1340 		/* Unknown device */
1341 		Log_print("Unknown command frame: %02x %02x %02x %02x %02x",
1342 			   CommandFrame[0], CommandFrame[1], CommandFrame[2],
1343 			   CommandFrame[3], CommandFrame[4]);
1344 		TransferStatus = SIO_NoFrame;
1345 		return 0;
1346 	}
1347 	switch (CommandFrame[1]) {
1348 	case 0x4e:				/* Read Status */
1349 #ifdef DEBUG
1350 		Log_print("Read-status frame: %02x %02x %02x %02x %02x",
1351 			CommandFrame[0], CommandFrame[1], CommandFrame[2],
1352 			CommandFrame[3], CommandFrame[4]);
1353 #endif
1354 		DataBuffer[0] = SIO_ReadStatusBlock(unit, DataBuffer + 1);
1355 		DataBuffer[13] = SIO_ChkSum(DataBuffer + 1, 12);
1356 		DataIndex = 0;
1357 		ExpectedBytes = 14;
1358 		TransferStatus = SIO_ReadFrame;
1359 		POKEY_DELAYED_SERIN_IRQ = SIO_SERIN_INTERVAL;
1360 		return 'A';
1361 	case 0x4f:				/* Write status */
1362 #ifdef DEBUG
1363 		Log_print("Write-status frame: %02x %02x %02x %02x %02x",
1364 			CommandFrame[0], CommandFrame[1], CommandFrame[2],
1365 			CommandFrame[3], CommandFrame[4]);
1366 #endif
1367 		ExpectedBytes = 13;
1368 		DataIndex = 0;
1369 		TransferStatus = SIO_WriteFrame;
1370 		return 'A';
1371 	case 0x50:				/* Write */
1372 	case 0x57:
1373 	case 0xD0:				/* xf551 hispeed */
1374 	case 0xD7:
1375 #ifdef DEBUG
1376 		Log_print("Write-sector frame: %02x %02x %02x %02x %02x",
1377 			CommandFrame[0], CommandFrame[1], CommandFrame[2],
1378 			CommandFrame[3], CommandFrame[4]);
1379 #endif
1380 		SIO_SizeOfSector((UBYTE) unit, sector, &realsize, NULL);
1381 		ExpectedBytes = realsize + 1;
1382 		DataIndex = 0;
1383 		TransferStatus = SIO_WriteFrame;
1384 		SIO_last_op = SIO_LAST_WRITE;
1385 		SIO_last_op_time = 10;
1386 		SIO_last_drive = unit + 1;
1387 		return 'A';
1388 	case 0x52:				/* Read */
1389 	case 0xD2:				/* xf551 hispeed */
1390 #ifdef DEBUG
1391 		Log_print("Read-sector frame: %02x %02x %02x %02x %02x",
1392 			CommandFrame[0], CommandFrame[1], CommandFrame[2],
1393 			CommandFrame[3], CommandFrame[4]);
1394 #endif
1395 		SIO_SizeOfSector((UBYTE) unit, sector, &realsize, NULL);
1396 		DataBuffer[0] = SIO_ReadSector(unit, sector, DataBuffer + 1);
1397 		DataBuffer[1 + realsize] = SIO_ChkSum(DataBuffer + 1, realsize);
1398 		DataIndex = 0;
1399 		ExpectedBytes = 2 + realsize;
1400 		TransferStatus = SIO_ReadFrame;
1401 		/* wait longer before confirmation because bytes could be lost */
1402 		/* before the buffer was set (see $E9FB & $EA37 in XL-OS) */
1403 		POKEY_DELAYED_SERIN_IRQ = SIO_SERIN_INTERVAL << 2;
1404 		if (image_type[unit] == IMAGE_TYPE_VAPI) {
1405 			vapi_additional_info_t *info;
1406 			info = (vapi_additional_info_t *)additional_info[unit];
1407 			if (info == NULL)
1408 				POKEY_DELAYED_SERIN_IRQ = SIO_SERIN_INTERVAL << 2;
1409 			else
1410 				POKEY_DELAYED_SERIN_IRQ = ((info->vapi_delay_time + 114/2) / 114) - 12;
1411 		}
1412 #ifndef NO_SECTOR_DELAY
1413 		else if (sector == 1) {
1414 			POKEY_DELAYED_SERIN_IRQ += delay_counter;
1415 			delay_counter = SECTOR_DELAY;
1416 		}
1417 		else {
1418 			delay_counter = 0;
1419 		}
1420 #endif
1421 		SIO_last_op = SIO_LAST_READ;
1422 		SIO_last_op_time = 10;
1423 		SIO_last_drive = unit + 1;
1424 		return 'A';
1425 	case 0x53:				/* Status */
1426 #ifdef DEBUG
1427 		Log_print("Status frame: %02x %02x %02x %02x %02x",
1428 			CommandFrame[0], CommandFrame[1], CommandFrame[2],
1429 			CommandFrame[3], CommandFrame[4]);
1430 #endif
1431 		DataBuffer[0] = SIO_DriveStatus(unit, DataBuffer + 1);
1432 		DataBuffer[1 + 4] = SIO_ChkSum(DataBuffer + 1, 4);
1433 		DataIndex = 0;
1434 		ExpectedBytes = 6;
1435 		TransferStatus = SIO_ReadFrame;
1436 		POKEY_DELAYED_SERIN_IRQ = SIO_SERIN_INTERVAL;
1437 		return 'A';
1438 	/*case 0x66:*/			/* US Doubler Format - I think! */
1439 	case 0x21:				/* Format Disk */
1440 	case 0xa1:				/* xf551 hispeed */
1441 #ifdef DEBUG
1442 		Log_print("Format-disk frame: %02x %02x %02x %02x %02x",
1443 			CommandFrame[0], CommandFrame[1], CommandFrame[2],
1444 			CommandFrame[3], CommandFrame[4]);
1445 #endif
1446 		realsize = SIO_format_sectorsize[unit];
1447 		DataBuffer[0] = SIO_FormatDisk(unit, DataBuffer + 1, realsize, SIO_format_sectorcount[unit]);
1448 		DataBuffer[1 + realsize] = SIO_ChkSum(DataBuffer + 1, realsize);
1449 		DataIndex = 0;
1450 		ExpectedBytes = 2 + realsize;
1451 		TransferStatus = SIO_FormatFrame;
1452 		POKEY_DELAYED_SERIN_IRQ = SIO_SERIN_INTERVAL;
1453 		return 'A';
1454 	case 0x22:				/* Dual Density Format */
1455 	case 0xa2:				/* xf551 hispeed */
1456 #ifdef DEBUG
1457 		Log_print("Format-Medium frame: %02x %02x %02x %02x %02x",
1458 			CommandFrame[0], CommandFrame[1], CommandFrame[2],
1459 			CommandFrame[3], CommandFrame[4]);
1460 #endif
1461 		DataBuffer[0] = SIO_FormatDisk(unit, DataBuffer + 1, 128, 1040);
1462 		DataBuffer[1 + 128] = SIO_ChkSum(DataBuffer + 1, 128);
1463 		DataIndex = 0;
1464 		ExpectedBytes = 2 + 128;
1465 		TransferStatus = SIO_FormatFrame;
1466 		POKEY_DELAYED_SERIN_IRQ = SIO_SERIN_INTERVAL;
1467 		return 'A';
1468 	default:
1469 		/* Unknown command for a disk drive */
1470 #ifdef DEBUG
1471 		Log_print("Command frame: %02x %02x %02x %02x %02x",
1472 			CommandFrame[0], CommandFrame[1], CommandFrame[2],
1473 			CommandFrame[3], CommandFrame[4]);
1474 #endif
1475 		TransferStatus = SIO_NoFrame;
1476 		return 'E';
1477 	}
1478 }
1479 
1480 /* Enable/disable the Tape Motor */
1481 void SIO_TapeMotor(int onoff)
1482 {
1483 	CASSETTE_TapeMotor(onoff);
1484 	if (onoff) {
1485 		/* set frame to cassette frame, if not */
1486 		/* in a transfer with an intelligent peripheral */
1487 		if (TransferStatus == SIO_NoFrame || TransferStatus == SIO_CasReadWrite)
1488 			TransferStatus = SIO_CasReadWrite;
1489 		SIO_last_drive = 0x60;
1490 		SIO_last_op_time = 0x10;
1491 	}
1492 	else {
1493 		/* set frame to none */
1494 		if (TransferStatus == SIO_CasReadWrite)
1495 			TransferStatus = SIO_NoFrame;
1496 		SIO_last_op_time = 0;
1497 	}
1498 }
1499 
1500 /* Enable/disable the command frame */
1501 void SIO_SwitchCommandFrame(int onoff)
1502 {
1503 	if (onoff) {				/* Enabled */
1504 		if (TransferStatus != SIO_NoFrame)
1505 			Log_print("Unexpected command frame at state %x.", TransferStatus);
1506 		CommandIndex = 0;
1507 		DataIndex = 0;
1508 		ExpectedBytes = 5;
1509 		TransferStatus = SIO_CommandFrame;
1510 	}
1511 	else {
1512 		if (TransferStatus != SIO_StatusRead && TransferStatus != SIO_NoFrame &&
1513 			TransferStatus != SIO_ReadFrame) {
1514 			if (!(TransferStatus == SIO_CommandFrame && CommandIndex == 0))
1515 				Log_print("Command frame %02x unfinished.", TransferStatus);
1516 			TransferStatus = SIO_NoFrame;
1517 		}
1518 		CommandIndex = 0;
1519 	}
1520 }
1521 
1522 static UBYTE WriteSectorBack(void)
1523 {
1524 	UWORD sector;
1525 	UBYTE unit;
1526 
1527 	sector = CommandFrame[2] + (CommandFrame[3] << 8);
1528 	unit = CommandFrame[0] - '1';
1529 	if (unit >= SIO_MAX_DRIVES)		/* UBYTE range ! */
1530 		return 0;
1531 	switch (CommandFrame[1]) {
1532 	case 0x4f:				/* Write Status Block */
1533 		return SIO_WriteStatusBlock(unit, DataBuffer);
1534 	case 0x50:				/* Write */
1535 	case 0x57:
1536 	case 0xD0:				/* xf551 hispeed */
1537 	case 0xD7:
1538 		return SIO_WriteSector(unit, sector, DataBuffer);
1539 	default:
1540 		return 'E';
1541 	}
1542 }
1543 
1544 /* Put a byte that comes out of POKEY. So get it here... */
1545 void SIO_PutByte(int byte)
1546 {
1547 	switch (TransferStatus) {
1548 	case SIO_CommandFrame:
1549 		if (CommandIndex < ExpectedBytes) {
1550 			CommandFrame[CommandIndex++] = byte;
1551 			if (CommandIndex >= ExpectedBytes) {
1552 				if (CommandFrame[0] >= 0x31 && CommandFrame[0] <= 0x38 && (SIO_drive_status[CommandFrame[0]-0x31] != SIO_OFF || BINLOAD_start_binloading)) {
1553 					TransferStatus = SIO_StatusRead;
1554 					POKEY_DELAYED_SERIN_IRQ = SIO_SERIN_INTERVAL + SIO_ACK_INTERVAL;
1555 				}
1556 				else
1557 					TransferStatus = SIO_NoFrame;
1558 			}
1559 		}
1560 		else {
1561 			Log_print("Invalid command frame!");
1562 			TransferStatus = SIO_NoFrame;
1563 		}
1564 		break;
1565 	case SIO_WriteFrame:		/* Expect data */
1566 		if (DataIndex < ExpectedBytes) {
1567 			DataBuffer[DataIndex++] = byte;
1568 			if (DataIndex >= ExpectedBytes) {
1569 				UBYTE sum = SIO_ChkSum(DataBuffer, ExpectedBytes - 1);
1570 				if (sum == DataBuffer[ExpectedBytes - 1]) {
1571 					UBYTE result = WriteSectorBack();
1572 					if (result != 0) {
1573 						DataBuffer[0] = 'A';
1574 						DataBuffer[1] = result;
1575 						DataIndex = 0;
1576 						ExpectedBytes = 2;
1577 						POKEY_DELAYED_SERIN_IRQ = SIO_SERIN_INTERVAL + SIO_ACK_INTERVAL;
1578 						TransferStatus = SIO_FinalStatus;
1579 					}
1580 					else
1581 						TransferStatus = SIO_NoFrame;
1582 				}
1583 				else {
1584 					DataBuffer[0] = 'E';
1585 					DataIndex = 0;
1586 					ExpectedBytes = 1;
1587 					POKEY_DELAYED_SERIN_IRQ = SIO_SERIN_INTERVAL + SIO_ACK_INTERVAL;
1588 					TransferStatus = SIO_FinalStatus;
1589 				}
1590 			}
1591 		}
1592 		else {
1593 			Log_print("Invalid data frame!");
1594 		}
1595 		break;
1596 	case SIO_CasReadWrite:
1597 		CASSETTE_PutByte(byte);
1598 		break;
1599 	}
1600 	/* POKEY_DELAYED_SEROUT_IRQ = SIO_SEROUT_INTERVAL; */ /* already set in pokey.c */
1601 }
1602 
1603 /* Get a byte from the floppy to the pokey. */
1604 int SIO_GetByte(void)
1605 {
1606 	int byte = 0;
1607 
1608 	switch (TransferStatus) {
1609 	case SIO_StatusRead:
1610 		byte = Command_Frame();		/* Handle now the command */
1611 		break;
1612 	case SIO_FormatFrame:
1613 		TransferStatus = SIO_ReadFrame;
1614 		POKEY_DELAYED_SERIN_IRQ = SIO_SERIN_INTERVAL << 3;
1615 		/* FALL THROUGH */
1616 	case SIO_ReadFrame:
1617 		if (DataIndex < ExpectedBytes) {
1618 			byte = DataBuffer[DataIndex++];
1619 			if (DataIndex >= ExpectedBytes) {
1620 				TransferStatus = SIO_NoFrame;
1621 			}
1622 			else {
1623 				/* set delay using the expected transfer speed */
1624 				POKEY_DELAYED_SERIN_IRQ = (DataIndex == 1) ? SIO_SERIN_INTERVAL
1625 					: ((SIO_SERIN_INTERVAL * POKEY_AUDF[POKEY_CHAN3] - 1) / 0x28 + 1);
1626 			}
1627 		}
1628 		else {
1629 			Log_print("Invalid read frame!");
1630 			TransferStatus = SIO_NoFrame;
1631 		}
1632 		break;
1633 	case SIO_FinalStatus:
1634 		if (DataIndex < ExpectedBytes) {
1635 			byte = DataBuffer[DataIndex++];
1636 			if (DataIndex >= ExpectedBytes) {
1637 				TransferStatus = SIO_NoFrame;
1638 			}
1639 			else {
1640 				if (DataIndex == 0)
1641 					POKEY_DELAYED_SERIN_IRQ = SIO_SERIN_INTERVAL + SIO_ACK_INTERVAL;
1642 				else
1643 					POKEY_DELAYED_SERIN_IRQ = SIO_SERIN_INTERVAL;
1644 			}
1645 		}
1646 		else {
1647 			Log_print("Invalid read frame!");
1648 			TransferStatus = SIO_NoFrame;
1649 		}
1650 		break;
1651 	case SIO_CasReadWrite:
1652 		byte = CASSETTE_GetByte();
1653 		break;
1654 	default:
1655 		break;
1656 	}
1657 	return byte;
1658 }
1659 
1660 #if !defined(BASIC) && !defined(__PLUS)
1661 int SIO_RotateDisks(void)
1662 {
1663 	char tmp_filenames[SIO_MAX_DRIVES][FILENAME_MAX];
1664 	int i;
1665 	int bSuccess = TRUE;
1666 
1667 	for (i = 0; i < SIO_MAX_DRIVES; i++) {
1668 		strcpy(tmp_filenames[i], SIO_filename[i]);
1669 		SIO_Dismount(i + 1);
1670 	}
1671 
1672 	for (i = 1; i < SIO_MAX_DRIVES; i++) {
1673 		if (strcmp(tmp_filenames[i], "None") && strcmp(tmp_filenames[i], "Off") && strcmp(tmp_filenames[i], "Empty") ) {
1674 			if (!SIO_Mount(i, tmp_filenames[i], FALSE)) /* Note that this is NOT i-1 because SIO_Mount is 1 indexed */
1675 				bSuccess = FALSE;
1676 		}
1677 	}
1678 
1679 	i = SIO_MAX_DRIVES - 1;
1680 	while (i > -1 && (!strcmp(tmp_filenames[i], "None") || !strcmp(tmp_filenames[i], "Off") || !strcmp(tmp_filenames[i], "Empty")) ) {
1681 		i--;
1682 	}
1683 
1684 	if (i > -1)	{
1685 		if (!SIO_Mount(i + 1, tmp_filenames[0], FALSE))
1686 			bSuccess = FALSE;
1687 	}
1688 
1689 	return bSuccess;
1690 }
1691 #endif /* !defined(BASIC) && !defined(__PLUS) */
1692 
1693 #ifndef BASIC
1694 
1695 void SIO_StateSave(void)
1696 {
1697 	int i;
1698 
1699 	for (i = 0; i < 8; i++) {
1700 		StateSav_SaveINT((int *) &SIO_drive_status[i], 1);
1701 		StateSav_SaveFNAME(SIO_filename[i]);
1702 	}
1703 }
1704 
1705 void SIO_StateRead(void)
1706 {
1707 	int i;
1708 
1709 	for (i = 0; i < 8; i++) {
1710 		int saved_drive_status;
1711 		char filename[FILENAME_MAX];
1712 
1713 		StateSav_ReadINT(&saved_drive_status, 1);
1714 		SIO_drive_status[i] = (SIO_UnitStatus)saved_drive_status;
1715 
1716 		StateSav_ReadFNAME(filename);
1717 		if (filename[0] == 0)
1718 			continue;
1719 
1720 		/* If the disk drive wasn't empty or off when saved,
1721 		   mount the disk */
1722 		switch (saved_drive_status) {
1723 		case SIO_READ_ONLY:
1724 			SIO_Mount(i + 1, filename, TRUE);
1725 			break;
1726 		case SIO_READ_WRITE:
1727 			SIO_Mount(i + 1, filename, FALSE);
1728 			break;
1729 		default:
1730 			break;
1731 		}
1732 	}
1733 }
1734 
1735 #endif /* BASIC */
1736 
1737 /*
1738 vim:ts=4:sw=4:
1739 */
1740