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