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 (25 years, 2 months ago) by cebix
Branch: MAIN
Branch point for: cebix
Log Message:
Initial revision

File Contents

# User Rev Content
1 cebix 1.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     }