1 |
|
/* |
2 |
|
* sys_amiga.cpp - System dependent routines, Amiga implementation |
3 |
|
* |
4 |
< |
* Basilisk II (C) 1997-1999 Christian Bauer |
4 |
> |
* Basilisk II (C) 1997-2000 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 |
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 |
|
|
91 |
|
void SysExit(void) |
92 |
|
{ |
93 |
|
// Delete port and temporary buffer |
94 |
< |
if (the_port) |
94 |
> |
if (the_port) { |
95 |
|
DeleteMsgPort(the_port); |
96 |
< |
if (tmp_buf) |
96 |
> |
the_port = NULL; |
97 |
> |
} |
98 |
> |
if (tmp_buf) { |
99 |
|
FreeMem(tmp_buf, TMP_BUF_SIZE); |
100 |
+ |
tmp_buf = NULL; |
101 |
+ |
} |
102 |
|
} |
103 |
|
|
104 |
|
|
109 |
|
|
110 |
|
void SysAddFloppyPrefs(void) |
111 |
|
{ |
106 |
– |
#if 0 |
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/1474560/512", i); |
116 |
> |
sprintf(str, "/dev/mfm.device/%d/0/0/2880/512", i); |
117 |
|
PrefsAddString("floppy", str); |
118 |
|
} |
119 |
|
} |
115 |
– |
#endif |
120 |
|
} |
121 |
|
|
122 |
|
|
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 |
|
} |
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 |
|
*/ |
415 |
|
|
416 |
|
} else { |
417 |
|
|
418 |
< |
// Device, pre-read (partial read of first block) neccessary? |
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 |
< |
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) |
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 |
443 |
|
|
444 |
|
// Yes, read blocks |
445 |
|
size_t main_length = length & ~(fh->block_size - 1); |
446 |
< |
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) |
446 |
> |
if (send_io_request(fh, false, main_length, pos, buffer) == 0) |
447 |
|
return 0; |
448 |
|
|
449 |
|
// Adjust data pointers |
453 |
|
actual += main_length; |
454 |
|
} |
455 |
|
|
456 |
< |
// Post-read (partial read of last block) neccessary? |
456 |
> |
// Post-read (partial read of last block) necessary? |
457 |
|
if (length) { |
458 |
|
|
459 |
|
// Yes, read one block |
460 |
< |
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) |
460 |
> |
if (send_io_request(fh, false, fh->block_size, pos, tmp_buf) == 0) |
461 |
|
return 0; |
462 |
|
|
463 |
|
// Copy data to destination buffer |
484 |
|
// File or device? |
485 |
|
if (fh->is_file) { |
486 |
|
|
487 |
< |
// File, seek to position if neccessary |
487 |
> |
// File, seek to position if necessary |
488 |
|
if (Seek(fh->f, offset + fh->start_byte, OFFSET_BEGINNING) == -1) |
489 |
|
return 0; |
490 |
|
|
497 |
|
|
498 |
|
} else { |
499 |
|
|
500 |
< |
// Device, write data |
501 |
< |
fh->io->io_Command = CMD_WRITE; |
502 |
< |
fh->io->io_Length = length; |
503 |
< |
fh->io->io_Offset = offset + fh->start_byte; |
504 |
< |
fh->io->io_Data = buffer; |
505 |
< |
if (DoIO((struct IORequest *)fh->io)) |
506 |
< |
return 0; |
507 |
< |
else |
508 |
< |
return fh->io->io_Actual; |
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 |
|
|
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 |
|
|
636 |
|
} else { |
637 |
|
|
638 |
|
// Device, check write protection |
508 |
– |
fh->io->io_Flags = IOF_QUICK; |
639 |
|
fh->io->io_Command = TD_PROTSTATUS; |
640 |
< |
BeginIO((struct IORequest *)fh->io); |
640 |
> |
DoIO((struct IORequest *)fh->io); |
641 |
|
if (fh->io->io_Actual) |
642 |
|
return true; |
643 |
|
else |
675 |
|
else { |
676 |
|
|
677 |
|
// Check medium status |
548 |
– |
fh->io->io_Flags = IOF_QUICK; |
678 |
|
fh->io->io_Command = TD_CHANGESTATE; |
679 |
|
fh->io->io_Actual = 0; |
680 |
< |
BeginIO((struct IORequest *)fh->io); |
681 |
< |
return 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 |
|
|