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