ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/BasiliskII/src/AmigaOS/sys_amiga.cpp
Revision: 1.2
Committed: 1999-11-01T16:24:12Z (25 years, 1 month ago) by cebix
Branch: MAIN
CVS Tags: snapshot-22121999, release-0_8-1, snapshot-02111999
Changes since 1.1: +87 -27 lines
Log Message:
- AmigaOS: removed support for SAS/C
- AmigaOS: sys_amiga.cpp: supports 64-bit device access and respects
  device block size on writes
- AmigaOS: added support for resource forks and Finder info for ExtFS
- AmigaOS: added "ExtFS" gadget to prefs editor
- protection mask for all open()/creat()/mkdir() calls is now 0666 or
  0777

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 * Send one I/O request, using 64-bit addressing if the device supports it
302 */
303
304 static loff_t send_io_request(file_handle *fh, bool writing, ULONG length, loff_t offset, APTR data)
305 {
306 if (fh->does_64bit) {
307 fh->io->io_Command = writing ? NSCMD_TD_WRITE64 : NSCMD_TD_READ64;
308 fh->io->io_Actual = offset >> 32;
309 } else {
310 fh->io->io_Command = writing ? CMD_WRITE : CMD_READ;
311 fh->io->io_Actual = 0;
312 }
313 fh->io->io_Length = length;
314 fh->io->io_Offset = offset;
315 fh->io->io_Data = data;
316 if (DoIO((struct IORequest *)fh->io) || fh->io->io_Actual != length)
317 return 0;
318 return fh->io->io_Actual;
319 }
320
321
322 /*
323 * Read "length" bytes from file/device, starting at "offset", to "buffer",
324 * returns number of bytes read (or 0)
325 */
326
327 size_t Sys_read(void *arg, void *buffer, loff_t offset, size_t length)
328 {
329 file_handle *fh = (file_handle *)arg;
330 if (!fh)
331 return 0;
332
333 // File or device?
334 if (fh->is_file) {
335
336 // File, seek to position
337 if (Seek(fh->f, offset + fh->start_byte, OFFSET_BEGINNING) == -1)
338 return 0;
339
340 // Read data
341 LONG actual = Read(fh->f, buffer, length);
342 if (actual == -1)
343 return 0;
344 else
345 return actual;
346
347 } else {
348
349 // Device, pre-read (partial read of first block) necessary?
350 loff_t pos = offset + fh->start_byte;
351 size_t actual = 0;
352 uint32 pre_offset = pos % fh->block_size;
353 if (pre_offset) {
354
355 // Yes, read one block
356 if (send_io_request(fh, false, fh->block_size, pos - pre_offset, tmp_buf) == 0)
357 return 0;
358
359 // Copy data to destination buffer
360 size_t pre_length = fh->block_size - pre_offset;
361 if (pre_length > length)
362 pre_length = length;
363 memcpy(buffer, tmp_buf + pre_offset, pre_length);
364
365 // Adjust data pointers
366 buffer = (uint8 *)buffer + pre_length;
367 pos += pre_length;
368 length -= pre_length;
369 actual += pre_length;
370 }
371
372 // Main read (complete reads of middle blocks) possible?
373 if (length >= fh->block_size) {
374
375 // Yes, read blocks
376 size_t main_length = length & ~(fh->block_size - 1);
377 if (send_io_request(fh, false, main_length, pos, buffer) == 0)
378 return 0;
379
380 // Adjust data pointers
381 buffer = (uint8 *)buffer + main_length;
382 pos += main_length;
383 length -= main_length;
384 actual += main_length;
385 }
386
387 // Post-read (partial read of last block) necessary?
388 if (length) {
389
390 // Yes, read one block
391 if (send_io_request(fh, false, fh->block_size, pos, tmp_buf) == 0)
392 return 0;
393
394 // Copy data to destination buffer
395 memcpy(buffer, tmp_buf, length);
396 actual += length;
397 }
398
399 return actual;
400 }
401 }
402
403
404 /*
405 * Write "length" bytes from "buffer" to file/device, starting at "offset",
406 * returns number of bytes written (or 0)
407 */
408
409 size_t Sys_write(void *arg, void *buffer, loff_t offset, size_t length)
410 {
411 file_handle *fh = (file_handle *)arg;
412 if (!fh)
413 return 0;
414
415 // File or device?
416 if (fh->is_file) {
417
418 // File, seek to position if necessary
419 if (Seek(fh->f, offset + fh->start_byte, OFFSET_BEGINNING) == -1)
420 return 0;
421
422 // Write data
423 LONG actual = Write(fh->f, buffer, length);
424 if (actual == -1)
425 return 0;
426 else
427 return actual;
428
429 } else {
430
431 // Device, pre-write (partial write of first block) necessary
432 loff_t pos = offset + fh->start_byte;
433 size_t actual = 0;
434 uint32 pre_offset = pos % fh->block_size;
435 if (pre_offset) {
436
437 // Yes, read one block
438 if (send_io_request(fh, false, fh->block_size, pos - pre_offset, tmp_buf) == 0)
439 return 0;
440
441 // Copy data from source buffer
442 size_t pre_length = fh->block_size - pre_offset;
443 if (pre_length > length)
444 pre_length = length;
445 memcpy(tmp_buf + pre_offset, buffer, pre_length);
446
447 // Write block back
448 if (send_io_request(fh, true, fh->block_size, pos - pre_offset, tmp_buf) == 0)
449 return 0;
450
451 // Adjust data pointers
452 buffer = (uint8 *)buffer + pre_length;
453 pos += pre_length;
454 length -= pre_length;
455 actual += pre_length;
456 }
457
458 // Main write (complete writes of middle blocks) possible?
459 if (length >= fh->block_size) {
460
461 // Yes, write blocks
462 size_t main_length = length & ~(fh->block_size - 1);
463 if (send_io_request(fh, true, main_length, pos, buffer) == 0)
464 return 0;
465
466 // Adjust data pointers
467 buffer = (uint8 *)buffer + main_length;
468 pos += main_length;
469 length -= main_length;
470 actual += main_length;
471 }
472
473 // Post-write (partial write of last block) necessary?
474 if (length) {
475
476 // Yes, read one block
477 if (send_io_request(fh, false, fh->block_size, pos, tmp_buf) == 0)
478 return 0;
479
480 // Copy data from source buffer
481 memcpy(buffer, tmp_buf, length);
482
483 // Write block back
484 if (send_io_request(fh, true, fh->block_size, pos, tmp_buf) == 0)
485 return 0;
486 actual += length;
487 }
488
489 return actual;
490 }
491 }
492
493
494 /*
495 * Return size of file/device (minus header)
496 */
497
498 loff_t SysGetFileSize(void *arg)
499 {
500 file_handle *fh = (file_handle *)arg;
501 if (!fh)
502 return true;
503
504 return fh->size;
505 }
506
507
508 /*
509 * Eject volume (if applicable)
510 */
511
512 void SysEject(void *arg)
513 {
514 file_handle *fh = (file_handle *)arg;
515 if (!fh)
516 return;
517
518 if (!fh->is_file) {
519
520 // Flush buffer, turn off the drive motor and eject volume
521 fh->io->io_Command = CMD_UPDATE;
522 DoIO((struct IORequest *)fh->io);
523
524 fh->io->io_Command = TD_MOTOR;
525 fh->io->io_Length = 0;
526 DoIO((struct IORequest *)fh->io);
527
528 fh->io->io_Command = TD_EJECT;
529 fh->io->io_Length = 1;
530 DoIO((struct IORequest *)fh->io);
531 }
532 }
533
534
535 /*
536 * Format volume (if applicable)
537 */
538
539 bool SysFormat(void *arg)
540 {
541 file_handle *fh = (file_handle *)arg;
542 if (!fh)
543 return false;
544
545 //!!
546 return true;
547 }
548
549
550 /*
551 * Check if file/device is read-only (this includes the read-only flag on Sys_open())
552 */
553
554 bool SysIsReadOnly(void *arg)
555 {
556 file_handle *fh = (file_handle *)arg;
557 if (!fh)
558 return true;
559
560 if (fh->is_file) {
561
562 // File, return flag given to Sys_open
563 return fh->read_only;
564
565 } else {
566
567 // Device, check write protection
568 fh->io->io_Flags = IOF_QUICK;
569 fh->io->io_Command = TD_PROTSTATUS;
570 BeginIO((struct IORequest *)fh->io);
571 if (fh->io->io_Actual)
572 return true;
573 else
574 return fh->read_only;
575 }
576 }
577
578
579 /*
580 * Check if the given file handle refers to a fixed or a removable disk
581 */
582
583 bool SysIsFixedDisk(void *arg)
584 {
585 file_handle *fh = (file_handle *)arg;
586 if (!fh)
587 return true;
588
589 return true;
590 }
591
592
593 /*
594 * Check if a disk is inserted in the drive (always true for files)
595 */
596
597 bool SysIsDiskInserted(void *arg)
598 {
599 file_handle *fh = (file_handle *)arg;
600 if (!fh)
601 return false;
602
603 if (fh->is_file)
604 return true;
605 else {
606
607 // Check medium status
608 fh->io->io_Flags = IOF_QUICK;
609 fh->io->io_Command = TD_CHANGESTATE;
610 fh->io->io_Actual = 0;
611 BeginIO((struct IORequest *)fh->io);
612 return fh->io->io_Actual == 0;
613 }
614 }
615
616
617 /*
618 * Prevent medium removal (if applicable)
619 */
620
621 void SysPreventRemoval(void *arg)
622 {
623 file_handle *fh = (file_handle *)arg;
624 if (!fh)
625 return;
626
627 if (!fh->is_file) {
628
629 // Send PREVENT ALLOW MEDIUM REMOVAL SCSI command
630 struct SCSICmd scsi;
631 static const UBYTE the_cmd[6] = {0x1e, 0, 0, 0, 1, 0};
632 scsi.scsi_Length = 0;
633 scsi.scsi_Command = (UBYTE *)the_cmd;
634 scsi.scsi_CmdLength = 6;
635 scsi.scsi_Flags = SCSIF_READ;
636 scsi.scsi_Status = 0;
637 fh->io->io_Data = &scsi;
638 fh->io->io_Length = sizeof(scsi);
639 fh->io->io_Command = HD_SCSICMD;
640 DoIO((struct IORequest *)fh->io);
641 }
642 }
643
644
645 /*
646 * Allow medium removal (if applicable)
647 */
648
649 void SysAllowRemoval(void *arg)
650 {
651 file_handle *fh = (file_handle *)arg;
652 if (!fh)
653 return;
654
655 if (!fh->is_file) {
656
657 // Send PREVENT ALLOW MEDIUM REMOVAL SCSI command
658 struct SCSICmd scsi;
659 static const UBYTE the_cmd[6] = {0x1e, 0, 0, 0, 0, 0};
660 scsi.scsi_Length = 0;
661 scsi.scsi_Command = (UBYTE *)the_cmd;
662 scsi.scsi_CmdLength = 6;
663 scsi.scsi_Flags = SCSIF_READ;
664 scsi.scsi_Status = 0;
665 fh->io->io_Data = &scsi;
666 fh->io->io_Length = sizeof(scsi);
667 fh->io->io_Command = HD_SCSICMD;
668 DoIO((struct IORequest *)fh->io);
669 }
670 }
671
672
673 /*
674 * Read CD-ROM TOC (binary MSF format, 804 bytes max.)
675 */
676
677 bool SysCDReadTOC(void *arg, uint8 *toc)
678 {
679 file_handle *fh = (file_handle *)arg;
680 if (!fh)
681 return false;
682
683 if (fh->is_file)
684 return false;
685 else {
686
687 // Send READ TOC MSF SCSI command
688 struct SCSICmd scsi;
689 static const UBYTE read_toc_cmd[10] = {0x43, 0x02, 0, 0, 0, 0, 0, 0x03, 0x24, 0};
690 scsi.scsi_Data = (UWORD *)tmp_buf;
691 scsi.scsi_Length = 804;
692 scsi.scsi_Command = (UBYTE *)read_toc_cmd;
693 scsi.scsi_CmdLength = 10;
694 scsi.scsi_Flags = SCSIF_READ;
695 scsi.scsi_Status = 0;
696 fh->io->io_Data = &scsi;
697 fh->io->io_Length = sizeof(scsi);
698 fh->io->io_Command = HD_SCSICMD;
699 if (DoIO((struct IORequest *)fh->io) || scsi.scsi_Status)
700 return false;
701 memcpy(toc, tmp_buf, 804);
702 return true;
703 }
704 }
705
706
707 /*
708 * Read CD-ROM position data (Sub-Q Channel, 16 bytes, see SCSI standard)
709 */
710
711 bool SysCDGetPosition(void *arg, uint8 *pos)
712 {
713 file_handle *fh = (file_handle *)arg;
714 if (!fh)
715 return false;
716
717 if (fh->is_file)
718 return false;
719 else {
720
721 // Send READ SUB-CHANNEL SCSI command
722 struct SCSICmd scsi;
723 static const UBYTE read_subq_cmd[10] = {0x42, 0x02, 0x40, 0x01, 0, 0, 0, 0, 0x10, 0};
724 scsi.scsi_Data = (UWORD *)tmp_buf;
725 scsi.scsi_Length = 16;
726 scsi.scsi_Command = (UBYTE *)read_subq_cmd;
727 scsi.scsi_CmdLength = 10;
728 scsi.scsi_Flags = SCSIF_READ;
729 scsi.scsi_Status = 0;
730 fh->io->io_Data = &scsi;
731 fh->io->io_Length = sizeof(scsi);
732 fh->io->io_Command = HD_SCSICMD;
733 if (DoIO((struct IORequest *)fh->io) || scsi.scsi_Status)
734 return false;
735 memcpy(pos, tmp_buf, 16);
736 return true;
737 }
738 }
739
740
741 /*
742 * Play CD audio
743 */
744
745 bool SysCDPlay(void *arg, uint8 start_m, uint8 start_s, uint8 start_f, uint8 end_m, uint8 end_s, uint8 end_f)
746 {
747 file_handle *fh = (file_handle *)arg;
748 if (!fh)
749 return false;
750
751 if (fh->is_file)
752 return false;
753 else {
754
755 // Send PLAY AUDIO MSF SCSI command
756 struct SCSICmd scsi;
757 UBYTE play_cmd[10] = {0x47, 0, 0, start_m, start_s, start_f, end_m, end_s, end_f, 0};
758 scsi.scsi_Data = (UWORD *)tmp_buf;
759 scsi.scsi_Length = 0;
760 scsi.scsi_Command = play_cmd;
761 scsi.scsi_CmdLength = 10;
762 scsi.scsi_Flags = SCSIF_READ;
763 scsi.scsi_Status = 0;
764 fh->io->io_Data = &scsi;
765 fh->io->io_Length = sizeof(scsi);
766 fh->io->io_Command = HD_SCSICMD;
767 if (DoIO((struct IORequest *)fh->io) || scsi.scsi_Status)
768 return false;
769 return true;
770 }
771 }
772
773
774 /*
775 * Pause CD audio
776 */
777
778 bool SysCDPause(void *arg)
779 {
780 file_handle *fh = (file_handle *)arg;
781 if (!fh)
782 return false;
783
784 if (fh->is_file)
785 return false;
786 else {
787
788 // Send PAUSE RESUME SCSI command
789 struct SCSICmd scsi;
790 static const UBYTE pause_cmd[10] = {0x4b, 0, 0, 0, 0, 0, 0, 0, 0, 0};
791 scsi.scsi_Data = (UWORD *)tmp_buf;
792 scsi.scsi_Length = 0;
793 scsi.scsi_Command = (UBYTE *)pause_cmd;
794 scsi.scsi_CmdLength = 10;
795 scsi.scsi_Flags = SCSIF_READ;
796 scsi.scsi_Status = 0;
797 fh->io->io_Data = &scsi;
798 fh->io->io_Length = sizeof(scsi);
799 fh->io->io_Command = HD_SCSICMD;
800 if (DoIO((struct IORequest *)fh->io) || scsi.scsi_Status)
801 return false;
802 return true;
803 }
804 }
805
806
807 /*
808 * Resume paused CD audio
809 */
810
811 bool SysCDResume(void *arg)
812 {
813 file_handle *fh = (file_handle *)arg;
814 if (!fh)
815 return false;
816
817 if (fh->is_file)
818 return false;
819 else {
820
821 // Send PAUSE RESUME SCSI command
822 struct SCSICmd scsi;
823 static const UBYTE resume_cmd[10] = {0x4b, 0, 0, 0, 0, 0, 0, 0, 1, 0};
824 scsi.scsi_Data = (UWORD *)tmp_buf;
825 scsi.scsi_Length = 0;
826 scsi.scsi_Command = (UBYTE *)resume_cmd;
827 scsi.scsi_CmdLength = 10;
828 scsi.scsi_Flags = SCSIF_READ;
829 scsi.scsi_Status = 0;
830 fh->io->io_Data = &scsi;
831 fh->io->io_Length = sizeof(scsi);
832 fh->io->io_Command = HD_SCSICMD;
833 if (DoIO((struct IORequest *)fh->io) || scsi.scsi_Status)
834 return false;
835 return true;
836 }
837 }
838
839
840 /*
841 * Stop CD audio
842 */
843
844 bool SysCDStop(void *arg, uint8 lead_out_m, uint8 lead_out_s, uint8 lead_out_f)
845 {
846 file_handle *fh = (file_handle *)arg;
847 if (!fh)
848 return false;
849
850 if (fh->is_file)
851 return false;
852 else {
853
854 uint8 end_m = lead_out_m;
855 uint8 end_s = lead_out_s;
856 uint8 end_f = lead_out_f + 1;
857 if (end_f >= 75) {
858 end_f = 0;
859 end_s++;
860 if (end_s >= 60) {
861 end_s = 0;
862 end_m++;
863 }
864 }
865
866 // Send PLAY AUDIO MSF SCSI command (play first frame of lead-out area)
867 struct SCSICmd scsi;
868 UBYTE play_cmd[10] = {0x47, 0, 0, lead_out_m, lead_out_s, lead_out_f, end_m, end_s, end_f, 0};
869 scsi.scsi_Data = (UWORD *)tmp_buf;
870 scsi.scsi_Length = 0;
871 scsi.scsi_Command = play_cmd;
872 scsi.scsi_CmdLength = 10;
873 scsi.scsi_Flags = SCSIF_READ;
874 scsi.scsi_Status = 0;
875 fh->io->io_Data = &scsi;
876 fh->io->io_Length = sizeof(scsi);
877 fh->io->io_Command = HD_SCSICMD;
878 if (DoIO((struct IORequest *)fh->io) || scsi.scsi_Status)
879 return false;
880 return true;
881 }
882 }
883
884
885 /*
886 * Perform CD audio fast-forward/fast-reverse operation starting from specified address
887 */
888
889 bool SysCDScan(void *arg, uint8 start_m, uint8 start_s, uint8 start_f, bool reverse)
890 {
891 file_handle *fh = (file_handle *)arg;
892 if (!fh)
893 return false;
894
895 //!!
896 return false;
897 }
898
899
900 /*
901 * Set CD audio volume (0..255 each channel)
902 */
903
904 void SysCDSetVolume(void *arg, uint8 left, uint8 right)
905 {
906 file_handle *fh = (file_handle *)arg;
907 if (!fh)
908 return;
909
910 if (!fh->is_file) {
911
912 // Send MODE SENSE (CD-ROM Audio Control Parameters Page) SCSI command
913 struct SCSICmd scsi;
914 static const UBYTE mode_sense_cmd[6] = {0x1a, 0x08, 0x0e, 0, 20, 0};
915 scsi.scsi_Data = (UWORD *)tmp_buf;
916 scsi.scsi_Length = 20;
917 scsi.scsi_Command = (UBYTE *)mode_sense_cmd;
918 scsi.scsi_CmdLength = 6;
919 scsi.scsi_Flags = SCSIF_READ;
920 scsi.scsi_Status = 0;
921 fh->io->io_Data = &scsi;
922 fh->io->io_Length = sizeof(scsi);
923 fh->io->io_Command = HD_SCSICMD;
924 if (DoIO((struct IORequest *)fh->io) || scsi.scsi_Status)
925 return;
926
927 tmp_buf[6] = 0x04; // Immed
928 tmp_buf[9] = 0; // LBA/sec format
929 tmp_buf[10] = 0; // LBA/sec
930 tmp_buf[11] = 0;
931 tmp_buf[13] = left; // Port 0 volume
932 tmp_buf[15] = right; // Port 1 volume
933
934 // Send MODE SELECT (CD-ROM Audio Control Parameters Page) SCSI command
935 static const UBYTE mode_select_cmd[6] = {0x15, 0x10, 0, 0, 20, 0};
936 scsi.scsi_Data = (UWORD *)tmp_buf;
937 scsi.scsi_Length = 20;
938 scsi.scsi_Command = (UBYTE *)mode_select_cmd;
939 scsi.scsi_CmdLength = 6;
940 scsi.scsi_Flags = SCSIF_WRITE;
941 scsi.scsi_Status = 0;
942 fh->io->io_Data = &scsi;
943 fh->io->io_Length = sizeof(scsi);
944 fh->io->io_Command = HD_SCSICMD;
945 DoIO((struct IORequest *)fh->io);
946 }
947 }
948
949
950 /*
951 * Get CD audio volume (0..255 each channel)
952 */
953
954 void SysCDGetVolume(void *arg, uint8 &left, uint8 &right)
955 {
956 file_handle *fh = (file_handle *)arg;
957 if (!fh)
958 return;
959
960 if (!fh->is_file) {
961
962 // Send MODE SENSE (CD-ROM Audio Control Parameters Page) SCSI command
963 struct SCSICmd scsi;
964 static const UBYTE mode_sense_cmd[6] = {0x1a, 0x08, 0x0e, 0, 20, 0};
965 scsi.scsi_Data = (UWORD *)tmp_buf;
966 scsi.scsi_Length = 20;
967 scsi.scsi_Command = (UBYTE *)mode_sense_cmd;
968 scsi.scsi_CmdLength = 6;
969 scsi.scsi_Flags = SCSIF_READ;
970 scsi.scsi_Status = 0;
971 fh->io->io_Data = &scsi;
972 fh->io->io_Length = sizeof(scsi);
973 fh->io->io_Command = HD_SCSICMD;
974 if (DoIO((struct IORequest *)fh->io) || scsi.scsi_Status)
975 return;
976 left = tmp_buf[13]; // Port 0 volume
977 right = tmp_buf[15]; // Port 1 volume
978 }
979 }