1 /*
2  * UAE - The Un*x Amiga Emulator
3  *
4  * lowlevel cd device glue, scsi emulator
5  *
6 * Copyright 2009-2013 Toni Wilen
7  *
8  */
9 
10 #include "sysconfig.h"
11 #include "sysdeps.h"
12 #include "options.h"
13 #include "memory_uae.h"
14 
15 #include "blkdev.h"
16 #include "scsidev.h"
17 #include "savestate.h"
18 #include "crc32.h"
19 #include "threaddep/thread.h"
20 #include "execio.h"
21 #include "zfile.h"
22 #include "misc.h"
23 #include "scsi.h"
24 #ifdef RETROPLATFORM
25 #include "rp.h"
26 #endif
27 
28 int log_scsiemu = 0;
29 
30 #define PRE_INSERT_DELAY (3 * (currprefs.ntscmode ? 60 : 50))
31 
32 struct blkdevstate
33 {
34 	int scsiemu;
35 	struct device_functions *device_func;
36 	int isopen;
37 	int waspaused;
38 	int delayed;
39 	uae_sem_t sema;
40 	int sema_cnt;
41 	int play_end_pos;
42 	uae_u8 play_qcode[SUBQ_SIZE];
43 	TCHAR newimagefile[256];
44 	int imagechangetime;
45 	bool cdimagefileinuse;
46 	int wasopen;
47 	bool mediawaschanged;
48 };
49 
50 struct blkdevstate state[MAX_TOTAL_SCSI_DEVICES];
51 
52 #if 0
53 static int scsiemu[MAX_TOTAL_SCSI_DEVICES];
54 
55 struct device_functions *device_func[MAX_TOTAL_SCSI_DEVICES];
56 static int openlist[MAX_TOTAL_SCSI_DEVICES];
57 static int waspaused[MAX_TOTAL_SCSI_DEVICES];
58 static int delayed[MAX_TOTAL_SCSI_DEVICES];
59 static uae_sem_t unitsem[MAX_TOTAL_SCSI_DEVICES];
60 static int unitsem_cnt[MAX_TOTAL_SCSI_DEVICES];
61 
62 static int play_end_pos[MAX_TOTAL_SCSI_DEVICES];
63 static uae_u8 play_qcode[MAX_TOTAL_SCSI_DEVICES][SUBQ_SIZE];
64 
65 static TCHAR newimagefiles[MAX_TOTAL_SCSI_DEVICES][256];
66 static int imagechangetime[MAX_TOTAL_SCSI_DEVICES];
67 static bool cdimagefileinuse[MAX_TOTAL_SCSI_DEVICES];
68 static int wasopen[MAX_TOTAL_SCSI_DEVICES];
69 #endif
70 
71 static bool dev_init;
72 
73 /* convert minutes, seconds and frames -> logical sector number */
msf2lsn(int msf)74 int msf2lsn (int msf)
75 {
76 	int sector = (((msf >> 16) & 0xff) * 60 * 75 + ((msf >> 8) & 0xff) * 75 + ((msf >> 0) & 0xff));
77 	sector -= 150;
78 	return sector;
79 }
80 
81 /* convert logical sector number -> minutes, seconds and frames */
lsn2msf(int sectors)82 int lsn2msf (int sectors)
83 {
84 	int msf;
85 	sectors += 150;
86 	msf = (sectors / (75 * 60)) << 16;
87 	msf |= ((sectors / 75) % 60) << 8;
88 	msf |= (sectors % 75) << 0;
89 	return msf;
90 }
91 
frombcd(uae_u8 v)92 uae_u8 frombcd (uae_u8 v)
93 {
94 	return (v >> 4) * 10 + (v & 15);
95 }
tobcd(uae_u8 v)96 uae_u8 tobcd (uae_u8 v)
97 {
98 	return ((v / 10) << 4) | (v % 10);
99 }
fromlongbcd(uae_u8 * p)100 int fromlongbcd (uae_u8 *p)
101 {
102 	return (frombcd (p[0]) << 16) | (frombcd (p[1]) << 8) | (frombcd (p[2])  << 0);
103 }
tolongbcd(uae_u8 * p,int v)104 void tolongbcd (uae_u8 *p, int v)
105 {
106 	p[0] = tobcd ((v >> 16) & 0xff);
107 	p[1] = tobcd ((v >> 8) & 0xff);
108 	p[2] = tobcd ((v >> 0) & 0xff);
109 }
110 
gettoc(struct cd_toc_head * th,int block)111 static struct cd_toc *gettoc (struct cd_toc_head *th, int block)
112 {
113 	for (int i = th->first_track_offset + 1; i <= th->last_track_offset; i++) {
114 		struct cd_toc *t = &th->toc[i];
115 		if (block < t->paddress)
116 			return t - 1;
117 	}
118 	return &th->toc[th->last_track_offset];
119 }
120 
isaudiotrack(struct cd_toc_head * th,int block)121 int isaudiotrack (struct cd_toc_head *th, int block)
122 {
123 	struct cd_toc *t = gettoc (th, block);
124 	if (!t)
125 		return 0;
126 	return (t->control & 0x0c) != 4;
127 }
128 
isdatatrack(struct cd_toc_head * th,int block)129 int isdatatrack (struct cd_toc_head *th, int block)
130 {
131 	return !isaudiotrack (th, block);
132 }
133 
134 static int cdscsidevicetype[MAX_TOTAL_SCSI_DEVICES];
135 
136 extern struct device_functions devicefunc_cdimage;
137 
138 static struct device_functions *devicetable[] = {
139 	NULL,
140 	&devicefunc_cdimage,
141 	NULL
142 };
143 static int driver_installed[6];
144 
install_driver(int flags)145 static void install_driver (int flags)
146 {
147 	for (int i = 0; i < MAX_TOTAL_SCSI_DEVICES; i++) {
148 		struct blkdevstate *st = &state[i];
149 		st->scsiemu = false;
150 		st->device_func = NULL;
151 	}
152 	if (flags > 0) {
153 		state[0].device_func = devicetable[flags];
154 		state[0].scsiemu = true;
155 	} else {
156 		for (int i = 0; i < MAX_TOTAL_SCSI_DEVICES; i++) {
157 			struct blkdevstate *st = &state[i];
158 			st->scsiemu = false;
159 			st->device_func = NULL;
160 			switch (cdscsidevicetype[i])
161 			{
162 				case SCSI_UNIT_IMAGE:
163 				st->device_func = devicetable[SCSI_UNIT_IMAGE];
164 				st->scsiemu = true;
165 				break;
166 				case SCSI_UNIT_IOCTL:
167 				st->device_func = devicetable[SCSI_UNIT_IOCTL];
168 				st->scsiemu = true;
169 				break;
170 				case SCSI_UNIT_SPTI:
171 				st->device_func = devicetable[SCSI_UNIT_SPTI];
172 				break;
173 			}
174 		}
175 	}
176 
177 	for (int j = 1; devicetable[j]; j++) {
178 		if (!driver_installed[j]) {
179 			for (int i = 0; i < MAX_TOTAL_SCSI_DEVICES; i++) {
180 				struct blkdevstate *st = &state[i];
181 				if (st->device_func == devicetable[j]) {
182 					int ok = st->device_func->openbus (0);
183 					driver_installed[j] = 1;
184 					write_log (_T("%s driver installed, ok=%d\n"), st->device_func->name, ok);
185 					break;
186 				}
187 			}
188 		}
189 	}
190 
191 }
192 /*#else
193 	#ifdef TARGET_AMIGAOS
194 extern struct device_functions devicefunc_scsi_amiga;
195 static void install_driver (int flags){}
196 	#else
197 		#ifdef SCSIEMU_LINUX_IOCTL
198 extern struct device_functions devicefunc_scsi_linux_ioctl;
199 static void install_driver (int flags){}
200 		#else
201 extern struct device_functions devicefunc_scsi_libscg;
202 static void install_driver (int flags){}
203 		#endif
204 	#endif
205 #endif*/
206 
blkdev_default_prefs(struct uae_prefs * p)207 void blkdev_default_prefs (struct uae_prefs *p)
208 {
209 	for (int i = 0; i < MAX_TOTAL_SCSI_DEVICES; i++) {
210 		p->cdslots[i].name[0] = 0;
211 		p->cdslots[i].inuse = false;
212 		p->cdslots[i].type = SCSI_UNIT_DEFAULT;
213 		cdscsidevicetype[i] = SCSI_UNIT_DEFAULT;
214 	}
215 }
216 
blkdev_fix_prefs(struct uae_prefs * p)217 void blkdev_fix_prefs (struct uae_prefs *p)
218 {
219 	for (int i = 0; i < MAX_TOTAL_SCSI_DEVICES; i++) {
220 		cdscsidevicetype[i] = p->cdslots[i].type;
221 		if (p->cdslots[i].inuse == false && p->cdslots[i].name[0] && p->cdslots[i].type != SCSI_UNIT_DISABLED)
222 			p->cdslots[i].inuse = true;
223 	}
224 
225 	for (int i = 0; i < MAX_TOTAL_SCSI_DEVICES; i++) {
226 		if (cdscsidevicetype[i] != SCSI_UNIT_DEFAULT)
227 			continue;
228 		if (p->cdslots[i].inuse || p->cdslots[i].name[0]) {
229 			TCHAR *name = p->cdslots[i].name;
230 			if (_tcslen (name) == 3 && name[1] == ':' && name[2] == '\\') {
231 //SPTI				if (currprefs.scsi && (currprefs.win32_uaescsimode == UAESCSI_SPTI || currprefs.win32_uaescsimode == UAESCSI_SPTISCAN))
232 //					cdscsidevicetype[i] = SCSI_UNIT_SPTI;
233 //				else
234 					cdscsidevicetype[i] = SCSI_UNIT_IOCTL;
235 			} else {
236 				cdscsidevicetype[i] = SCSI_UNIT_IMAGE;
237 			}
238 		} else if (currprefs.scsi) {
239 //EMU			if (currprefs.win32_uaescsimode == UAESCSI_CDEMU)
240 //				cdscsidevicetype[i] = SCSI_UNIT_IOCTL;
241 //			else
242 				cdscsidevicetype[i] = SCSI_UNIT_SPTI;
243 		} else {
244 			cdscsidevicetype[i] = SCSI_UNIT_IOCTL;
245 		}
246 	}
247 
248 }
249 
getsem2(int unitnum,bool dowait)250 static bool getsem2 (int unitnum, bool dowait)
251 {
252 	struct blkdevstate *st = &state[unitnum];
253 #ifdef _WIN32
254 	if (st->sema == INVALID_HANDLE_VALUE)
255 #else
256 	if (st->sema.sem == NULL)
257 #endif
258 		uae_sem_init (&st->sema, 0, 1);
259 	bool gotit = false;
260 	if (dowait) {
261 		uae_sem_wait (&st->sema);
262 		gotit = true;
263 	} else {
264 		gotit = uae_sem_trywait (&st->sema) == 0;
265 	}
266 	if (gotit)
267 		st->sema_cnt++;
268 	if (st->sema_cnt > 1)
269 		write_log (_T("CD: unitsem%d acquire mismatch! cnt=%d\n"), unitnum, st->sema_cnt);
270 	return gotit;
271 }
getsem(int unitnum)272 static bool getsem (int unitnum)
273 {
274 	return getsem2 (unitnum, false);
275 }
freesem(int unitnum)276 static void freesem (int unitnum)
277 {
278 	struct blkdevstate *st = &state[unitnum];
279 	st->sema_cnt--;
280 	if (st->sema_cnt < 0)
281 		write_log (_T("CD: unitsem%d release mismatch! cnt=%d\n"), unitnum, st->sema_cnt);
282 	uae_sem_post (&st->sema);
283 }
sys_command_close_internal(int unitnum)284 static void sys_command_close_internal (int unitnum)
285 {
286 	struct blkdevstate *st = &state[unitnum];
287 	getsem2 (unitnum, true);
288 	st->waspaused = 0;
289 	if (st->isopen <= 0)
290 		write_log (_T("BUG unit %d close: opencnt=%d!\n"), unitnum, st->isopen);
291 	if (st->device_func) {
292 		state[unitnum].device_func->closedev (unitnum);
293 		if (st->isopen > 0)
294 			st->isopen--;
295 	}
296 	freesem (unitnum);
297 	if (st->isopen == 0) {
298 		uae_sem_destroy (&st->sema);
299 #ifdef _WIN32
300 		st->sema = INVALID_HANDLE_VALUE;
301 #else
302 		st->sema.sem = NULL;
303 #endif
304 	}
305 }
306 
sys_command_open_internal(int unitnum,const TCHAR * ident,unsigned int csu)307 static int sys_command_open_internal (int unitnum, const TCHAR *ident, unsigned int csu)
308 {
309 	struct blkdevstate *st = &state[unitnum];
310 	int ret = 0;
311 #ifdef _WIN32
312 	if (st->sema == INVALID_HANDLE_VALUE)
313 #else
314 	if (st->sema.sem == NULL)
315 #endif
316 		uae_sem_init (&st->sema, 0, 1);
317 	getsem2 (unitnum, true);
318 	if (st->isopen)
319 		write_log (_T("BUG unit %d open: opencnt=%d!\n"), unitnum, st->isopen);
320 	if (st->device_func) {
321 		ret = state[unitnum].device_func->opendev (unitnum, ident, csu != CD_STANDARD_UNIT_DEFAULT);
322 		if (ret)
323 			st->isopen++;
324 	}
325 	freesem (unitnum);
326 	return ret;
327 }
328 
getunitinfo(int unitnum,int drive,unsigned int csu,int * isaudio)329 static int getunitinfo (int unitnum, int drive, unsigned int csu, int *isaudio)
330 {
331 	struct device_info di;
332 	if (sys_command_info (unitnum, &di, 0)) {
333 		write_log (_T("Scanning drive %s: "), di.label);
334 		if (di.media_inserted) {
335 			if (isaudiotrack (&di.toc, 0)) {
336 				if (*isaudio == 0)
337 					*isaudio = drive;
338 				write_log (_T("CDA"));
339 			}
340 			uae_u8 buffer[2048];
341 			if (sys_command_cd_read (unitnum, buffer, 16, 1)) {
342 				if (!memcmp (buffer + 8, "CDTV", 4) || !memcmp (buffer + 8, "CD32", 4) || !memcmp (buffer + 8, "COMM", 4)) {
343 					uae_u32 crc;
344 					write_log (_T("CD32 or CDTV"));
345 					if (sys_command_cd_read (unitnum, buffer, 21, 1)) {
346 						crc = get_crc32 (buffer, sizeof buffer);
347 						if (crc == 0xe56c340f) {
348 							write_log (_T(" [CD32.TM]"));
349 							if (csu == CD_STANDARD_UNIT_CD32) {
350 								write_log (_T("\n"));
351 								return 1;
352 							}
353 						}
354 					}
355 					if (csu == CD_STANDARD_UNIT_CDTV || csu == CD_STANDARD_UNIT_CD32) {
356 						write_log (_T("\n"));
357 						return 1;
358 					}
359 				}
360 			}
361 		} else {
362 			write_log (_T("no media"));
363 		}
364 	}
365 	write_log (_T("\n"));
366 	return 0;
367 }
368 
get_standard_cd_unit2(struct uae_prefs * p,unsigned int csu)369 static int get_standard_cd_unit2 (struct uae_prefs *p, unsigned int csu)
370 {
371 	int unitnum = 0;
372 	int isaudio = 0;
373 	if (p->cdslots[unitnum].name[0] || p->cdslots[unitnum].inuse) {
374 		if (p->cdslots[unitnum].name[0]) {
375 			device_func_init (SCSI_UNIT_IOCTL);
376 			if (!sys_command_open_internal (unitnum, p->cdslots[unitnum].name, csu)) {
377 				device_func_init (SCSI_UNIT_IMAGE);
378 				if (!sys_command_open_internal (unitnum, p->cdslots[unitnum].name, csu))
379 					goto fallback;
380 			}
381 		} else {
382 			goto fallback;
383 		}
384 		return unitnum;
385 	}
386 	device_func_init (SCSI_UNIT_IOCTL);
387 	for (int drive = 'C'; drive <= 'Z'; ++drive) {
388 		TCHAR vol[100];
389 		_stprintf (vol, _T("%c:\\"), drive);
390 		int drivetype = 0; //GetDriveType (vol);
391 		if (drivetype == -1 /*DRIVE_CDROM*/) {
392 			if (sys_command_open_internal (unitnum, vol, csu)) {
393 				if (getunitinfo (unitnum, drive, csu, &isaudio))
394 					return unitnum;
395 				sys_command_close (unitnum);
396 			}
397 		}
398 	}
399 	if (isaudio) {
400 		TCHAR vol[100];
401 		_stprintf (vol, _T("%c:\\"), isaudio);
402 		if (sys_command_open_internal (unitnum, vol, csu))
403 			return unitnum;
404 	}
405 fallback:
406 	device_func_init (SCSI_UNIT_IMAGE);
407 	if (!sys_command_open_internal (unitnum, _T(""), csu)) {
408 		write_log (_T("image mounter failed to open as empty!?\n"));
409 		return -1;
410 	}
411 	return unitnum;
412 }
413 
get_standard_cd_unit(unsigned int csu)414 int get_standard_cd_unit (unsigned int csu)
415 {
416 	int unitnum = get_standard_cd_unit2 (&currprefs, csu);
417 	if (unitnum < 0)
418 		return -1;
419 	struct blkdevstate *st = &state[unitnum];
420 #ifdef RETROPLATFORM
421 	rp_cd_device_enable (unitnum, true);
422 #endif
423 	st->delayed = 0;
424 	if (currprefs.cdslots[unitnum].delayed) {
425 		st->delayed = PRE_INSERT_DELAY;
426 	}
427 	return unitnum;
428 }
429 
close_standard_cd_unit(int unitnum)430 void close_standard_cd_unit (int unitnum)
431 {
432 	sys_command_close (unitnum);
433 }
434 
sys_command_isopen(int unitnum)435 int sys_command_isopen (int unitnum)
436 {
437 	struct blkdevstate *st = &state[unitnum];
438 	return st->isopen;
439 }
440 
sys_command_open(int unitnum)441 int sys_command_open (int unitnum)
442 {
443 	struct blkdevstate *st = &state[unitnum];
444 	blkdev_fix_prefs (&currprefs);
445 	if (!dev_init) {
446 		device_func_init (0);
447 		dev_init = true;
448 	}
449 
450 	if (st->isopen) {
451 		st->isopen++;
452 		return -1;
453 	}
454 	st->waspaused = 0;
455 	int v = sys_command_open_internal (unitnum, currprefs.cdslots[unitnum].name[0] ? currprefs.cdslots[unitnum].name : NULL, CD_STANDARD_UNIT_DEFAULT);
456 	if (!v)
457 		return 0;
458 #ifdef RETROPLATFORM
459 	rp_cd_device_enable (unitnum, true);
460 #endif
461 	return v;
462 }
463 
sys_command_close(int unitnum)464 void sys_command_close (int unitnum)
465 {
466 	struct blkdevstate *st = &state[unitnum];
467 	if (st->isopen > 1) {
468 		st->isopen--;
469 		return;
470 	}
471 #ifdef RETROPLATFORM
472 	rp_cd_device_enable (unitnum, false);
473 #endif
474 	sys_command_close_internal (unitnum);
475 }
476 
blkdev_cd_change(int unitnum,const TCHAR * name)477 void blkdev_cd_change (int unitnum, const TCHAR *name)
478 {
479 	struct device_info di;
480 	sys_command_info (unitnum, &di, 1);
481 #ifdef RETROPLATFORM
482 	rp_cd_image_change (unitnum, name);
483 #endif
484 }
485 
device_func_reset(void)486 void device_func_reset (void)
487 {
488 	for (int i = 0; i < MAX_TOTAL_SCSI_DEVICES; i++) {
489 		struct blkdevstate *st = &state[i];
490 		st->wasopen = 0;
491 		st->waspaused = false;
492 		st->imagechangetime = 0;
493 		st->cdimagefileinuse = false;
494 		st->newimagefile[0] = 0;
495 	}
496 }
497 
device_func_init(int flags)498 int device_func_init (int flags)
499 {
500 	blkdev_fix_prefs (&currprefs);
501 	install_driver (flags);
502 	return 1;
503 }
504 
blkdev_get_info(struct uae_prefs * p,int unitnum,struct device_info * di)505 bool blkdev_get_info (struct uae_prefs *p, int unitnum, struct device_info *di)
506 {
507 	bool open = true, opened = false, ok = false;
508 	struct blkdevstate *st = &state[unitnum];
509 	if (!st->isopen) {
510 		blkdev_fix_prefs (p);
511 		install_driver (0);
512 		opened = true;
513 		open = sys_command_open_internal (unitnum, p->cdslots[unitnum].name[0] ? p->cdslots[unitnum].name : NULL, CD_STANDARD_UNIT_DEFAULT) != 0;
514 	}
515 	if (open) {
516 		ok = sys_command_info (unitnum, di, true) != 0;
517 	}
518 	if (open && opened)
519 		sys_command_close_internal (unitnum);
520 	return ok;
521 }
522 
blkdev_entergui(void)523 void blkdev_entergui (void)
524 {
525 	for (int i = 0; i < MAX_TOTAL_SCSI_DEVICES; i++) {
526 		struct blkdevstate *st = &state[i];
527 		st->waspaused = 0;
528 		struct device_info di;
529 		if (sys_command_info (i, &di, 1)) {
530 			if (sys_command_cd_pause (i, 1) == 0)
531 				st->waspaused = 1;
532 		}
533 	}
534 }
blkdev_exitgui(void)535 void blkdev_exitgui (void)
536 {
537 	for (int i = 0; i < MAX_TOTAL_SCSI_DEVICES; i++) {
538 		struct blkdevstate *st = &state[i];
539 		if (st->waspaused) {
540 			struct device_info di;
541 			if (sys_command_info (i, &di, 1)) {
542 				sys_command_cd_pause (i, 0);
543 			}
544 		}
545 		st->waspaused = 0;
546 	}
547 }
548 
check_prefs_changed_cd(void)549 void check_prefs_changed_cd (void)
550 {
551 	if (!config_changed)
552 		return;
553 	currprefs.sound_volume_cd = changed_prefs.sound_volume_cd;
554 }
555 
check_changes(int unitnum)556 static void check_changes (int unitnum)
557 {
558 	struct blkdevstate *st = &state[unitnum];
559 	bool changed = false;
560 	bool gotsem = false;
561 
562 	if (st->device_func == NULL)
563 		return;
564 
565 	if (st->delayed) {
566 		st->delayed--;
567 		if (st->delayed == 0)
568 			write_log (_T("CD: startup delayed insert '%s'\n"), currprefs.cdslots[unitnum].name[0] ? currprefs.cdslots[unitnum].name : _T("<EMPTY>"));
569 		return;
570 	}
571 
572 	if (_tcscmp (changed_prefs.cdslots[unitnum].name, currprefs.cdslots[unitnum].name) != 0)
573 		changed = true;
574 	if (!changed && changed_prefs.cdslots[unitnum].name[0] == 0 && changed_prefs.cdslots[unitnum].inuse != currprefs.cdslots[unitnum].inuse)
575 		changed = true;
576 
577 	if (changed) {
578 		bool wasimage = currprefs.cdslots[unitnum].name[0] != 0;
579 #ifdef _WIN32
580 	if (st->sema != INVALID_HANDLE_VALUE)
581 #else
582 	if (st->sema.sem != NULL)
583 #endif
584 			gotsem = getsem2 (unitnum, true);
585 		st->cdimagefileinuse = changed_prefs.cdslots[unitnum].inuse;
586 		_tcscpy (st->newimagefile, changed_prefs.cdslots[unitnum].name);
587 		changed_prefs.cdslots[unitnum].name[0] = currprefs.cdslots[unitnum].name[0] = 0;
588 		currprefs.cdslots[unitnum].inuse = changed_prefs.cdslots[unitnum].inuse;
589 		int pollmode = 0;
590 		st->imagechangetime = 3 * 50;
591 		struct device_info di;
592 		st->device_func->info (unitnum, &di, 0, -1);
593 		if (st->wasopen >= 0)
594 			st->wasopen = di.open ? 1 : 0;
595 		if (st->wasopen) {
596 			st->device_func->closedev (unitnum);
597 			st->wasopen = -1;
598 			if (currprefs.scsi)  {
599 				scsi_do_disk_change (unitnum, 0, &pollmode);
600 				if (pollmode)
601 					st->imagechangetime = 8 * 50;
602 				if (filesys_do_disk_change (unitnum, 0)) {
603 					st->imagechangetime = st->newimagefile[0] ? 3 * 50 : 0;
604 					pollmode = 0;
605 				}
606 			}
607 		}
608 		write_log (_T("CD: eject (%s) open=%d\n"), pollmode ? _T("slow") : _T("fast"), st->wasopen ? 1 : 0);
609 #ifdef RETROPLATFORM
610 		rp_cd_image_change (unitnum, NULL);
611 #endif
612 		if (gotsem) {
613 			freesem (unitnum);
614 			gotsem = false;
615 		}
616 	}
617 	if (st->imagechangetime == 0)
618 		return;
619 	st->imagechangetime--;
620 	if (st->imagechangetime > 0)
621 		return;
622 #ifdef _WIN32
623 	if (st->sema != INVALID_HANDLE_VALUE)
624 #else
625 	if (st->sema.sem != NULL)
626 #endif
627 		gotsem = getsem2 (unitnum, true);
628 	_tcscpy (currprefs.cdslots[unitnum].name, st->newimagefile);
629 	_tcscpy (changed_prefs.cdslots[unitnum].name, st->newimagefile);
630 	currprefs.cdslots[unitnum].inuse = changed_prefs.cdslots[unitnum].inuse = st->cdimagefileinuse;
631 	st->newimagefile[0] = 0;
632 	write_log (_T("CD: delayed insert '%s' (open=%d,unit=%d)\n"), currprefs.cdslots[unitnum].name[0] ? currprefs.cdslots[unitnum].name : _T("<EMPTY>"), st->wasopen ? 1 : 0, unitnum);
633 	device_func_init (0);
634 	if (st->wasopen) {
635 		if (!st->device_func->opendev (unitnum, currprefs.cdslots[unitnum].name, 0)) {
636 			write_log (_T("-> device open failed\n"));
637 			st->wasopen = 0;
638 		} else {
639 			st->wasopen = 1;
640 			write_log (_T("-> device reopened\n"));
641 		}
642 	}
643 	if (currprefs.scsi && st->wasopen) {
644 		struct device_info di;
645 		st->device_func->info (unitnum, &di, 0, -1);
646 		int pollmode;
647 		if (gotsem) {
648 			freesem (unitnum);
649 			gotsem = false;
650 		}
651 		scsi_do_disk_change (unitnum, 1, &pollmode);
652 		filesys_do_disk_change (unitnum, 1);
653 	}
654 	st->mediawaschanged = true;
655 #ifdef RETROPLATFORM
656 	rp_cd_image_change (unitnum, currprefs.cdslots[unitnum].name);
657 #endif
658 	if (gotsem) {
659 		freesem (unitnum);
660 		gotsem = false;
661 	}
662 
663 	config_changed = 1;
664 
665 }
666 
blkdev_vsync(void)667 void blkdev_vsync (void)
668 {
669 	for (int i = 0; i < MAX_TOTAL_SCSI_DEVICES; i++)
670 		check_changes (i);
671 }
672 
do_scsi(int unitnum,uae_u8 * cmd,int cmdlen)673 static int do_scsi (int unitnum, uae_u8 *cmd, int cmdlen)
674 {
675 	uae_u8 *p = state[unitnum].device_func->exec_out (unitnum, cmd, cmdlen);
676 	return p != NULL;
677 }
do_scsi2(int unitnum,uae_u8 * cmd,int cmdlen,uae_u8 * out,int outsize)678 static int do_scsi2 (int unitnum, uae_u8 *cmd, int cmdlen, uae_u8 *out, int outsize)
679 {
680 	uae_u8 *p = state[unitnum].device_func->exec_in (unitnum, cmd, cmdlen, &outsize);
681 	if (p)
682 		memcpy (out, p, outsize);
683 	return p != NULL;
684 }
685 
failunit(int unitnum)686 static int failunit (int unitnum)
687 {
688 	if (unitnum < 0 || unitnum >= MAX_TOTAL_SCSI_DEVICES)
689 		return 1;
690 	if (state[unitnum].device_func == NULL)
691 		return 1;
692 	return 0;
693 }
694 
audiostatus(int unitnum)695 static int audiostatus (int unitnum)
696 {
697 	if (!getsem (unitnum))
698 		return 0;
699 	uae_u8 cmd[10] = {0x42,2,0x40,1,0,0,0,(uae_u8)(DEVICE_SCSI_BUFSIZE>>8),(uae_u8)(DEVICE_SCSI_BUFSIZE&0xff),0};
700 	uae_u8 *p = state[unitnum].device_func->exec_in (unitnum, cmd, sizeof (cmd), 0);
701 	freesem (unitnum);
702 	if (!p)
703 		return 0;
704 	return p[1];
705 }
706 
707 /* pause/unpause CD audio */
sys_command_cd_pause(int unitnum,int paused)708 int sys_command_cd_pause (int unitnum, int paused)
709 {
710 	if (failunit (unitnum))
711 		return -1;
712 	if (!getsem (unitnum))
713 		return 0;
714 	int v;
715 	if (state[unitnum].device_func->pause == NULL) {
716 		int as = audiostatus (unitnum);
717 		uae_u8 cmd[10] = {0x4b,0,0,0,0,0,0,0,paused?0:1,0};
718 		do_scsi (unitnum, cmd, sizeof cmd);
719 		v = as == AUDIO_STATUS_PAUSED;
720 	} else {
721 		v = state[unitnum].device_func->pause (unitnum, paused);
722 	}
723 	freesem (unitnum);
724 	return v;
725 }
726 
727 /* stop CD audio */
sys_command_cd_stop(int unitnum)728 void sys_command_cd_stop (int unitnum)
729 {
730 	if (failunit (unitnum))
731 		return;
732 	if (!getsem (unitnum))
733 		return;
734 	if (state[unitnum].device_func->stop == NULL) {
735 		int as = audiostatus (unitnum);
736 		uae_u8 cmd[6] = {0x4e,0,0,0,0,0};
737 		do_scsi (unitnum, cmd, sizeof cmd);
738 	} else {
739 		state[unitnum].device_func->stop (unitnum);
740 	}
741 	freesem (unitnum);
742 }
743 
744 /* play CD audio */
sys_command_cd_play(int unitnum,int startlsn,int endlsn,int scan)745 int sys_command_cd_play (int unitnum, int startlsn, int endlsn, int scan)
746 {
747 	int v;
748 	if (failunit (unitnum))
749 		return 0;
750 	if (!getsem (unitnum))
751 		return 0;
752 	state[unitnum].play_end_pos = endlsn;
753 	if (state[unitnum].device_func->play == NULL) {
754 		uae_u8 cmd[12] = {0,0,0,0,0,0,0,0,0,0,0,0};
755 		int startmsf = lsn2msf (startlsn);
756 		int endmsf = lsn2msf (endlsn);
757 		cmd[0] = 0x47;
758 		cmd[3] = (uae_u8)(startmsf >> 16);
759 		cmd[4] = (uae_u8)(startmsf >> 8);
760 		cmd[5] = (uae_u8)(startmsf >> 0);
761 		cmd[6] = (uae_u8)(endmsf >> 16);
762 		cmd[7] = (uae_u8)(endmsf >> 8);
763 		cmd[8] = (uae_u8)(endmsf >> 0);
764 		v = do_scsi (unitnum, cmd, sizeof cmd) ? 0 : 1;
765 	} else {
766 		v = state[unitnum].device_func->play (unitnum, startlsn, endlsn, scan, NULL, NULL);
767 	}
768 	freesem (unitnum);
769 	return v;
770 }
771 
772 /* play CD audio with subchannels */
sys_command_cd_play2(int unitnum,int startlsn,int endlsn,int scan,play_status_callback statusfunc,play_subchannel_callback subfunc)773 int sys_command_cd_play2 (int unitnum, int startlsn, int endlsn, int scan, play_status_callback statusfunc, play_subchannel_callback subfunc)
774 {
775 	int v;
776 	if (failunit (unitnum))
777 		return 0;
778 	if (!getsem (unitnum))
779 		return 0;
780 	if (state[unitnum].device_func->play == NULL)
781 		v = sys_command_cd_play (unitnum, startlsn, endlsn, scan);
782 	else
783 		v = state[unitnum].device_func->play (unitnum, startlsn, endlsn, scan, statusfunc, subfunc);
784 	freesem (unitnum);
785 	return v;
786 }
787 
788 /* set CD audio volume */
sys_command_cd_volume(int unitnum,uae_u16 volume_left,uae_u16 volume_right)789 uae_u32 sys_command_cd_volume (int unitnum, uae_u16 volume_left, uae_u16 volume_right)
790 {
791 	int v;
792 	if (failunit (unitnum))
793 		return 0;
794 	if (!getsem (unitnum))
795 		return 0;
796 	if (state[unitnum].device_func->volume == NULL)
797 		v = -1;
798 	else
799 		v = state[unitnum].device_func->volume (unitnum, volume_left, volume_right);
800 	freesem (unitnum);
801 	return v;
802 }
803 
804 /* read qcode */
sys_command_cd_qcode(int unitnum,uae_u8 * buf)805 int sys_command_cd_qcode (int unitnum, uae_u8 *buf)
806 {
807 	int v;
808 	if (failunit (unitnum))
809 		return 0;
810 	if (!getsem (unitnum))
811 		return 0;
812 	if (state[unitnum].device_func->qcode == NULL) {
813 		uae_u8 cmd[10] = {0x42,2,0x40,1,0,0,0,(uae_u8)(SUBQ_SIZE>>8),(uae_u8)(SUBQ_SIZE&0xff),0};
814 		v = do_scsi2 (unitnum, cmd, sizeof cmd, buf, SUBQ_SIZE);
815 	} else {
816 		v = state[unitnum].device_func->qcode (unitnum, buf, -1);
817 	}
818 	freesem (unitnum);
819 	return v;
820 };
821 
822 /* read table of contents */
sys_command_cd_toc(int unitnum,struct cd_toc_head * toc)823 int sys_command_cd_toc (int unitnum, struct cd_toc_head *toc)
824 {
825 	int v;
826 	if (failunit (unitnum))
827 		return 0;
828 	if (!getsem (unitnum))
829 		return 0;
830 	if (state[unitnum].device_func->toc == NULL) {
831 		uae_u8 buf[4 + 8 * 103];
832 		int size = sizeof buf;
833 		uae_u8 cmd [10] = { 0x43,0,2,0,0,0,0,(uae_u8)(size>>8),(uae_u8)(size&0xff),0};
834 		if (do_scsi2 (unitnum, cmd, sizeof cmd, buf, size)) {
835 			// toc parse to do
836 			v = 0;
837 		}
838 		v = 0;
839 	} else {
840 		v = state[unitnum].device_func->toc (unitnum, toc);
841 	}
842 	freesem (unitnum);
843 	return v;
844 }
845 
846 /* read one cd sector */
sys_command_cd_read(int unitnum,uae_u8 * data,int block,int size)847 int sys_command_cd_read (int unitnum, uae_u8 *data, int block, int size)
848 {
849 	int v;
850 	if (failunit (unitnum))
851 		return 0;
852 	if (!getsem (unitnum))
853 		return 0;
854 	if (state[unitnum].device_func->read == NULL) {
855 		uae_u8 cmd1[12] = { 0x28, 0, block >> 24, block >> 16, block >> 8, block >> 0, 0, size >> 8, size >> 0, 0, 0, 0 };
856 		v = do_scsi2 (unitnum, cmd1, sizeof cmd1, data, size * 2048);
857 #if 0
858 		if (!v) {
859 			uae_u8 cmd2[12] = { 0xbe, 0, block >> 24, block >> 16, block >> 8, block >> 0, size >> 16, size >> 8, size >> 0, 0x10, 0, 0 };
860 			v = do_scsi (unitnum, cmd2, sizeof cmd2, data, size * 2048);
861 		}
862 #endif
863 	} else {
864 		v = state[unitnum].device_func->read (unitnum, data, block, size);
865 	}
866 	freesem (unitnum);
867 	return v;
868 }
sys_command_cd_rawread(int unitnum,uae_u8 * data,int block,int size,int sectorsize)869 int sys_command_cd_rawread (int unitnum, uae_u8 *data, int block, int size, int sectorsize)
870 {
871 	int v;
872 	if (failunit (unitnum))
873 		return -1;
874 	if (!getsem (unitnum))
875 		return 0;
876 	if (state[unitnum].device_func->rawread == NULL) {
877 		uae_u8 cmd[12] = { 0xbe, 0, block >> 24, block >> 16, block >> 8, block >> 0, size >> 16, size >> 8, size >> 0, 0x10, 0, 0 };
878 		v = do_scsi2 (unitnum, cmd, sizeof cmd, data, size * sectorsize);
879 	} else {
880 		v = state[unitnum].device_func->rawread (unitnum, data, block, size, sectorsize, 0xffffffff);
881 	}
882 	freesem (unitnum);
883 	return v;
884 }
sys_command_cd_rawread2(int unitnum,uae_u8 * data,int block,int size,int sectorsize,uae_u8 sectortype,uae_u8 scsicmd9,uae_u8 subs)885 int sys_command_cd_rawread2 (int unitnum, uae_u8 *data, int block, int size, int sectorsize, uae_u8 sectortype, uae_u8 scsicmd9, uae_u8 subs)
886 {
887 	int v;
888 	if (failunit (unitnum))
889 		return -1;
890 	if (!getsem (unitnum))
891 		return 0;
892 	if (state[unitnum].device_func->rawread == NULL) {
893 		uae_u8 cmd[12] = { 0xbe, 0, block >> 24, block >> 16, block >> 8, block >> 0, size >> 16, size >> 8, size >> 0, 0x10, 0, 0 };
894 		v = do_scsi2 (unitnum, cmd, sizeof cmd, data, size * sectorsize);
895 	} else {
896 		v = state[unitnum].device_func->rawread (unitnum, data, block, size, sectorsize, (sectortype << 16) | (scsicmd9 << 8) | subs);
897 	}
898 	freesem (unitnum);
899 	return v;
900 }
901 
902 /* read block */
sys_command_read(int unitnum,uae_u8 * data,int block,int size)903 int sys_command_read (int unitnum, uae_u8 *data, int block, int size)
904 {
905 	int v;
906 	if (failunit (unitnum))
907 		return 0;
908 	if (!getsem (unitnum))
909 		return 0;
910 	if (state[unitnum].device_func->read == NULL) {
911 		uae_u8 cmd[12] = { 0xa8, 0, 0, 0, 0, 0, size >> 24, size >> 16, size >> 8, size >> 0, 0, 0 };
912 		cmd[2] = (uae_u8)(block >> 24);
913 		cmd[3] = (uae_u8)(block >> 16);
914 		cmd[4] = (uae_u8)(block >> 8);
915 		cmd[5] = (uae_u8)(block >> 0);
916 		v = do_scsi2 (unitnum, cmd, sizeof cmd, data, size * 2048);
917 	} else {
918 		v = state[unitnum].device_func->read (unitnum, data, block, size);
919 	}
920 	freesem (unitnum);
921 	return v;
922 }
923 
924 /* write block */
sys_command_write(int unitnum,uae_u8 * data,int offset,int size)925 int sys_command_write (int unitnum, uae_u8 *data, int offset, int size)
926 {
927 	int v;
928 	if (failunit (unitnum))
929 		return 0;
930 	if (!getsem (unitnum))
931 		return 0;
932 	if (state[unitnum].device_func->write == NULL) {
933 		v = 0;
934 	} else {
935 		v = state[unitnum].device_func->write (unitnum, data, offset, size);
936 	}
937 	freesem (unitnum);
938 	return v;
939 }
940 
sys_command_ismedia(int unitnum,int quick)941 int sys_command_ismedia (int unitnum, int quick)
942 {
943 	int v;
944 	struct blkdevstate *st = &state[unitnum];
945 	if (failunit (unitnum))
946 		return -1;
947 	if (st->delayed)
948 		return 0;
949 	if (!getsem (unitnum))
950 		return 0;
951 	if (state[unitnum].device_func->ismedia == NULL) {
952 		uae_u8 cmd[6] = { 0, 0, 0, 0, 0, 0 };
953 		v = do_scsi (unitnum, cmd, sizeof cmd);
954 	} else {
955 		v = state[unitnum].device_func->ismedia (unitnum, quick);
956 	}
957 	freesem (unitnum);
958 	return v;
959 }
960 
sys_command_info_session(int unitnum,struct device_info * di,int quick,int session)961 struct device_info *sys_command_info_session (int unitnum, struct device_info *di, int quick, int session)
962 {
963 	struct blkdevstate *st = &state[unitnum];
964 	if (failunit (unitnum))
965 		return NULL;
966 	if (!getsem (unitnum))
967 		return 0;
968 	if (st->device_func->info == NULL)
969 		return 0;
970 	struct device_info *di2 = st->device_func->info (unitnum, di, quick, -1);
971 	if (di2 && st->delayed)
972 		di2->media_inserted = 0;
973 	freesem (unitnum);
974 	return di2;
975 }
sys_command_info(int unitnum,struct device_info * di,int quick)976 struct device_info *sys_command_info (int unitnum, struct device_info *di, int quick)
977 {
978 	return sys_command_info_session (unitnum, di, quick, -1);
979 }
980 
981 #define MODE_SELECT_6 0x15
982 #define MODE_SENSE_6 0x1a
983 #define MODE_SELECT_10 0x55
984 #define MODE_SENSE_10 0x5a
985 
scsi_atapi_fixup_pre(uae_u8 * scsi_cmd,int * len,uae_u8 ** datap,int * datalenp,int * parm)986 void scsi_atapi_fixup_pre (uae_u8 *scsi_cmd, int *len, uae_u8 **datap, int *datalenp, int *parm)
987 {
988 	uae_u8 cmd, *p, *data = *datap;
989 	int l, datalen = *datalenp;
990 
991 	*parm = 0;
992 	cmd = scsi_cmd[0];
993 	if (cmd != MODE_SELECT_6 && cmd != MODE_SENSE_6)
994 		return;
995 	l = scsi_cmd[4];
996 	if (l > 4)
997 		l += 4;
998 	scsi_cmd[7] = l >> 8;
999 	scsi_cmd[8] = l;
1000 	if (cmd == MODE_SELECT_6) {
1001 		scsi_cmd[0] = MODE_SELECT_10;
1002 		scsi_cmd[9] = scsi_cmd[5];
1003 		scsi_cmd[2] = scsi_cmd[3] = scsi_cmd[4] = scsi_cmd[5] = scsi_cmd[6] = 0;
1004 		*len = 10;
1005 		p = xmalloc (uae_u8, 8 + datalen + 4);
1006 		if (datalen > 4)
1007 			memcpy (p + 8, data + 4, datalen - 4);
1008 		p[0] = 0;
1009 		p[1] = data[0];
1010 		p[2] = data[1];
1011 		p[3] = data[2];
1012 		p[4] = p[5] = p[6] = 0;
1013 		p[7] = data[3];
1014 		if (l > 8)
1015 			datalen += 4;
1016 		*parm = MODE_SELECT_10;
1017 		*datap = p;
1018 	} else {
1019 		scsi_cmd[0] = MODE_SENSE_10;
1020 		scsi_cmd[9] = scsi_cmd[5];
1021 		scsi_cmd[3] = scsi_cmd[4] = scsi_cmd[5] = scsi_cmd[6] = 0;
1022 		if (l > 8)
1023 			datalen += 4;
1024 		*datap = xmalloc (uae_u8, datalen);
1025 		*len = 10;
1026 		*parm = MODE_SENSE_10;
1027 	}
1028 	*datalenp = datalen;
1029 }
1030 
scsi_atapi_fixup_post(uae_u8 * scsi_cmd,int len,uae_u8 * olddata,uae_u8 * data,int * datalenp,int parm)1031 void scsi_atapi_fixup_post (uae_u8 *scsi_cmd, int len, uae_u8 *olddata, uae_u8 *data, int *datalenp, int parm)
1032 {
1033 	int datalen = *datalenp;
1034 	if (!data || !datalen)
1035 		return;
1036 	if (parm == MODE_SENSE_10) {
1037 		olddata[0] = data[1];
1038 		olddata[1] = data[2];
1039 		olddata[2] = data[3];
1040 		olddata[3] = data[7];
1041 		datalen -= 4;
1042 		if (datalen > 4)
1043 			memcpy (olddata + 4, data + 8, datalen - 4);
1044 		*datalenp = datalen;
1045 	}
1046 }
1047 
scsi_atapi_fixup_inquiry(struct amigascsi * as)1048 static void scsi_atapi_fixup_inquiry (struct amigascsi *as)
1049 {
1050 	uae_u8 *scsi_data = as->data;
1051 	uae_u32 scsi_len = as->len;
1052 	uae_u8 *scsi_cmd = as->cmd;
1053 	uae_u8 cmd;
1054 
1055 	cmd = scsi_cmd[0];
1056 	/* CDROM INQUIRY: most Amiga programs expect ANSI version == 2
1057 	* (ATAPI normally responds with zero)
1058 	*/
1059 	if (cmd == 0x12 && scsi_len > 2 && scsi_data) {
1060 		uae_u8 per = scsi_data[0];
1061 		uae_u8 b = scsi_data[2];
1062 		/* CDROM and ANSI version == 0 ? */
1063 		if ((per & 31) == 5 && (b & 7) == 0) {
1064 			b |= 2;
1065 			scsi_data[2] = b;
1066 		}
1067 	}
1068 }
1069 
scsi_log_before(uae_u8 * cdb,int cdblen,uae_u8 * data,int datalen)1070 void scsi_log_before (uae_u8 *cdb, int cdblen, uae_u8 *data, int datalen)
1071 {
1072 	int i;
1073 	for (i = 0; i < cdblen; i++) {
1074 		write_log (_T("%s%02X"), i > 0 ? _T(".") : _T(""), cdb[i]);
1075 	}
1076 	write_log (_T("\n"));
1077 	if (data) {
1078 		write_log (_T("DATAOUT: %d\n"), datalen);
1079 		for (i = 0; i < datalen && i < 100; i++)
1080 			write_log (_T("%s%02X"), i > 0 ? _T(".") : _T(""), data[i]);
1081 		if (datalen > 0)
1082 			write_log (_T("\n"));
1083 	}
1084 }
1085 
scsi_log_after(uae_u8 * data,int datalen,uae_u8 * sense,int senselen)1086 void scsi_log_after (uae_u8 *data, int datalen, uae_u8 *sense, int senselen)
1087 {
1088 	int i;
1089 	write_log (_T("DATAIN: %d\n"), datalen);
1090 	for (i = 0; i < datalen && i < 100 && data; i++)
1091 		write_log (_T("%s%02X"), i > 0 ? _T(".") : _T(""), data[i]);
1092 	if (data && datalen > 0)
1093 		write_log (_T("\n"));
1094 	if (senselen > 0) {
1095 		write_log (_T("SENSE: %d,"), senselen);
1096 		for (i = 0; i < senselen && i < 32; i++) {
1097 			write_log (_T("%s%02X"), i > 0 ? _T(".") : _T(""), sense[i]);
1098 		}
1099 		write_log (_T("\n"));
1100 	}
1101 }
1102 
nodisk(struct device_info * di)1103 static bool nodisk (struct device_info *di)
1104 {
1105 	return di->media_inserted == 0;
1106 }
cmd_readx(int unitnum,uae_u8 * dataptr,int offset,int len)1107 static uae_u64 cmd_readx (int unitnum, uae_u8 *dataptr, int offset, int len)
1108 {
1109 	if (!getsem (unitnum))
1110 		return 0;
1111 	int v = state[unitnum].device_func->read (unitnum, dataptr, offset, len);
1112 	freesem (unitnum);
1113 	if (v >= 0)
1114 		return len;
1115 	return v;
1116 }
1117 
wl(uae_u8 * p,int v)1118 static void wl (uae_u8 *p, int v)
1119 {
1120 	p[0] = v >> 24;
1121 	p[1] = v >> 16;
1122 	p[2] = v >> 8;
1123 	p[3] = v;
1124 }
ww(uae_u8 * p,int v)1125 static void ww (uae_u8 *p, int v)
1126 {
1127 	p[0] = v >> 8;
1128 	p[1] = v;
1129 }
rl(uae_u8 * p)1130 static int rl (uae_u8 *p)
1131 {
1132 	return (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | (p[3]);
1133 }
rw(uae_u8 * p)1134 static int rw (uae_u8 *p)
1135 {
1136 	return (p[0] << 8) | (p[1]);
1137 }
1138 
stopplay(int unitnum)1139 static void stopplay (int unitnum)
1140 {
1141 	sys_command_cd_stop (unitnum);
1142 }
1143 
addtocentry(uae_u8 ** dstp,int * len,int point,int newpoint,int msf,uae_u8 * head,struct cd_toc_head * th)1144 static int addtocentry (uae_u8 **dstp, int *len, int point, int newpoint, int msf, uae_u8 *head, struct cd_toc_head *th)
1145 {
1146 	uae_u8 *dst = *dstp;
1147 
1148 	for (int i = 0; i < th->points; i++) {
1149 		struct cd_toc *t = &th->toc[i];
1150 		if (t->point == point) {
1151 			if (*len < 8)
1152 				return 0;
1153 			int addr = t->paddress;
1154 			if (msf)
1155 				addr = lsn2msf (addr);
1156 			dst[0] = 0;
1157 			dst[1] = (t->adr << 4) | t->control;
1158 			dst[2] = newpoint >= 0 ? newpoint : point;
1159 			dst[3] = 0;
1160 			dst[4] = addr >> 24;
1161 			dst[5] = addr >> 16;
1162 			dst[6] = addr >>  8;
1163 			dst[7] = addr >>  0;
1164 
1165 			if (point >= 1 && point <= 99) {
1166 				if (head[2] == 0)
1167 					head[2] = point;
1168 				head[3] = point;
1169 			}
1170 
1171 			*len -= 8;
1172 			*dstp = dst + 8;
1173 			return 1;
1174 		}
1175 	}
1176 	return -1;
1177 }
1178 
scsiemudrv(int unitnum,uae_u8 * cmd)1179 static int scsiemudrv (int unitnum, uae_u8 *cmd)
1180 {
1181 	if (failunit (unitnum))
1182 		return -1;
1183 	if (!getsem (unitnum))
1184 		return 0;
1185 	int v = 0;
1186 	if (state[unitnum].device_func->scsiemu)
1187 		v = state[unitnum].device_func->scsiemu (unitnum, cmd);
1188 	freesem (unitnum);
1189 	return v;
1190 }
1191 
scsi_read_cd(int unitnum,uae_u8 * cmd,uae_u8 * data,struct device_info * di)1192 static int scsi_read_cd (int unitnum, uae_u8 *cmd, uae_u8 *data, struct device_info *di)
1193 {
1194 	int msf = cmd[0] == 0xb9;
1195 	int start = msf ? msf2lsn (rl (cmd + 2) & 0x00ffffff) : rl (cmd + 2);
1196 	int len = rl (cmd + 5) & 0x00ffffff;
1197 	if (msf) {
1198 		int end = msf2lsn (len);
1199 		len = end - start;
1200 		if (len < 0)
1201 			return -1;
1202 	}
1203 	int subs = cmd[10] & 7;
1204 	if (len == 0)
1205 		return 0;
1206 	return sys_command_cd_rawread2 (unitnum, data, start, len, 0, (cmd[1] >> 2) & 7, cmd[9], subs);
1207 }
1208 
scsi_read_cd_data(int unitnum,uae_u8 * scsi_data,uae_u32 offset,uae_u32 len,struct device_info * di,int * scsi_len)1209 static int scsi_read_cd_data (int unitnum, uae_u8 *scsi_data, uae_u32 offset, uae_u32 len, struct device_info *di, int *scsi_len)
1210 {
1211 	if (len == 0) {
1212 		*scsi_len = 0;
1213 		return 0;
1214 	} else {
1215 		if (len * di->bytespersector > SCSI_DATA_BUFFER_SIZE)
1216 			return -3;
1217 		if (offset >= di->sectorspertrack)
1218 			return -1;
1219 		int v = cmd_readx (unitnum, scsi_data, offset, len) * di->bytespersector;
1220 		if (v > 0) {
1221 			*scsi_len = v;
1222 			return 0;
1223 		}
1224 		return -2;
1225 	}
1226 }
1227 
scsi_cd_emulate(int unitnum,uae_u8 * cmdbuf,int scsi_cmd_len,uae_u8 * scsi_data,int * data_len,uae_u8 * r,int * reply_len,uae_u8 * s,int * sense_len,bool atapi)1228 int scsi_cd_emulate (int unitnum, uae_u8 *cmdbuf, int scsi_cmd_len,
1229 	uae_u8 *scsi_data, int *data_len, uae_u8 *r, int *reply_len, uae_u8 *s, int *sense_len, bool atapi)
1230 {
1231 	struct blkdevstate *st = &state[unitnum];
1232 	uae_u32 len, offset;
1233 	int lr = 0, ls = 0;
1234 	int scsi_len = -1;
1235 	int v;
1236 	int status = 0;
1237 	struct device_info di;
1238 	uae_u8 cmd = cmdbuf[0];
1239 	int dlen;
1240 
1241 	if (cmd == 0x03) { /* REQUEST SENSE */
1242 		st->mediawaschanged = false;
1243 		return 0;
1244 	}
1245 
1246 	dlen = *data_len;
1247 	*reply_len = *sense_len = 0;
1248 	memset (r, 0, 256);
1249 	memset (s, 0, 256);
1250 
1251 	sys_command_info (unitnum, &di, 1);
1252 
1253 	if (log_scsiemu) {
1254 		write_log (_T("SCSIEMU %d: %02X.%02X.%02X.%02X.%02X.%02X.%02X.%02X.%02X.%02X.%02X.%02X CMDLEN=%d DATA=%08X LEN=%d\n"), unitnum,
1255 			cmdbuf[0], cmdbuf[1], cmdbuf[2], cmdbuf[3], cmdbuf[4], cmdbuf[5], cmdbuf[6],
1256 			cmdbuf[7], cmdbuf[8], cmdbuf[9], cmdbuf[10], cmdbuf[11],
1257 			scsi_cmd_len, scsi_data, dlen);
1258 	}
1259 
1260 	// media changed and not inquiry
1261 	if (st->mediawaschanged && cmd != 0x12) {
1262 		if (log_scsiemu) {
1263 			write_log (_T("SCSIEMU %d: MEDIUM MAY HAVE CHANGED STATE\n"));
1264 		}
1265 		lr = -1;
1266 		status = 2; /* CHECK CONDITION */
1267 		s[0] = 0x70;
1268 		s[2] = 6; /* UNIT ATTENTION */
1269 		s[12] = 0x28; /* MEDIUM MAY HAVE CHANGED */
1270 		ls = 0x12;
1271 		goto end;
1272 	}
1273 
1274 	switch (cmdbuf[0])
1275 	{
1276 	case 0x00: /* TEST UNIT READY */
1277 		if (nodisk (&di))
1278 			goto nodisk;
1279 		scsi_len = 0;
1280 		break;
1281 	case 0x1e: /* PREVENT/ALLOW MEDIUM REMOVAL */
1282 		scsi_len = 0;
1283 		break;
1284 	case 0x12: /* INQUIRY */
1285 	{
1286 		if ((cmdbuf[1] & 1) || cmdbuf[2] != 0)
1287 			goto err;
1288 		len = cmdbuf[4];
1289 		if (cmdbuf[1] >> 5) {
1290 			r[0] = 0x7f;
1291 		} else {
1292 			r[0] = 5; // CDROM
1293 		}
1294 		r[1] |= 0x80; // removable
1295 		r[2] = 2; /* supports SCSI-2 */
1296 		r[3] = 2; /* response data format */
1297 		if (atapi)
1298 			r[3] |= 3 << 5; // atapi transport version
1299 		r[4] = 32; /* additional length */
1300 		r[7] = 0;
1301 		scsi_len = lr = len < 36 ? (uae_u32)len : 36;
1302 		r[2] = 2;
1303 		r[3] = 2;
1304 		char *s = ua (di.vendorid);
1305 		memcpy (r + 8, s, strlen (s));
1306 		xfree (s);
1307 		s = ua (di.productid);
1308 		memcpy (r + 16, s, strlen (s));
1309 		xfree (s);
1310 		s = ua (di.revision);
1311 		memcpy (r + 32, s, strlen (s));
1312 		xfree (s);
1313 		for (int i = 8; i < 36; i++) {
1314 			if (r[i] == 0)
1315 				r[i] = 32;
1316 		}
1317 	}
1318 	break;
1319 	case 0xbe: // READ CD
1320 	case 0xb9: // READ CD MSF
1321 		if (nodisk (&di))
1322 			goto nodisk;
1323 		scsi_len = scsi_read_cd (unitnum, cmdbuf, scsi_data, &di);
1324 		if (scsi_len == -2)
1325 			goto notdatatrack;
1326 		if (scsi_len == -1)
1327 			goto errreq;
1328 		break;
1329 	case 0x55: // MODE SELECT(10)
1330 	case 0x15: // MODE SELECT(6)
1331 	{
1332 		uae_u8 *p;
1333 		bool mode10 = cmdbuf[0] == 0x55;
1334 		p = scsi_data + 4;
1335 		if (mode10)
1336 			p += 4;
1337 		int pcode = p[0] & 0x3f;
1338 		if (pcode == 14) { // CD audio control
1339 			uae_u16 vol_left = (p[9] << 7) | (p[9] >> 1);
1340 			uae_u16 vol_right = (p[11] << 7) | (p[11] >> 1);
1341 			sys_command_cd_volume (unitnum, vol_left, vol_right);
1342 			scsi_len = 0;
1343 		} else {
1344 			if (log_scsiemu)
1345 				write_log (_T("MODE SELECT PC=%d not supported\n"), pcode);
1346 			goto errreq;
1347 		}
1348 	}
1349 	break;
1350 	case 0x5a: // MODE SENSE(10)
1351 	case 0x1a: /* MODE SENSE(6) */
1352 	{
1353 		uae_u8 *p;
1354 		int maxlen;
1355 		bool pcodeloop = false;
1356 		bool sense10 = cmdbuf[0] == 0x5a;
1357 		int psize, totalsize, bdsize;
1358 		int pc = cmdbuf[2] >> 6;
1359 		int pcode = cmdbuf[2] & 0x3f;
1360 		int dbd = cmdbuf[1] & 8;
1361 		if (cmdbuf[0] == 0x5a)
1362 			dbd = 1;
1363 		if (log_scsiemu)
1364 			write_log (_T("MODE SENSE PC=%d CODE=%d DBD=%d\n"), pc, pcode, dbd);
1365 		p = r;
1366 		if (sense10) {
1367 			totalsize = 8 - 2;
1368 			maxlen = (cmdbuf[7] << 8) | cmdbuf[8];
1369 			p[2] = 0;
1370 			p[3] = 0;
1371 			p[4] = 0;
1372 			p[5] = 0;
1373 			p[6] = 0;
1374 			p[7] = 0;
1375 			p += 8;
1376 		} else {
1377 			totalsize = 4 - 1;
1378 			maxlen = cmdbuf[4];
1379 			p[1] = 0;
1380 			p[2] = 0;
1381 			p[3] = 0;
1382 			p += 4;
1383 		}
1384 		bdsize = 0;
1385 		if (!dbd) {
1386 			wl(p + 0, 0);
1387 			wl(p + 4, di.bytespersector);
1388 			bdsize = 8;
1389 			p += bdsize;
1390 		}
1391 		if (pcode == 0x3f) {
1392 			pcode = 1; // page = 0 must be last
1393 			pcodeloop = true;
1394 		}
1395 		for (;;) {
1396 			psize = 0;
1397 		if (pcode == 0) {
1398 			p[0] = 0;
1399 			p[1] = 0;
1400 			p[2] = 0x20;
1401 			p[3] = 0;
1402 				psize = 4;
1403 		} else if (pcode == 14) { // CD audio control
1404 			uae_u32 vol = sys_command_cd_volume (unitnum, 0xffff, 0xffff);
1405 			p[0] = 0x0e;
1406 			p[1] = 0x0e;
1407 				p[2] = 4|1;
1408 			p[3] = 4;
1409 			p[6] = 0;
1410 			p[7] = 75;
1411 			p[8] = 1;
1412 			p[9] = pc == 0 ? (vol >> 7) & 0xff : 0xff;
1413 			p[10] = 2;
1414 			p[11] = pc == 0 ? (vol >> (16 + 7)) & 0xff : 0xff;
1415 				psize = p[1] + 2;
1416 			} else if (pcode == 0x2a) {  // cd/dvd capabilities
1417 				p[0] = 0x2a;
1418 				p[1] = 0x18;
1419 				p[2] = 1; // | 0x10 | 0x20; // read: CD-R/DVD-ROM/DVD-R
1420 				p[3] = 0; // write: nothing
1421 				p[4] = 0x40 | 0x20 | 0x10 | 0x01;
1422 				p[5] = 0x08 | 0x04 | 0x02 | 0x01;
1423 				p[6] = (1 << 5) | 0x10; // type = tray, eject supported
1424 				p[7] = 3; // separate channel mute and volume
1425 				p[8] = 2; p[9] = 0;
1426 				p[10] = 0xff; p[11] = 0xff; // number of volume levels
1427 				p[12] = 4; p[13] = 0; // "1M buffer"
1428 				p[14] = 2; p[15] = 0;
1429 				p[16] = 0;
1430 				p[17] = 0;
1431 				p[18] = p[19] = 0;
1432 				p[20] = p[21] = 0;
1433 				p[22] = p[23] = 0;
1434 				psize = p[1] + 2;
1435 			} else {
1436 				if (!pcodeloop)
1437 					goto err;
1438 			}
1439 			totalsize += psize;
1440 			p += psize;
1441 			if (!pcodeloop)
1442 				break;
1443 			if (pcode == 0)
1444 				break;
1445 			pcode++;
1446 			if (pcode == 0x3f)
1447 				pcode = 0;
1448 		}
1449 		if (sense10) {
1450 			totalsize += bdsize;
1451 			r[6] = bdsize >> 8;
1452 			r[7] = bdsize & 0xff;
1453 			r[0] = totalsize >> 8;
1454 			r[1] = totalsize & 0xff;
1455 		} else {
1456 			totalsize += bdsize;
1457 			r[3] = bdsize & 0xff;
1458 			r[0] = totalsize & 0xff;
1459 	}
1460 		scsi_len = lr = totalsize + 1;
1461 		if (scsi_len > maxlen)
1462 			scsi_len = maxlen;
1463 	}
1464 	break;
1465 	case 0x01: /* REZERO UNIT */
1466 		scsi_len = 0;
1467 	break;
1468 	case 0x1d: /* SEND DIAGNOSTICS */
1469 		scsi_len = 0;
1470 		break;
1471 	case 0x25: /* READ CAPACITY */
1472 		{
1473 			int pmi = cmdbuf[8] & 1;
1474 			uae_u32 lba = (cmdbuf[2] << 24) | (cmdbuf[3] << 16) | (cmdbuf[4] << 8) | cmdbuf[5];
1475 			int cyl, cylsec, head, tracksec;
1476 			if (nodisk (&di))
1477 				goto nodisk;
1478 			uae_u32 blocks = di.sectorspertrack * di.cylinders * di.trackspercylinder - 1;
1479 			cyl = di.cylinders;
1480 			head = 1;
1481 			cylsec = tracksec = di.trackspercylinder;
1482 			if (pmi == 0 && lba != 0)
1483 				goto errreq;
1484 			if (pmi) {
1485 				lba += tracksec * head;
1486 				lba /= tracksec * head;
1487 				lba *= tracksec * head;
1488 				if (lba > blocks)
1489 					lba = blocks;
1490 				blocks = lba;
1491 			}
1492 			wl (r, blocks);
1493 			wl (r + 4, di.bytespersector);
1494 			scsi_len = lr = 8;
1495 		}
1496 		break;
1497 	case 0x08: /* READ (6) */
1498 	{
1499 		if (nodisk (&di))
1500 			goto nodisk;
1501 		stopplay (unitnum);
1502 		offset = ((cmdbuf[1] & 31) << 16) | (cmdbuf[2] << 8) | cmdbuf[3];
1503 		struct cd_toc *t = gettoc (&di.toc, offset);
1504 		if ((t->control & 0x0c) == 0x04) {
1505 			len = cmdbuf[4];
1506 			if (!len)
1507 				len = 256;
1508 			v = scsi_read_cd_data (unitnum, scsi_data, offset, len, &di, &scsi_len);
1509 			if (v == -1)
1510 				goto outofbounds;
1511 			if (v == -2)
1512 				goto readerr;
1513 			if (v == -3)
1514 				goto toolarge;
1515 		} else {
1516 			goto notdatatrack;
1517 		}
1518 	}
1519 	break;
1520 	case 0x0a: /* WRITE (6) */
1521 		goto readprot;
1522 	case 0x28: /* READ (10) */
1523 	{
1524 		if (nodisk (&di))
1525 			goto nodisk;
1526 		stopplay (unitnum);
1527 		offset = rl (cmdbuf + 2);
1528 		struct cd_toc *t = gettoc (&di.toc, offset);
1529 		if ((t->control & 0x0c) == 0x04) {
1530 			len = rl (cmdbuf + 7 - 2) & 0xffff;
1531 			v = scsi_read_cd_data (unitnum, scsi_data, offset, len, &di, &scsi_len);
1532 			if (v == -1)
1533 				goto outofbounds;
1534 			if (v == -2)
1535 				goto readerr;
1536 			if (v == -3)
1537 				goto toolarge;
1538 		} else {
1539 			goto notdatatrack;
1540 		}
1541 	}
1542 	break;
1543 	case 0x2a: /* WRITE (10) */
1544 		goto readprot;
1545 	case 0xa8: /* READ (12) */
1546 	{
1547 		if (nodisk (&di))
1548 			goto nodisk;
1549 		stopplay (unitnum);
1550 		offset = rl (cmdbuf + 2);
1551 		struct cd_toc *t = gettoc (&di.toc, offset);
1552 		if ((t->control & 0x0c) == 0x04) {
1553 			len = rl (cmdbuf + 6);
1554 			v = scsi_read_cd_data (unitnum, scsi_data, offset, len, &di, &scsi_len);
1555 			if (v == -1)
1556 				goto outofbounds;
1557 			if (v == -2)
1558 				goto readerr;
1559 			if (v == -3)
1560 				goto toolarge;
1561 		} else {
1562 			goto notdatatrack;
1563 		}
1564 	}
1565 	break;
1566 	case 0xaa: /* WRITE (12) */
1567 		goto readprot;
1568 	case 0x51: /* READ DISC INFORMATION */
1569 		{
1570 			struct cd_toc_head ttoc;
1571 			int maxlen = (cmdbuf[7] << 8) | cmdbuf[8];
1572 			if (nodisk (&di))
1573 				goto nodisk;
1574 			if (!sys_command_cd_toc (unitnum, &ttoc))
1575 				goto readerr;
1576 			struct cd_toc_head *toc = &ttoc;
1577 			uae_u8 *p = scsi_data;
1578 			p[0] = 0;
1579 			p[1] = 34 - 2;
1580 			p[2] = 2 | (3 << 2); // complete cd rom, last session is complete
1581 			p[3] = toc->first_track;
1582 			p[4] = 1;
1583 			p[5] = toc->first_track;
1584 			p[6] = toc->last_track;
1585 			wl (p + 16, lsn2msf (toc->lastaddress));
1586 			wl (p + 20, 0x00ffffff);
1587 			scsi_len = p[1] + 2;
1588 			if (scsi_len > maxlen)
1589 				scsi_len = maxlen;
1590 		}
1591 		break;
1592 	case 0x52: /* READ TRACK INFORMATION */
1593 		{
1594 			struct cd_toc_head ttoc;
1595 			int maxlen = (cmdbuf[7] << 8) | cmdbuf[8];
1596 			if (nodisk (&di))
1597 				goto nodisk;
1598 			if (!sys_command_cd_toc (unitnum, &ttoc))
1599 				goto readerr;
1600 			struct cd_toc_head *toc = &ttoc;
1601 			uae_u8 *p = scsi_data;
1602 			int lsn;
1603 			if (cmdbuf[1] & 1) {
1604 				int track = cmdbuf[5];
1605 				lsn = toc->toc[track].address;
1606 			} else {
1607 				lsn = rl (p + 2);
1608 			}
1609 			struct cd_toc *t = gettoc (toc, lsn);
1610 			p[0] = 0;
1611 			p[1] = 28 - 2;
1612 			p[2] = t->track;
1613 			p[3] = 1;
1614 			p[5] = t->control;
1615 			p[6] = 0; // data mode, fixme
1616 			wl (p + 8, t->address);
1617 			wl (p + 24, t[1].address - t->address);
1618 			scsi_len = p[1] + 2;
1619 			if (scsi_len > maxlen)
1620 				scsi_len = maxlen;
1621 		}
1622 		break;
1623 	case 0x43: // READ TOC
1624 		{
1625 			if (nodisk (&di))
1626 				goto nodisk;
1627 			uae_u8 *p = scsi_data;
1628 			int strack = cmdbuf[6];
1629 			int msf = cmdbuf[1] & 2;
1630 			int format = cmdbuf[2] & 7;
1631 			if (format >= 3)
1632 				goto errreq;
1633 			int maxlen = (cmdbuf[7] << 8) | cmdbuf[8];
1634 			int maxlen2 = maxlen;
1635 			struct cd_toc_head ttoc;
1636 			if (!sys_command_cd_toc (unitnum, &ttoc))
1637 				goto readerr;
1638 			struct cd_toc_head *toc = &ttoc;
1639 			if (maxlen < 4)
1640 				goto errreq;
1641 			if (format == 1) {
1642 				p[0] = 0;
1643 				p[1] = 2 + 8;
1644 				p[2] = 1;
1645 				p[3] = 1;
1646 				p[4] = 0;
1647 				p[5] = (toc->toc[0].adr << 4) | toc->toc[0].control;
1648 				p[6] = toc->first_track;
1649 				p[7] = 0;
1650 				if (msf)
1651 					wl (p + 8, lsn2msf (toc->toc[0].address));
1652 				else
1653 					wl (p + 8 , toc->toc[0].address);
1654 				scsi_len = 12;
1655 			} else if (format == 2 || format == 0) {
1656 				if (format == 2 && !msf)
1657 					goto errreq;
1658 				if (strack == 0)
1659 					strack = toc->first_track;
1660 				if (format == 0 && strack >= 100 && strack != 0xaa)
1661 					goto errreq;
1662 				uae_u8 *p2 = p + 4;
1663 				p[2] = 0;
1664 				p[3] = 0;
1665 				maxlen -= 4;
1666 				if (format == 2) {
1667 					if (!addtocentry (&p2, &maxlen, 0xa0, -1, msf, p, toc))
1668 						break;
1669 					if (!addtocentry (&p2, &maxlen, 0xa1, -1, msf, p, toc))
1670 						break;
1671 					if (!addtocentry (&p2, &maxlen, 0xa2, -1, msf, p, toc))
1672 						break;
1673 				}
1674 				while (strack < 100) {
1675 					if (!addtocentry (&p2, &maxlen, strack, -1, msf, p, toc))
1676 						break;
1677 					strack++;
1678 				}
1679 				addtocentry (&p2, &maxlen, 0xa2, 0xaa, msf, p, toc);
1680 				int tlen = p2 - (p + 2);
1681 				p[0] = tlen >> 8;
1682 				p[1] = tlen >> 0;
1683 				scsi_len = tlen + 2;
1684 				if (scsi_len > maxlen2)
1685 					scsi_len = maxlen2;
1686 			}
1687 		}
1688 		break;
1689 		case 0x42: // READ SUB-CHANNEL
1690 		{
1691 			int msf = cmdbuf[1] & 2;
1692 			int subq = cmdbuf[2] & 0x40;
1693 			int format = cmdbuf[3];
1694 			int track = cmdbuf[6];
1695 			int len = rw (cmdbuf + 7);
1696 			uae_u8 buf[SUBQ_SIZE] = { 0 };
1697 
1698 			if (nodisk (&di))
1699 				goto nodisk;
1700 			sys_command_cd_qcode (unitnum, buf);
1701 			if (len < 4)
1702 				goto errreq;
1703 			scsi_len = 4;
1704 			scsi_data[0] = 0;
1705 			scsi_data[1] = buf[1];
1706 			if (subq && format == 1) {
1707 				if (len < 4 + 12)
1708 					goto errreq;
1709 				scsi_data[2] = 0;
1710 				scsi_data[3] = 12;
1711 				scsi_len += 12;
1712 				scsi_data[4] = 1;
1713 				scsi_data[5] = (buf[4 + 0] << 4) | (buf[4 + 0] >> 4);
1714 				scsi_data[6] = frombcd (buf[4 + 1]); // track
1715 				scsi_data[7] = frombcd (buf[4 + 2]); // index
1716 				int reladdr = fromlongbcd (&buf[4 + 3]);
1717 				int absaddr = fromlongbcd (&buf[4 + 7]);
1718 				if (!msf) {
1719 					reladdr = msf2lsn (reladdr);
1720 					absaddr = msf2lsn (absaddr);
1721 				}
1722 				wl (scsi_data +  8, absaddr);
1723 				wl (scsi_data + 12, reladdr);
1724 			} else {
1725 				scsi_data[2] = 0;
1726 				scsi_data[3] = 0;
1727 			}
1728 		}
1729 		break;
1730 		case 0x1b: // START/STOP
1731 			sys_command_cd_stop (unitnum);
1732 			scsiemudrv (unitnum, cmdbuf);
1733 			scsi_len = 0;
1734 		break;
1735 		case 0x4e: // STOP PLAY/SCAN
1736 			if (nodisk (&di))
1737 				goto nodisk;
1738 			sys_command_cd_stop (unitnum);
1739 			scsi_len = 0;
1740 		break;
1741 		case 0xba: // SCAN
1742 		{
1743 			if (nodisk (&di))
1744 				goto nodisk;
1745 			struct cd_toc_head ttoc;
1746 			if (!sys_command_cd_toc (unitnum, &ttoc))
1747 				goto readerr;
1748 			struct cd_toc_head *toc = &ttoc;
1749 			int scan = (cmdbuf[1] & 0x10) ? -1 : 1;
1750 			int start = rl (cmdbuf + 1) & 0x00ffffff;
1751 			int end = scan > 0 ? toc->lastaddress : toc->toc[toc->first_track_offset].paddress;
1752 			int type = cmdbuf[9] >> 6;
1753 			if (type == 1)
1754 				start = lsn2msf (start);
1755 			if (type == 3)
1756 				goto errreq;
1757 			if (type == 2) {
1758 				if (toc->first_track_offset + start >= toc->last_track_offset)
1759 					goto errreq;
1760 				start = toc->toc[toc->first_track_offset + start].paddress;
1761 			}
1762 			sys_command_cd_pause (unitnum, 0);
1763 			sys_command_cd_play (unitnum, start, end, scan);
1764 			scsi_len = 0;
1765 		}
1766 		break;
1767 		case 0x48: // PLAY AUDIO TRACK/INDEX
1768 		{
1769 			if (nodisk (&di))
1770 				goto nodisk;
1771 			int strack = cmdbuf[4];
1772 			int etrack = cmdbuf[7];
1773 			struct cd_toc_head ttoc;
1774 			if (!sys_command_cd_toc (unitnum, &ttoc))
1775 				goto readerr;
1776 			struct cd_toc_head *toc = &ttoc;
1777 			if (strack < toc->first_track || strack > toc->last_track ||
1778 				etrack < toc->first_track || etrack > toc->last_track ||
1779 				strack > etrack)
1780 				goto errreq;
1781 			int start = toc->toc[toc->first_track_offset + strack - 1].paddress;
1782 			int end = etrack == toc->last_track ? toc->lastaddress : toc->toc[toc->first_track_offset + etrack - 1 + 1].paddress;
1783 			sys_command_cd_pause (unitnum, 0);
1784 			if (!sys_command_cd_play (unitnum, start, end, 0))
1785 				goto notdatatrack;
1786 			scsi_len = 0;
1787 		}
1788 		break;
1789 		case 0x49: // PLAY AUDIO TRACK RELATIVE (10)
1790 		case 0xa9: // PLAY AUDIO TRACK RELATIVE (12)
1791 		{
1792 			if (nodisk (&di))
1793 				goto nodisk;
1794 			int len = cmd == 0xa9 ? rl (cmdbuf + 6) : rw (cmdbuf + 7);
1795 			int track = cmd == 0xa9 ? cmdbuf[10] : cmdbuf[6];
1796 			if (track < di.toc.first_track || track > di.toc.last_track)
1797 				goto errreq;
1798 			int start = di.toc.toc[di.toc.first_track_offset + track - 1].paddress;
1799 			int rel = rl (cmdbuf + 2);
1800 			start += rel;
1801 			int end = start + len;
1802 			if (end > di.toc.lastaddress)
1803 				end = di.toc.lastaddress;
1804 			if (len > 0) {
1805 				sys_command_cd_pause (unitnum, 0);
1806 				if (!sys_command_cd_play (unitnum, start, start + len, 0))
1807 					goto notdatatrack;
1808 			}
1809 			scsi_len = 0;
1810 		}
1811 		break;
1812 		case 0x47: // PLAY AUDIO MSF
1813 		{
1814 			if (nodisk (&di))
1815 				goto nodisk;
1816 			int start = rl (cmdbuf + 2) & 0x00ffffff;
1817 			if (start == 0x00ffffff) {
1818 				uae_u8 buf[SUBQ_SIZE] = { 0 };
1819 				sys_command_cd_qcode (unitnum, buf);
1820 				start = fromlongbcd (buf + 4 + 7);
1821 			}
1822 			int end = msf2lsn (rl (cmdbuf + 5) & 0x00ffffff);
1823 			if (end > di.toc.lastaddress)
1824 				end = di.toc.lastaddress;
1825 			start = msf2lsn (start);
1826 			if (start > end)
1827 				goto errreq;
1828 			if (start < end)
1829 				sys_command_cd_pause (unitnum, 0);
1830 				if (!sys_command_cd_play (unitnum, start, end, 0))
1831 					goto notdatatrack;
1832 			scsi_len = 0;
1833 		}
1834 		break;
1835 		case 0x45: // PLAY AUDIO (10)
1836 		case 0xa5: // PLAY AUDIO (12)
1837 		{
1838 			if (nodisk (&di))
1839 				goto nodisk;
1840 			int start = rl (cmdbuf + 2);
1841 			int len;
1842 			if (cmd == 0xa5)
1843 				len = rl (cmdbuf + 6);
1844 			else
1845 				len = rw (cmdbuf + 7);
1846 			if (len > 0) {
1847 				if (start == -1) {
1848 					uae_u8 buf[SUBQ_SIZE] = { 0 };
1849 					sys_command_cd_qcode (unitnum, buf);
1850 					start = msf2lsn (fromlongbcd (buf + 4 + 7));
1851 				}
1852 				int end = start + len;
1853 				if (end > di.toc.lastaddress)
1854 					end = di.toc.lastaddress;
1855 				sys_command_cd_pause (unitnum, 0);
1856 				if (!sys_command_cd_play (unitnum, start, end, 0))
1857 					goto notdatatrack;
1858 			}
1859 			scsi_len = 0;
1860 		}
1861 		break;
1862 		case 0xbc: // PLAY CD
1863 		{
1864 			if (nodisk (&di))
1865 				goto nodisk;
1866 			int start = -1;
1867 			int end = -1;
1868 			if (cmdbuf[1] & 2) {
1869 				start = msf2lsn (rl (cmdbuf + 2) & 0x00ffffff);
1870 				end = msf2lsn (rl (cmdbuf + 5) & 0x00ffffff);
1871 			} else {
1872 				start = rl (cmdbuf + 2);
1873 				end = start + rl (cmdbuf + 6);
1874 			}
1875 			if (end > di.toc.lastaddress)
1876 				end = di.toc.lastaddress;
1877 			if (start > end)
1878 				goto errreq;
1879 			if (start < end) {
1880 				sys_command_cd_pause (unitnum, 0);
1881 				if (!sys_command_cd_play (unitnum, start, end, 0))
1882 					goto notdatatrack;
1883 			}
1884 		}
1885 		break;
1886 		case 0x4b: // PAUSE/RESUME
1887 		{
1888 			if (nodisk (&di))
1889 				goto nodisk;
1890 			uae_u8 buf[SUBQ_SIZE] = { 0 };
1891 			int resume = cmdbuf[8] & 1;
1892 			sys_command_cd_qcode (unitnum, buf);
1893 			if (buf[1] != AUDIO_STATUS_IN_PROGRESS && buf[1] != AUDIO_STATUS_PAUSED)
1894 				goto errreq;
1895 			sys_command_cd_pause (unitnum, resume ? 0 : 1);
1896 			scsi_len = 0;
1897 		}
1898 		break;
1899 		case 0x35: /* SYNCRONIZE CACHE (10) */
1900 			scsi_len = 0;
1901 		break;
1902 
1903 		default:
1904 err:
1905 		write_log (_T("CDEMU: unsupported scsi command 0x%02X\n"), cmdbuf[0]);
1906 readprot:
1907 		status = 2; /* CHECK CONDITION */
1908 		s[0] = 0x70;
1909 		s[2] = 5;
1910 		s[12] = 0x20; /* INVALID COMMAND */
1911 		ls = 0x12;
1912 		break;
1913 nodisk:
1914 		status = 2; /* CHECK CONDITION */
1915 		s[0] = 0x70;
1916 		s[2] = 2; /* NOT READY */
1917 		s[12] = 0x3A; /* MEDIUM NOT PRESENT */
1918 		ls = 0x12;
1919 		break;
1920 readerr:
1921 		status = 2; /* CHECK CONDITION */
1922 		s[0] = 0x70;
1923 		s[2] = 2; /* NOT READY */
1924 		s[12] = 0x11; /* UNRECOVERED READ ERROR */
1925 		ls = 0x12;
1926 		break;
1927 notdatatrack:
1928 		status = 2;
1929 		s[0] = 0x70;
1930 		s[2] = 5;
1931 		s[12] = 0x64; /* ILLEGAL MODE FOR THIS TRACK */
1932 		ls = 0x12;
1933 		break;
1934 outofbounds:
1935 		status = 2; /* CHECK CONDITION */
1936 		s[0] = 0x70;
1937 		s[2] = 5; /* ILLEGAL REQUEST */
1938 		s[12] = 0x21; /* LOGICAL BLOCK OUT OF RANGE */
1939 		ls = 0x12;
1940 		break;
1941 toolarge:
1942 		write_log (_T("CDEMU: too large scsi data tranfer %d > %d\n"), len, dlen);
1943 		status = 2; /* CHECK CONDITION */
1944 		s[0] = 0x70;
1945 		s[2] = 2; /* NOT READY */
1946 		s[12] = 0x11; /* UNRECOVERED READ ERROR */
1947 		ls = 0x12;
1948 		break;
1949 errreq:
1950 		lr = -1;
1951 		status = 2; /* CHECK CONDITION */
1952 		s[0] = 0x70;
1953 		s[2] = 5; /* ILLEGAL REQUEST */
1954 		s[12] = 0x24; /* ILLEGAL FIELD IN CDB */
1955 		ls = 0x12;
1956 		break;
1957 	}
1958 end:
1959 	*data_len = scsi_len;
1960 	*reply_len = lr;
1961 	*sense_len = ls;
1962 	if (ls) {
1963 		//s[0] |= 0x80;
1964 		s[7] = ls - 7; // additional sense length
1965 	}
1966 	if (cmdbuf[0] && log_scsiemu)
1967 		write_log (_T("-> DATAOUT=%d ST=%d SENSELEN=%d\n"), scsi_len, status, ls);
1968 	return status;
1969 }
1970 
execscsicmd_direct(int unitnum,struct amigascsi * as)1971 static int execscsicmd_direct (int unitnum, struct amigascsi *as)
1972 {
1973 	int io_error = 0;
1974 	uae_u8 *scsi_datap, *scsi_datap_org;
1975 	uae_u32 scsi_cmd_len_orig = as->cmd_len;
1976 	uae_u8 cmd[16] = { 0 };
1977 	uae_u8 replydata[256];
1978 	int datalen = as->len;
1979 	int senselen = as->sense_len;
1980 	int replylen = 0;
1981 
1982 	memcpy (cmd, as->cmd, as->cmd_len);
1983 	scsi_datap = scsi_datap_org = as->len ? as->data : 0;
1984 	if (as->sense_len > 32)
1985 		as->sense_len = 32;
1986 
1987 	/* never report media change state if uaescsi.device */
1988 	state[unitnum].mediawaschanged = false;
1989 
1990 	as->status = scsi_cd_emulate (unitnum, cmd, as->cmd_len, scsi_datap, &datalen, replydata, &replylen, as->sensedata, &senselen, false);
1991 
1992 	as->cmdactual = as->status != 0 ? 0 : as->cmd_len; /* fake scsi_CmdActual */
1993 	if (as->status) {
1994 		io_error = IOERR_BadStatus;
1995 		as->sactual = senselen;
1996 		as->actual = 0; /* scsi_Actual */
1997 	} else {
1998 		int i;
1999 		if (replylen > 0) {
2000 			for (i = 0; i < replylen; i++)
2001 				scsi_datap[i] = replydata[i];
2002 			datalen = replylen;
2003 		}
2004 		for (i = 0; i < as->sense_len; i++)
2005 			as->sensedata[i] = 0;
2006 		if (datalen < 0) {
2007 			io_error = IOERR_NotSpecified;
2008 			as->actual = 0; /* scsi_Actual */
2009 		} else {
2010 			as->len = datalen;
2011 			io_error = 0;
2012 			as->actual = as->len; /* scsi_Actual */
2013 		}
2014 	}
2015 
2016 	return io_error;
2017 }
2018 
sys_command_scsi_direct_native(int unitnum,struct amigascsi * as)2019 int sys_command_scsi_direct_native (int unitnum, struct amigascsi *as)
2020 {
2021 	struct blkdevstate *st = &state[unitnum];
2022 	if (st->scsiemu) {
2023 		return execscsicmd_direct (unitnum, as);
2024 	} else {
2025 		if (!st->device_func->exec_direct)
2026 			return -1;
2027 	}
2028 	int ret = st->device_func->exec_direct (unitnum, as);
2029 	if (!ret && st->device_func->isatapi(unitnum))
2030 		scsi_atapi_fixup_inquiry (as);
2031 	return ret;
2032 }
2033 
sys_command_scsi_direct(int unitnum,uaecptr acmd)2034 int sys_command_scsi_direct (int unitnum, uaecptr acmd)
2035 {
2036 	int ret, i;
2037 	struct amigascsi as = { 0 };
2038 	uaecptr ap;
2039 	addrbank *bank;
2040 
2041 	ap = get_long (acmd + 0);
2042 	as.len = get_long (acmd + 4);
2043 
2044 	bank = &get_mem_bank (ap);
2045 	if (!bank || !bank->check(ap, as.len))
2046 		return IOERR_BADADDRESS;
2047 	as.data = bank->xlateaddr (ap);
2048 
2049 	ap = get_long (acmd + 12);
2050 	as.cmd_len = get_word (acmd + 16);
2051 	if (as.cmd_len > sizeof as.cmd)
2052 		return IOERR_BADLENGTH;
2053 	for (i = 0; i < as.cmd_len; i++)
2054 		as.cmd[i] = get_byte (ap++);
2055 	while (i < sizeof as.cmd)
2056 		as.cmd[i++] = 0;
2057 	as.flags = get_byte (acmd + 20);
2058 	as.sense_len = get_word (acmd + 26);
2059 
2060 	ret = sys_command_scsi_direct_native (unitnum, &as);
2061 
2062 	put_long (acmd + 8, as.actual);
2063 	put_word (acmd + 18, as.cmdactual);
2064 	put_byte (acmd + 21, as.status);
2065 	put_word (acmd + 28, as.sactual);
2066 
2067 	if (as.flags & (2 | 4)) { // autosense
2068 	ap = get_long (acmd + 22);
2069 		for (i = 0; i < as.sactual && i < as.sense_len; i++)
2070 			put_byte (ap + i, as.sensedata[i]);
2071 	}
2072 	return ret;
2073 }
2074 
2075 #ifdef SAVESTATE
2076 
save_cd(int num,int * len)2077 uae_u8 *save_cd (int num, int *len)
2078 {
2079 	struct blkdevstate *st = &state[num];
2080 	uae_u8 *dstbak, *dst;
2081 
2082 	memset(st->play_qcode, 0, SUBQ_SIZE);
2083 	if (!currprefs.cdslots[num].inuse || num >= MAX_TOTAL_SCSI_DEVICES)
2084 		return NULL;
2085 #ifdef CD32
2086 	if (!currprefs.cs_cd32cd && !currprefs.cs_cdtvcd && !currprefs.scsi)
2087 		return NULL;
2088 #endif
2089 	dstbak = dst = xmalloc (uae_u8, 4 + 256 + 4 + 4);
2090 	save_u32 (4 | 8);
2091 	save_path (currprefs.cdslots[num].name, SAVESTATE_PATH_CD);
2092 	save_u32 (currprefs.cdslots[num].type);
2093 	save_u32 (0);
2094 	save_u32 (0);
2095 	sys_command_cd_qcode (num, st->play_qcode);
2096 	for (int i = 0; i < SUBQ_SIZE; i++)
2097 		save_u8 (st->play_qcode[i]);
2098 	save_u32 (st->play_end_pos);
2099 	*len = dst - dstbak;
2100 	return dstbak;
2101 }
2102 
restore_cd(int num,uae_u8 * src)2103 uae_u8 *restore_cd (int num, uae_u8 *src)
2104 {
2105 	struct blkdevstate *st = &state[num];
2106 	uae_u32 flags;
2107 	TCHAR *s;
2108 
2109 	if (num >= MAX_TOTAL_SCSI_DEVICES)
2110 		return NULL;
2111 	flags = restore_u32 ();
2112 	s = restore_path (SAVESTATE_PATH_CD);
2113 	int type = restore_u32 ();
2114 	restore_u32 ();
2115 	if (flags & 4) {
2116 		if (currprefs.cdslots[num].name[0] == 0 || zfile_exists (s)) {
2117 			_tcscpy (changed_prefs.cdslots[num].name, s);
2118 			_tcscpy (currprefs.cdslots[num].name, s);
2119 		}
2120 		changed_prefs.cdslots[num].type = currprefs.cdslots[num].type = type;
2121 	}
2122 	if (flags & 8) {
2123 		restore_u32 ();
2124 		for (int i = 0; i < SUBQ_SIZE; i++)
2125 			st->play_qcode[i] = restore_u8 ();
2126 		st->play_end_pos = restore_u32 ();
2127 	}
2128 	return src;
2129 }
2130 
2131 #endif
2132 
2133