ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/BasiliskII/src/AmigaOS/sys_amiga.cpp
Revision: 1.1
Committed: 1999-10-03T14:16:25Z (24 years, 9 months ago) by cebix
Branch: MAIN
Branch point for: cebix
Log Message:
Initial revision

File Contents

# Content
1 /*
2 * sys_amiga.cpp - System dependent routines, Amiga implementation
3 *
4 * Basilisk II (C) 1997-1999 Christian Bauer
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 */
20
21 #include <exec/types.h>
22 #include <exec/memory.h>
23 #include <devices/newstyle.h>
24 #include <devices/trackdisk.h>
25 #include <devices/scsidisk.h>
26 #include <resources/disk.h>
27 #include <proto/dos.h>
28 #include <proto/exec.h>
29 #include <proto/disk.h>
30
31 #include "sysdeps.h"
32 #include "main.h"
33 #include "macos_util.h"
34 #include "prefs.h"
35 #include "user_strings.h"
36 #include "sys.h"
37
38 #define DEBUG 0
39 #include "debug.h"
40
41
42 // File handles are pointers to these structures
43 struct file_handle {
44 bool is_file; // Flag: plain file or /dev/something?
45 bool read_only; // Copy of Sys_open() flag
46 loff_t start_byte; // Size of file header (if any)
47 loff_t size; // Size of file/device (minus header)
48
49 BPTR f; // AmigaDOS file handle (if is_file == true)
50
51 struct IOStdReq *io; // Pointer to IORequest (if is_file == false)
52 ULONG block_size; // Block size of device (must be a power of two)
53 bool is_nsd; // New style device?
54 bool does_64bit; // Supports 64 bit trackdisk commands?
55 };
56
57
58 // FileInfoBlock (must be global because it has to be on a longword boundary)
59 static struct FileInfoBlock FIB;
60
61 // Message port for device communication
62 static struct MsgPort *the_port = NULL;
63
64 // Temporary buffer in chip memory
65 const int TMP_BUF_SIZE = 0x10000;
66 static UBYTE *tmp_buf = NULL;
67
68
69 /*
70 * Initialization
71 */
72
73 void SysInit(void)
74 {
75 // Create port and temporary buffer
76 the_port = CreateMsgPort();
77 tmp_buf = (UBYTE *)AllocMem(TMP_BUF_SIZE, MEMF_CHIP | MEMF_PUBLIC);
78 if (the_port == NULL || tmp_buf == NULL) {
79 ErrorAlert(GetString(STR_NO_MEM_ERR));
80 QuitEmulator();
81 }
82 }
83
84
85 /*
86 * Deinitialization
87 */
88
89 void SysExit(void)
90 {
91 // Delete port and temporary buffer
92 if (the_port)
93 DeleteMsgPort(the_port);
94 if (tmp_buf)
95 FreeMem(tmp_buf, TMP_BUF_SIZE);
96 }
97
98
99 /*
100 * This gets called when no "floppy" prefs items are found
101 * It scans for available floppy drives and adds appropriate prefs items
102 */
103
104 void SysAddFloppyPrefs(void)
105 {
106 #if 0
107 for (int i=0; i<4; i++) {
108 ULONG id = GetUnitID(i);
109 if (id == DRT_150RPM) { // We need an HD drive
110 char str[256];
111 sprintf(str, "/dev/mfm.device/%d/0/0/1474560/512", i);
112 PrefsAddString("floppy", str);
113 }
114 }
115 #endif
116 }
117
118
119 /*
120 * This gets called when no "disk" prefs items are found
121 * It scans for available HFS volumes and adds appropriate prefs items
122 */
123
124 void SysAddDiskPrefs(void)
125 {
126 // AmigaOS doesn't support MacOS partitioning, so this probably doesn't make much sense...
127 }
128
129
130 /*
131 * This gets called when no "cdrom" prefs items are found
132 * It scans for available CD-ROM drives and adds appropriate prefs items
133 */
134
135 void SysAddCDROMPrefs(void)
136 {
137 // Don't scan for drives if nocdrom option given
138 if (PrefsFindBool("nocdrom"))
139 return;
140
141 //!!
142 }
143
144
145 /*
146 * Add default serial prefs (must be added, even if no ports present)
147 */
148
149 void SysAddSerialPrefs(void)
150 {
151 PrefsAddString("seriala", "serial.device/0");
152 PrefsAddString("serialb", "*parallel.device/0");
153 }
154
155
156 /*
157 * Open file/device, create new file handle (returns NULL on error)
158 *
159 * Format for device names: /dev/<name>/<unit>/<open flags>/<start block>/<size (blocks)>/<block size>
160 */
161
162 void *Sys_open(const char *name, bool read_only)
163 {
164 bool is_file = (strstr(name, "/dev/") != name);
165
166 D(bug("Sys_open(%s, %s)\n", name, read_only ? "read-only" : "read/write"));
167
168 // File or device?
169 if (is_file) {
170
171 // File, open it and get stats
172 BPTR f = Open((char *)name, MODE_OLDFILE);
173 if (!f)
174 return NULL;
175 if (!ExamineFH(f, &FIB)) {
176 Close(f);
177 return NULL;
178 }
179
180 // Check if file is write protected
181 if (FIB.fib_Protection & FIBF_WRITE)
182 read_only = true;
183
184 // Create file_handle
185 file_handle *fh = new file_handle;
186 fh->f = f;
187 fh->is_file = true;
188 fh->read_only = read_only;
189
190 // Detect disk image file layout
191 loff_t size = FIB.fib_Size;
192 Seek(fh->f, 0, OFFSET_BEGINNING);
193 Read(fh->f, tmp_buf, 256);
194 FileDiskLayout(size, tmp_buf, fh->start_byte, fh->size);
195 return fh;
196
197 } else {
198
199 // Device, parse string
200 char dev_name[256];
201 ULONG dev_unit = 0, dev_flags = 0, dev_start = 0, dev_size = 16, dev_bsize = 512;
202 if (sscanf(name, "/dev/%[^/]/%ld/%ld/%ld/%ld/%ld", dev_name, &dev_unit, &dev_flags, &dev_start, &dev_size, &dev_bsize) < 2)
203 return NULL;
204
205 // Create IORequest
206 struct IOStdReq *io = (struct IOStdReq *)CreateIORequest(the_port, sizeof(struct IOExtTD));
207 if (io == NULL)
208 return NULL;
209
210 // Open device
211 if (OpenDevice((UBYTE *)dev_name, dev_unit, (struct IORequest *)io, dev_flags)) {
212 D(bug(" couldn't open device\n"));
213 DeleteIORequest(io);
214 return NULL;
215 }
216
217 // Check for new style device
218 bool is_nsd = false, does_64bit = false;
219 struct NSDeviceQueryResult nsdqr;
220 nsdqr.DevQueryFormat = 0;
221 nsdqr.SizeAvailable = 0;
222 io->io_Command = NSCMD_DEVICEQUERY;
223 io->io_Length = sizeof(nsdqr);
224 io->io_Data = (APTR)&nsdqr;
225 LONG error = DoIO((struct IORequest *)io);
226 D(bug("DEVICEQUERY returned %ld (length %ld, actual %ld)\n", error, io->io_Length, io->io_Actual));
227 if ((!error) && (io->io_Actual >= 16) && (io->io_Actual <= sizeof(nsdqr)) && (nsdqr.SizeAvailable == io->io_Actual)) {
228
229 // Looks like an NSD
230 is_nsd = true;
231 D(bug(" new style device, type %ld\n", nsdqr.DeviceType));
232
233 // We only work with trackdisk-like devices
234 if (nsdqr.DeviceType != NSDEVTYPE_TRACKDISK) {
235 CloseDevice((struct IORequest *)io);
236 DeleteIORequest(io);
237 return NULL;
238 }
239
240 // Check whether device is 64 bit capable
241 UWORD *cmdcheck;
242 for (cmdcheck = nsdqr.SupportedCommands; *cmdcheck; cmdcheck++) {
243 if (*cmdcheck == NSCMD_TD_READ64) {
244 D(bug(" supports 64 bit commands\n"));
245 does_64bit = true;
246 }
247 }
248 }
249
250 // Create file_handle
251 file_handle *fh = new file_handle;
252 fh->io = io;
253 fh->is_file = false;
254 fh->read_only = read_only;
255 fh->start_byte = (loff_t)dev_start * dev_bsize;
256 fh->size = (loff_t)dev_size * dev_bsize;
257 fh->block_size = dev_bsize;
258 fh->is_nsd = is_nsd;
259 fh->does_64bit = does_64bit;
260 return fh;
261 }
262 }
263
264
265 /*
266 * Close file/device, delete file handle
267 */
268
269 void Sys_close(void *arg)
270 {
271 file_handle *fh = (file_handle *)arg;
272 if (!fh)
273 return;
274
275 D(bug("Sys_close(%08lx)\n", arg));
276
277 // File or device?
278 if (fh->is_file) {
279
280 // File, simply close it
281 Close(fh->f);
282
283 } else {
284
285 // Device, close it and delete IORequest
286 fh->io->io_Command = CMD_UPDATE;
287 DoIO((struct IORequest *)fh->io);
288
289 fh->io->io_Command = TD_MOTOR;
290 fh->io->io_Length = 0;
291 DoIO((struct IORequest *)fh->io);
292
293 CloseDevice((struct IORequest *)fh->io);
294 DeleteIORequest(fh->io);
295 }
296 delete fh;
297 }
298
299
300 /*
301 * Read "length" bytes from file/device, starting at "offset", to "buffer",
302 * returns number of bytes read (or 0)
303 */
304
305 size_t Sys_read(void *arg, void *buffer, loff_t offset, size_t length)
306 {
307 file_handle *fh = (file_handle *)arg;
308 if (!fh)
309 return 0;
310
311 // File or device?
312 if (fh->is_file) {
313
314 // File, seek to position
315 if (Seek(fh->f, offset + fh->start_byte, OFFSET_BEGINNING) == -1)
316 return 0;
317
318 // Read data
319 LONG actual = Read(fh->f, buffer, length);
320 if (actual == -1)
321 return 0;
322 else
323 return actual;
324
325 } else {
326
327 // Device, pre-read (partial read of first block) neccessary?
328 loff_t pos = offset + fh->start_byte;
329 size_t actual = 0;
330 uint32 pre_offset = pos % fh->block_size;
331 if (pre_offset) {
332
333 // Yes, read one block
334 fh->io->io_Command = CMD_READ;
335 fh->io->io_Length = fh->block_size;
336 fh->io->io_Offset = pos - pre_offset;
337 fh->io->io_Data = tmp_buf;
338 if (DoIO((struct IORequest *)fh->io) || fh->io->io_Actual != fh->block_size)
339 return 0;
340
341 // Copy data to destination buffer
342 size_t pre_length = fh->block_size - pre_offset;
343 if (pre_length > length)
344 pre_length = length;
345 memcpy(buffer, tmp_buf + pre_offset, pre_length);
346
347 // Adjust data pointers
348 buffer = (uint8 *)buffer + pre_length;
349 pos += pre_length;
350 length -= pre_length;
351 actual += pre_length;
352 }
353
354 // Main read (complete reads of middle blocks) possible?
355 if (length >= fh->block_size) {
356
357 // Yes, read blocks
358 size_t main_length = length & ~(fh->block_size - 1);
359 fh->io->io_Command = CMD_READ;
360 fh->io->io_Length = main_length;
361 fh->io->io_Offset = pos;
362 fh->io->io_Data = buffer;
363 if (DoIO((struct IORequest *)fh->io) || fh->io->io_Actual != main_length)
364 return 0;
365
366 // Adjust data pointers
367 buffer = (uint8 *)buffer + main_length;
368 pos += main_length;
369 length -= main_length;
370 actual += main_length;
371 }
372
373 // Post-read (partial read of last block) neccessary?
374 if (length) {
375
376 // Yes, read one block
377 fh->io->io_Command = CMD_READ;
378 fh->io->io_Length = fh->block_size;
379 fh->io->io_Offset = pos;
380 fh->io->io_Data = tmp_buf;
381 if (DoIO((struct IORequest *)fh->io) || fh->io->io_Actual != fh->block_size)
382 return 0;
383
384 // Copy data to destination buffer
385 memcpy(buffer, tmp_buf, length);
386 actual += length;
387 }
388
389 return actual;
390 }
391 }
392
393
394 /*
395 * Write "length" bytes from "buffer" to file/device, starting at "offset",
396 * returns number of bytes written (or 0)
397 */
398
399 size_t Sys_write(void *arg, void *buffer, loff_t offset, size_t length)
400 {
401 file_handle *fh = (file_handle *)arg;
402 if (!fh)
403 return 0;
404
405 // File or device?
406 if (fh->is_file) {
407
408 // File, seek to position if neccessary
409 if (Seek(fh->f, offset + fh->start_byte, OFFSET_BEGINNING) == -1)
410 return 0;
411
412 // Write data
413 LONG actual = Write(fh->f, buffer, length);
414 if (actual == -1)
415 return 0;
416 else
417 return actual;
418
419 } else {
420
421 // Device, write data
422 fh->io->io_Command = CMD_WRITE;
423 fh->io->io_Length = length;
424 fh->io->io_Offset = offset + fh->start_byte;
425 fh->io->io_Data = buffer;
426 if (DoIO((struct IORequest *)fh->io))
427 return 0;
428 else
429 return fh->io->io_Actual;
430 }
431 }
432
433
434 /*
435 * Return size of file/device (minus header)
436 */
437
438 loff_t SysGetFileSize(void *arg)
439 {
440 file_handle *fh = (file_handle *)arg;
441 if (!fh)
442 return true;
443
444 return fh->size;
445 }
446
447
448 /*
449 * Eject volume (if applicable)
450 */
451
452 void SysEject(void *arg)
453 {
454 file_handle *fh = (file_handle *)arg;
455 if (!fh)
456 return;
457
458 if (!fh->is_file) {
459
460 // Flush buffer, turn off the drive motor and eject volume
461 fh->io->io_Command = CMD_UPDATE;
462 DoIO((struct IORequest *)fh->io);
463
464 fh->io->io_Command = TD_MOTOR;
465 fh->io->io_Length = 0;
466 DoIO((struct IORequest *)fh->io);
467
468 fh->io->io_Command = TD_EJECT;
469 fh->io->io_Length = 1;
470 DoIO((struct IORequest *)fh->io);
471 }
472 }
473
474
475 /*
476 * Format volume (if applicable)
477 */
478
479 bool SysFormat(void *arg)
480 {
481 file_handle *fh = (file_handle *)arg;
482 if (!fh)
483 return false;
484
485 //!!
486 return true;
487 }
488
489
490 /*
491 * Check if file/device is read-only (this includes the read-only flag on Sys_open())
492 */
493
494 bool SysIsReadOnly(void *arg)
495 {
496 file_handle *fh = (file_handle *)arg;
497 if (!fh)
498 return true;
499
500 if (fh->is_file) {
501
502 // File, return flag given to Sys_open
503 return fh->read_only;
504
505 } else {
506
507 // Device, check write protection
508 fh->io->io_Flags = IOF_QUICK;
509 fh->io->io_Command = TD_PROTSTATUS;
510 BeginIO((struct IORequest *)fh->io);
511 if (fh->io->io_Actual)
512 return true;
513 else
514 return fh->read_only;
515 }
516 }
517
518
519 /*
520 * Check if the given file handle refers to a fixed or a removable disk
521 */
522
523 bool SysIsFixedDisk(void *arg)
524 {
525 file_handle *fh = (file_handle *)arg;
526 if (!fh)
527 return true;
528
529 return true;
530 }
531
532
533 /*
534 * Check if a disk is inserted in the drive (always true for files)
535 */
536
537 bool SysIsDiskInserted(void *arg)
538 {
539 file_handle *fh = (file_handle *)arg;
540 if (!fh)
541 return false;
542
543 if (fh->is_file)
544 return true;
545 else {
546
547 // Check medium status
548 fh->io->io_Flags = IOF_QUICK;
549 fh->io->io_Command = TD_CHANGESTATE;
550 fh->io->io_Actual = 0;
551 BeginIO((struct IORequest *)fh->io);
552 return fh->io->io_Actual == 0;
553 }
554 }
555
556
557 /*
558 * Prevent medium removal (if applicable)
559 */
560
561 void SysPreventRemoval(void *arg)
562 {
563 file_handle *fh = (file_handle *)arg;
564 if (!fh)
565 return;
566
567 if (!fh->is_file) {
568
569 // Send PREVENT ALLOW MEDIUM REMOVAL SCSI command
570 struct SCSICmd scsi;
571 static const UBYTE the_cmd[6] = {0x1e, 0, 0, 0, 1, 0};
572 scsi.scsi_Length = 0;
573 scsi.scsi_Command = (UBYTE *)the_cmd;
574 scsi.scsi_CmdLength = 6;
575 scsi.scsi_Flags = SCSIF_READ;
576 scsi.scsi_Status = 0;
577 fh->io->io_Data = &scsi;
578 fh->io->io_Length = sizeof(scsi);
579 fh->io->io_Command = HD_SCSICMD;
580 DoIO((struct IORequest *)fh->io);
581 }
582 }
583
584
585 /*
586 * Allow medium removal (if applicable)
587 */
588
589 void SysAllowRemoval(void *arg)
590 {
591 file_handle *fh = (file_handle *)arg;
592 if (!fh)
593 return;
594
595 if (!fh->is_file) {
596
597 // Send PREVENT ALLOW MEDIUM REMOVAL SCSI command
598 struct SCSICmd scsi;
599 static const UBYTE the_cmd[6] = {0x1e, 0, 0, 0, 0, 0};
600 scsi.scsi_Length = 0;
601 scsi.scsi_Command = (UBYTE *)the_cmd;
602 scsi.scsi_CmdLength = 6;
603 scsi.scsi_Flags = SCSIF_READ;
604 scsi.scsi_Status = 0;
605 fh->io->io_Data = &scsi;
606 fh->io->io_Length = sizeof(scsi);
607 fh->io->io_Command = HD_SCSICMD;
608 DoIO((struct IORequest *)fh->io);
609 }
610 }
611
612
613 /*
614 * Read CD-ROM TOC (binary MSF format, 804 bytes max.)
615 */
616
617 bool SysCDReadTOC(void *arg, uint8 *toc)
618 {
619 file_handle *fh = (file_handle *)arg;
620 if (!fh)
621 return false;
622
623 if (fh->is_file)
624 return false;
625 else {
626
627 // Send READ TOC MSF SCSI command
628 struct SCSICmd scsi;
629 static const UBYTE read_toc_cmd[10] = {0x43, 0x02, 0, 0, 0, 0, 0, 0x03, 0x24, 0};
630 scsi.scsi_Data = (UWORD *)tmp_buf;
631 scsi.scsi_Length = 804;
632 scsi.scsi_Command = (UBYTE *)read_toc_cmd;
633 scsi.scsi_CmdLength = 10;
634 scsi.scsi_Flags = SCSIF_READ;
635 scsi.scsi_Status = 0;
636 fh->io->io_Data = &scsi;
637 fh->io->io_Length = sizeof(scsi);
638 fh->io->io_Command = HD_SCSICMD;
639 if (DoIO((struct IORequest *)fh->io) || scsi.scsi_Status)
640 return false;
641 memcpy(toc, tmp_buf, 804);
642 return true;
643 }
644 }
645
646
647 /*
648 * Read CD-ROM position data (Sub-Q Channel, 16 bytes, see SCSI standard)
649 */
650
651 bool SysCDGetPosition(void *arg, uint8 *pos)
652 {
653 file_handle *fh = (file_handle *)arg;
654 if (!fh)
655 return false;
656
657 if (fh->is_file)
658 return false;
659 else {
660
661 // Send READ SUB-CHANNEL SCSI command
662 struct SCSICmd scsi;
663 static const UBYTE read_subq_cmd[10] = {0x42, 0x02, 0x40, 0x01, 0, 0, 0, 0, 0x10, 0};
664 scsi.scsi_Data = (UWORD *)tmp_buf;
665 scsi.scsi_Length = 16;
666 scsi.scsi_Command = (UBYTE *)read_subq_cmd;
667 scsi.scsi_CmdLength = 10;
668 scsi.scsi_Flags = SCSIF_READ;
669 scsi.scsi_Status = 0;
670 fh->io->io_Data = &scsi;
671 fh->io->io_Length = sizeof(scsi);
672 fh->io->io_Command = HD_SCSICMD;
673 if (DoIO((struct IORequest *)fh->io) || scsi.scsi_Status)
674 return false;
675 memcpy(pos, tmp_buf, 16);
676 return true;
677 }
678 }
679
680
681 /*
682 * Play CD audio
683 */
684
685 bool SysCDPlay(void *arg, uint8 start_m, uint8 start_s, uint8 start_f, uint8 end_m, uint8 end_s, uint8 end_f)
686 {
687 file_handle *fh = (file_handle *)arg;
688 if (!fh)
689 return false;
690
691 if (fh->is_file)
692 return false;
693 else {
694
695 // Send PLAY AUDIO MSF SCSI command
696 struct SCSICmd scsi;
697 UBYTE play_cmd[10] = {0x47, 0, 0, start_m, start_s, start_f, end_m, end_s, end_f, 0};
698 scsi.scsi_Data = (UWORD *)tmp_buf;
699 scsi.scsi_Length = 0;
700 scsi.scsi_Command = play_cmd;
701 scsi.scsi_CmdLength = 10;
702 scsi.scsi_Flags = SCSIF_READ;
703 scsi.scsi_Status = 0;
704 fh->io->io_Data = &scsi;
705 fh->io->io_Length = sizeof(scsi);
706 fh->io->io_Command = HD_SCSICMD;
707 if (DoIO((struct IORequest *)fh->io) || scsi.scsi_Status)
708 return false;
709 return true;
710 }
711 }
712
713
714 /*
715 * Pause CD audio
716 */
717
718 bool SysCDPause(void *arg)
719 {
720 file_handle *fh = (file_handle *)arg;
721 if (!fh)
722 return false;
723
724 if (fh->is_file)
725 return false;
726 else {
727
728 // Send PAUSE RESUME SCSI command
729 struct SCSICmd scsi;
730 static const UBYTE pause_cmd[10] = {0x4b, 0, 0, 0, 0, 0, 0, 0, 0, 0};
731 scsi.scsi_Data = (UWORD *)tmp_buf;
732 scsi.scsi_Length = 0;
733 scsi.scsi_Command = (UBYTE *)pause_cmd;
734 scsi.scsi_CmdLength = 10;
735 scsi.scsi_Flags = SCSIF_READ;
736 scsi.scsi_Status = 0;
737 fh->io->io_Data = &scsi;
738 fh->io->io_Length = sizeof(scsi);
739 fh->io->io_Command = HD_SCSICMD;
740 if (DoIO((struct IORequest *)fh->io) || scsi.scsi_Status)
741 return false;
742 return true;
743 }
744 }
745
746
747 /*
748 * Resume paused CD audio
749 */
750
751 bool SysCDResume(void *arg)
752 {
753 file_handle *fh = (file_handle *)arg;
754 if (!fh)
755 return false;
756
757 if (fh->is_file)
758 return false;
759 else {
760
761 // Send PAUSE RESUME SCSI command
762 struct SCSICmd scsi;
763 static const UBYTE resume_cmd[10] = {0x4b, 0, 0, 0, 0, 0, 0, 0, 1, 0};
764 scsi.scsi_Data = (UWORD *)tmp_buf;
765 scsi.scsi_Length = 0;
766 scsi.scsi_Command = (UBYTE *)resume_cmd;
767 scsi.scsi_CmdLength = 10;
768 scsi.scsi_Flags = SCSIF_READ;
769 scsi.scsi_Status = 0;
770 fh->io->io_Data = &scsi;
771 fh->io->io_Length = sizeof(scsi);
772 fh->io->io_Command = HD_SCSICMD;
773 if (DoIO((struct IORequest *)fh->io) || scsi.scsi_Status)
774 return false;
775 return true;
776 }
777 }
778
779
780 /*
781 * Stop CD audio
782 */
783
784 bool SysCDStop(void *arg, uint8 lead_out_m, uint8 lead_out_s, uint8 lead_out_f)
785 {
786 file_handle *fh = (file_handle *)arg;
787 if (!fh)
788 return false;
789
790 if (fh->is_file)
791 return false;
792 else {
793
794 uint8 end_m = lead_out_m;
795 uint8 end_s = lead_out_s;
796 uint8 end_f = lead_out_f + 1;
797 if (end_f >= 75) {
798 end_f = 0;
799 end_s++;
800 if (end_s >= 60) {
801 end_s = 0;
802 end_m++;
803 }
804 }
805
806 // Send PLAY AUDIO MSF SCSI command (play first frame of lead-out area)
807 struct SCSICmd scsi;
808 UBYTE play_cmd[10] = {0x47, 0, 0, lead_out_m, lead_out_s, lead_out_f, end_m, end_s, end_f, 0};
809 scsi.scsi_Data = (UWORD *)tmp_buf;
810 scsi.scsi_Length = 0;
811 scsi.scsi_Command = play_cmd;
812 scsi.scsi_CmdLength = 10;
813 scsi.scsi_Flags = SCSIF_READ;
814 scsi.scsi_Status = 0;
815 fh->io->io_Data = &scsi;
816 fh->io->io_Length = sizeof(scsi);
817 fh->io->io_Command = HD_SCSICMD;
818 if (DoIO((struct IORequest *)fh->io) || scsi.scsi_Status)
819 return false;
820 return true;
821 }
822 }
823
824
825 /*
826 * Perform CD audio fast-forward/fast-reverse operation starting from specified address
827 */
828
829 bool SysCDScan(void *arg, uint8 start_m, uint8 start_s, uint8 start_f, bool reverse)
830 {
831 file_handle *fh = (file_handle *)arg;
832 if (!fh)
833 return false;
834
835 //!!
836 return false;
837 }
838
839
840 /*
841 * Set CD audio volume (0..255 each channel)
842 */
843
844 void SysCDSetVolume(void *arg, uint8 left, uint8 right)
845 {
846 file_handle *fh = (file_handle *)arg;
847 if (!fh)
848 return;
849
850 if (!fh->is_file) {
851
852 // Send MODE SENSE (CD-ROM Audio Control Parameters Page) SCSI command
853 struct SCSICmd scsi;
854 static const UBYTE mode_sense_cmd[6] = {0x1a, 0x08, 0x0e, 0, 20, 0};
855 scsi.scsi_Data = (UWORD *)tmp_buf;
856 scsi.scsi_Length = 20;
857 scsi.scsi_Command = (UBYTE *)mode_sense_cmd;
858 scsi.scsi_CmdLength = 6;
859 scsi.scsi_Flags = SCSIF_READ;
860 scsi.scsi_Status = 0;
861 fh->io->io_Data = &scsi;
862 fh->io->io_Length = sizeof(scsi);
863 fh->io->io_Command = HD_SCSICMD;
864 if (DoIO((struct IORequest *)fh->io) || scsi.scsi_Status)
865 return;
866
867 tmp_buf[6] = 0x04; // Immed
868 tmp_buf[9] = 0; // LBA/sec format
869 tmp_buf[10] = 0; // LBA/sec
870 tmp_buf[11] = 0;
871 tmp_buf[13] = left; // Port 0 volume
872 tmp_buf[15] = right; // Port 1 volume
873
874 // Send MODE SELECT (CD-ROM Audio Control Parameters Page) SCSI command
875 static const UBYTE mode_select_cmd[6] = {0x15, 0x10, 0, 0, 20, 0};
876 scsi.scsi_Data = (UWORD *)tmp_buf;
877 scsi.scsi_Length = 20;
878 scsi.scsi_Command = (UBYTE *)mode_select_cmd;
879 scsi.scsi_CmdLength = 6;
880 scsi.scsi_Flags = SCSIF_WRITE;
881 scsi.scsi_Status = 0;
882 fh->io->io_Data = &scsi;
883 fh->io->io_Length = sizeof(scsi);
884 fh->io->io_Command = HD_SCSICMD;
885 DoIO((struct IORequest *)fh->io);
886 }
887 }
888
889
890 /*
891 * Get CD audio volume (0..255 each channel)
892 */
893
894 void SysCDGetVolume(void *arg, uint8 &left, uint8 &right)
895 {
896 file_handle *fh = (file_handle *)arg;
897 if (!fh)
898 return;
899
900 if (!fh->is_file) {
901
902 // Send MODE SENSE (CD-ROM Audio Control Parameters Page) SCSI command
903 struct SCSICmd scsi;
904 static const UBYTE mode_sense_cmd[6] = {0x1a, 0x08, 0x0e, 0, 20, 0};
905 scsi.scsi_Data = (UWORD *)tmp_buf;
906 scsi.scsi_Length = 20;
907 scsi.scsi_Command = (UBYTE *)mode_sense_cmd;
908 scsi.scsi_CmdLength = 6;
909 scsi.scsi_Flags = SCSIF_READ;
910 scsi.scsi_Status = 0;
911 fh->io->io_Data = &scsi;
912 fh->io->io_Length = sizeof(scsi);
913 fh->io->io_Command = HD_SCSICMD;
914 if (DoIO((struct IORequest *)fh->io) || scsi.scsi_Status)
915 return;
916 left = tmp_buf[13]; // Port 0 volume
917 right = tmp_buf[15]; // Port 1 volume
918 }
919 }