ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/BasiliskII/src/AmigaOS/sys_amiga.cpp
Revision: 1.9
Committed: 2008-01-01T09:40:31Z (16 years, 5 months ago) by gbeauche
Branch: MAIN
CVS Tags: HEAD
Changes since 1.8: +1 -1 lines
Log Message:
Happy New Year!

File Contents

# User Rev Content
1 cebix 1.1 /*
2     * sys_amiga.cpp - System dependent routines, Amiga implementation
3     *
4 gbeauche 1.9 * Basilisk II (C) 1997-2008 Christian Bauer
5 cebix 1.1 *
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 jlachmann 1.8 #define __USE_SYSBASE
28 cebix 1.1 #include <proto/dos.h>
29     #include <proto/exec.h>
30     #include <proto/disk.h>
31 jlachmann 1.8 #include <inline/dos.h>
32     #include <inline/exec.h>
33     #include <inline/disk.h>
34 cebix 1.1
35     #include "sysdeps.h"
36     #include "main.h"
37     #include "macos_util.h"
38     #include "prefs.h"
39     #include "user_strings.h"
40     #include "sys.h"
41    
42     #define DEBUG 0
43     #include "debug.h"
44    
45    
46     // File handles are pointers to these structures
47     struct file_handle {
48     bool is_file; // Flag: plain file or /dev/something?
49     bool read_only; // Copy of Sys_open() flag
50     loff_t start_byte; // Size of file header (if any)
51     loff_t size; // Size of file/device (minus header)
52    
53     BPTR f; // AmigaDOS file handle (if is_file == true)
54    
55     struct IOStdReq *io; // Pointer to IORequest (if is_file == false)
56     ULONG block_size; // Block size of device (must be a power of two)
57     bool is_nsd; // New style device?
58     bool does_64bit; // Supports 64 bit trackdisk commands?
59 cebix 1.4 bool is_ejected; // Volume has been (logically) ejected
60     bool is_2060scsi; // Enable workaround for 2060scsi.device CD-ROM TD_READ bug
61 cebix 1.1 };
62    
63    
64     // FileInfoBlock (must be global because it has to be on a longword boundary)
65     static struct FileInfoBlock FIB;
66    
67     // Message port for device communication
68     static struct MsgPort *the_port = NULL;
69    
70     // Temporary buffer in chip memory
71     const int TMP_BUF_SIZE = 0x10000;
72     static UBYTE *tmp_buf = NULL;
73    
74    
75     /*
76     * Initialization
77     */
78    
79     void SysInit(void)
80     {
81     // Create port and temporary buffer
82     the_port = CreateMsgPort();
83     tmp_buf = (UBYTE *)AllocMem(TMP_BUF_SIZE, MEMF_CHIP | MEMF_PUBLIC);
84     if (the_port == NULL || tmp_buf == NULL) {
85 cebix 1.6 ErrorAlert(STR_NO_MEM_ERR);
86 cebix 1.1 QuitEmulator();
87     }
88     }
89    
90    
91     /*
92     * Deinitialization
93     */
94    
95     void SysExit(void)
96     {
97     // Delete port and temporary buffer
98 cebix 1.4 if (the_port) {
99 cebix 1.1 DeleteMsgPort(the_port);
100 cebix 1.4 the_port = NULL;
101     }
102     if (tmp_buf) {
103 cebix 1.1 FreeMem(tmp_buf, TMP_BUF_SIZE);
104 cebix 1.4 tmp_buf = NULL;
105     }
106 cebix 1.1 }
107    
108    
109     /*
110     * This gets called when no "floppy" prefs items are found
111     * It scans for available floppy drives and adds appropriate prefs items
112     */
113    
114     void SysAddFloppyPrefs(void)
115     {
116     for (int i=0; i<4; i++) {
117     ULONG id = GetUnitID(i);
118     if (id == DRT_150RPM) { // We need an HD drive
119     char str[256];
120 cebix 1.4 sprintf(str, "/dev/mfm.device/%d/0/0/2880/512", i);
121 cebix 1.1 PrefsAddString("floppy", str);
122     }
123     }
124     }
125    
126    
127     /*
128     * This gets called when no "disk" prefs items are found
129     * It scans for available HFS volumes and adds appropriate prefs items
130     */
131    
132     void SysAddDiskPrefs(void)
133     {
134     // AmigaOS doesn't support MacOS partitioning, so this probably doesn't make much sense...
135     }
136    
137    
138     /*
139     * This gets called when no "cdrom" prefs items are found
140     * It scans for available CD-ROM drives and adds appropriate prefs items
141     */
142    
143     void SysAddCDROMPrefs(void)
144     {
145     // Don't scan for drives if nocdrom option given
146     if (PrefsFindBool("nocdrom"))
147     return;
148    
149     //!!
150     }
151    
152    
153     /*
154     * Add default serial prefs (must be added, even if no ports present)
155     */
156    
157     void SysAddSerialPrefs(void)
158     {
159     PrefsAddString("seriala", "serial.device/0");
160     PrefsAddString("serialb", "*parallel.device/0");
161     }
162    
163    
164     /*
165     * Open file/device, create new file handle (returns NULL on error)
166     *
167     * Format for device names: /dev/<name>/<unit>/<open flags>/<start block>/<size (blocks)>/<block size>
168     */
169    
170     void *Sys_open(const char *name, bool read_only)
171     {
172     bool is_file = (strstr(name, "/dev/") != name);
173    
174     D(bug("Sys_open(%s, %s)\n", name, read_only ? "read-only" : "read/write"));
175    
176     // File or device?
177     if (is_file) {
178    
179     // File, open it and get stats
180     BPTR f = Open((char *)name, MODE_OLDFILE);
181     if (!f)
182     return NULL;
183     if (!ExamineFH(f, &FIB)) {
184     Close(f);
185     return NULL;
186     }
187    
188     // Check if file is write protected
189     if (FIB.fib_Protection & FIBF_WRITE)
190     read_only = true;
191    
192     // Create file_handle
193     file_handle *fh = new file_handle;
194     fh->f = f;
195     fh->is_file = true;
196     fh->read_only = read_only;
197    
198     // Detect disk image file layout
199     loff_t size = FIB.fib_Size;
200     Seek(fh->f, 0, OFFSET_BEGINNING);
201     Read(fh->f, tmp_buf, 256);
202     FileDiskLayout(size, tmp_buf, fh->start_byte, fh->size);
203     return fh;
204    
205     } else {
206    
207     // Device, parse string
208     char dev_name[256];
209     ULONG dev_unit = 0, dev_flags = 0, dev_start = 0, dev_size = 16, dev_bsize = 512;
210     if (sscanf(name, "/dev/%[^/]/%ld/%ld/%ld/%ld/%ld", dev_name, &dev_unit, &dev_flags, &dev_start, &dev_size, &dev_bsize) < 2)
211     return NULL;
212    
213     // Create IORequest
214     struct IOStdReq *io = (struct IOStdReq *)CreateIORequest(the_port, sizeof(struct IOExtTD));
215     if (io == NULL)
216     return NULL;
217    
218     // Open device
219 jlachmann 1.8 if (OpenDevice((UBYTE *) dev_name, dev_unit, (struct IORequest *)io, dev_flags)) {
220 cebix 1.1 D(bug(" couldn't open device\n"));
221     DeleteIORequest(io);
222     return NULL;
223     }
224    
225     // Check for new style device
226     bool is_nsd = false, does_64bit = false;
227     struct NSDeviceQueryResult nsdqr;
228     nsdqr.DevQueryFormat = 0;
229     nsdqr.SizeAvailable = 0;
230     io->io_Command = NSCMD_DEVICEQUERY;
231     io->io_Length = sizeof(nsdqr);
232     io->io_Data = (APTR)&nsdqr;
233     LONG error = DoIO((struct IORequest *)io);
234     D(bug("DEVICEQUERY returned %ld (length %ld, actual %ld)\n", error, io->io_Length, io->io_Actual));
235     if ((!error) && (io->io_Actual >= 16) && (io->io_Actual <= sizeof(nsdqr)) && (nsdqr.SizeAvailable == io->io_Actual)) {
236    
237     // Looks like an NSD
238     is_nsd = true;
239     D(bug(" new style device, type %ld\n", nsdqr.DeviceType));
240    
241     // We only work with trackdisk-like devices
242     if (nsdqr.DeviceType != NSDEVTYPE_TRACKDISK) {
243     CloseDevice((struct IORequest *)io);
244     DeleteIORequest(io);
245     return NULL;
246     }
247    
248     // Check whether device is 64 bit capable
249     UWORD *cmdcheck;
250     for (cmdcheck = nsdqr.SupportedCommands; *cmdcheck; cmdcheck++) {
251     if (*cmdcheck == NSCMD_TD_READ64) {
252     D(bug(" supports 64 bit commands\n"));
253     does_64bit = true;
254     }
255     }
256     }
257    
258     // Create file_handle
259     file_handle *fh = new file_handle;
260     fh->io = io;
261     fh->is_file = false;
262     fh->read_only = read_only;
263     fh->start_byte = (loff_t)dev_start * dev_bsize;
264     fh->size = (loff_t)dev_size * dev_bsize;
265     fh->block_size = dev_bsize;
266     fh->is_nsd = is_nsd;
267     fh->does_64bit = does_64bit;
268 cebix 1.4 fh->is_ejected = false;
269     fh->is_2060scsi = (strcmp(dev_name, "2060scsi.device") == 0);
270 cebix 1.1 return fh;
271     }
272     }
273    
274    
275     /*
276     * Close file/device, delete file handle
277     */
278    
279     void Sys_close(void *arg)
280     {
281     file_handle *fh = (file_handle *)arg;
282     if (!fh)
283     return;
284    
285     D(bug("Sys_close(%08lx)\n", arg));
286    
287     // File or device?
288     if (fh->is_file) {
289    
290     // File, simply close it
291     Close(fh->f);
292    
293     } else {
294    
295     // Device, close it and delete IORequest
296     fh->io->io_Command = CMD_UPDATE;
297     DoIO((struct IORequest *)fh->io);
298    
299     fh->io->io_Command = TD_MOTOR;
300     fh->io->io_Length = 0;
301     DoIO((struct IORequest *)fh->io);
302    
303     CloseDevice((struct IORequest *)fh->io);
304     DeleteIORequest(fh->io);
305     }
306     delete fh;
307     }
308    
309    
310     /*
311 cebix 1.2 * Send one I/O request, using 64-bit addressing if the device supports it
312     */
313    
314     static loff_t send_io_request(file_handle *fh, bool writing, ULONG length, loff_t offset, APTR data)
315     {
316     if (fh->does_64bit) {
317     fh->io->io_Command = writing ? NSCMD_TD_WRITE64 : NSCMD_TD_READ64;
318     fh->io->io_Actual = offset >> 32;
319     } else {
320     fh->io->io_Command = writing ? CMD_WRITE : CMD_READ;
321     fh->io->io_Actual = 0;
322     }
323     fh->io->io_Length = length;
324     fh->io->io_Offset = offset;
325     fh->io->io_Data = data;
326 cebix 1.4
327     if (fh->is_2060scsi && fh->block_size == 2048) {
328    
329     // 2060scsi.device has serious problems reading CD-ROMs via TD_READ
330     static struct SCSICmd scsi;
331     const int SENSE_LENGTH = 256;
332     static UBYTE sense_buffer[SENSE_LENGTH]; // Buffer for autosense data
333     static UBYTE cmd_buffer[10] = { 0x28, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
334    
335     D(bug("send_io_request length=%lu offset=%lu\n", length, (ULONG) offset));
336    
337     memset(sense_buffer, 0, sizeof(sense_buffer));
338    
339     scsi.scsi_Command = cmd_buffer;
340     scsi.scsi_CmdLength = sizeof(cmd_buffer);
341     scsi.scsi_SenseData = sense_buffer;
342     scsi.scsi_SenseLength = SENSE_LENGTH;
343     scsi.scsi_Flags = SCSIF_AUTOSENSE | (writing ? SCSIF_WRITE : SCSIF_READ);
344     scsi.scsi_Data = (UWORD *) data;
345     scsi.scsi_Length = length;
346    
347     ULONG block_offset = (ULONG) offset / fh->block_size;
348     ULONG block_length = length / fh->block_size;
349    
350     cmd_buffer[2] = block_offset >> 24;
351     cmd_buffer[3] = block_offset >> 16;
352     cmd_buffer[4] = block_offset >> 8;
353     cmd_buffer[5] = block_offset & 0xff;
354    
355     cmd_buffer[7] = block_length >> 8;
356     cmd_buffer[8] = block_length & 0xff;
357    
358     fh->io->io_Command = HD_SCSICMD;
359     fh->io->io_Actual = 0;
360     fh->io->io_Offset = 0;
361     fh->io->io_Data = &scsi;
362     fh->io->io_Length = sizeof(scsi);
363    
364     BYTE result = DoIO((struct IORequest *)fh->io);
365    
366     if (result) {
367     D(bug("send_io_request SCSI FAIL result=%lu\n", result));
368    
369     if (result == HFERR_BadStatus) {
370     D(bug("send_io_request SCSI Status=%lu\n", scsi.scsi_Status));
371     if (scsi.scsi_Status == 2) {
372     D(bug("send_io_request Sense Key=%02lx\n", sense_buffer[2] & 0x0f));
373     D(bug("send_io_request ASC=%02lx ASCQ=%02lx\n", sense_buffer[12], sense_buffer[13]));
374     }
375     }
376     return 0;
377     }
378    
379     D(bug("send_io_request SCSI Actual=%lu\n", scsi.scsi_Actual));
380    
381     if (scsi.scsi_Actual != length)
382     return 0;
383    
384     return scsi.scsi_Actual;
385    
386     } else {
387    
388 jlachmann 1.8 // if (DoIO((struct IORequest *)fh->io) || fh->io->io_Actual != length)
389     if (DoIO((struct IORequest *)fh->io))
390     {
391     D(bug("send_io_request/%ld: Actual=%lu length=%lu Err=%ld\n", __LINE__, fh->io->io_Actual, length, fh->io->io_Error));
392 cebix 1.4 return 0;
393 jlachmann 1.8 }
394 cebix 1.4 return fh->io->io_Actual;
395     }
396 cebix 1.2 }
397    
398    
399     /*
400 cebix 1.1 * Read "length" bytes from file/device, starting at "offset", to "buffer",
401     * returns number of bytes read (or 0)
402     */
403    
404     size_t Sys_read(void *arg, void *buffer, loff_t offset, size_t length)
405     {
406     file_handle *fh = (file_handle *)arg;
407     if (!fh)
408 jlachmann 1.8 {
409     D(bug("Sys_read/%ld return 0\n", __LINE__));
410 cebix 1.1 return 0;
411 jlachmann 1.8 }
412    
413     D(bug("Sys_read/%ld length=%ld\n", __LINE__, length));
414 cebix 1.1
415     // File or device?
416     if (fh->is_file) {
417    
418     // File, seek to position
419     if (Seek(fh->f, offset + fh->start_byte, OFFSET_BEGINNING) == -1)
420 jlachmann 1.8 {
421     D(bug("Sys_read/%ld return 0\n", __LINE__));
422 cebix 1.1 return 0;
423 jlachmann 1.8 }
424 cebix 1.1
425     // Read data
426     LONG actual = Read(fh->f, buffer, length);
427     if (actual == -1)
428 jlachmann 1.8 {
429     D(bug("Sys_read/%ld return 0\n", __LINE__));
430 cebix 1.1 return 0;
431 jlachmann 1.8 }
432 cebix 1.1 else
433 jlachmann 1.8 {
434     D(bug("Sys_read/%ld return %ld\n", __LINE__, actual));
435 cebix 1.1 return actual;
436 jlachmann 1.8 }
437 cebix 1.1
438     } else {
439    
440 cebix 1.2 // Device, pre-read (partial read of first block) necessary?
441 cebix 1.1 loff_t pos = offset + fh->start_byte;
442     size_t actual = 0;
443     uint32 pre_offset = pos % fh->block_size;
444     if (pre_offset) {
445    
446     // Yes, read one block
447 cebix 1.2 if (send_io_request(fh, false, fh->block_size, pos - pre_offset, tmp_buf) == 0)
448 jlachmann 1.8 {
449     D(bug("Sys_read/%ld return %ld\n", __LINE__, 0));
450 cebix 1.1 return 0;
451 jlachmann 1.8 }
452 cebix 1.1
453     // Copy data to destination buffer
454     size_t pre_length = fh->block_size - pre_offset;
455     if (pre_length > length)
456     pre_length = length;
457     memcpy(buffer, tmp_buf + pre_offset, pre_length);
458    
459     // Adjust data pointers
460     buffer = (uint8 *)buffer + pre_length;
461     pos += pre_length;
462     length -= pre_length;
463     actual += pre_length;
464     }
465    
466     // Main read (complete reads of middle blocks) possible?
467     if (length >= fh->block_size) {
468    
469     // Yes, read blocks
470     size_t main_length = length & ~(fh->block_size - 1);
471 cebix 1.2 if (send_io_request(fh, false, main_length, pos, buffer) == 0)
472 jlachmann 1.8 {
473     D(bug("Sys_read/%ld return %ld\n", __LINE__, 0));
474 cebix 1.1 return 0;
475 jlachmann 1.8 }
476 cebix 1.1
477     // Adjust data pointers
478     buffer = (uint8 *)buffer + main_length;
479     pos += main_length;
480     length -= main_length;
481     actual += main_length;
482     }
483    
484 cebix 1.2 // Post-read (partial read of last block) necessary?
485 cebix 1.1 if (length) {
486    
487     // Yes, read one block
488 cebix 1.2 if (send_io_request(fh, false, fh->block_size, pos, tmp_buf) == 0)
489 jlachmann 1.8 {
490     D(bug("Sys_read/%ld return %ld\n", __LINE__, 0));
491 cebix 1.1 return 0;
492 jlachmann 1.8 }
493 cebix 1.1
494     // Copy data to destination buffer
495     memcpy(buffer, tmp_buf, length);
496     actual += length;
497     }
498    
499 jlachmann 1.8 D(bug("Sys_read/%ld return %ld\n", __LINE__, actual));
500 cebix 1.1 return actual;
501     }
502     }
503    
504    
505     /*
506     * Write "length" bytes from "buffer" to file/device, starting at "offset",
507     * returns number of bytes written (or 0)
508     */
509    
510     size_t Sys_write(void *arg, void *buffer, loff_t offset, size_t length)
511     {
512     file_handle *fh = (file_handle *)arg;
513     if (!fh)
514 jlachmann 1.8 {
515     D(bug("Sys_write/%ld return %ld\n", __LINE__, 0));
516 cebix 1.1 return 0;
517 jlachmann 1.8 }
518    
519     D(bug("Sys_write/%ld length=%ld\n", __LINE__, length));
520 cebix 1.1
521     // File or device?
522     if (fh->is_file) {
523    
524 cebix 1.2 // File, seek to position if necessary
525 cebix 1.1 if (Seek(fh->f, offset + fh->start_byte, OFFSET_BEGINNING) == -1)
526 jlachmann 1.8 {
527     D(bug("Sys_write/%ld return %ld\n", __LINE__, 0));
528 cebix 1.1 return 0;
529 jlachmann 1.8 }
530 cebix 1.1
531     // Write data
532     LONG actual = Write(fh->f, buffer, length);
533     if (actual == -1)
534 jlachmann 1.8 {
535     D(bug("Sys_write/%ld return %ld\n", __LINE__, 0));
536 cebix 1.1 return 0;
537 jlachmann 1.8 }
538 cebix 1.1 else
539 jlachmann 1.8 {
540     D(bug("Sys_write/%ld return %ld\n", __LINE__, actual));
541 cebix 1.1 return actual;
542 jlachmann 1.8 }
543 cebix 1.1
544     } else {
545    
546 cebix 1.2 // Device, pre-write (partial write of first block) necessary
547     loff_t pos = offset + fh->start_byte;
548     size_t actual = 0;
549     uint32 pre_offset = pos % fh->block_size;
550     if (pre_offset) {
551    
552     // Yes, read one block
553     if (send_io_request(fh, false, fh->block_size, pos - pre_offset, tmp_buf) == 0)
554 jlachmann 1.8 {
555     D(bug("Sys_write/%ld return %ld\n", __LINE__, 0));
556 cebix 1.2 return 0;
557 jlachmann 1.8 }
558 cebix 1.2
559     // Copy data from source buffer
560     size_t pre_length = fh->block_size - pre_offset;
561     if (pre_length > length)
562     pre_length = length;
563     memcpy(tmp_buf + pre_offset, buffer, pre_length);
564    
565     // Write block back
566     if (send_io_request(fh, true, fh->block_size, pos - pre_offset, tmp_buf) == 0)
567 jlachmann 1.8 {
568     D(bug("Sys_write/%ld return %ld\n", __LINE__, 0));
569 cebix 1.2 return 0;
570 jlachmann 1.8 }
571 cebix 1.2
572     // Adjust data pointers
573     buffer = (uint8 *)buffer + pre_length;
574     pos += pre_length;
575     length -= pre_length;
576     actual += pre_length;
577     }
578    
579     // Main write (complete writes of middle blocks) possible?
580     if (length >= fh->block_size) {
581    
582     // Yes, write blocks
583     size_t main_length = length & ~(fh->block_size - 1);
584     if (send_io_request(fh, true, main_length, pos, buffer) == 0)
585 jlachmann 1.8 {
586     D(bug("Sys_write/%ld return %ld\n", __LINE__, 0));
587 cebix 1.2 return 0;
588 jlachmann 1.8 }
589 cebix 1.2
590     // Adjust data pointers
591     buffer = (uint8 *)buffer + main_length;
592     pos += main_length;
593     length -= main_length;
594     actual += main_length;
595     }
596    
597     // Post-write (partial write of last block) necessary?
598     if (length) {
599    
600     // Yes, read one block
601     if (send_io_request(fh, false, fh->block_size, pos, tmp_buf) == 0)
602 jlachmann 1.8 {
603     D(bug("Sys_write/%ld return %ld\n", __LINE__, 0));
604 cebix 1.2 return 0;
605 jlachmann 1.8 }
606 cebix 1.2
607     // Copy data from source buffer
608     memcpy(buffer, tmp_buf, length);
609    
610     // Write block back
611     if (send_io_request(fh, true, fh->block_size, pos, tmp_buf) == 0)
612 jlachmann 1.8 {
613     D(bug("Sys_write/%ld return %ld\n", __LINE__, 0));
614 cebix 1.2 return 0;
615 jlachmann 1.8 }
616 cebix 1.2 actual += length;
617     }
618    
619 jlachmann 1.8 D(bug("Sys_write/%ld return %ld\n", __LINE__, actual));
620 cebix 1.2 return actual;
621 cebix 1.1 }
622     }
623    
624    
625     /*
626     * Return size of file/device (minus header)
627     */
628    
629     loff_t SysGetFileSize(void *arg)
630     {
631     file_handle *fh = (file_handle *)arg;
632     if (!fh)
633     return true;
634    
635     return fh->size;
636     }
637    
638    
639     /*
640     * Eject volume (if applicable)
641     */
642    
643     void SysEject(void *arg)
644     {
645     file_handle *fh = (file_handle *)arg;
646     if (!fh)
647     return;
648    
649     if (!fh->is_file) {
650    
651     // Flush buffer, turn off the drive motor and eject volume
652     fh->io->io_Command = CMD_UPDATE;
653     DoIO((struct IORequest *)fh->io);
654    
655     fh->io->io_Command = TD_MOTOR;
656     fh->io->io_Length = 0;
657     DoIO((struct IORequest *)fh->io);
658    
659     fh->io->io_Command = TD_EJECT;
660     fh->io->io_Length = 1;
661     DoIO((struct IORequest *)fh->io);
662 cebix 1.4
663     fh->is_ejected = true;
664 cebix 1.1 }
665     }
666    
667    
668     /*
669     * Format volume (if applicable)
670     */
671    
672     bool SysFormat(void *arg)
673     {
674     file_handle *fh = (file_handle *)arg;
675     if (!fh)
676     return false;
677    
678     //!!
679     return true;
680     }
681    
682    
683     /*
684     * Check if file/device is read-only (this includes the read-only flag on Sys_open())
685     */
686    
687     bool SysIsReadOnly(void *arg)
688     {
689     file_handle *fh = (file_handle *)arg;
690     if (!fh)
691     return true;
692    
693     if (fh->is_file) {
694    
695     // File, return flag given to Sys_open
696     return fh->read_only;
697    
698     } else {
699    
700     // Device, check write protection
701     fh->io->io_Command = TD_PROTSTATUS;
702 cebix 1.4 DoIO((struct IORequest *)fh->io);
703 cebix 1.1 if (fh->io->io_Actual)
704     return true;
705     else
706     return fh->read_only;
707     }
708     }
709    
710    
711     /*
712     * Check if the given file handle refers to a fixed or a removable disk
713     */
714    
715     bool SysIsFixedDisk(void *arg)
716     {
717     file_handle *fh = (file_handle *)arg;
718     if (!fh)
719     return true;
720    
721     return true;
722     }
723    
724    
725     /*
726     * Check if a disk is inserted in the drive (always true for files)
727     */
728    
729     bool SysIsDiskInserted(void *arg)
730     {
731     file_handle *fh = (file_handle *)arg;
732     if (!fh)
733     return false;
734    
735     if (fh->is_file)
736     return true;
737     else {
738    
739     // Check medium status
740     fh->io->io_Command = TD_CHANGESTATE;
741     fh->io->io_Actual = 0;
742 cebix 1.4 DoIO((struct IORequest *)fh->io);
743     bool inserted = (fh->io->io_Actual == 0);
744    
745     if (!inserted) {
746     // Disk was ejected and has now been taken out
747     fh->is_ejected = false;
748     }
749    
750     if (fh->is_ejected) {
751     // Disk was ejected but has not yet been taken out, report it as
752     // no longer in the drive
753     return false;
754     } else
755     return inserted;
756 cebix 1.1 }
757     }
758    
759    
760     /*
761     * Prevent medium removal (if applicable)
762     */
763    
764     void SysPreventRemoval(void *arg)
765     {
766     file_handle *fh = (file_handle *)arg;
767     if (!fh)
768     return;
769    
770     if (!fh->is_file) {
771    
772     // Send PREVENT ALLOW MEDIUM REMOVAL SCSI command
773     struct SCSICmd scsi;
774     static const UBYTE the_cmd[6] = {0x1e, 0, 0, 0, 1, 0};
775     scsi.scsi_Length = 0;
776     scsi.scsi_Command = (UBYTE *)the_cmd;
777     scsi.scsi_CmdLength = 6;
778     scsi.scsi_Flags = SCSIF_READ;
779     scsi.scsi_Status = 0;
780     fh->io->io_Data = &scsi;
781     fh->io->io_Length = sizeof(scsi);
782     fh->io->io_Command = HD_SCSICMD;
783     DoIO((struct IORequest *)fh->io);
784     }
785     }
786    
787    
788     /*
789     * Allow medium removal (if applicable)
790     */
791    
792     void SysAllowRemoval(void *arg)
793     {
794     file_handle *fh = (file_handle *)arg;
795     if (!fh)
796     return;
797    
798     if (!fh->is_file) {
799    
800     // Send PREVENT ALLOW MEDIUM REMOVAL SCSI command
801     struct SCSICmd scsi;
802     static const UBYTE the_cmd[6] = {0x1e, 0, 0, 0, 0, 0};
803     scsi.scsi_Length = 0;
804     scsi.scsi_Command = (UBYTE *)the_cmd;
805     scsi.scsi_CmdLength = 6;
806     scsi.scsi_Flags = SCSIF_READ;
807     scsi.scsi_Status = 0;
808     fh->io->io_Data = &scsi;
809     fh->io->io_Length = sizeof(scsi);
810     fh->io->io_Command = HD_SCSICMD;
811     DoIO((struct IORequest *)fh->io);
812     }
813     }
814    
815    
816     /*
817     * Read CD-ROM TOC (binary MSF format, 804 bytes max.)
818     */
819    
820     bool SysCDReadTOC(void *arg, uint8 *toc)
821     {
822     file_handle *fh = (file_handle *)arg;
823     if (!fh)
824     return false;
825    
826     if (fh->is_file)
827     return false;
828     else {
829    
830     // Send READ TOC MSF SCSI command
831     struct SCSICmd scsi;
832     static const UBYTE read_toc_cmd[10] = {0x43, 0x02, 0, 0, 0, 0, 0, 0x03, 0x24, 0};
833     scsi.scsi_Data = (UWORD *)tmp_buf;
834     scsi.scsi_Length = 804;
835     scsi.scsi_Command = (UBYTE *)read_toc_cmd;
836     scsi.scsi_CmdLength = 10;
837     scsi.scsi_Flags = SCSIF_READ;
838     scsi.scsi_Status = 0;
839     fh->io->io_Data = &scsi;
840     fh->io->io_Length = sizeof(scsi);
841     fh->io->io_Command = HD_SCSICMD;
842     if (DoIO((struct IORequest *)fh->io) || scsi.scsi_Status)
843     return false;
844     memcpy(toc, tmp_buf, 804);
845     return true;
846     }
847     }
848    
849    
850     /*
851     * Read CD-ROM position data (Sub-Q Channel, 16 bytes, see SCSI standard)
852     */
853    
854     bool SysCDGetPosition(void *arg, uint8 *pos)
855     {
856     file_handle *fh = (file_handle *)arg;
857     if (!fh)
858     return false;
859    
860     if (fh->is_file)
861     return false;
862     else {
863    
864     // Send READ SUB-CHANNEL SCSI command
865     struct SCSICmd scsi;
866     static const UBYTE read_subq_cmd[10] = {0x42, 0x02, 0x40, 0x01, 0, 0, 0, 0, 0x10, 0};
867     scsi.scsi_Data = (UWORD *)tmp_buf;
868     scsi.scsi_Length = 16;
869     scsi.scsi_Command = (UBYTE *)read_subq_cmd;
870     scsi.scsi_CmdLength = 10;
871     scsi.scsi_Flags = SCSIF_READ;
872     scsi.scsi_Status = 0;
873     fh->io->io_Data = &scsi;
874     fh->io->io_Length = sizeof(scsi);
875     fh->io->io_Command = HD_SCSICMD;
876     if (DoIO((struct IORequest *)fh->io) || scsi.scsi_Status)
877     return false;
878     memcpy(pos, tmp_buf, 16);
879     return true;
880     }
881     }
882    
883    
884     /*
885     * Play CD audio
886     */
887    
888     bool SysCDPlay(void *arg, uint8 start_m, uint8 start_s, uint8 start_f, uint8 end_m, uint8 end_s, uint8 end_f)
889     {
890     file_handle *fh = (file_handle *)arg;
891     if (!fh)
892     return false;
893    
894     if (fh->is_file)
895     return false;
896     else {
897    
898     // Send PLAY AUDIO MSF SCSI command
899     struct SCSICmd scsi;
900     UBYTE play_cmd[10] = {0x47, 0, 0, start_m, start_s, start_f, end_m, end_s, end_f, 0};
901     scsi.scsi_Data = (UWORD *)tmp_buf;
902     scsi.scsi_Length = 0;
903     scsi.scsi_Command = play_cmd;
904     scsi.scsi_CmdLength = 10;
905     scsi.scsi_Flags = SCSIF_READ;
906     scsi.scsi_Status = 0;
907     fh->io->io_Data = &scsi;
908     fh->io->io_Length = sizeof(scsi);
909     fh->io->io_Command = HD_SCSICMD;
910     if (DoIO((struct IORequest *)fh->io) || scsi.scsi_Status)
911     return false;
912     return true;
913     }
914     }
915    
916    
917     /*
918     * Pause CD audio
919     */
920    
921     bool SysCDPause(void *arg)
922     {
923     file_handle *fh = (file_handle *)arg;
924     if (!fh)
925     return false;
926    
927     if (fh->is_file)
928     return false;
929     else {
930    
931     // Send PAUSE RESUME SCSI command
932     struct SCSICmd scsi;
933     static const UBYTE pause_cmd[10] = {0x4b, 0, 0, 0, 0, 0, 0, 0, 0, 0};
934     scsi.scsi_Data = (UWORD *)tmp_buf;
935     scsi.scsi_Length = 0;
936     scsi.scsi_Command = (UBYTE *)pause_cmd;
937     scsi.scsi_CmdLength = 10;
938     scsi.scsi_Flags = SCSIF_READ;
939     scsi.scsi_Status = 0;
940     fh->io->io_Data = &scsi;
941     fh->io->io_Length = sizeof(scsi);
942     fh->io->io_Command = HD_SCSICMD;
943     if (DoIO((struct IORequest *)fh->io) || scsi.scsi_Status)
944     return false;
945     return true;
946     }
947     }
948    
949    
950     /*
951     * Resume paused CD audio
952     */
953    
954     bool SysCDResume(void *arg)
955     {
956     file_handle *fh = (file_handle *)arg;
957     if (!fh)
958     return false;
959    
960     if (fh->is_file)
961     return false;
962     else {
963    
964     // Send PAUSE RESUME SCSI command
965     struct SCSICmd scsi;
966     static const UBYTE resume_cmd[10] = {0x4b, 0, 0, 0, 0, 0, 0, 0, 1, 0};
967     scsi.scsi_Data = (UWORD *)tmp_buf;
968     scsi.scsi_Length = 0;
969     scsi.scsi_Command = (UBYTE *)resume_cmd;
970     scsi.scsi_CmdLength = 10;
971     scsi.scsi_Flags = SCSIF_READ;
972     scsi.scsi_Status = 0;
973     fh->io->io_Data = &scsi;
974     fh->io->io_Length = sizeof(scsi);
975     fh->io->io_Command = HD_SCSICMD;
976     if (DoIO((struct IORequest *)fh->io) || scsi.scsi_Status)
977     return false;
978     return true;
979     }
980     }
981    
982    
983     /*
984     * Stop CD audio
985     */
986    
987     bool SysCDStop(void *arg, uint8 lead_out_m, uint8 lead_out_s, uint8 lead_out_f)
988     {
989     file_handle *fh = (file_handle *)arg;
990     if (!fh)
991     return false;
992    
993     if (fh->is_file)
994     return false;
995     else {
996    
997     uint8 end_m = lead_out_m;
998     uint8 end_s = lead_out_s;
999     uint8 end_f = lead_out_f + 1;
1000     if (end_f >= 75) {
1001     end_f = 0;
1002     end_s++;
1003     if (end_s >= 60) {
1004     end_s = 0;
1005     end_m++;
1006     }
1007     }
1008    
1009     // Send PLAY AUDIO MSF SCSI command (play first frame of lead-out area)
1010     struct SCSICmd scsi;
1011     UBYTE play_cmd[10] = {0x47, 0, 0, lead_out_m, lead_out_s, lead_out_f, end_m, end_s, end_f, 0};
1012     scsi.scsi_Data = (UWORD *)tmp_buf;
1013     scsi.scsi_Length = 0;
1014     scsi.scsi_Command = play_cmd;
1015     scsi.scsi_CmdLength = 10;
1016     scsi.scsi_Flags = SCSIF_READ;
1017     scsi.scsi_Status = 0;
1018     fh->io->io_Data = &scsi;
1019     fh->io->io_Length = sizeof(scsi);
1020     fh->io->io_Command = HD_SCSICMD;
1021     if (DoIO((struct IORequest *)fh->io) || scsi.scsi_Status)
1022     return false;
1023     return true;
1024     }
1025     }
1026    
1027    
1028     /*
1029     * Perform CD audio fast-forward/fast-reverse operation starting from specified address
1030     */
1031    
1032     bool SysCDScan(void *arg, uint8 start_m, uint8 start_s, uint8 start_f, bool reverse)
1033     {
1034     file_handle *fh = (file_handle *)arg;
1035     if (!fh)
1036     return false;
1037    
1038     //!!
1039     return false;
1040     }
1041    
1042    
1043     /*
1044     * Set CD audio volume (0..255 each channel)
1045     */
1046    
1047     void SysCDSetVolume(void *arg, uint8 left, uint8 right)
1048     {
1049     file_handle *fh = (file_handle *)arg;
1050     if (!fh)
1051     return;
1052    
1053     if (!fh->is_file) {
1054    
1055     // Send MODE SENSE (CD-ROM Audio Control Parameters Page) SCSI command
1056     struct SCSICmd scsi;
1057     static const UBYTE mode_sense_cmd[6] = {0x1a, 0x08, 0x0e, 0, 20, 0};
1058     scsi.scsi_Data = (UWORD *)tmp_buf;
1059     scsi.scsi_Length = 20;
1060     scsi.scsi_Command = (UBYTE *)mode_sense_cmd;
1061     scsi.scsi_CmdLength = 6;
1062     scsi.scsi_Flags = SCSIF_READ;
1063     scsi.scsi_Status = 0;
1064     fh->io->io_Data = &scsi;
1065     fh->io->io_Length = sizeof(scsi);
1066     fh->io->io_Command = HD_SCSICMD;
1067     if (DoIO((struct IORequest *)fh->io) || scsi.scsi_Status)
1068     return;
1069    
1070     tmp_buf[6] = 0x04; // Immed
1071     tmp_buf[9] = 0; // LBA/sec format
1072     tmp_buf[10] = 0; // LBA/sec
1073     tmp_buf[11] = 0;
1074     tmp_buf[13] = left; // Port 0 volume
1075     tmp_buf[15] = right; // Port 1 volume
1076    
1077     // Send MODE SELECT (CD-ROM Audio Control Parameters Page) SCSI command
1078     static const UBYTE mode_select_cmd[6] = {0x15, 0x10, 0, 0, 20, 0};
1079     scsi.scsi_Data = (UWORD *)tmp_buf;
1080     scsi.scsi_Length = 20;
1081     scsi.scsi_Command = (UBYTE *)mode_select_cmd;
1082     scsi.scsi_CmdLength = 6;
1083     scsi.scsi_Flags = SCSIF_WRITE;
1084     scsi.scsi_Status = 0;
1085     fh->io->io_Data = &scsi;
1086     fh->io->io_Length = sizeof(scsi);
1087     fh->io->io_Command = HD_SCSICMD;
1088     DoIO((struct IORequest *)fh->io);
1089     }
1090     }
1091    
1092    
1093     /*
1094     * Get CD audio volume (0..255 each channel)
1095     */
1096    
1097     void SysCDGetVolume(void *arg, uint8 &left, uint8 &right)
1098     {
1099     file_handle *fh = (file_handle *)arg;
1100     if (!fh)
1101     return;
1102    
1103     if (!fh->is_file) {
1104    
1105     // Send MODE SENSE (CD-ROM Audio Control Parameters Page) SCSI command
1106     struct SCSICmd scsi;
1107     static const UBYTE mode_sense_cmd[6] = {0x1a, 0x08, 0x0e, 0, 20, 0};
1108     scsi.scsi_Data = (UWORD *)tmp_buf;
1109     scsi.scsi_Length = 20;
1110     scsi.scsi_Command = (UBYTE *)mode_sense_cmd;
1111     scsi.scsi_CmdLength = 6;
1112     scsi.scsi_Flags = SCSIF_READ;
1113     scsi.scsi_Status = 0;
1114     fh->io->io_Data = &scsi;
1115     fh->io->io_Length = sizeof(scsi);
1116     fh->io->io_Command = HD_SCSICMD;
1117     if (DoIO((struct IORequest *)fh->io) || scsi.scsi_Status)
1118     return;
1119     left = tmp_buf[13]; // Port 0 volume
1120     right = tmp_buf[15]; // Port 1 volume
1121     }
1122     }