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