ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/BasiliskII/src/AmigaOS/sys_amiga.cpp
Revision: 1.7
Committed: 2002-01-15T14:58:34Z (22 years, 5 months ago) by cebix
Branch: MAIN
CVS Tags: snapshot-15012002
Changes since 1.6: +1 -1 lines
Log Message:
- documentation updates
- 2001 -> 2002
- version 0.9 -> 1.0

File Contents

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