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, 4 months ago) by gbeauche
Branch: MAIN
CVS Tags: HEAD
Changes since 1.8: +1 -1 lines
Log Message:
Happy New Year!

File Contents

# Content
1 /*
2 * sys_amiga.cpp - System dependent routines, Amiga implementation
3 *
4 * Basilisk II (C) 1997-2008 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 #define __USE_SYSBASE
28 #include <proto/dos.h>
29 #include <proto/exec.h>
30 #include <proto/disk.h>
31 #include <inline/dos.h>
32 #include <inline/exec.h>
33 #include <inline/disk.h>
34
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 bool is_ejected; // Volume has been (logically) ejected
60 bool is_2060scsi; // Enable workaround for 2060scsi.device CD-ROM TD_READ bug
61 };
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 ErrorAlert(STR_NO_MEM_ERR);
86 QuitEmulator();
87 }
88 }
89
90
91 /*
92 * Deinitialization
93 */
94
95 void SysExit(void)
96 {
97 // Delete port and temporary buffer
98 if (the_port) {
99 DeleteMsgPort(the_port);
100 the_port = NULL;
101 }
102 if (tmp_buf) {
103 FreeMem(tmp_buf, TMP_BUF_SIZE);
104 tmp_buf = NULL;
105 }
106 }
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 sprintf(str, "/dev/mfm.device/%d/0/0/2880/512", i);
121 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 if (OpenDevice((UBYTE *) dev_name, dev_unit, (struct IORequest *)io, dev_flags)) {
220 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 fh->is_ejected = false;
269 fh->is_2060scsi = (strcmp(dev_name, "2060scsi.device") == 0);
270 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 * 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
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 // 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 return 0;
393 }
394 return fh->io->io_Actual;
395 }
396 }
397
398
399 /*
400 * 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 {
409 D(bug("Sys_read/%ld return 0\n", __LINE__));
410 return 0;
411 }
412
413 D(bug("Sys_read/%ld length=%ld\n", __LINE__, length));
414
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 {
421 D(bug("Sys_read/%ld return 0\n", __LINE__));
422 return 0;
423 }
424
425 // Read data
426 LONG actual = Read(fh->f, buffer, length);
427 if (actual == -1)
428 {
429 D(bug("Sys_read/%ld return 0\n", __LINE__));
430 return 0;
431 }
432 else
433 {
434 D(bug("Sys_read/%ld return %ld\n", __LINE__, actual));
435 return actual;
436 }
437
438 } else {
439
440 // Device, pre-read (partial read of first block) necessary?
441 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 if (send_io_request(fh, false, fh->block_size, pos - pre_offset, tmp_buf) == 0)
448 {
449 D(bug("Sys_read/%ld return %ld\n", __LINE__, 0));
450 return 0;
451 }
452
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 if (send_io_request(fh, false, main_length, pos, buffer) == 0)
472 {
473 D(bug("Sys_read/%ld return %ld\n", __LINE__, 0));
474 return 0;
475 }
476
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 // Post-read (partial read of last block) necessary?
485 if (length) {
486
487 // Yes, read one block
488 if (send_io_request(fh, false, fh->block_size, pos, tmp_buf) == 0)
489 {
490 D(bug("Sys_read/%ld return %ld\n", __LINE__, 0));
491 return 0;
492 }
493
494 // Copy data to destination buffer
495 memcpy(buffer, tmp_buf, length);
496 actual += length;
497 }
498
499 D(bug("Sys_read/%ld return %ld\n", __LINE__, actual));
500 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 {
515 D(bug("Sys_write/%ld return %ld\n", __LINE__, 0));
516 return 0;
517 }
518
519 D(bug("Sys_write/%ld length=%ld\n", __LINE__, length));
520
521 // File or device?
522 if (fh->is_file) {
523
524 // File, seek to position if necessary
525 if (Seek(fh->f, offset + fh->start_byte, OFFSET_BEGINNING) == -1)
526 {
527 D(bug("Sys_write/%ld return %ld\n", __LINE__, 0));
528 return 0;
529 }
530
531 // Write data
532 LONG actual = Write(fh->f, buffer, length);
533 if (actual == -1)
534 {
535 D(bug("Sys_write/%ld return %ld\n", __LINE__, 0));
536 return 0;
537 }
538 else
539 {
540 D(bug("Sys_write/%ld return %ld\n", __LINE__, actual));
541 return actual;
542 }
543
544 } else {
545
546 // 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 {
555 D(bug("Sys_write/%ld return %ld\n", __LINE__, 0));
556 return 0;
557 }
558
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 {
568 D(bug("Sys_write/%ld return %ld\n", __LINE__, 0));
569 return 0;
570 }
571
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 {
586 D(bug("Sys_write/%ld return %ld\n", __LINE__, 0));
587 return 0;
588 }
589
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 {
603 D(bug("Sys_write/%ld return %ld\n", __LINE__, 0));
604 return 0;
605 }
606
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 {
613 D(bug("Sys_write/%ld return %ld\n", __LINE__, 0));
614 return 0;
615 }
616 actual += length;
617 }
618
619 D(bug("Sys_write/%ld return %ld\n", __LINE__, actual));
620 return actual;
621 }
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
663 fh->is_ejected = true;
664 }
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 DoIO((struct IORequest *)fh->io);
703 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 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 }
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 }