From 6155802b593e511fa4bae0c66b8738fdb6b8bf2c Mon Sep 17 00:00:00 2001 From: OBattler Date: Wed, 10 Oct 2018 22:33:24 +0200 Subject: [PATCH] Split generic CD-ROM from SCSI-style CD-ROM; Redid the way SCSI and ATAPI devices are handled; Slight timings change in the NCR 5380; Devices are now closed by device_close_all() in the reverse order of the one in which they were started; Slight changes to some code in win/; Added the WM_HARDRESET and WM_SHUTDOWN window messages for configuration manager purposes. --- src/Makefile.local | 3 +- src/cdrom/cdrom.c | 3085 +--------------------------------- src/cdrom/cdrom.h | 121 +- src/cdrom/cdrom_image.cc | 32 +- src/cdrom/cdrom_null.c | 4 +- src/device.c | 6 +- src/disk/hdc_ide.c | 761 +++------ src/disk/hdc_ide.h | 92 +- src/disk/zip.c | 457 +++--- src/disk/zip.h | 60 +- src/intel_piix.c | 5 +- src/pc.c | 32 +- src/scsi/scsi.c | 52 +- src/scsi/scsi_buslogic.c | 42 +- src/scsi/scsi_cdrom.c | 3091 +++++++++++++++++++++++++++++++++++ src/scsi/scsi_cdrom.h | 75 + src/scsi/scsi_device.c | 320 +--- src/scsi/scsi_device.h | 120 +- src/scsi/scsi_disk.c | 175 +- src/scsi/scsi_disk.h | 40 +- src/scsi/scsi_ncr5380.c | 119 +- src/scsi/scsi_ncr53c810.c | 78 +- src/scsi/scsi_x54x.c | 231 +-- src/sound/midi.c | 7 +- src/sound/midi_fluidsynth.c | 39 +- src/sound/midi_mt32.c | 51 +- src/sound/sound.c | 135 +- src/win/Makefile.mingw | 2 +- src/win/win.h | 4 +- src/win/win_cdrom.c | 58 +- src/win/win_d3d.cpp | 1 + src/win/win_ddraw.cpp | 14 +- src/win/win_devconf.c | 10 +- src/win/win_sdl.c | 8 +- src/win/win_stbar.c | 9 +- src/win/win_ui.c | 10 +- 36 files changed, 4557 insertions(+), 4792 deletions(-) create mode 100644 src/scsi/scsi_cdrom.c create mode 100644 src/scsi/scsi_cdrom.h diff --git a/src/Makefile.local b/src/Makefile.local index aec3856c5..bef02fd13 100644 --- a/src/Makefile.local +++ b/src/Makefile.local @@ -106,8 +106,7 @@ STUFF := # -DENABLE_BUSLOGIC_LOG=N sets logging level at N. # -DENABLE_NCR5380_LOG=N sets logging level at N. # -DENABLE_NCR53C810_LOG=N sets logging level at N. -# -DENABLE_SCSI_LOG=N sets logging level at N. -# -DENABLE_SCSI_BUS_LOG=N sets logging level at N. +# -DENABLE_SCSI_CDROM_LOG=N sets logging level at N. # -DENABLE_SCSI_DISK_LOG=N sets logging level at N. # -DENABLE_X54X_LOG=N sets logging level at N. # sound/ logging: diff --git a/src/cdrom/cdrom.c b/src/cdrom/cdrom.c index eeb343d0c..71002bb19 100644 --- a/src/cdrom/cdrom.c +++ b/src/cdrom/cdrom.c @@ -6,14 +6,13 @@ * * This file is part of the 86Box distribution. * - * Implementation of the CD-ROM drive with SCSI(-like) - * commands, for both ATAPI and SCSI usage. + * Generic CD-ROM drive core. * - * Version: @(#)cdrom.c 1.0.52 2018/10/09 + * Version: @(#)cdrom.c 1.0.0 2018/10/09 * * Author: Miran Grca, * - * Copyright 2016-2018 Miran Grca. + * Copyright 2018 Miran Grca. */ #include #include @@ -24,321 +23,18 @@ #include #define HAVE_STDARG_H #include "../86box.h" -#include "../config.h" -#include "../timer.h" -#include "../device.h" -#include "../piix.h" -#include "../scsi/scsi_device.h" -#include "../nvr.h" -#include "../disk/hdc.h" -#include "../disk/hdc_ide.h" -#include "../plat.h" -#include "../sound/sound.h" -#include "../ui.h" #include "cdrom.h" #include "cdrom_image.h" #include "cdrom_null.h" +#include "../sound/sound.h" -/* Bits of 'status' */ -#define ERR_STAT 0x01 -#define DRQ_STAT 0x08 /* Data request */ -#define DSC_STAT 0x10 -#define SERVICE_STAT 0x10 -#define READY_STAT 0x40 -#define BUSY_STAT 0x80 - -/* Bits of 'error' */ -#define ABRT_ERR 0x04 /* Command aborted */ -#define MCR_ERR 0x08 /* Media change request */ - #define MIN_SEEK 2000 #define MAX_SEEK 333333 -#define cdbufferb dev->buffer - -cdrom_t *cdrom[CDROM_NUM]; cdrom_image_t cdrom_image[CDROM_NUM]; cdrom_drive_t cdrom_drives[CDROM_NUM]; -uint8_t atapi_cdrom_drives[8] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; -uint8_t scsi_cdrom_drives[16] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; - - -#pragma pack(push,1) -typedef struct -{ - uint8_t opcode; - uint8_t polled; - uint8_t reserved2[2]; - uint8_t class; - uint8_t reserved3[2]; - uint16_t len; - uint8_t control; -} gesn_cdb_t; -#pragma pack(pop) - -#pragma pack(push,1) -typedef struct -{ - uint16_t len; - uint8_t notification_class; - uint8_t supported_events; -} gesn_event_header_t; -#pragma pack(pop) - - -/* Table of all SCSI commands and their flags, needed for the new disc change / not ready handler. */ -const uint8_t cdrom_command_flags[0x100] = -{ - IMPLEMENTED | CHECK_READY | NONDATA, /* 0x00 */ - IMPLEMENTED | ALLOW_UA | NONDATA | SCSI_ONLY, /* 0x01 */ - 0, /* 0x02 */ - IMPLEMENTED | ALLOW_UA, /* 0x03 */ - 0, 0, 0, 0, /* 0x04-0x07 */ - IMPLEMENTED | CHECK_READY, /* 0x08 */ - 0, 0, /* 0x09-0x0A */ - IMPLEMENTED | CHECK_READY | NONDATA, /* 0x0B */ - 0, 0, 0, 0, 0, 0, /* 0x0C-0x11 */ - IMPLEMENTED | ALLOW_UA, /* 0x12 */ - IMPLEMENTED | CHECK_READY | NONDATA | SCSI_ONLY, /* 0x13 */ - 0, /* 0x14 */ - IMPLEMENTED, /* 0x15 */ - 0, 0, 0, 0, /* 0x16-0x19 */ - IMPLEMENTED, /* 0x1A */ - IMPLEMENTED | CHECK_READY, /* 0x1B */ - 0, 0, /* 0x1C-0x1D */ - IMPLEMENTED | CHECK_READY, /* 0x1E */ - 0, 0, 0, 0, 0, 0, /* 0x1F-0x24 */ - IMPLEMENTED | CHECK_READY, /* 0x25 */ - 0, 0, /* 0x26-0x27 */ - IMPLEMENTED | CHECK_READY, /* 0x28 */ - 0, 0, /* 0x29-0x2A */ - IMPLEMENTED | CHECK_READY | NONDATA, /* 0x2B */ - 0, 0, 0, /* 0x2C-0x2E */ - IMPLEMENTED | CHECK_READY | NONDATA | SCSI_ONLY, /* 0x2F */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x30-0x3F */ - 0, 0, /* 0x40-0x41 */ - IMPLEMENTED | CHECK_READY, /* 0x42 */ - IMPLEMENTED | CHECK_READY, /* 0x43 - Read TOC - can get through UNIT_ATTENTION, per VIDE-CDD.SYS - NOTE: The ATAPI reference says otherwise, but I think this is a question of - interpreting things right - the UNIT ATTENTION condition we have here - is a tradition from not ready to ready, by definition the drive - eventually becomes ready, make the condition go away. */ - IMPLEMENTED | CHECK_READY, /* 0x44 */ - IMPLEMENTED | CHECK_READY, /* 0x45 */ - IMPLEMENTED | ALLOW_UA, /* 0x46 */ - IMPLEMENTED | CHECK_READY, /* 0x47 */ - IMPLEMENTED | CHECK_READY, /* 0x48 */ - 0, /* 0x49 */ - IMPLEMENTED | ALLOW_UA, /* 0x4A */ - IMPLEMENTED | CHECK_READY, /* 0x4B */ - 0, 0, /* 0x4C-0x4D */ - IMPLEMENTED | CHECK_READY, /* 0x4E */ - 0, 0, /* 0x4F-0x50 */ - IMPLEMENTED | CHECK_READY, /* 0x51 */ - IMPLEMENTED | CHECK_READY, /* 0x52 */ - 0, 0, /* 0x53-0x54 */ - IMPLEMENTED, /* 0x55 */ - 0, 0, 0, 0, /* 0x56-0x59 */ - IMPLEMENTED, /* 0x5A */ - 0, 0, 0, 0, 0, /* 0x5B-0x5F */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x60-0x6F */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x70-0x7F */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x80-0x8F */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x90-0x9F */ - 0, 0, 0, 0, 0, /* 0xA0-0xA4 */ - IMPLEMENTED | CHECK_READY, /* 0xA5 */ - 0, 0, /* 0xA6-0xA7 */ - IMPLEMENTED | CHECK_READY, /* 0xA8 */ - 0, 0, 0, 0, /* 0xA9-0xAC */ - IMPLEMENTED | CHECK_READY, /* 0xAD */ - 0, /* 0xAE */ - IMPLEMENTED | CHECK_READY | NONDATA | SCSI_ONLY, /* 0xAF */ - 0, 0, 0, 0, /* 0xB0-0xB3 */ - IMPLEMENTED | CHECK_READY | ATAPI_ONLY, /* 0xB4 */ - 0, 0, 0, /* 0xB5-0xB7 */ - IMPLEMENTED | CHECK_READY | ATAPI_ONLY, /* 0xB8 */ - IMPLEMENTED | CHECK_READY, /* 0xB9 */ - IMPLEMENTED | CHECK_READY, /* 0xBA */ - IMPLEMENTED, /* 0xBB */ - IMPLEMENTED | CHECK_READY, /* 0xBC */ - IMPLEMENTED, /* 0xBD */ - IMPLEMENTED | CHECK_READY, /* 0xBE */ - IMPLEMENTED | CHECK_READY, /* 0xBF */ - 0, 0, /* 0xC0-0xC1 */ - IMPLEMENTED | CHECK_READY | SCSI_ONLY, /* 0xC2 */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xC3-0xCC */ - IMPLEMENTED | CHECK_READY | SCSI_ONLY, /* 0xCD */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xCE-0xD9 */ - IMPLEMENTED | SCSI_ONLY, /* 0xDA */ - 0, 0, 0, 0, 0, /* 0xDB-0xDF */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xE0-0xEF */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 /* 0xF0-0xFF */ -}; - -static uint64_t cdrom_mode_sense_page_flags = (GPMODEP_R_W_ERROR_PAGE | - GPMODEP_CDROM_PAGE | - GPMODEP_CDROM_AUDIO_PAGE | - GPMODEP_CAPABILITIES_PAGE | - GPMODEP_ALL_PAGES); - - -static const mode_sense_pages_t cdrom_mode_sense_pages_default = -{ { - { 0, 0 }, - { GPMODE_R_W_ERROR_PAGE, 6, 0, 5, 0, 0, 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { GPMODE_CDROM_PAGE, 6, 0, 1, 0, 60, 0, 75 }, - { 0x8E, 0xE, 4, 0, 0, 0, 0, 75, 1, 255, 2, 255, 0, 0, 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { GPMODE_CAPABILITIES_PAGE, 0x12, 0, 0, 1, 0, 0, 0, 2, 0xC2, 1, 0, 0, 0, 2, 0xC2, 0, 0, 0, 0 } -} }; - -static const mode_sense_pages_t cdrom_mode_sense_pages_default_scsi = -{ { - { 0, 0 }, - { GPMODE_R_W_ERROR_PAGE, 6, 0, 5, 0, 0, 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { GPMODE_CDROM_PAGE, 6, 0, 1, 0, 60, 0, 75 }, - { 0x8E, 0xE, 5, 4, 0,128, 0, 75, 1, 255, 2, 255, 0, 0, 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { GPMODE_CAPABILITIES_PAGE, 0x12, 0, 0, 1, 0, 0, 0, 2, 0xC2, 1, 0, 0, 0, 2, 0xC2, 0, 0, 0, 0 } -} }; - -static const mode_sense_pages_t cdrom_mode_sense_pages_changeable = -{ { - { 0, 0 }, - { GPMODE_R_W_ERROR_PAGE, 6, 0xFF, 0xFF, 0, 0, 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { GPMODE_CDROM_PAGE, 6, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, - { 0x8E, 0xE, 0xFF, 0, 0, 0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { GPMODE_CAPABILITIES_PAGE, 0x12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } -} }; - -uint8_t cdrom_read_capacity_cdb[12] = {0x25, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; - -static gesn_cdb_t *gesn_cdb; -static gesn_event_header_t *gesn_event_header; - - -static void cdrom_command_complete(cdrom_t *dev); - -static void cdrom_mode_sense_load(cdrom_t *dev); - -static void cdrom_init(cdrom_t *dev); -void cdrom_phase_callback(cdrom_t *dev); - #ifdef ENABLE_CDROM_LOG int cdrom_do_log = ENABLE_CDROM_LOG; @@ -360,182 +56,6 @@ cdrom_log(const char *format, ...) } -int -find_cdrom_for_channel(uint8_t channel) -{ - uint8_t i = 0; - - for (i = 0; i < CDROM_NUM; i++) { - if ((cdrom_drives[i].bus_type == CDROM_BUS_ATAPI) && (cdrom_drives[i].ide_channel == channel)) - return i; - } - return 0xff; -} - - -void -build_atapi_cdrom_map() -{ - uint8_t i = 0; - - memset(atapi_cdrom_drives, 0xff, 8); - - for (i = 0; i < 8; i++) - atapi_cdrom_drives[i] = find_cdrom_for_channel(i); -} - - -int -find_cdrom_for_scsi_id(uint8_t scsi_id) -{ - uint8_t i = 0; - - for (i = 0; i < CDROM_NUM; i++) { - if ((cdrom_drives[i].bus_type == CDROM_BUS_SCSI) && (cdrom_drives[i].scsi_device_id == scsi_id)) - return i; - } - return 0xff; -} - - -void -build_scsi_cdrom_map() -{ - uint8_t i = 0; - - memset(scsi_cdrom_drives, 0xff, 16); - - for (i = 0; i < 16; i++) - scsi_cdrom_drives[i] = find_cdrom_for_scsi_id(i); -} - - -static void -cdrom_set_callback(cdrom_t *dev) -{ - if (dev && dev->drv && (dev->drv->bus_type != CDROM_BUS_SCSI)) - ide_set_callback(dev->drv->ide_channel >> 1, dev->callback); -} - - -void -cdrom_set_signature(cdrom_t *dev) -{ - if (!dev) - return; - dev->phase = 1; - dev->request_length = 0xEB14; -} - - -static void -cdrom_init(cdrom_t *dev) -{ - if (!dev) - return; - - /* Tell the cdrom_t struct what cdrom_drives element corresponds to it. */ - dev->drv = &(cdrom_drives[dev->id]); - - /* Do a reset (which will also rezero it). */ - cdrom_reset(dev); - - /* Configure the drive. */ - dev->requested_blocks = 1; - - dev->drv->bus_mode = 0; - if (dev->drv->bus_type >= CDROM_BUS_ATAPI) - dev->drv->bus_mode |= 2; - if (dev->drv->bus_type < CDROM_BUS_SCSI) - dev->drv->bus_mode |= 1; - cdrom_log("CD-ROM %i: Bus type %i, bus mode %i\n", dev->id, dev->drv->bus_type, dev->drv->bus_mode); - dev->cdb_len = 12; - - dev->sense[0] = 0xf0; - dev->sense[7] = 10; - dev->status = READY_STAT | DSC_STAT; - dev->pos = 0; - dev->packet_status = 0xff; - cdrom_sense_key = cdrom_asc = cdrom_ascq = dev->unit_attention = 0; - dev->cur_speed = dev->drv->speed; - cdrom_mode_sense_load(dev); -} - - -static int -cdrom_supports_pio(cdrom_t *dev) -{ - return (dev->drv->bus_mode & 1); -} - - -static int -cdrom_supports_dma(cdrom_t *dev) -{ - return (dev->drv->bus_mode & 2); -} - - -/* Returns: 0 for none, 1 for PIO, 2 for DMA. */ -static int -cdrom_current_mode(cdrom_t *dev) -{ - if (!cdrom_supports_pio(dev) && !cdrom_supports_dma(dev)) - return 0; - if (cdrom_supports_pio(dev) && !cdrom_supports_dma(dev)) { - cdrom_log("CD-ROM %i: Drive does not support DMA, setting to PIO\n", dev->id); - return 1; - } - if (!cdrom_supports_pio(dev) && cdrom_supports_dma(dev)) - return 2; - if (cdrom_supports_pio(dev) && cdrom_supports_dma(dev)) { - cdrom_log("CD-ROM %i: Drive supports both, setting to %s\n", dev->id, - (dev->features & 1) ? "DMA" : "PIO", - dev->id); - return (dev->features & 1) ? 2 : 1; - } - - return 0; -} - - -/* Translates ATAPI status (ERR_STAT flag) to SCSI status. */ -int -cdrom_CDROM_PHASE_to_scsi(cdrom_t *dev) -{ - if (dev->status & ERR_STAT) - return SCSI_STATUS_CHECK_CONDITION; - else - return SCSI_STATUS_OK; -} - - -/* Translates ATAPI phase (DRQ, I/O, C/D) to SCSI phase (MSG, C/D, I/O). */ -int -cdrom_atapi_phase_to_scsi(cdrom_t *dev) -{ - if (dev->status & 8) { - switch (dev->phase & 3) { - case 0: - return 0; - case 1: - return 2; - case 2: - return 1; - case 3: - return 7; - } - } else { - if ((dev->phase & 3) == 3) - return 3; - else - return 4; - } - - return 0; -} - - int cdrom_lba_to_msf_accurate(int lba) { @@ -555,217 +75,8 @@ cdrom_lba_to_msf_accurate(int lba) } -uint32_t -cdrom_mode_sense_get_channel(cdrom_t *dev, int channel) -{ - return dev->ms_pages_saved.pages[GPMODE_CDROM_AUDIO_PAGE][channel ? 10 : 8]; -} - - -uint32_t -cdrom_mode_sense_get_volume(cdrom_t *dev, int channel) -{ - return dev->ms_pages_saved.pages[GPMODE_CDROM_AUDIO_PAGE][channel ? 11 : 9]; -} - - -static void -cdrom_mode_sense_load(cdrom_t *dev) -{ - FILE *f; - wchar_t file_name[512]; - int i; - - memset(&dev->ms_pages_saved, 0, sizeof(mode_sense_pages_t)); - for (i = 0; i < 0x3f; i++) { - if (cdrom_mode_sense_pages_default.pages[i][1] != 0) { - if (dev->drv->bus_type == CDROM_BUS_SCSI) - memcpy(dev->ms_pages_saved.pages[i], - cdrom_mode_sense_pages_default_scsi.pages[i], - cdrom_mode_sense_pages_default_scsi.pages[i][1] + 2); - else - memcpy(dev->ms_pages_saved.pages[i], - cdrom_mode_sense_pages_default.pages[i], - cdrom_mode_sense_pages_default.pages[i][1] + 2); - } - } - memset(file_name, 0, 512 * sizeof(wchar_t)); - if (dev->drv->bus_type == CDROM_BUS_SCSI) - swprintf(file_name, 512, L"scsi_cdrom_%02i_mode_sense_bin", dev->id); - else - swprintf(file_name, 512, L"cdrom_%02i_mode_sense_bin", dev->id); - f = plat_fopen(nvr_path(file_name), L"rb"); - if (f) { - fread(dev->ms_pages_saved.pages[GPMODE_CDROM_AUDIO_PAGE], 1, 0x10, f); - fclose(f); - } -} - - -static void -cdrom_mode_sense_save(cdrom_t *dev) -{ - FILE *f; - wchar_t file_name[512]; - - memset(file_name, 0, 512 * sizeof(wchar_t)); - if (dev->drv->bus_type == CDROM_BUS_SCSI) - swprintf(file_name, 512, L"scsi_cdrom_%02i_mode_sense_bin", dev->id); - else - swprintf(file_name, 512, L"cdrom_%02i_mode_sense_bin", dev->id); - f = plat_fopen(nvr_path(file_name), L"wb"); - if (f) { - fwrite(dev->ms_pages_saved.pages[GPMODE_CDROM_AUDIO_PAGE], 1, 0x10, f); - fclose(f); - } -} - - -int -cdrom_read_capacity(cdrom_t *dev, uint8_t *cdb, uint8_t *buffer, uint32_t *len) -{ - int size = 0; - - size = dev->handler->size(dev->id) - 1; /* IMPORTANT: What's returned is the last LBA block. */ - memset(buffer, 0, 8); - buffer[0] = (size >> 24) & 0xff; - buffer[1] = (size >> 16) & 0xff; - buffer[2] = (size >> 8) & 0xff; - buffer[3] = size & 0xff; - buffer[6] = 8; /* 2048 = 0x0800 */ - *len = 8; - - return 1; -} - - -/*SCSI Mode Sense 6/10*/ -static uint8_t -cdrom_mode_sense_read(cdrom_t *dev, uint8_t page_control, uint8_t page, uint8_t pos) -{ - switch (page_control) { - case 0: - case 3: - return dev->ms_pages_saved.pages[page][pos]; - break; - case 1: - return cdrom_mode_sense_pages_changeable.pages[page][pos]; - break; - case 2: - if (dev->drv->bus_type == CDROM_BUS_SCSI) - return cdrom_mode_sense_pages_default_scsi.pages[page][pos]; - else - return cdrom_mode_sense_pages_default.pages[page][pos]; - break; - } - - return 0; -} - - -static uint32_t -cdrom_mode_sense(cdrom_t *dev, uint8_t *buf, uint32_t pos, uint8_t type, uint8_t block_descriptor_len) -{ - uint8_t page_control = (type >> 6) & 3; - int i = 0, j = 0; - - uint8_t msplen; - - type &= 0x3f; - - if (block_descriptor_len) { - buf[pos++] = 1; /* Density code. */ - buf[pos++] = 0; /* Number of blocks (0 = all). */ - buf[pos++] = 0; - buf[pos++] = 0; - buf[pos++] = 0; /* Reserved. */ - buf[pos++] = 0; /* Block length (0x800 = 2048 bytes). */ - buf[pos++] = 8; - buf[pos++] = 0; - } - - for (i = 0; i < 0x40; i++) { - if ((type == GPMODE_ALL_PAGES) || (type == i)) { - if (cdrom_mode_sense_page_flags & (1LL << dev->current_page_code)) { - buf[pos++] = cdrom_mode_sense_read(dev, page_control, i, 0); - msplen = cdrom_mode_sense_read(dev, page_control, i, 1); - buf[pos++] = msplen; - cdrom_log("CD-ROM %i: MODE SENSE: Page [%02X] length %i\n", dev->id, i, msplen); - for (j = 0; j < msplen; j++) { - if ((i == GPMODE_CAPABILITIES_PAGE) && (j >= 6) && (j <= 7)) { - if (j & 1) - buf[pos++] = ((dev->drv->speed * 176) & 0xff); - else - buf[pos++] = ((dev->drv->speed * 176) >> 8); - } else if ((i == GPMODE_CAPABILITIES_PAGE) && (j >= 12) && (j <= 13)) { - if (j & 1) - buf[pos++] = ((dev->cur_speed * 176) & 0xff); - else - buf[pos++] = ((dev->cur_speed * 176) >> 8); - } else - buf[pos++] = cdrom_mode_sense_read(dev, page_control, i, 2 + j); - } - } - } - } - - return pos; -} - - -static void -cdrom_update_request_length(cdrom_t *dev, int len, int block_len) -{ - int32_t bt, min_len = 0; - - dev->max_transfer_len = dev->request_length; - - /* For media access commands, make sure the requested DRQ length matches the block length. */ - switch (dev->current_cdb[0]) { - case 0x08: - case 0x28: - case 0xa8: - case 0xb9: - case 0xbe: - /* Make sure total length is not bigger than sum of the lengths of - all the requested blocks. */ - bt = (dev->requested_blocks * block_len); - if (len > bt) - len = bt; - - min_len = block_len; - - if (len <= block_len) { - /* Total length is less or equal to block length. */ - if (dev->max_transfer_len < block_len) { - /* Transfer a minimum of (block size) bytes. */ - dev->max_transfer_len = block_len; - dev->packet_len = block_len; - break; - } - } - default: - dev->packet_len = len; - break; - } - /* If the DRQ length is odd, and the total remaining length is bigger, make sure it's even. */ - if ((dev->max_transfer_len & 1) && (dev->max_transfer_len < len)) - dev->max_transfer_len &= 0xfffe; - /* If the DRQ length is smaller or equal in size to the total remaining length, set it to that. */ - if (!dev->max_transfer_len) - dev->max_transfer_len = 65534; - - if ((len <= dev->max_transfer_len) && (len >= min_len)) - dev->request_length = dev->max_transfer_len = len; - else if (len > dev->max_transfer_len) - dev->request_length = dev->max_transfer_len; - - return; -} - - -static double -cdrom_get_short_seek(cdrom_t *dev) +double +cdrom_get_short_seek(cdrom_drive_t *dev) { switch(dev->cur_speed) { case 0: @@ -796,8 +107,8 @@ cdrom_get_short_seek(cdrom_t *dev) } -static double -cdrom_get_long_seek(cdrom_t *dev) +double +cdrom_get_long_seek(cdrom_drive_t *dev) { switch(dev->cur_speed) { case 0: @@ -828,8 +139,8 @@ cdrom_get_long_seek(cdrom_t *dev) } -static double -cdrom_seek_time(cdrom_t *dev) +double +cdrom_seek_time(cdrom_drive_t *dev) { uint32_t diff = dev->seek_diff; double sd = (double) (MAX_SEEK - MIN_SEEK); @@ -845,720 +156,8 @@ cdrom_seek_time(cdrom_t *dev) } -static double -cdrom_bus_speed(cdrom_t *dev) -{ - if (dev->drv->bus_type == CDROM_BUS_SCSI) { - dev->callback = -1LL; /* Speed depends on SCSI controller */ - return 0.0; - } else { - if (cdrom_current_mode(dev) == 2) - return 66666666.666666666666666; /* 66 MB/s MDMA-2 speed */ - else - return 8333333.333333333333333; /* 8.3 MB/s PIO-2 speed */ - } -} - - -static void -cdrom_command_bus(cdrom_t *dev) -{ - dev->status = BUSY_STAT; - dev->phase = 1; - dev->pos = 0; - dev->callback = 1LL * CDROM_TIME; - cdrom_set_callback(dev); -} - - -static void -cdrom_command_common(cdrom_t *dev) -{ - double bytes_per_second, period; - double dusec; - - dev->status = BUSY_STAT; - dev->phase = 1; - dev->pos = 0; - dev->callback = 0LL; - - cdrom_log("CD-ROM %i: Current speed: %ix\n", dev->id, dev->cur_speed); - - if (dev->packet_status == CDROM_PHASE_COMPLETE) { - cdrom_phase_callback(dev); - dev->callback = 0LL; - } else { - switch(dev->current_cdb[0]) { - case GPCMD_REZERO_UNIT: - case 0x0b: - case 0x2b: - /* Seek time is in us. */ - period = cdrom_seek_time(dev); - cdrom_log("CD-ROM %i: Seek period: %" PRIu64 " us\n", - dev->id, (int64_t) period); - period = period * ((double) TIMER_USEC); - dev->callback += ((int64_t) period); - cdrom_set_callback(dev); - return; - case 0x08: - case 0x28: - case 0xa8: - /* Seek time is in us. */ - period = cdrom_seek_time(dev); - cdrom_log("CD-ROM %i: Seek period: %" PRIu64 " us\n", - dev->id, (int64_t) period); - period = period * ((double) TIMER_USEC); - dev->callback += ((int64_t) period); - case 0x25: - case 0x42: - case 0x43: - case 0x44: - case 0x51: - case 0x52: - case 0xad: - case 0xb8: - case 0xb9: - case 0xbe: - if (dev->current_cdb[0] == 0x42) - dev->callback += 200LL * CDROM_TIME; - /* Account for seek time. */ - bytes_per_second = 176.0 * 1024.0; - bytes_per_second *= (double) dev->cur_speed; - break; - default: - bytes_per_second = cdrom_bus_speed(dev); - if (bytes_per_second == 0.0) { - dev->callback = -1LL; /* Speed depends on SCSI controller */ - return; - } - break; - } - - period = 1000000.0 / bytes_per_second; - cdrom_log("CD-ROM %i: Byte transfer period: %" PRIu64 " us\n", dev->id, (int64_t) period); - period = period * (double) (dev->packet_len); - cdrom_log("CD-ROM %i: Sector transfer period: %" PRIu64 " us\n", dev->id, (int64_t) period); - dusec = period * ((double) TIMER_USEC); - dev->callback += ((int64_t) dusec); - } - cdrom_set_callback(dev); -} - - -static void -cdrom_command_complete(cdrom_t *dev) -{ - dev->packet_status = CDROM_PHASE_COMPLETE; - cdrom_command_common(dev); -} - - -static void -cdrom_command_read(cdrom_t *dev) -{ - dev->packet_status = CDROM_PHASE_DATA_IN; - cdrom_command_common(dev); - dev->total_read = 0; -} - - -static void -cdrom_command_read_dma(cdrom_t *dev) -{ - dev->packet_status = CDROM_PHASE_DATA_IN_DMA; - cdrom_command_common(dev); - dev->total_read = 0; -} - - -static void -cdrom_command_write(cdrom_t *dev) -{ - dev->packet_status = CDROM_PHASE_DATA_OUT; - cdrom_command_common(dev); -} - - -static void cdrom_command_write_dma(cdrom_t *dev) -{ - dev->packet_status = CDROM_PHASE_DATA_OUT_DMA; - cdrom_command_common(dev); -} - - -/* id = Current CD-ROM device ID; - len = Total transfer length; - block_len = Length of a single block (why does it matter?!); - alloc_len = Allocated transfer length; - direction = Transfer direction (0 = read from host, 1 = write to host). */ -static void cdrom_data_command_finish(cdrom_t *dev, int len, int block_len, int alloc_len, int direction) -{ - cdrom_log("CD-ROM %i: Finishing command (%02X): %i, %i, %i, %i, %i\n", - dev->id, dev->current_cdb[0], len, block_len, alloc_len, direction, dev->request_length); - dev->pos = 0; - if (alloc_len >= 0) { - if (alloc_len < len) - len = alloc_len; - } - if ((len == 0) || (cdrom_current_mode(dev) == 0)) { - if (dev->drv->bus_type != CDROM_BUS_SCSI) - dev->packet_len = 0; - - cdrom_command_complete(dev); - } else { - if (cdrom_current_mode(dev) == 2) { - if (dev->drv->bus_type != CDROM_BUS_SCSI) - dev->packet_len = alloc_len; - - if (direction == 0) - cdrom_command_read_dma(dev); - else - cdrom_command_write_dma(dev); - } else { - cdrom_update_request_length(dev, len, block_len); - if (direction == 0) - cdrom_command_read(dev); - else - cdrom_command_write(dev); - } - } - - cdrom_log("CD-ROM %i: Status: %i, cylinder %i, packet length: %i, position: %i, phase: %i\n", - dev->id, dev->packet_status, dev->request_length, dev->packet_len, dev->pos, dev->phase); -} - - -static void -cdrom_sense_clear(cdrom_t *dev, int command) -{ - dev->previous_command = command; - cdrom_sense_key = cdrom_asc = cdrom_ascq = 0; -} - - -static void -cdrom_set_phase(cdrom_t *dev, uint8_t phase) -{ - uint8_t scsi_id = dev->drv->scsi_device_id; - - if (dev->drv->bus_type != CDROM_BUS_SCSI) - return; - - SCSIDevices[scsi_id].Phase = phase; -} - - -static void -cdrom_cmd_error(cdrom_t *dev) -{ - cdrom_set_phase(dev, SCSI_PHASE_STATUS); - dev->error = ((cdrom_sense_key & 0xf) << 4) | ABRT_ERR; - if (dev->unit_attention) - dev->error |= MCR_ERR; - dev->status = READY_STAT | ERR_STAT; - dev->phase = 3; - dev->pos = 0; - dev->packet_status = 0x80; - dev->callback = 50LL * CDROM_TIME; - cdrom_set_callback(dev); - cdrom_log("CD-ROM %i: ERROR: %02X/%02X/%02X\n", dev->id, cdrom_sense_key, cdrom_asc, cdrom_ascq); -} - - -static void -cdrom_unit_attention(cdrom_t *dev) -{ - cdrom_set_phase(dev, SCSI_PHASE_STATUS); - dev->error = (SENSE_UNIT_ATTENTION << 4) | ABRT_ERR; - if (dev->unit_attention) - dev->error |= MCR_ERR; - dev->status = READY_STAT | ERR_STAT; - dev->phase = 3; - dev->pos = 0; - dev->packet_status = 0x80; - dev->callback = 50LL * CDROM_TIME; - cdrom_set_callback(dev); - cdrom_log("CD-ROM %i: UNIT ATTENTION\n", dev->id); -} - - -static void -cdrom_bus_master_error(cdrom_t *dev) -{ - cdrom_sense_key = cdrom_asc = cdrom_ascq = 0; - cdrom_cmd_error(dev); -} - - -static void -cdrom_not_ready(cdrom_t *dev) -{ - cdrom_sense_key = SENSE_NOT_READY; - cdrom_asc = ASC_MEDIUM_NOT_PRESENT; - cdrom_ascq = 0; - cdrom_cmd_error(dev); -} - - -static void -cdrom_invalid_lun(cdrom_t *dev) -{ - cdrom_sense_key = SENSE_ILLEGAL_REQUEST; - cdrom_asc = ASC_INV_LUN; - cdrom_ascq = 0; - cdrom_cmd_error(dev); -} - - -static void -cdrom_illegal_opcode(cdrom_t *dev) -{ - cdrom_sense_key = SENSE_ILLEGAL_REQUEST; - cdrom_asc = ASC_ILLEGAL_OPCODE; - cdrom_ascq = 0; - cdrom_cmd_error(dev); -} - - -static void -cdrom_lba_out_of_range(cdrom_t *dev) -{ - cdrom_sense_key = SENSE_ILLEGAL_REQUEST; - cdrom_asc = ASC_LBA_OUT_OF_RANGE; - cdrom_ascq = 0; - cdrom_cmd_error(dev); -} - - -static void -cdrom_invalid_field(cdrom_t *dev) -{ - cdrom_sense_key = SENSE_ILLEGAL_REQUEST; - cdrom_asc = ASC_INV_FIELD_IN_CMD_PACKET; - cdrom_ascq = 0; - cdrom_cmd_error(dev); - dev->status = 0x53; -} - - -static void -cdrom_invalid_field_pl(cdrom_t *dev) -{ - cdrom_sense_key = SENSE_ILLEGAL_REQUEST; - cdrom_asc = ASC_INV_FIELD_IN_PARAMETER_LIST; - cdrom_ascq = 0; - cdrom_cmd_error(dev); - dev->status = 0x53; -} - - -static void -cdrom_illegal_mode(cdrom_t *dev) -{ - cdrom_sense_key = SENSE_ILLEGAL_REQUEST; - cdrom_asc = ASC_ILLEGAL_MODE_FOR_THIS_TRACK; - cdrom_ascq = 0; - cdrom_cmd_error(dev); -} - - -static void -cdrom_incompatible_format(cdrom_t *dev) -{ - cdrom_sense_key = SENSE_ILLEGAL_REQUEST; - cdrom_asc = ASC_INCOMPATIBLE_FORMAT; - cdrom_ascq = 2; - cdrom_cmd_error(dev); -} - - -static void -cdrom_data_phase_error(cdrom_t *dev) -{ - cdrom_sense_key = SENSE_ILLEGAL_REQUEST; - cdrom_asc = ASC_DATA_PHASE_ERROR; - cdrom_ascq = 0; - cdrom_cmd_error(dev); -} - - void -cdrom_update_cdb(uint8_t *cdb, int lba_pos, int number_of_blocks) -{ - int temp = 0; - - switch(cdb[0]) { - case GPCMD_READ_6: - cdb[1] = (lba_pos >> 16) & 0xff; - cdb[2] = (lba_pos >> 8) & 0xff; - cdb[3] = lba_pos & 0xff; - break; - - case GPCMD_READ_10: - cdb[2] = (lba_pos >> 24) & 0xff; - cdb[3] = (lba_pos >> 16) & 0xff; - cdb[4] = (lba_pos >> 8) & 0xff; - cdb[5] = lba_pos & 0xff; - cdb[7] = (number_of_blocks >> 8) & 0xff; - cdb[8] = number_of_blocks & 0xff; - break; - - case GPCMD_READ_12: - cdb[2] = (lba_pos >> 24) & 0xff; - cdb[3] = (lba_pos >> 16) & 0xff; - cdb[4] = (lba_pos >> 8) & 0xff; - cdb[5] = lba_pos & 0xff; - cdb[6] = (number_of_blocks >> 24) & 0xff; - cdb[7] = (number_of_blocks >> 16) & 0xff; - cdb[8] = (number_of_blocks >> 8) & 0xff; - cdb[9] = number_of_blocks & 0xff; - break; - - case GPCMD_READ_CD_MSF: - temp = cdrom_lba_to_msf_accurate(lba_pos); - cdb[3] = (temp >> 16) & 0xff; - cdb[4] = (temp >> 8) & 0xff; - cdb[5] = temp & 0xff; - - temp = cdrom_lba_to_msf_accurate(lba_pos + number_of_blocks - 1); - cdb[6] = (temp >> 16) & 0xff; - cdb[7] = (temp >> 8) & 0xff; - cdb[8] = temp & 0xff; - break; - - case GPCMD_READ_CD: - cdb[2] = (lba_pos >> 24) & 0xff; - cdb[3] = (lba_pos >> 16) & 0xff; - cdb[4] = (lba_pos >> 8) & 0xff; - cdb[5] = lba_pos & 0xff; - cdb[6] = (number_of_blocks >> 16) & 0xff; - cdb[7] = (number_of_blocks >> 8) & 0xff; - cdb[8] = number_of_blocks & 0xff; - break; - } -} - - -static int -cdrom_read_data(cdrom_t *dev, int msf, int type, int flags, int32_t *len) -{ - int ret = 0; - uint32_t cdsize = 0; - - int i = 0; - int temp_len = 0; - - cdsize = dev->handler->size(dev->id); - - if (dev->sector_pos >= cdsize) { - cdrom_log("CD-ROM %i: Trying to read from beyond the end of disc (%i >= %i)\n", dev->id, - dev->sector_pos, cdsize); - cdrom_lba_out_of_range(dev); - return 0; - } - - if ((dev->sector_pos + dev->sector_len - 1) >= cdsize) { - cdrom_log("CD-ROM %i: Trying to read to beyond the end of disc (%i >= %i)\n", dev->id, - (dev->sector_pos + dev->sector_len - 1), cdsize); - cdrom_lba_out_of_range(dev); - return 0; - } - - dev->old_len = 0; - *len = 0; - - for (i = 0; i < dev->requested_blocks; i++) { - ret = dev->handler->readsector_raw(dev->id, cdbufferb + dev->data_pos, dev->sector_pos + i, - msf, type, flags, &temp_len); - - dev->data_pos += temp_len; - dev->old_len += temp_len; - - *len += temp_len; - - if (!ret) { - cdrom_illegal_mode(dev); - return 0; - } - } - - return 1; -} - - -static int -cdrom_read_blocks(cdrom_t *dev, int32_t *len, int first_batch) -{ - int ret = 0, msf = 0; - int type = 0, flags = 0; - - if (dev->current_cdb[0] == 0xb9) - msf = 1; - - if ((dev->current_cdb[0] == 0xb9) || (dev->current_cdb[0] == 0xbe)) { - type = (dev->current_cdb[1] >> 2) & 7; - flags = dev->current_cdb[9] | (((uint32_t) dev->current_cdb[10]) << 8); - } else { - type = 8; - flags = 0x10; - } - - dev->data_pos = 0; - - if (!dev->sector_len) { - cdrom_command_complete(dev); - return -1; - } - - cdrom_log("Reading %i blocks starting from %i...\n", dev->requested_blocks, dev->sector_pos); - - cdrom_update_cdb(dev->current_cdb, dev->sector_pos, dev->requested_blocks); - - ret = cdrom_read_data(dev, msf, type, flags, len); - - cdrom_log("Read %i bytes of blocks...\n", *len); - - if (!ret || ((dev->old_len != *len) && !first_batch)) { - if ((dev->old_len != *len) && !first_batch) - cdrom_illegal_mode(dev); - - return 0; - } - - dev->sector_pos += dev->requested_blocks; - dev->sector_len -= dev->requested_blocks; - - return 1; -} - - -/*SCSI Read DVD Structure*/ -static int -cdrom_read_dvd_structure(cdrom_t *dev, int format, const uint8_t *packet, uint8_t *buf) -{ - int layer = packet[6]; - uint64_t total_sectors; - - switch (format) { - case 0x00: /* Physical format information */ - total_sectors = (uint64_t) dev->handler->size(dev->id); - - if (layer != 0) { - cdrom_invalid_field(dev); - return 0; - } - - total_sectors >>= 2; - if (total_sectors == 0) { - /* return -ASC_MEDIUM_NOT_PRESENT; */ - cdrom_not_ready(dev); - return 0; - } - - buf[4] = 1; /* DVD-ROM, part version 1 */ - buf[5] = 0xf; /* 120mm disc, minimum rate unspecified */ - buf[6] = 1; /* one layer, read-only (per MMC-2 spec) */ - buf[7] = 0; /* default densities */ - - /* FIXME: 0x30000 per spec? */ - buf[8] = buf[9] = buf[10] = buf[11] = 0; /* start sector */ - buf[12] = (total_sectors >> 24) & 0xff; /* end sector */ - buf[13] = (total_sectors >> 16) & 0xff; - buf[14] = (total_sectors >> 8) & 0xff; - buf[15] = total_sectors & 0xff; - - buf[16] = (total_sectors >> 24) & 0xff; /* l0 end sector */ - buf[17] = (total_sectors >> 16) & 0xff; - buf[18] = (total_sectors >> 8) & 0xff; - buf[19] = total_sectors & 0xff; - - /* Size of buffer, not including 2 byte size field */ - buf[0] = ((2048 +2 ) >> 8) & 0xff; - buf[1] = (2048 + 2) & 0xff; - - /* 2k data + 4 byte header */ - return (2048 + 4); - - case 0x01: /* DVD copyright information */ - buf[4] = 0; /* no copyright data */ - buf[5] = 0; /* no region restrictions */ - - /* Size of buffer, not including 2 byte size field */ - buf[0] = ((4 + 2) >> 8) & 0xff; - buf[1] = (4 + 2) & 0xff; - - /* 4 byte header + 4 byte data */ - return (4 + 4); - - case 0x03: /* BCA information - invalid field for no BCA info */ - cdrom_invalid_field(dev); - return 0; - - case 0x04: /* DVD disc manufacturing information */ - /* Size of buffer, not including 2 byte size field */ - buf[0] = ((2048 + 2) >> 8) & 0xff; - buf[1] = (2048 + 2) & 0xff; - - /* 2k data + 4 byte header */ - return (2048 + 4); - - case 0xff: - /* - * This lists all the command capabilities above. Add new ones - * in order and update the length and buffer return values. - */ - - buf[4] = 0x00; /* Physical format */ - buf[5] = 0x40; /* Not writable, is readable */ - buf[6] = ((2048 + 4) >> 8) & 0xff; - buf[7] = (2048 + 4) & 0xff; - - buf[8] = 0x01; /* Copyright info */ - buf[9] = 0x40; /* Not writable, is readable */ - buf[10] = ((4 + 4) >> 8) & 0xff; - buf[11] = (4 + 4) & 0xff; - - buf[12] = 0x03; /* BCA info */ - buf[13] = 0x40; /* Not writable, is readable */ - buf[14] = ((188 + 4) >> 8) & 0xff; - buf[15] = (188 + 4) & 0xff; - - buf[16] = 0x04; /* Manufacturing info */ - buf[17] = 0x40; /* Not writable, is readable */ - buf[18] = ((2048 + 4) >> 8) & 0xff; - buf[19] = (2048 + 4) & 0xff; - - /* Size of buffer, not including 2 byte size field */ - buf[6] = ((16 + 2) >> 8) & 0xff; - buf[7] = (16 + 2) & 0xff; - - /* data written + 4 byte header */ - return (16 + 4); - - default: /* TODO: formats beyond DVD-ROM requires */ - cdrom_invalid_field(dev); - return 0; - } -} - - -void -cdrom_insert(cdrom_t *dev) -{ - dev->unit_attention = 1; - cdrom_log("CD-ROM %i: Media insert\n", dev->id); -} - - -/*SCSI Sense Initialization*/ -void -cdrom_sense_code_ok(uint8_t id) -{ - cdrom_t *dev = cdrom[id]; - - cdrom_sense_key = SENSE_NONE; - cdrom_asc = 0; - cdrom_ascq = 0; -} - - -static int -cdrom_pre_execution_check(cdrom_t *dev, uint8_t *cdb) -{ - int ready = 0, status = 0; - - if (dev->drv->bus_type == CDROM_BUS_SCSI) { - if ((cdb[0] != GPCMD_REQUEST_SENSE) && (cdb[1] & 0xe0)) { - cdrom_log("CD-ROM %i: Attempting to execute a unknown command targeted at SCSI LUN %i\n", - dev->id, ((dev->request_length >> 5) & 7)); - cdrom_invalid_lun(dev); - return 0; - } - } - - if (!(cdrom_command_flags[cdb[0]] & IMPLEMENTED)) { - cdrom_log("CD-ROM %i: Attempting to execute unknown command %02X over %s\n", dev->id, cdb[0], - (dev->drv->bus_type == CDROM_BUS_SCSI) ? "SCSI" : "ATAPI"); - - cdrom_illegal_opcode(dev); - return 0; - } - - if ((dev->drv->bus_type < CDROM_BUS_SCSI) && (cdrom_command_flags[cdb[0]] & SCSI_ONLY)) { - cdrom_log("CD-ROM %i: Attempting to execute SCSI-only command %02X over ATAPI\n", dev->id, cdb[0]); - cdrom_illegal_opcode(dev); - return 0; - } - - if ((dev->drv->bus_type == CDROM_BUS_SCSI) && (cdrom_command_flags[cdb[0]] & ATAPI_ONLY)) { - cdrom_log("CD-ROM %i: Attempting to execute ATAPI-only command %02X over SCSI\n", dev->id, cdb[0]); - cdrom_illegal_opcode(dev); - return 0; - } - - status = dev->handler->status(dev->id); - - if ((status == CD_STATUS_PLAYING) || (status == CD_STATUS_PAUSED)) { - ready = 1; - goto skip_ready_check; - } - - if (dev->handler->medium_changed(dev->id)) - cdrom_insert(dev); - - ready = dev->handler->ready(dev->id); - -skip_ready_check: - /* If the drive is not ready, there is no reason to keep the - UNIT ATTENTION condition present, as we only use it to mark - disc changes. */ - if (!ready && dev->unit_attention) - dev->unit_attention = 0; - - /* If the UNIT ATTENTION condition is set and the command does not allow - execution under it, error out and report the condition. */ - if (dev->unit_attention == 1) { - /* Only increment the unit attention phase if the command can not pass through it. */ - if (!(cdrom_command_flags[cdb[0]] & ALLOW_UA)) { - /* cdrom_log("CD-ROM %i: Unit attention now 2\n", dev->id); */ - dev->unit_attention++; - cdrom_log("CD-ROM %i: UNIT ATTENTION: Command %02X not allowed to pass through\n", - dev->id, cdb[0]); - cdrom_unit_attention(dev); - return 0; - } - } else if (dev->unit_attention == 2) { - if (cdb[0] != GPCMD_REQUEST_SENSE) { - /* cdrom_log("CD-ROM %i: Unit attention now 0\n", dev->id); */ - dev->unit_attention = 0; - } - } - - /* Unless the command is REQUEST SENSE, clear the sense. This will *NOT* - the UNIT ATTENTION condition if it's set. */ - if (cdb[0] != GPCMD_REQUEST_SENSE) - cdrom_sense_clear(dev, cdb[0]); - - /* Next it's time for NOT READY. */ - if (!ready) - dev->media_status = MEC_MEDIA_REMOVAL; - else - dev->media_status = (dev->unit_attention) ? MEC_NEW_MEDIA : MEC_NO_CHANGE; - - if ((cdrom_command_flags[cdb[0]] & CHECK_READY) && !ready) { - cdrom_log("CD-ROM %i: Not ready (%02X)\n", dev->id, cdb[0]); - cdrom_not_ready(dev); - return 0; - } - - cdrom_log("CD-ROM %i: Continuing with command %02X\n", dev->id, cdb[0]); - - return 1; -} - - -static void -cdrom_seek(cdrom_t *dev, uint32_t pos) +cdrom_seek(cdrom_drive_t *dev, uint32_t pos) { /* cdrom_log("CD-ROM %i: Seek %08X\n", dev->id, pos); */ dev->seek_pos = pos; @@ -1567,1657 +166,58 @@ cdrom_seek(cdrom_t *dev, uint32_t pos) } -static void -cdrom_rezero(cdrom_t *dev) -{ - if (dev->handler && dev->handler->stop) - dev->handler->stop(dev->id); - dev->sector_pos = dev->sector_len = 0; - cdrom_seek(dev, 0); -} - - -void -cdrom_reset(cdrom_t *dev) -{ - if (!dev) - return; - - cdrom_rezero(dev); - dev->status = 0; - dev->callback = 0LL; - cdrom_set_callback(dev); - dev->packet_status = 0xff; - dev->unit_attention = 0xff; -} - - -static int -cdrom_playing_completed(cdrom_t *dev) +int +cdrom_playing_completed(cdrom_drive_t *dev) { dev->prev_status = dev->cd_status; dev->cd_status = dev->handler->status(dev->id); - if (((dev->prev_status == CD_STATUS_PLAYING) || (dev->prev_status == CD_STATUS_PAUSED)) && ((dev->cd_status != CD_STATUS_PLAYING) && (dev->cd_status != CD_STATUS_PAUSED))) + if (((dev->prev_status == CD_STATUS_PLAYING) || (dev->prev_status == CD_STATUS_PAUSED)) && + ((dev->cd_status != CD_STATUS_PLAYING) && (dev->cd_status != CD_STATUS_PAUSED))) return 1; else return 0; } -static void -cdrom_request_sense(cdrom_t *dev, uint8_t *buffer, uint8_t alloc_length) -{ - /*Will return 18 bytes of 0*/ - if (alloc_length != 0) { - memset(buffer, 0, alloc_length); - memcpy(buffer, dev->sense, alloc_length); - } - - buffer[0] = 0x70; - - if ((cdrom_sense_key > 0) && ((dev->cd_status < CD_STATUS_PLAYING) || - (dev->cd_status == CD_STATUS_STOPPED)) && cdrom_playing_completed(dev)) { - buffer[2]=SENSE_ILLEGAL_REQUEST; - buffer[12]=ASC_AUDIO_PLAY_OPERATION; - buffer[13]=ASCQ_AUDIO_PLAY_OPERATION_COMPLETED; - } else if ((cdrom_sense_key == 0) && (dev->cd_status >= CD_STATUS_PLAYING) && - (dev->cd_status != CD_STATUS_STOPPED)) { - buffer[2]=SENSE_ILLEGAL_REQUEST; - buffer[12]=ASC_AUDIO_PLAY_OPERATION; - buffer[13]=(dev->cd_status == CD_STATUS_PLAYING) ? ASCQ_AUDIO_PLAY_OPERATION_IN_PROGRESS : ASCQ_AUDIO_PLAY_OPERATION_PAUSED; - } else { - if (dev->unit_attention && (cdrom_sense_key == 0)) { - buffer[2]=SENSE_UNIT_ATTENTION; - buffer[12]=ASC_MEDIUM_MAY_HAVE_CHANGED; - buffer[13]=0; - } - } - - cdrom_log("CD-ROM %i: Reporting sense: %02X %02X %02X\n", dev->id, buffer[2], buffer[12], buffer[13]); - - if (buffer[2] == SENSE_UNIT_ATTENTION) { - /* If the last remaining sense is unit attention, clear - that condition. */ - dev->unit_attention = 0; - } - - /* Clear the sense stuff as per the spec. */ - cdrom_sense_clear(dev, GPCMD_REQUEST_SENSE); -} - - -void -cdrom_request_sense_for_scsi(cdrom_t *dev, uint8_t *buffer, uint8_t alloc_length) -{ - int ready = 0; - - if (dev->handler->medium_changed(dev->id)) - cdrom_insert(dev); - - ready = dev->handler->ready(dev->id); - - if (!ready && dev->unit_attention) { - /* If the drive is not ready, there is no reason to keep the - UNIT ATTENTION condition present, as we only use it to mark - disc changes. */ - dev->unit_attention = 0; - } - - /* Do *NOT* advance the unit attention phase. */ - cdrom_request_sense(dev, buffer, alloc_length); -} - - -static void -cdrom_set_buf_len(cdrom_t *dev, int32_t *BufLen, int32_t *src_len) -{ - if (dev->drv->bus_type == CDROM_BUS_SCSI) { - if (*BufLen == -1) - *BufLen = *src_len; - else { - *BufLen = MIN(*src_len, *BufLen); - *src_len = *BufLen; - } - cdrom_log("CD-ROM %i: Actual transfer length: %i\n", dev->id, *BufLen); - } -} - - -static void -cdrom_buf_alloc(cdrom_t *dev, uint32_t len) -{ - cdrom_log("CD-ROM %i: Allocated buffer length: %i\n", dev->id, len); - cdbufferb = (uint8_t *) malloc(len); -} - - -static void -cdrom_buf_free(cdrom_t *dev) -{ - if (cdbufferb) { - cdrom_log("CD-ROM %i: Freeing buffer...\n", dev->id); - free(cdbufferb); - cdbufferb = NULL; - } -} - - -void -cdrom_command(cdrom_t *dev, uint8_t *cdb) -{ - int len, max_len, used_len, alloc_length, msf; - int pos = 0, i= 0, size_idx, idx = 0; - uint32_t feature; - unsigned preamble_len; - int toc_format, block_desc = 0; - int ret, format = 0; - int real_pos, track = 0; - char device_identify[9] = { '8', '6', 'B', '_', 'C', 'D', '0', '0', 0 }; - char device_identify_ex[15] = { '8', '6', 'B', '_', 'C', 'D', '0', '0', ' ', 'v', '1', '.', '0', '0', 0 }; - int32_t blen = 0, *BufLen; - uint8_t *b; - uint32_t profiles[2] = { MMC_PROFILE_CD_ROM, MMC_PROFILE_DVD_ROM }; - - if (dev->drv->bus_type == CDROM_BUS_SCSI) { - BufLen = &SCSIDevices[dev->drv->scsi_device_id].BufferLength; - dev->status &= ~ERR_STAT; - } else { - BufLen = &blen; - dev->error = 0; - } - - dev->packet_len = 0; - dev->request_pos = 0; - - device_identify[7] = dev->id + 0x30; - - device_identify_ex[7] = dev->id + 0x30; - device_identify_ex[10] = EMU_VERSION[0]; - device_identify_ex[12] = EMU_VERSION[2]; - device_identify_ex[13] = EMU_VERSION[3]; - - dev->data_pos = 0; - - memcpy(dev->current_cdb, cdb, dev->cdb_len); - - dev->cd_status = dev->handler->status(dev->id); - - if (cdb[0] != 0) { - cdrom_log("CD-ROM %i: Command 0x%02X, Sense Key %02X, Asc %02X, Ascq %02X, Unit attention: %i\n", - dev->id, cdb[0], cdrom_sense_key, cdrom_asc, cdrom_ascq, dev->unit_attention); - cdrom_log("CD-ROM %i: Request length: %04X\n", dev->id, dev->request_length); - - cdrom_log("CD-ROM %i: CDB: %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X\n", dev->id, - cdb[0], cdb[1], cdb[2], cdb[3], cdb[4], cdb[5], cdb[6], cdb[7], - cdb[8], cdb[9], cdb[10], cdb[11]); - } - - msf = cdb[1] & 2; - dev->sector_len = 0; - - cdrom_set_phase(dev, SCSI_PHASE_STATUS); - - /* This handles the Not Ready/Unit Attention check if it has to be handled at this point. */ - if (cdrom_pre_execution_check(dev, cdb) == 0) - return; - - switch (cdb[0]) { - case GPCMD_TEST_UNIT_READY: - cdrom_set_phase(dev, SCSI_PHASE_STATUS); - cdrom_command_complete(dev); - break; - - case GPCMD_REZERO_UNIT: - if (dev->handler->stop) - dev->handler->stop(dev->id); - dev->sector_pos = dev->sector_len = 0; - dev->seek_diff = dev->seek_pos; - cdrom_seek(dev, 0); - cdrom_set_phase(dev, SCSI_PHASE_STATUS); - break; - - case GPCMD_REQUEST_SENSE: - /* If there's a unit attention condition and there's a buffered not ready, a standalone REQUEST SENSE - should forget about the not ready, and report unit attention straight away. */ - cdrom_set_phase(dev, SCSI_PHASE_DATA_IN); - max_len = cdb[4]; - - if (!max_len) { - cdrom_set_phase(dev, SCSI_PHASE_STATUS); - dev->packet_status = CDROM_PHASE_COMPLETE; - dev->callback = 20LL * CDROM_TIME; - cdrom_set_callback(dev); - break; - } - - cdrom_buf_alloc(dev, 256); - cdrom_set_buf_len(dev, BufLen, &max_len); - cdrom_request_sense(dev, cdbufferb, max_len); - cdrom_data_command_finish(dev, 18, 18, cdb[4], 0); - break; - - case GPCMD_SET_SPEED: - case GPCMD_SET_SPEED_ALT: - dev->cur_speed = (cdb[3] | (cdb[2] << 8)) / 176; - if (dev->cur_speed < 1) - dev->cur_speed = 1; - else if (dev->cur_speed > dev->drv->speed) - dev->cur_speed = dev->drv->speed; - cdrom_set_phase(dev, SCSI_PHASE_STATUS); - cdrom_command_complete(dev); - break; - - case GPCMD_MECHANISM_STATUS: - cdrom_set_phase(dev, SCSI_PHASE_DATA_IN); - len = (cdb[7] << 16) | (cdb[8] << 8) | cdb[9]; - - cdrom_buf_alloc(dev, 8); - - cdrom_set_buf_len(dev, BufLen, &len); - - memset(cdbufferb, 0, 8); - cdbufferb[5] = 1; - - cdrom_data_command_finish(dev, 8, 8, len, 0); - break; - - case GPCMD_READ_TOC_PMA_ATIP: - cdrom_set_phase(dev, SCSI_PHASE_DATA_IN); - - max_len = cdb[7]; - max_len <<= 8; - max_len |= cdb[8]; - - cdrom_buf_alloc(dev, 65536); - - toc_format = cdb[2] & 0xf; - - if (toc_format == 0) - toc_format = (cdb[9] >> 6) & 3; - - switch (toc_format) { - case 0: /*Normal*/ - len = dev->handler->readtoc(dev->id, cdbufferb, cdb[6], msf, max_len, - 0); - break; - case 1: /*Multi session*/ - len = dev->handler->readtoc_session(dev->id, cdbufferb, msf, max_len); - cdbufferb[0] = 0; cdbufferb[1] = 0xA; - break; - case 2: /*Raw*/ - len = dev->handler->readtoc_raw(dev->id, cdbufferb, max_len); - break; - default: - cdrom_invalid_field(dev); - cdrom_buf_free(dev); - return; - } - - if (len > max_len) { - len = max_len; - - cdbufferb[0] = ((len - 2) >> 8) & 0xff; - cdbufferb[1] = (len - 2) & 0xff; - } - - cdrom_set_buf_len(dev, BufLen, &len); - - if (len >= 8) { - cdrom_log("CD-ROM %i: TOC: %02X %02X %02X %02X %02X %02X %02X %02X\n", dev->id, - cdbufferb[0], cdbufferb[1], cdbufferb[2], cdbufferb[3], - cdbufferb[4], cdbufferb[5], cdbufferb[6], cdbufferb[7]); - } - - if (len >= 16) { - cdrom_log(" %02X %02X %02X %02X %02X %02X %02X %02X\n", - cdbufferb[8], cdbufferb[9], cdbufferb[10], cdbufferb[11], - cdbufferb[12], cdbufferb[13], cdbufferb[14], cdbufferb[15]); - } - - if (len >= 24) { - cdrom_log(" %02X %02X %02X %02X %02X %02X %02X %02X\n", - cdbufferb[16], cdbufferb[17], cdbufferb[18], cdbufferb[19], - cdbufferb[20], cdbufferb[21], cdbufferb[22], cdbufferb[23]); - } - - if (len >= 32) { - cdrom_log(" %02X %02X %02X %02X %02X %02X %02X %02X\n", - cdbufferb[24], cdbufferb[25], cdbufferb[26], cdbufferb[27], - cdbufferb[28], cdbufferb[29], cdbufferb[30], cdbufferb[31]); - } - - if (len >= 36) { - cdrom_log(" %02X %02X %02X %02X\n", - cdbufferb[32], cdbufferb[33], cdbufferb[34], cdbufferb[35]); - } - - cdrom_data_command_finish(dev, len, len, len, 0); - /* cdrom_log("CD-ROM %i: READ_TOC_PMA_ATIP format %02X, length %i (%i)\n", dev->id, - toc_format, ide->cylinder, cdbufferb[1]); */ - return; - - case GPCMD_READ_CD_OLD: - /* IMPORTANT: Convert the command to new read CD - for pass through purposes. */ - dev->current_cdb[0] = 0xbe; - case GPCMD_READ_6: - case GPCMD_READ_10: - case GPCMD_READ_12: - case GPCMD_READ_CD: - case GPCMD_READ_CD_MSF: - cdrom_set_phase(dev, SCSI_PHASE_DATA_IN); - alloc_length = 2048; - - switch(cdb[0]) { - case GPCMD_READ_6: - dev->sector_len = cdb[4]; - dev->sector_pos = ((((uint32_t) cdb[1]) & 0x1f) << 16) | (((uint32_t) cdb[2]) << 8) | ((uint32_t) cdb[3]); - msf = 0; - break; - case GPCMD_READ_10: - dev->sector_len = (cdb[7] << 8) | cdb[8]; - dev->sector_pos = (cdb[2] << 24) | (cdb[3] << 16) | (cdb[4] << 8) | cdb[5]; - cdrom_log("CD-ROM %i: Length: %i, LBA: %i\n", dev->id, dev->sector_len, - dev->sector_pos); - msf = 0; - break; - case GPCMD_READ_12: - dev->sector_len = (((uint32_t) cdb[6]) << 24) | (((uint32_t) cdb[7]) << 16) | (((uint32_t) cdb[8]) << 8) | ((uint32_t) cdb[9]); - dev->sector_pos = (((uint32_t) cdb[2]) << 24) | (((uint32_t) cdb[3]) << 16) | (((uint32_t) cdb[4]) << 8) | ((uint32_t) cdb[5]); - cdrom_log("CD-ROM %i: Length: %i, LBA: %i\n", dev->id, dev->sector_len, - dev->sector_pos); - msf = 0; - break; - case GPCMD_READ_CD_MSF: - alloc_length = 2856; - dev->sector_len = MSFtoLBA(cdb[6], cdb[7], cdb[8]); - dev->sector_pos = MSFtoLBA(cdb[3], cdb[4], cdb[5]); - - dev->sector_len -= dev->sector_pos; - dev->sector_len++; - msf = 1; - break; - case GPCMD_READ_CD_OLD: - case GPCMD_READ_CD: - alloc_length = 2856; - dev->sector_len = (cdb[6] << 16) | (cdb[7] << 8) | cdb[8]; - dev->sector_pos = (cdb[2] << 24) | (cdb[3] << 16) | (cdb[4] << 8) | cdb[5]; - - msf = 0; - break; - } - - dev->seek_diff = ABS((int) (pos - dev->seek_pos)); - dev->seek_pos = dev->sector_pos; - - if (!dev->sector_len) { - cdrom_set_phase(dev, SCSI_PHASE_STATUS); - /* cdrom_log("CD-ROM %i: All done - callback set\n", dev->id); */ - dev->packet_status = CDROM_PHASE_COMPLETE; - dev->callback = 20LL * CDROM_TIME; - cdrom_set_callback(dev); - break; - } - - max_len = dev->sector_len; - dev->requested_blocks = max_len; /* If we're reading all blocks in one go for DMA, why not also for PIO, it should NOT - matter anyway, this step should be identical and only the way the read dat is - transferred to the host should be different. */ - - dev->packet_len = max_len * alloc_length; - cdrom_buf_alloc(dev, dev->packet_len); - - ret = cdrom_read_blocks(dev, &alloc_length, 1); - if (ret <= 0) { - cdrom_buf_free(dev); - return; - } - - dev->requested_blocks = max_len; - dev->packet_len = alloc_length; - - cdrom_set_buf_len(dev, BufLen, (int32_t *) &dev->packet_len); - - cdrom_data_command_finish(dev, alloc_length, alloc_length / dev->requested_blocks, - alloc_length, 0); - - dev->all_blocks_total = dev->block_total; - if (dev->packet_status != CDROM_PHASE_COMPLETE) - ui_sb_update_icon(SB_CDROM | dev->id, 1); - else - ui_sb_update_icon(SB_CDROM | dev->id, 0); - return; - - case GPCMD_READ_HEADER: - cdrom_set_phase(dev, SCSI_PHASE_DATA_IN); - - alloc_length = ((cdb[7] << 8) | cdb[8]); - cdrom_buf_alloc(dev, 8); - - dev->sector_len = 1; - dev->sector_pos = (cdb[2] << 24) | (cdb[3] << 16) | (cdb[4]<<8) | cdb[5]; - if (msf) - real_pos = cdrom_lba_to_msf_accurate(dev->sector_pos); - else - real_pos = dev->sector_pos; - cdbufferb[0] = 1; /*2048 bytes user data*/ - cdbufferb[1] = cdbufferb[2] = cdbufferb[3] = 0; - cdbufferb[4] = (real_pos >> 24); - cdbufferb[5] = ((real_pos >> 16) & 0xff); - cdbufferb[6] = ((real_pos >> 8) & 0xff); - cdbufferb[7] = real_pos & 0xff; - - len = 8; - len = MIN(len, alloc_length); - - cdrom_set_buf_len(dev, BufLen, &len); - - cdrom_data_command_finish(dev, len, len, len, 0); - return; - - case GPCMD_MODE_SENSE_6: - case GPCMD_MODE_SENSE_10: - cdrom_set_phase(dev, SCSI_PHASE_DATA_IN); - - if (dev->drv->bus_type == CDROM_BUS_SCSI) - block_desc = ((cdb[1] >> 3) & 1) ? 0 : 1; - else - block_desc = 0; - - if (cdb[0] == GPCMD_MODE_SENSE_6) { - len = cdb[4]; - cdrom_buf_alloc(dev, 256); - } else { - len = (cdb[8] | (cdb[7] << 8)); - cdrom_buf_alloc(dev, 65536); - } - - dev->current_page_code = cdb[2] & 0x3F; - - if (!(cdrom_mode_sense_page_flags & (1LL << dev->current_page_code))) { - cdrom_invalid_field(dev); - cdrom_buf_free(dev); - return; - } - - memset(cdbufferb, 0, len); - alloc_length = len; - - if (cdb[0] == GPCMD_MODE_SENSE_6) { - len = cdrom_mode_sense(dev, cdbufferb, 4, cdb[2], block_desc); - len = MIN(len, alloc_length); - cdbufferb[0] = len - 1; - cdbufferb[1] = dev->handler->media_type_id(dev->id); - if (block_desc) - cdbufferb[3] = 8; - } else { - len = cdrom_mode_sense(dev, cdbufferb, 8, cdb[2], block_desc); - len = MIN(len, alloc_length); - cdbufferb[0]=(len - 2) >> 8; - cdbufferb[1]=(len - 2) & 255; - cdbufferb[2] = dev->handler->media_type_id(dev->id); - if (block_desc) { - cdbufferb[6] = 0; - cdbufferb[7] = 8; - } - } - - cdrom_set_buf_len(dev, BufLen, &len); - - cdrom_log("CD-ROM %i: Reading mode page: %02X...\n", dev->id, cdb[2]); - - cdrom_data_command_finish(dev, len, len, alloc_length, 0); - return; - - case GPCMD_MODE_SELECT_6: - case GPCMD_MODE_SELECT_10: - cdrom_set_phase(dev, SCSI_PHASE_DATA_OUT); - - if (cdb[0] == GPCMD_MODE_SELECT_6) { - len = cdb[4]; - cdrom_buf_alloc(dev, 256); - } else { - len = (cdb[7] << 8) | cdb[8]; - cdrom_buf_alloc(dev, 65536); - } - - cdrom_set_buf_len(dev, BufLen, &len); - - dev->total_length = len; - dev->do_page_save = cdb[1] & 1; - - dev->current_page_pos = 0; - - cdrom_data_command_finish(dev, len, len, len, 1); - return; - - case GPCMD_GET_CONFIGURATION: - cdrom_set_phase(dev, SCSI_PHASE_DATA_IN); - - /* XXX: could result in alignment problems in some architectures */ - feature = (cdb[2] << 8) | cdb[3]; - max_len = (cdb[7] << 8) | cdb[8]; - - /* only feature 0 is supported */ - if ((cdb[2] != 0) || (cdb[3] > 2)) { - cdrom_invalid_field(dev); - cdrom_buf_free(dev); - return; - } - - cdrom_buf_alloc(dev, 65536); - memset(cdbufferb, 0, max_len); - - alloc_length = 0; - b = cdbufferb; - - /* - * the number of sectors from the media tells us which profile - * to use as current. 0 means there is no media - */ - if (dev->handler->ready(dev->id)) { - len = dev->handler->size(dev->id); - if (len > CD_MAX_SECTORS) { - b[6] = (MMC_PROFILE_DVD_ROM >> 8) & 0xff; - b[7] = MMC_PROFILE_DVD_ROM & 0xff; - ret = 1; - } else { - b[6] = (MMC_PROFILE_CD_ROM >> 8) & 0xff; - b[7] = MMC_PROFILE_CD_ROM & 0xff; - ret = 0; - } - } else - ret = 2; - - alloc_length = 8; - b += 8; - - if ((feature == 0) || ((cdb[1] & 3) < 2)) { - b[2] = (0 << 2) | 0x02 | 0x01; /* persistent and current */ - b[3] = 8; - - alloc_length += 4; - b += 4; - - for (i = 0; i < 2; i++) { - b[0] = (profiles[i] >> 8) & 0xff; - b[1] = profiles[i] & 0xff; - - if (ret == i) - b[2] |= 1; - - alloc_length += 4; - b += 4; - } - } - if ((feature == 1) || ((cdb[1] & 3) < 2)) { - b[1] = 1; - b[2] = (2 << 2) | 0x02 | 0x01; /* persistent and current */ - b[3] = 8; - - if (dev->drv->bus_type == CDROM_BUS_SCSI) - b[7] = 1; - else - b[7] = 2; - b[8] = 1; - - alloc_length += 12; - b += 12; - } - if ((feature == 2) || ((cdb[1] & 3) < 2)) { - b[1] = 2; - b[2] = (1 << 2) | 0x02 | 0x01; /* persistent and current */ - b[3] = 4; - - b[4] = 2; - - alloc_length += 8; - b += 8; - } - - cdbufferb[0] = ((alloc_length - 4) >> 24) & 0xff; - cdbufferb[1] = ((alloc_length - 4) >> 16) & 0xff; - cdbufferb[2] = ((alloc_length - 4) >> 8) & 0xff; - cdbufferb[3] = (alloc_length - 4) & 0xff; - - alloc_length = MIN(alloc_length, max_len); - - cdrom_set_buf_len(dev, BufLen, &alloc_length); - - cdrom_data_command_finish(dev, alloc_length, alloc_length, alloc_length, 0); - break; - - case GPCMD_GET_EVENT_STATUS_NOTIFICATION: - cdrom_set_phase(dev, SCSI_PHASE_DATA_IN); - - cdrom_buf_alloc(dev, 8 + sizeof(gesn_event_header_t)); - - gesn_cdb = (void *) cdb; - gesn_event_header = (void *) cdbufferb; - - /* It is fine by the MMC spec to not support async mode operations. */ - if (!(gesn_cdb->polled & 0x01)) { - /* asynchronous mode */ - /* Only polling is supported, asynchronous mode is not. */ - cdrom_invalid_field(dev); - cdrom_buf_free(dev); - return; - } - - /* - * These are the supported events. - * - * We currently only support requests of the 'media' type. - * Notification class requests and supported event classes are bitmasks, - * but they are built from the same values as the "notification class" - * field. - */ - gesn_event_header->supported_events = 1 << GESN_MEDIA; - - /* - * We use |= below to set the class field; other bits in this byte - * are reserved now but this is useful to do if we have to use the - * reserved fields later. - */ - gesn_event_header->notification_class = 0; - - /* - * Responses to requests are to be based on request priority. The - * notification_class_request_type enum above specifies the - * priority: upper elements are higher prio than lower ones. - */ - if (gesn_cdb->class & (1 << GESN_MEDIA)) { - gesn_event_header->notification_class |= GESN_MEDIA; - - cdbufferb[4] = dev->media_status; /* Bits 7-4 = Reserved, Bits 4-1 = Media Status */ - cdbufferb[5] = 1; /* Power Status (1 = Active) */ - cdbufferb[6] = 0; - cdbufferb[7] = 0; - used_len = 8; - } else { - gesn_event_header->notification_class = 0x80; /* No event available */ - used_len = sizeof(*gesn_event_header); - } - gesn_event_header->len = used_len - sizeof(*gesn_event_header); - - memcpy(cdbufferb, gesn_event_header, 4); - - cdrom_set_buf_len(dev, BufLen, &used_len); - - cdrom_data_command_finish(dev, used_len, used_len, used_len, 0); - break; - - case GPCMD_READ_DISC_INFORMATION: - cdrom_set_phase(dev, SCSI_PHASE_DATA_IN); - - max_len = cdb[7]; - max_len <<= 8; - max_len |= cdb[8]; - - cdrom_buf_alloc(dev, 65536); - - memset(cdbufferb, 0, 34); - memset(cdbufferb, 1, 9); - cdbufferb[0] = 0; - cdbufferb[1] = 32; - cdbufferb[2] = 0xe; /* last session complete, disc finalized */ - cdbufferb[7] = 0x20; /* unrestricted use */ - cdbufferb[8] = 0x00; /* CD-ROM */ - - len=34; - len = MIN(len, max_len); - - cdrom_set_buf_len(dev, BufLen, &len); - - cdrom_data_command_finish(dev, len, len, len, 0); - break; - - case GPCMD_READ_TRACK_INFORMATION: - cdrom_set_phase(dev, SCSI_PHASE_DATA_IN); - - max_len = cdb[7]; - max_len <<= 8; - max_len |= cdb[8]; - - cdrom_buf_alloc(dev, 65536); - - track = ((uint32_t) cdb[2]) << 24; - track |= ((uint32_t) cdb[3]) << 16; - track |= ((uint32_t) cdb[4]) << 8; - track |= (uint32_t) cdb[5]; - - if (((cdb[1] & 0x03) != 1) || (track != 1)) { - cdrom_invalid_field(dev); - cdrom_buf_free(dev); - return; - } - - len = 36; - - memset(cdbufferb, 0, 36); - cdbufferb[0] = 0; - cdbufferb[1] = 34; - cdbufferb[2] = 1; /* track number (LSB) */ - cdbufferb[3] = 1; /* session number (LSB) */ - cdbufferb[5] = (0 << 5) | (0 << 4) | (4 << 0); /* not damaged, primary copy, data track */ - cdbufferb[6] = (0 << 7) | (0 << 6) | (0 << 5) | (0 << 6) | (1 << 0); /* not reserved track, not blank, not packet writing, not fixed packet, data mode 1 */ - cdbufferb[7] = (0 << 1) | (0 << 0); /* last recorded address not valid, next recordable address not valid */ - cdbufferb[24] = (dev->handler->size(dev->id) >> 24) & 0xff; /* track size */ - cdbufferb[25] = (dev->handler->size(dev->id) >> 16) & 0xff; /* track size */ - cdbufferb[26] = (dev->handler->size(dev->id) >> 8) & 0xff; /* track size */ - cdbufferb[27] = dev->handler->size(dev->id) & 0xff; /* track size */ - - if (len > max_len) { - len = max_len; - cdbufferb[0] = ((max_len - 2) >> 8) & 0xff; - cdbufferb[1] = (max_len - 2) & 0xff; - } - - cdrom_set_buf_len(dev, BufLen, &len); - - cdrom_data_command_finish(dev, len, len, max_len, 0); - break; - - case GPCMD_PLAY_AUDIO_10: - case GPCMD_PLAY_AUDIO_12: - case GPCMD_PLAY_AUDIO_MSF: - case GPCMD_PLAY_AUDIO_TRACK_INDEX: - cdrom_set_phase(dev, SCSI_PHASE_STATUS); - - switch(cdb[0]) { - case GPCMD_PLAY_AUDIO_10: - msf = 0; - pos = (cdb[2] << 24) | (cdb[3] << 16) | (cdb[4] << 8) | cdb[5]; - len = (cdb[7] << 8) | cdb[8]; - break; - case GPCMD_PLAY_AUDIO_12: - msf = 0; - pos = (cdb[2] << 24) | (cdb[3] << 16) | (cdb[4] << 8) | cdb[5]; - len = (cdb[6] << 24) | (cdb[7] << 16) | (cdb[8] << 8) | cdb[9]; - break; - case GPCMD_PLAY_AUDIO_MSF: - /* This is apparently deprecated in the ATAPI spec, and apparently - has been since 1995 (!). Hence I'm having to guess most of it. */ - msf = 1; - pos = (cdb[3] << 16) | (cdb[4] << 8) | cdb[5]; - len = (cdb[6] << 16) | (cdb[7] << 8) | cdb[8]; - break; - case GPCMD_PLAY_AUDIO_TRACK_INDEX: - msf = 2; - pos = (cdb[4] << 8) | cdb[5]; - len = (cdb[7] << 8) | cdb[8]; - break; - } - - if ((dev->drv->host_drive < 1) || (dev->cd_status <= CD_STATUS_DATA_ONLY)) { - cdrom_illegal_mode(dev); - break; - } - - if (dev->handler->playaudio) - ret = dev->handler->playaudio(dev->id, pos, len, msf); - else - ret = 0; - - if (ret) - cdrom_command_complete(dev); - else - cdrom_illegal_mode(dev); - break; - - case GPCMD_READ_SUBCHANNEL: - cdrom_set_phase(dev, SCSI_PHASE_DATA_IN); - - max_len = cdb[7]; - max_len <<= 8; - max_len |= cdb[8]; - msf = (cdb[1] >> 1) & 1; - - cdrom_buf_alloc(dev, 32); - - cdrom_log("CD-ROM %i: Getting page %i (%s)\n", dev->id, cdb[3], msf ? "MSF" : "LBA"); - - if (cdb[3] > 3) { - /* cdrom_log("CD-ROM %i: Read subchannel check condition %02X\n", dev->id, - cdb[3]); */ - cdrom_invalid_field(dev); - cdrom_buf_free(dev); - return; - } - - switch(cdb[3]) { - case 0: - alloc_length = 4; - break; - case 1: - alloc_length = 16; - break; - default: - alloc_length = 24; - break; - } - - memset(cdbufferb, 0, 24); - pos = 0; - cdbufferb[pos++] = 0; - cdbufferb[pos++] = 0; /*Audio status*/ - cdbufferb[pos++] = 0; cdbufferb[pos++] = 0; /*Subchannel length*/ - cdbufferb[pos++] = cdb[3] & 3; /*Format code*/ - if (cdb[3] == 1) { - cdbufferb[1] = dev->handler->getcurrentsubchannel(dev->id, &cdbufferb[5], msf); - switch(dev->cd_status) { - case CD_STATUS_PLAYING: - cdbufferb[1] = 0x11; - break; - case CD_STATUS_PAUSED: - cdbufferb[1] = 0x12; - break; - case CD_STATUS_DATA_ONLY: - cdbufferb[1] = 0x15; - break; - default: - cdbufferb[1] = 0x13; - break; - } - } - - if (!(cdb[2] & 0x40) || (cdb[3] == 0)) - len = 4; - else - len = alloc_length; - - len = MIN(len, max_len); - cdrom_set_buf_len(dev, BufLen, &len); - - cdrom_log("CD-ROM %i: Read subchannel:", dev->id); - for (i = 0; i < 32; i += 8) { - cdrom_log("[%02X] %02X %02X %02X %02X %02X %02X %02X %02X\n", i, - cdbufferb[i], cdbufferb[i + 1], cdbufferb[i + 2], cdbufferb[i + 3], - cdbufferb[i + 4], cdbufferb[i + 5], cdbufferb[i + 6], cdbufferb[i + 7]); - } - - cdrom_data_command_finish(dev, len, len, len, 0); - break; - - case GPCMD_READ_DVD_STRUCTURE: - cdrom_set_phase(dev, SCSI_PHASE_DATA_IN); - - alloc_length = (((uint32_t) cdb[8]) << 8) | ((uint32_t) cdb[9]); - - cdrom_buf_alloc(dev, alloc_length); - - len = dev->handler->size(dev->id); - - if ((cdb[7] < 0xc0) && (len <= CD_MAX_SECTORS)) { - cdrom_incompatible_format(dev); - cdrom_buf_free(dev); - return; - } - - memset(cdbufferb, 0, alloc_length); - - if ((cdb[7] <= 0x7f) || (cdb[7] == 0xff)) { - if (cdb[1] == 0) { - ret = cdrom_read_dvd_structure(dev, format, cdb, cdbufferb); - if (ret) { - cdrom_set_buf_len(dev, BufLen, &alloc_length); - cdrom_data_command_finish(dev, alloc_length, alloc_length, - len, 0); - } else - cdrom_buf_free(dev); - return; - } - } else { - cdrom_invalid_field(dev); - cdrom_buf_free(dev); - return; - } - break; - - case GPCMD_START_STOP_UNIT: - cdrom_set_phase(dev, SCSI_PHASE_STATUS); - - switch(cdb[4] & 3) { - case 0: /* Stop the disc. */ - if (dev->handler->stop) - dev->handler->stop(dev->id); - break; - case 1: /* Start the disc and read the TOC. */ - dev->handler->medium_changed(dev->id); /* This causes a TOC reload. */ - break; - case 2: /* Eject the disc if possible. */ - if (dev->handler->stop) - dev->handler->stop(dev->id); - cdrom_eject(dev->id); - break; - case 3: /* Load the disc (close tray). */ - cdrom_reload(dev->id); - break; - } - - cdrom_command_complete(dev); - break; - - case GPCMD_INQUIRY: - cdrom_set_phase(dev, SCSI_PHASE_DATA_IN); - - max_len = cdb[3]; - max_len <<= 8; - max_len |= cdb[4]; - - cdrom_buf_alloc(dev, 65536); - - if (cdb[1] & 1) { - preamble_len = 4; - size_idx = 3; - - cdbufferb[idx++] = 05; - cdbufferb[idx++] = cdb[2]; - cdbufferb[idx++] = 0; - - idx++; - - switch (cdb[2]) { - case 0x00: - cdbufferb[idx++] = 0x00; - cdbufferb[idx++] = 0x83; - break; - case 0x83: - if (idx + 24 > max_len) { - cdrom_data_phase_error(dev); - cdrom_buf_free(dev); - return; - } - - cdbufferb[idx++] = 0x02; - cdbufferb[idx++] = 0x00; - cdbufferb[idx++] = 0x00; - cdbufferb[idx++] = 20; - ide_padstr8(cdbufferb + idx, 20, "53R141"); /* Serial */ - idx += 20; - - if (idx + 72 > cdb[4]) - goto atapi_out; - cdbufferb[idx++] = 0x02; - cdbufferb[idx++] = 0x01; - cdbufferb[idx++] = 0x00; - cdbufferb[idx++] = 68; - ide_padstr8(cdbufferb + idx, 8, EMU_NAME); /* Vendor */ - idx += 8; - ide_padstr8(cdbufferb + idx, 40, device_identify_ex); /* Product */ - idx += 40; - ide_padstr8(cdbufferb + idx, 20, "53R141"); /* Product */ - idx += 20; - break; - default: - cdrom_log("INQUIRY: Invalid page: %02X\n", cdb[2]); - cdrom_invalid_field(dev); - cdrom_buf_free(dev); - return; - } - } else { - preamble_len = 5; - size_idx = 4; - - memset(cdbufferb, 0, 8); - cdbufferb[0] = 5; /*CD-ROM*/ - cdbufferb[1] = 0x80; /*Removable*/ - cdbufferb[2] = (dev->drv->bus_type == CDROM_BUS_SCSI) ? 0x02 : 0x00; /*SCSI-2 compliant*/ - cdbufferb[3] = (dev->drv->bus_type == CDROM_BUS_SCSI) ? 0x12 : 0x21; - cdbufferb[4] = 31; - if (dev->drv->bus_type == CDROM_BUS_SCSI) { - cdbufferb[6] = 1; /* 16-bit transfers supported */ - cdbufferb[7] = 0x20; /* Wide bus supported */ - } - - ide_padstr8(cdbufferb + 8, 8, EMU_NAME); /* Vendor */ - ide_padstr8(cdbufferb + 16, 16, device_identify); /* Product */ - ide_padstr8(cdbufferb + 32, 4, EMU_VERSION); /* Revision */ - idx = 36; - - if (max_len == 96) { - cdbufferb[4] = 91; - idx = 96; - } - } - -atapi_out: - cdbufferb[size_idx] = idx - preamble_len; - len=idx; - - len = MIN(len, max_len); - cdrom_set_buf_len(dev, BufLen, &len); - - cdrom_data_command_finish(dev, len, len, max_len, 0); - break; - - case GPCMD_PREVENT_REMOVAL: - cdrom_set_phase(dev, SCSI_PHASE_STATUS); - cdrom_command_complete(dev); - break; - - case GPCMD_PAUSE_RESUME_ALT: - case GPCMD_PAUSE_RESUME: - cdrom_set_phase(dev, SCSI_PHASE_STATUS); - - if (cdb[8] & 1) { - if (dev->handler->resume) - dev->handler->resume(dev->id); - else { - cdrom_illegal_mode(dev); - break; - } - } else { - if (dev->handler->pause) - dev->handler->pause(dev->id); - else { - cdrom_illegal_mode(dev); - break; - } - } - cdrom_command_complete(dev); - break; - - case GPCMD_SEEK_6: - case GPCMD_SEEK_10: - cdrom_set_phase(dev, SCSI_PHASE_STATUS); - - switch(cdb[0]) { - case GPCMD_SEEK_6: - pos = (cdb[2] << 8) | cdb[3]; - break; - case GPCMD_SEEK_10: - pos = (cdb[2] << 24) | (cdb[3]<<16) | (cdb[4]<<8) | cdb[5]; - break; - } - dev->seek_diff = ABS((int) (pos - dev->seek_pos)); - cdrom_seek(dev, pos); - cdrom_command_complete(dev); - break; - - case GPCMD_READ_CDROM_CAPACITY: - cdrom_set_phase(dev, SCSI_PHASE_DATA_IN); - - cdrom_buf_alloc(dev, 8); - - if (cdrom_read_capacity(dev, dev->current_cdb, cdbufferb, (uint32_t *) &len) == 0) { - cdrom_buf_free(dev); - return; - } - - cdrom_set_buf_len(dev, BufLen, &len); - - cdrom_data_command_finish(dev, len, len, len, 0); - break; - - case GPCMD_STOP_PLAY_SCAN: - cdrom_set_phase(dev, SCSI_PHASE_STATUS); - - if (dev->handler->stop) - dev->handler->stop(dev->id); - else { - cdrom_illegal_mode(dev); - break; - } - cdrom_command_complete(dev); - break; - - default: - cdrom_illegal_opcode(dev); - break; - } - - /* cdrom_log("CD-ROM %i: Phase: %02X, request length: %i\n", dev->phase, dev->request_length); */ - - if (cdrom_atapi_phase_to_scsi(dev) == SCSI_PHASE_STATUS) - cdrom_buf_free(dev); -} - - -/* The command second phase function, needed for Mode Select. */ -static uint8_t -cdrom_phase_data_out(cdrom_t *dev) -{ - uint16_t block_desc_len, pos; - uint16_t i = 0; - - uint8_t error = 0; - uint8_t page, page_len, hdr_len, val, old_val, ch; - - FILE *f; - - switch(dev->current_cdb[0]) { - case GPCMD_MODE_SELECT_6: - case GPCMD_MODE_SELECT_10: - f = nvr_fopen(L"modeselect.bin", L"wb"); - fwrite(cdbufferb, 1, dev->total_length, f); - fclose(f); - - if (dev->current_cdb[0] == GPCMD_MODE_SELECT_10) - hdr_len = 8; - else - hdr_len = 4; - - if (dev->drv->bus_type == CDROM_BUS_SCSI) { - if (dev->current_cdb[0] == GPCMD_MODE_SELECT_6) { - block_desc_len = cdbufferb[2]; - block_desc_len <<= 8; - block_desc_len |= cdbufferb[3]; - } else { - block_desc_len = cdbufferb[6]; - block_desc_len <<= 8; - block_desc_len |= cdbufferb[7]; - } - } else - block_desc_len = 0; - - pos = hdr_len + block_desc_len; - - while(1) { - page = cdbufferb[pos] & 0x3F; - page_len = cdbufferb[pos + 1]; - - pos += 2; - - if (!(cdrom_mode_sense_page_flags & (1LL << ((uint64_t) page)))) { - cdrom_log("Unimplemented page %02X\n", page); - error |= 1; - } else { - for (i = 0; i < page_len; i++) { - ch = cdrom_mode_sense_pages_changeable.pages[page][i + 2]; - val = cdbufferb[pos + i]; - old_val = dev->ms_pages_saved.pages[page][i + 2]; - if (val != old_val) { - if (ch) - dev->ms_pages_saved.pages[page][i + 2] = val; - else { - cdrom_log("Unchangeable value on position %02X on page %02X\n", i + 2, page); - error |= 1; - } - } - } - } - - pos += page_len; - - if (dev->drv->bus_type == CDROM_BUS_SCSI) - val = cdrom_mode_sense_pages_default_scsi.pages[page][0] & 0x80; - else - val = cdrom_mode_sense_pages_default.pages[page][0] & 0x80; - - if (dev->do_page_save && val) - cdrom_mode_sense_save(dev); - - if (pos >= dev->total_length) - break; - } - - if (error) { - cdrom_invalid_field_pl(dev); - return 0; - } - break; - } - - return 1; -} - - -/* This is the general ATAPI PIO request function. */ -static void -cdrom_pio_request(cdrom_t *dev, uint8_t out) -{ - int ret = 0; - - if (dev->drv->bus_type < CDROM_BUS_SCSI) { - cdrom_log("CD-ROM %i: Lowering IDE IRQ\n", dev->id); - ide_irq_lower(ide_drives[dev->drv->ide_channel]); - } - - dev->status = BUSY_STAT; - - if (dev->pos >= dev->packet_len) { - cdrom_log("CD-ROM %i: %i bytes %s, command done\n", dev->id, dev->pos, out ? "written" : "read"); - - dev->pos = dev->request_pos = 0; - if (out) { - ret = cdrom_phase_data_out(dev); - /* If ret = 0 (phase 1 error), then we do not do anything else other than - free the buffer, as the phase and callback have already been set by the - error function. */ - if (ret) - cdrom_command_complete(dev); - } else - cdrom_command_complete(dev); - cdrom_buf_free(dev); - } else { - cdrom_log("CD-ROM %i: %i bytes %s, %i bytes are still left\n", dev->id, dev->pos, - out ? "written" : "read", dev->packet_len - dev->pos); - - /* If less than (packet length) bytes are remaining, update packet length - accordingly. */ - if ((dev->packet_len - dev->pos) < (dev->max_transfer_len)) - dev->max_transfer_len = dev->packet_len - dev->pos; - cdrom_log("CD-ROM %i: Packet length %i, request length %i\n", dev->id, dev->packet_len, - dev->max_transfer_len); - - dev->packet_status = out ? CDROM_PHASE_DATA_OUT : CDROM_PHASE_DATA_IN; - - dev->status = BUSY_STAT; - dev->phase = 1; - cdrom_phase_callback(dev); - dev->callback = 0LL; - cdrom_set_callback(dev); - - dev->request_pos = 0; - } -} - - -static int -cdrom_read_from_ide_dma(uint8_t channel) -{ - cdrom_t *dev; - - uint8_t id = atapi_cdrom_drives[channel]; - int ret; - - if (id > CDROM_NUM) - return 0; - - dev = cdrom[id]; - - if (ide_bus_master_write) { - ret = ide_bus_master_write(channel >> 1, - cdbufferb, dev->packet_len, - ide_bus_master_priv[channel >> 1]); - if (ret == 2) /* DMA not enabled, wait for it to be enabled. */ - return 2; - else if (ret == 1) { /* DMA error. */ - cdrom_bus_master_error(dev); - return 0; - } else - return 1; - } else - return 0; - - return 0; -} - - -static int -cdrom_read_from_scsi_dma(uint8_t scsi_id) -{ - cdrom_t *dev; - - uint8_t id = scsi_cdrom_drives[scsi_id]; - int32_t *BufLen = &SCSIDevices[scsi_id].BufferLength; - - if (id > CDROM_NUM) - return 0; - - dev = cdrom[id]; - - cdrom_log("Reading from SCSI DMA: SCSI ID %02X, init length %i\n", scsi_id, *BufLen); - memcpy(cdbufferb, SCSIDevices[scsi_id].CmdBuffer, *BufLen); - return 1; -} - - -static void -cdrom_irq_raise(cdrom_t *dev) -{ - if (dev->drv->bus_type < CDROM_BUS_SCSI) - ide_irq_raise(ide_drives[dev->drv->ide_channel]); -} - - -static int -cdrom_read_from_dma(cdrom_t *dev) -{ - int32_t *BufLen = &SCSIDevices[dev->drv->scsi_device_id].BufferLength; - int ret = 0; - - if (dev->drv->bus_type == CDROM_BUS_SCSI) - ret = cdrom_read_from_scsi_dma(dev->drv->scsi_device_id); - else - ret = cdrom_read_from_ide_dma(dev->drv->ide_channel); - - if (ret != 1) - return ret; - - if (dev->drv->bus_type == CDROM_BUS_SCSI) - cdrom_log("CD-ROM %i: SCSI Input data length: %i\n", dev->id, *BufLen); - else - cdrom_log("CD-ROM %i: ATAPI Input data length: %i\n", dev->id, dev->packet_len); - - ret = cdrom_phase_data_out(dev); - - if (ret) - return 1; - else - return 0; -} - - -static int -cdrom_write_to_ide_dma(uint8_t channel) -{ - cdrom_t *dev; - - uint8_t id = atapi_cdrom_drives[channel]; - int ret; - - if (id > CDROM_NUM) - return 0; - - dev = cdrom[id]; - - if (ide_bus_master_read) { - ret = ide_bus_master_read(channel >> 1, - cdbufferb, dev->packet_len, - ide_bus_master_priv[channel >> 1]); - if (ret == 2) /* DMA not enabled, wait for it to be enabled. */ - return 2; - else if (ret == 1) { /* DMA error. */ - cdrom_bus_master_error(dev); - return 0; - } else - return 1; - } else - return 0; -} - - -static int -cdrom_write_to_scsi_dma(uint8_t scsi_id) -{ - cdrom_t *dev; - - uint8_t id = scsi_cdrom_drives[scsi_id]; - int32_t *BufLen = &SCSIDevices[scsi_id].BufferLength; - - if (id > CDROM_NUM) - return 0; - - dev = cdrom[id]; - - cdrom_log("Writing to SCSI DMA: SCSI ID %02X, init length %i\n", scsi_id, *BufLen); - memcpy(SCSIDevices[scsi_id].CmdBuffer, cdbufferb, *BufLen); - cdrom_log("CD-ROM %i: Data from CD buffer: %02X %02X %02X %02X %02X %02X %02X %02X\n", id, - cdbufferb[0], cdbufferb[1], cdbufferb[2], cdbufferb[3], cdbufferb[4], cdbufferb[5], - cdbufferb[6], cdbufferb[7]); - cdrom_log("CD-ROM %i: Data from SCSI DMA : %02X %02X %02X %02X %02X %02X %02X %02X\n", id, - SCSIDevices[scsi_id].CmdBuffer[0], SCSIDevices[scsi_id].CmdBuffer[1], - SCSIDevices[scsi_id].CmdBuffer[2], SCSIDevices[scsi_id].CmdBuffer[3], - SCSIDevices[scsi_id].CmdBuffer[4], SCSIDevices[scsi_id].CmdBuffer[5], - SCSIDevices[scsi_id].CmdBuffer[6], SCSIDevices[scsi_id].CmdBuffer[7]); - return 1; -} - - -static int -cdrom_write_to_dma(cdrom_t *dev) -{ - int32_t *BufLen = &SCSIDevices[dev->drv->scsi_device_id].BufferLength; - int ret = 0; - - if (dev->drv->bus_type == CDROM_BUS_SCSI) { - cdrom_log("Write to SCSI DMA: (ID %02X)\n", dev->drv->scsi_device_id); - ret = cdrom_write_to_scsi_dma(dev->drv->scsi_device_id); - } else - ret = cdrom_write_to_ide_dma(dev->drv->ide_channel); - - if (dev->drv->bus_type == CDROM_BUS_SCSI) - cdrom_log("CD-ROM %i: SCSI Output data length: %i\n", dev->id, *BufLen); - else - cdrom_log("CD-ROM %i: ATAPI Output data length: %i\n", dev->id, dev->packet_len); - - return ret; -} - - -void -cdrom_phase_callback(cdrom_t *dev) -{ - int ret; - - switch(dev->packet_status) { - case CDROM_PHASE_IDLE: - cdrom_log("CD-ROM %i: CDROM_PHASE_IDLE\n", dev->id); - dev->pos = 0; - dev->phase = 1; - dev->status = READY_STAT | DRQ_STAT | (dev->status & ERR_STAT); - return; - case CDROM_PHASE_COMMAND: - cdrom_log("CD-ROM %i: CDROM_PHASE_COMMAND\n", dev->id); - dev->status = BUSY_STAT | (dev->status & ERR_STAT); - memcpy(dev->atapi_cdb, cdbufferb, dev->cdb_len); - cdrom_command(dev, dev->atapi_cdb); - return; - case CDROM_PHASE_COMPLETE: - cdrom_log("CD-ROM %i: CDROM_PHASE_COMPLETE\n", dev->id); - dev->status = READY_STAT; - dev->phase = 3; - dev->packet_status = 0xFF; - ui_sb_update_icon(SB_CDROM | dev->id, 0); - cdrom_irq_raise(dev); - return; - case CDROM_PHASE_DATA_OUT: - cdrom_log("CD-ROM %i: CDROM_PHASE_DATA_OUT\n", dev->id); - dev->status = READY_STAT | DRQ_STAT | (dev->status & ERR_STAT); - dev->phase = 0; - cdrom_irq_raise(dev); - return; - case CDROM_PHASE_DATA_OUT_DMA: - cdrom_log("CD-ROM %i: CDROM_PHASE_DATA_OUT_DMA\n", dev->id); - ret = cdrom_read_from_dma(dev); - - if ((ret == 1) || (dev->drv->bus_type == CDROM_BUS_SCSI)) { - cdrom_log("CD-ROM %i: DMA data out phase done\n"); - cdrom_buf_free(dev); - cdrom_command_complete(dev); - } else if (ret == 2) { - cdrom_log("CD-ROM %i: DMA out not enabled, wait\n"); - cdrom_command_bus(dev); - } else { - cdrom_log("CD-ROM %i: DMA data out phase failure\n"); - cdrom_buf_free(dev); - } - return; - case CDROM_PHASE_DATA_IN: - cdrom_log("CD-ROM %i: CDROM_PHASE_DATA_IN\n", dev->id); - dev->status = READY_STAT | DRQ_STAT | (dev->status & ERR_STAT); - dev->phase = 2; - cdrom_irq_raise(dev); - return; - case CDROM_PHASE_DATA_IN_DMA: - cdrom_log("CD-ROM %i: CDROM_PHASE_DATA_IN_DMA\n", dev->id); - ret = cdrom_write_to_dma(dev); - - if ((ret == 1) || (dev->drv->bus_type == CDROM_BUS_SCSI)) { - cdrom_log("CD-ROM %i: DMA data in phase done\n", dev->id); - cdrom_buf_free(dev); - cdrom_command_complete(dev); - } else if (ret == 2) { - cdrom_log("CD-ROM %i: DMA in not enabled, wait\n", dev->id); - cdrom_command_bus(dev); - } else { - cdrom_log("CD-ROM %i: DMA data in phase failure\n", dev->id); - cdrom_buf_free(dev); - } - return; - case CDROM_PHASE_ERROR: - cdrom_log("CD-ROM %i: CDROM_PHASE_ERROR\n", dev->id); - dev->status = READY_STAT | ERR_STAT; - dev->phase = 3; - cdrom_irq_raise(dev); - ui_sb_update_icon(SB_CDROM | dev->id, 0); - return; - } -} - - -uint32_t -cdrom_read(uint8_t channel, int length) -{ - cdrom_t *dev; - - uint16_t *cdbufferw; - uint32_t *cdbufferl; - - uint8_t id = atapi_cdrom_drives[channel]; - - uint32_t temp = 0; - - if (id > CDROM_NUM) - return 0; - - dev = cdrom[id]; - - cdbufferw = (uint16_t *) cdbufferb; - cdbufferl = (uint32_t *) cdbufferb; - - if (!cdbufferb) - return 0; - - /* Make sure we return a 0 and don't attempt to read from the buffer if we're transferring bytes beyond it, - which can happen when issuing media access commands with an allocated length below minimum request length - (which is 1 sector = 2048 bytes). */ - switch(length) { - case 1: - temp = (dev->pos < dev->packet_len) ? cdbufferb[dev->pos] : 0; - dev->pos++; - dev->request_pos++; - break; - case 2: - temp = (dev->pos < dev->packet_len) ? cdbufferw[dev->pos >> 1] : 0; - dev->pos += 2; - dev->request_pos += 2; - break; - case 4: - temp = (dev->pos < dev->packet_len) ? cdbufferl[dev->pos >> 2] : 0; - dev->pos += 4; - dev->request_pos += 4; - break; - default: - return 0; - } - - if (dev->packet_status == CDROM_PHASE_DATA_IN) { - cdrom_log("CD-ROM %i: Returning: %04X (buffer position: %05i, request position: %05i)\n", - id, temp, (dev->pos - 2) & 0xffff, (dev->request_pos - 2) & 0xffff); - if ((dev->request_pos >= dev->max_transfer_len) || (dev->pos >= dev->packet_len)) { - /* Time for a DRQ. */ - cdrom_log("CD-ROM %i: Issuing read callback\n", id); - cdrom_pio_request(dev, 0); - } - return temp; - } else { - cdrom_log("CD-ROM %i: Returning: 0000 (buffer position: %05i, request position: %05i)\n", - id, (dev->pos - 2) & 0xffff, (dev->request_pos - 2) & 0xffff); - return 0; - } -} - - -void -cdrom_write(uint8_t channel, uint32_t val, int length) -{ - cdrom_t *dev; - - uint16_t *cdbufferw; - uint32_t *cdbufferl; - - uint8_t id = atapi_cdrom_drives[channel]; - - if (id > CDROM_NUM) - return; - - dev = cdrom[id]; - - if ((dev->packet_status == CDROM_PHASE_IDLE) && !cdbufferb) - cdrom_buf_alloc(dev, dev->cdb_len); - - cdbufferw = (uint16_t *) cdbufferb; - cdbufferl = (uint32_t *) cdbufferb; - - if (!cdbufferb) - return; - - switch(length) { - case 1: - cdbufferb[dev->pos] = val & 0xff; - dev->pos++; - dev->request_pos++; - break; - case 2: - cdbufferw[dev->pos >> 1] = val & 0xffff; - dev->pos += 2; - dev->request_pos += 2; - break; - case 4: - cdbufferl[dev->pos >> 2] = val; - dev->pos += 4; - dev->request_pos += 4; - break; - default: - return; - } - - if (dev->packet_status == CDROM_PHASE_DATA_OUT) { - if ((dev->request_pos >= dev->max_transfer_len) || (dev->pos >= dev->packet_len)) { - /* Time for a DRQ. */ - cdrom_pio_request(dev, 1); - } - return; - } else if (dev->packet_status == CDROM_PHASE_IDLE) { - if (dev->pos >= dev->cdb_len) { - dev->pos = 0; - dev->status = BUSY_STAT; - dev->packet_status = CDROM_PHASE_COMMAND; - timer_process(); - cdrom_phase_callback(dev); - timer_update_outstanding(); - } - return; - } -} - - /* Peform a master init on the entire module. */ void cdrom_global_init(void) { /* Clear the global data. */ - memset(cdrom, 0x00, sizeof(cdrom)); memset(cdrom_drives, 0x00, sizeof(cdrom_drives)); } +static void +cdrom_drive_reset(cdrom_drive_t *drv) +{ + drv->p = NULL; + drv->insert = NULL; + drv->get_volume = NULL; + drv->get_channel = NULL; + drv->close = NULL; +} + + void cdrom_hard_reset(void) { int c; - cdrom_t *dev; + cdrom_drive_t *drv; for (c = 0; c < CDROM_NUM; c++) { if (cdrom_drives[c].bus_type) { cdrom_log("CDROM hard_reset drive=%d\n", c); - if (!cdrom[c]) { - cdrom[c] = (cdrom_t *) malloc(sizeof(cdrom_t)); - memset(cdrom[c], 0, sizeof(cdrom_t)); - } + drv = &cdrom_drives[c]; + drv->id = c; - dev = cdrom[c]; + cdrom_drive_reset(drv); - /* Set the numerical ID because of ->handler and logging. */ - dev->id = c; + if ((drv->bus_type == CDROM_BUS_ATAPI) || (drv->bus_type == CDROM_BUS_SCSI)) + scsi_cdrom_drive_reset(c); - cdrom_init(dev); - - if (dev->drv->host_drive == 200) { + if (drv->host_drive == 200) { image_open(c, cdrom_image[c].image_path); image_reset(c); } else @@ -3225,8 +225,6 @@ cdrom_hard_reset(void) } } - build_atapi_cdrom_map(); - sound_cd_thread_reset(); } @@ -3234,9 +232,9 @@ cdrom_hard_reset(void) void cdrom_close_handler(uint8_t id) { - cdrom_t *dev = cdrom[id]; + cdrom_drive_t *dev = &cdrom_drives[id]; - switch (dev->drv->host_drive) { + switch (dev->host_drive) { case 200: image_close(id); break; @@ -3250,18 +248,15 @@ cdrom_close_handler(uint8_t id) void cdrom_close(void) { - cdrom_t *dev; int c; for (c = 0; c < CDROM_NUM; c++) { - dev = cdrom[c]; + if (cdrom_drives[c].handler) + cdrom_close_handler(c); - if (dev) { - if (dev->drv && dev->handler) - cdrom_close_handler(c); + if (cdrom_drives[c].close) + cdrom_drives[c].close(cdrom_drives[c].p); - free(cdrom[c]); - cdrom[c] = NULL; - } + cdrom_drive_reset(&cdrom_drives[c]); } } diff --git a/src/cdrom/cdrom.h b/src/cdrom/cdrom.h index 9f6f4d476..1bead62e3 100644 --- a/src/cdrom/cdrom.h +++ b/src/cdrom/cdrom.h @@ -6,10 +6,9 @@ * * This file is part of the 86Box distribution. * - * Implementation of the CD-ROM drive with SCSI(-like) - * commands, for both ATAPI and SCSI usage. + * Generic CD-ROM drive core header. * - * Version: @(#)cdrom.h 1.0.13 2018/06/18 + * Version: @(#)cdrom.h 1.0.14 2018/10/09 * * Author: Miran Grca, * @@ -27,21 +26,10 @@ #define CD_STATUS_PAUSED 3 #define CD_STATUS_STOPPED 4 -#define CDROM_PHASE_IDLE 0x00 -#define CDROM_PHASE_COMMAND 0x01 -#define CDROM_PHASE_COMPLETE 0x02 -#define CDROM_PHASE_DATA_IN 0x03 -#define CDROM_PHASE_DATA_IN_DMA 0x04 -#define CDROM_PHASE_DATA_OUT 0x05 -#define CDROM_PHASE_DATA_OUT_DMA 0x06 -#define CDROM_PHASE_ERROR 0x80 - #define BUF_SIZE 32768 #define CDROM_IMAGE 200 -#define CDROM_TIME (5LL * 100LL * (1LL << TIMER_SHIFT)) - enum { CDROM_BUS_DISABLED = 0, @@ -73,116 +61,67 @@ typedef struct { } CDROM; typedef struct { - int host_drive; - int prev_host_drive; + CDROM *handler; - unsigned int bus_type; /* 0 = ATAPI, 1 = SCSI */ + int16_t cd_buffer[BUF_SIZE]; uint8_t speed, ide_channel, - bus_mode; /* Bit 0 = PIO suported; + pad, bus_mode; /* Bit 0 = PIO suported; Bit 1 = DMA supportd. */ + int host_drive, prev_host_drive, + cd_status, prev_status, + cd_buflen, cd_state, + handler_inited, cur_speed, + id; - unsigned int scsi_device_id, sound_on; + unsigned int bus_type, /* 0 = ATAPI, 1 = SCSI */ + scsi_device_id, sound_on; + + uint32_t seek_pos, seek_diff, + cd_end, cdrom_capacity; + + void *p; + + void (*insert)(void *p); + uint32_t (*get_volume)(void *p, int channel); + uint32_t (*get_channel)(void *p, int channel); + void (*close)(void *p); } cdrom_drive_t; typedef struct { - mode_sense_pages_t ms_pages_saved; - - CDROM *handler; - cdrom_drive_t *drv; - - uint8_t previous_command, - error, features, - status, phase, - id, *buffer, - atapi_cdb[16], - current_cdb[16], - sense[256]; - - uint16_t request_length, max_transfer_len; - int16_t cd_buffer[BUF_SIZE]; - - int media_status, is_dma, - packet_status, requested_blocks, - current_page_len, current_page_pos, - mode_select_phase, do_page_save, - total_length, written_length, - callback, data_pos, - cd_status, prev_status, - unit_attention, request_pos, - total_read, cur_speed, - block_total, all_blocks_total, - old_len, block_descriptor_len, - init_length, last_subchannel_pos, - cd_buflen, cd_state, - handler_inited, disc_changed; - - uint32_t sector_pos, sector_len, - seek_pos, seek_diff, - pos, packet_len, - cdb_len, cd_end, - cdrom_capacity; - - uint64_t current_page_code; -} cdrom_t; - -typedef struct { - int image_is_iso; wchar_t image_path[1024], *prev_image_path; FILE* image; + + int image_is_iso; } cdrom_image_t; -extern cdrom_t *cdrom[CDROM_NUM]; extern cdrom_drive_t cdrom_drives[CDROM_NUM]; extern cdrom_image_t cdrom_image[CDROM_NUM]; -extern uint8_t atapi_cdrom_drives[8]; -extern uint8_t scsi_cdrom_drives[16]; - -#define cdrom_sense_error dev->sense[0] -#define cdrom_sense_key dev->sense[2] -#define cdrom_asc dev->sense[12] -#define cdrom_ascq dev->sense[13] -#define cdrom_drive cdrom_drives[id].host_drive #ifdef __cplusplus extern "C" { #endif -extern int (*ide_bus_master_read)(int channel, uint8_t *data, int transfer_length, void *priv); -extern int (*ide_bus_master_write)(int channel, uint8_t *data, int transfer_length, void *priv); -extern void (*ide_bus_master_set_irq)(int channel, void *priv); -extern void *ide_bus_master_priv[2]; - -extern uint32_t cdrom_mode_sense_get_channel(cdrom_t *dev, int channel); -extern uint32_t cdrom_mode_sense_get_volume(cdrom_t *dev, int channel); -extern void build_atapi_cdrom_map(void); -extern void build_scsi_cdrom_map(void); -extern int cdrom_CDROM_PHASE_to_scsi(cdrom_t *dev); -extern int cdrom_atapi_phase_to_scsi(cdrom_t *dev); -extern void cdrom_command(cdrom_t *dev, uint8_t *cdb); -extern void cdrom_phase_callback(cdrom_t *dev); -extern uint32_t cdrom_read(uint8_t channel, int length); -extern void cdrom_write(uint8_t channel, uint32_t val, int length); - extern int cdrom_lba_to_msf_accurate(int lba); +extern double cdrom_get_short_seek(cdrom_drive_t *dev); +extern double cdrom_get_long_seek(cdrom_drive_t *dev); +extern double cdrom_seek_time(cdrom_drive_t *dev); +extern void cdrom_seek(cdrom_drive_t *dev, uint32_t pos); +extern int cdrom_playing_completed(cdrom_drive_t *dev); extern void cdrom_close_handler(uint8_t id); extern void cdrom_close(void); -extern void cdrom_reset(cdrom_t *dev); -extern void cdrom_set_signature(cdrom_t *dev); -extern void cdrom_request_sense_for_scsi(cdrom_t *dev, uint8_t *buffer, uint8_t alloc_length); extern void cdrom_update_cdb(uint8_t *cdb, int lba_pos, int number_of_blocks); -extern void cdrom_insert(cdrom_t *dev); extern int find_cdrom_for_scsi_id(uint8_t scsi_id); -extern int cdrom_read_capacity(cdrom_t *dev, uint8_t *cdb, uint8_t *buffer, uint32_t *len); extern void cdrom_global_init(void); extern void cdrom_global_reset(void); extern void cdrom_hard_reset(void); +extern void scsi_cdrom_drive_reset(int c); #ifdef __cplusplus } diff --git a/src/cdrom/cdrom_image.cc b/src/cdrom/cdrom_image.cc index 230fd6e4a..0b05fe8d9 100644 --- a/src/cdrom/cdrom_image.cc +++ b/src/cdrom/cdrom_image.cc @@ -8,7 +8,7 @@ * * CD-ROM image support. * - * Version: @(#)cdrom_image.cc 1.0.1 2018/10/02 + * Version: @(#)cdrom_image.cc 1.0.2 2018/10/09 * * Author: RichardG867, * Miran Grca, @@ -138,10 +138,10 @@ cdrom_image_log(const char *format, ...) int image_audio_callback(uint8_t id, int16_t *output, int len) { - cdrom_t *dev = cdrom[id]; + cdrom_drive_t *dev = &cdrom_drives[id]; int ret = 1; - if (!cdrom_drives[id].sound_on || (dev->cd_state != CD_PLAYING) || cdrom_image[id].image_is_iso) { + if (!dev->sound_on || (dev->cd_state != CD_PLAYING) || cdrom_image[id].image_is_iso) { cdrom_image_log("image_audio_callback(i): Not playing\n", id); if (dev->cd_state == CD_PLAYING) dev->seek_pos += (len >> 11); @@ -179,7 +179,7 @@ image_audio_callback(uint8_t id, int16_t *output, int len) void image_audio_stop(uint8_t id) { - cdrom_t *dev = cdrom[id]; + cdrom_drive_t *dev = &cdrom_drives[id]; dev->cd_state = CD_STOPPED; } @@ -188,7 +188,7 @@ image_audio_stop(uint8_t id) static uint8_t image_playaudio(uint8_t id, uint32_t pos, uint32_t len, int ismsf) { - cdrom_t *dev = cdrom[id]; + cdrom_drive_t *dev = &cdrom_drives[id]; if (!cdimg[id]) return 0; int number; @@ -245,7 +245,7 @@ image_playaudio(uint8_t id, uint32_t pos, uint32_t len, int ismsf) static void image_pause(uint8_t id) { - cdrom_t *dev = cdrom[id]; + cdrom_drive_t *dev = &cdrom_drives[id]; if (!cdimg[id] || cdrom_image[id].image_is_iso) return; if (dev->cd_state == CD_PLAYING) @@ -256,7 +256,7 @@ image_pause(uint8_t id) static void image_resume(uint8_t id) { - cdrom_t *dev = cdrom[id]; + cdrom_drive_t *dev = &cdrom_drives[id]; if (!cdimg[id] || cdrom_image[id].image_is_iso) return; @@ -268,7 +268,7 @@ image_resume(uint8_t id) static void image_stop(uint8_t id) { - cdrom_t *dev = cdrom[id]; + cdrom_drive_t *dev = &cdrom_drives[id]; if (!cdimg[id] || cdrom_image[id].image_is_iso) return; @@ -322,7 +322,7 @@ image_medium_changed(uint8_t id) static uint8_t image_getcurrentsubchannel(uint8_t id, uint8_t *b, int msf) { - cdrom_t *dev = cdrom[id]; + cdrom_drive_t *dev = &cdrom_drives[id]; uint8_t ret; int pos = 0; uint32_t cdpos; @@ -837,7 +837,7 @@ image_readsector_raw(uint8_t id, uint8_t *buffer, int sector, int ismsf, int cdr static uint32_t image_size(uint8_t id) { - cdrom_t *dev = cdrom[id]; + cdrom_drive_t *dev = &cdrom_drives[id]; return dev->cdrom_capacity; } @@ -987,7 +987,7 @@ image_readtoc_raw(uint8_t id, unsigned char *b, int maxlen) static int image_status(uint8_t id) { - cdrom_t *dev = cdrom[id]; + cdrom_drive_t *dev = &cdrom_drives[id]; if (!cdimg[id]) return CD_STATUS_EMPTY; @@ -1021,7 +1021,7 @@ image_reset(UNUSED(uint8_t id)) void image_close(uint8_t id) { - cdrom_t *dev = cdrom[id]; + cdrom_drive_t *dev = &cdrom_drives[id]; dev->cd_state = CD_STOPPED; if (cdimg[id]) { @@ -1034,7 +1034,7 @@ image_close(uint8_t id) int image_open(uint8_t id, wchar_t *fn) { - cdrom_t *dev = cdrom[id]; + cdrom_drive_t *dev = &cdrom_drives[id]; wcscpy(cdrom_image[id].image_path, fn); @@ -1049,14 +1049,14 @@ image_open(uint8_t id, wchar_t *fn) if (!cdimg[id]->SetDevice(afn, false)) { image_close(id); cdrom_set_null_handler(id); - cdrom_image_log("[f] image_open(): cdrom[%i]->handler = %08X\n", id, cdrom[id]->handler); + cdrom_image_log("[f] image_open(): cdrom_drives[%i].handler = %08X\n", id, cdrom_drives[id].handler); return 1; } dev->cd_state = CD_STOPPED; dev->seek_pos = 0; dev->cd_buflen = 0; dev->cdrom_capacity = image_get_last_block(id) + 1; - cdrom[id]->handler = &image_cdrom; + cdrom_drives[id].handler = &image_cdrom; return 0; } @@ -1065,7 +1065,7 @@ image_open(uint8_t id, wchar_t *fn) static void image_exit(uint8_t id) { - cdrom_t *dev = cdrom[id]; + cdrom_drive_t *dev = &cdrom_drives[id]; dev->handler_inited = 0; } diff --git a/src/cdrom/cdrom_null.c b/src/cdrom/cdrom_null.c index da5e0db5e..7479e1230 100644 --- a/src/cdrom/cdrom_null.c +++ b/src/cdrom/cdrom_null.c @@ -9,7 +9,7 @@ * Implementation of the CD-ROM null interface for unmounted * guest CD-ROM drives. * - * Version: @(#)cdrom_null.c 1.0.8 2018/10/02 + * Version: @(#)cdrom_null.c 1.0.9 2018/10/09 * * Authors: Sarah Walker, * Miran Grca, @@ -134,7 +134,7 @@ null_media_type_id(uint8_t id) void cdrom_set_null_handler(uint8_t id) { - cdrom[id]->handler = &null_cdrom; + cdrom_drives[id].handler = &null_cdrom; cdrom_drives[id].host_drive = 0; memset(cdrom_image[id].image_path, 0, sizeof(cdrom_image[id].image_path)); } diff --git a/src/device.c b/src/device.c index c2b508399..663a6a331 100644 --- a/src/device.c +++ b/src/device.c @@ -9,7 +9,7 @@ * Implementation of the generic device interface to handle * all devices attached to the emulator. * - * Version: @(#)device.c 1.0.17 2018/10/02 + * Version: @(#)device.c 1.0.18 2018/10/10 * * Authors: Fred N. van Kempen, * Miran Grca, @@ -217,8 +217,10 @@ device_close_all(void) { int c; - for (c = 0; c < DEVICE_MAX; c++) { + for (c = (DEVICE_MAX - 1); c >= 0; c--) { if (devices[c] != NULL) { + if (devices[c]->name) + devicelog("Closing device: \"%s\"...\n", devices[c]->name); if (devices[c]->close != NULL) devices[c]->close(device_priv[c]); devices[c] = device_priv[c] = NULL; diff --git a/src/disk/hdc_ide.c b/src/disk/hdc_ide.c index 2ba635c31..e3d9015e1 100644 --- a/src/disk/hdc_ide.c +++ b/src/disk/hdc_ide.c @@ -9,7 +9,7 @@ * Implementation of the IDE emulation for hard disks and ATAPI * CD-ROM devices. * - * Version: @(#)hdc_ide.c 1.0.49 2018/10/02 + * Version: @(#)hdc_ide.c 1.0.50 2018/10/10 * * Authors: Sarah Walker, * Miran Grca, @@ -109,26 +109,6 @@ #define FEATURE_DISABLE_IRQ_OVERLAPPED 0xdd #define FEATURE_DISABLE_IRQ_SERVICE 0xde -#if 0 -/* In the future, there's going to be just the IDE_ATAPI type, - leaving it to the common ATAPI/SCSI device handler to know - what type the device is. */ -enum -{ - IDE_NONE = 0, - IDE_HDD, - IDE_ATAPI -}; -#else -enum -{ - IDE_NONE = 0, - IDE_HDD, - IDE_CDROM, - IDE_ZIP -}; -#endif - #define IDE_PCI (PCI && pio_override) @@ -296,40 +276,17 @@ ide_get_seek_time(ide_t *ide, uint32_t new_pos) int -ide_drive_is_cdrom(ide_t *ide) +ide_drive_is_atapi(ide_t *ide) { int ch = ide->channel; if (ch >= 8) return 0; - if (atapi_cdrom_drives[ch] >= CDROM_NUM) + if (ide->type == IDE_ATAPI) + return 1; + else return 0; - else { - if (cdrom_drives[atapi_cdrom_drives[ch]].bus_type == CDROM_BUS_ATAPI) - return 1; - else - return 0; - } -} - - -int -ide_drive_is_zip(ide_t *ide) -{ - int ch = ide->channel; - - if (ch >= 8) - return 0; - - if (atapi_zip_drives[ch] >= ZIP_NUM) - return 0; - else { - if (zip_drives[atapi_zip_drives[ch]].bus_type == ZIP_BUS_ATAPI) - return 1; - else - return 0; - } } @@ -381,7 +338,7 @@ ide_irq_lower(ide_t *ide) * @param len Length of destination buffer to fill in. Strings shorter than * this length will be padded with spaces. */ -static void +void ide_padstr(char *str, const char *src, int len) { int i, v; @@ -418,51 +375,29 @@ void ide_padstr8(uint8_t *buf, int buf_size, const char *src) } -/* Type: - 0 = PIO, - 1 = SDMA, - 2 = MDMA, - 3 = UDMA - Return: - -1 = Not supported, - Anything else = maximum mode - - This will eventually be hookable. */ -enum { - TYPE_PIO = 0, - TYPE_SDMA, - TYPE_MDMA, - TYPE_UDMA -}; - static int ide_get_max(ide_t *ide, int type) { + if (ide_drive_is_atapi(ide)) + return ide->get_max(!IDE_PCI || (ide->board >= 2), type); + switch(type) { case TYPE_PIO: /* PIO */ if (!IDE_PCI || (ide->board >= 2)) return 0; /* Maximum PIO 0 for legacy PIO-only drive. */ - else { - if (ide_drive_is_zip(ide)) - return 3; - else - return 4; - } + else + return 4; break; case TYPE_SDMA: /* SDMA */ - if (!IDE_PCI || (ide->board >= 2) || ide_drive_is_zip(ide)) + if (!IDE_PCI || (ide->board >= 2)) return -1; else return 2; case TYPE_MDMA: /* MDMA */ if (!IDE_PCI || (ide->board >= 2)) return -1; - else { - if (ide_drive_is_zip(ide)) - return 1; - else - return 2; - } + else + return 2; case TYPE_UDMA: /* UDMA */ if (!IDE_PCI || (ide->board >= 2)) return -1; @@ -475,50 +410,27 @@ ide_get_max(ide_t *ide, int type) } -/* Return: - 0 = Not supported, - Anything else = timings - - This will eventually be hookable. */ -enum { - TIMINGS_DMA = 0, - TIMINGS_PIO, - TIMINGS_PIO_FC -}; - static int ide_get_timings(ide_t *ide, int type) { + if (ide_drive_is_atapi(ide)) + return ide->get_timings(!IDE_PCI || (ide->board >= 2), type); + switch(type) { case TIMINGS_DMA: if (!IDE_PCI || (ide->board >= 2)) return 0; - else { - if (ide_drive_is_zip(ide)) - return 0x96; - else - return 120; - } + else + return 120; break; case TIMINGS_PIO: if (!IDE_PCI || (ide->board >= 2)) return 0; - else { - if (ide_drive_is_zip(ide)) - return 0xb4; - else - return 120; - } + else + return 120; break; case TIMINGS_PIO_FC: - if (!IDE_PCI || (ide->board >= 2)) - return 0; - else { - if (ide_drive_is_zip(ide)) - return 0xb4; - else - return 0; - } + return 0; break; default: fatal("Unknown transfer type: %i\n", type); @@ -621,81 +533,6 @@ static void ide_hd_identify(ide_t *ide) } -/** - * Fill in ide->buffer with the output of the "IDENTIFY PACKET DEVICE" command - */ -static void -ide_atapi_cdrom_identify(ide_t *ide) -{ - char device_identify[9] = { '8', '6', 'B', '_', 'C', 'D', '0', '0', 0 }; - - uint8_t cdrom_id; - - cdrom_id = atapi_cdrom_drives[ide->channel]; - - device_identify[7] = cdrom_id + 0x30; - ide_log("ATAPI Identify: %s\n", device_identify); - - ide->buffer[0] = 0x8000 | (5<<8) | 0x80 | (2<<5); /* ATAPI device, CD-ROM drive, removable media, accelerated DRQ */ - ide_padstr((char *) (ide->buffer + 10), "", 20); /* Serial Number */ -#if 0 - ide_padstr((char *) (ide->buffer + 23), EMU_VERSION, 8); /* Firmware */ - ide_padstr((char *) (ide->buffer + 27), device_identify, 40); /* Model */ -#else - ide_padstr((char *) (ide->buffer + 23), "4.20 ", 8); /* Firmware */ - ide_padstr((char *) (ide->buffer + 27), "NEC CD-ROM DRIVE:273 ", 40); /* Model */ -#endif - ide->buffer[49] = 0x200; /* LBA supported */ - ide->buffer[126] = 0xfffe; /* Interpret zero byte count limit as maximum length */ - - if (IDE_PCI && (ide->board < 2)) { - ide->buffer[71] = 30; - ide->buffer[72] = 30; - } -} - - -static void -ide_atapi_zip_100_identify(ide_t *ide) -{ - ide_padstr((char *) (ide->buffer + 23), "E.08", 8); /* Firmware */ - ide_padstr((char *) (ide->buffer + 27), "IOMEGA ZIP 100 ATAPI", 40); /* Model */ -} - - -static void -ide_atapi_zip_250_identify(ide_t *ide) -{ - ide_padstr((char *) (ide->buffer + 23), "42.S", 8); /* Firmware */ - ide_padstr((char *) (ide->buffer + 27), "IOMEGA ZIP 250 ATAPI", 40); /* Model */ - - if (IDE_PCI && (ide->board < 2)) { - ide->buffer[80] = 0x30; /*Supported ATA versions : ATA/ATAPI-4 ATA/ATAPI-5*/ - ide->buffer[81] = 0x15; /*Maximum ATA revision supported : ATA/ATAPI-5 T13 1321D revision 1*/ - } -} - - -static void -ide_atapi_zip_identify(ide_t *ide) -{ - uint8_t zip_id; - - zip_id = atapi_zip_drives[ide->channel]; - - /* Using (2<<5) below makes the ASUS P/I-P54TP4XE misdentify the ZIP drive - as a LS-120. */ - ide->buffer[0] = 0x8000 | (0<<8) | 0x80 | (1<<5); /* ATAPI device, direct-access device, removable media, interrupt DRQ */ - ide_padstr((char *) (ide->buffer + 10), "", 20); /* Serial Number */ - ide->buffer[49] = 0x200; /* LBA supported */ - ide->buffer[126] = 0xfffe; /* Interpret zero byte count limit as maximum length */ - - if (zip_drives[zip_id].is_250) - ide_atapi_zip_250_identify(ide); - else - ide_atapi_zip_100_identify(ide); -} - static void ide_identify(ide_t *ide) { @@ -705,10 +542,8 @@ ide_identify(ide_t *ide) memset(ide->buffer, 0, 512); - if (ide_drive_is_cdrom(ide)) - ide_atapi_cdrom_identify(ide); - else if (ide_drive_is_zip(ide)) - ide_atapi_zip_identify(ide); + if (ide_drive_is_atapi(ide)) + ide->identify(ide, IDE_PCI && (ide->board < 2)); else if (ide->type != IDE_NONE) ide_hd_identify(ide); else { @@ -838,20 +673,15 @@ loadhd(ide_t *ide, int d, const wchar_t *fn) void ide_set_signature(ide_t *ide) { - uint8_t cdrom_id = atapi_cdrom_drives[ide->channel]; - uint8_t zip_id = atapi_zip_drives[ide->channel]; + scsi_device_data_t *atapi = (scsi_device_data_t *) ide->p; ide->sector=1; ide->head=0; - if (ide_drive_is_zip(ide)) { - zip_set_signature(zip[zip_id]); - ide->secount = zip[zip_id]->phase; - ide->cylinder = zip[zip_id]->request_length; - } else if (ide_drive_is_cdrom(ide)) { - cdrom_set_signature(cdrom[cdrom_id]); - ide->secount = cdrom[cdrom_id]->phase; - ide->cylinder = cdrom[cdrom_id]->request_length; + if (ide_drive_is_atapi(ide)) { + ide->set_signature(ide->p); + ide->secount = atapi->phase; + ide->cylinder = atapi->request_length; } else { ide->secount=1; ide->cylinder=((ide->type == IDE_HDD) ? 0 : 0xFFFF); @@ -987,6 +817,7 @@ ide_board_close(int board) { ide_t *dev; int c, d; + scsi_device_data_t *atapi; /* Close hard disk image files (if previously open) */ for (d = 0; d < 2; d++) { @@ -997,10 +828,10 @@ ide_board_close(int board) hdd_image_close(dev->hdd_num); if (board < 4) { - if (ide_drive_is_zip(dev)) - zip[atapi_zip_drives[c]]->status = DRDY_STAT | DSC_STAT; - else if (ide_drive_is_cdrom(dev)) - cdrom[atapi_cdrom_drives[c]]->status = DRDY_STAT | DSC_STAT; + if (ide_drive_is_atapi(dev)) { + atapi = (scsi_device_data_t *) dev->p; + atapi->status = DRDY_STAT | DSC_STAT; + } } if (dev->buffer) @@ -1015,13 +846,38 @@ ide_board_close(int board) } +void +ide_allocate_buffer(ide_t *dev) +{ + if (dev->buffer) + return; + + dev->buffer = (uint16_t *) malloc(65536 * sizeof(uint16_t)); + memset(dev->buffer, 0, 65536 * sizeof(uint16_t)); +} + + +void +ide_atapi_attach(ide_t *dev) +{ + if (dev->type != IDE_NONE) + return; + + dev->type = IDE_ATAPI; + ide_allocate_buffer(dev); + ide_set_signature(dev); + dev->mdma_mode = (1 << dev->get_max(!IDE_PCI || (dev->board >= 2), TYPE_PIO)); + dev->error = 1; + dev->cfg_spt = dev->cfg_hpc = 0; +} + + static void ide_board_init(int board) { ide_t *dev; int c, d; - int max, ch; - int is_ide, valid_ch; + int ch, is_ide, valid_ch; int min_ch, max_ch; min_ch = (board << 1); @@ -1058,22 +914,14 @@ ide_board_init(int board) c = (board << 1) + d; dev = ide_drives[c]; - if (board < 4) { - if (ide_drive_is_zip(dev) && (dev->type == IDE_NONE)) - dev->type = IDE_ZIP; - else if (ide_drive_is_cdrom(dev) && (dev->type == IDE_NONE)) - dev->type = IDE_CDROM; - } + if (dev->type == IDE_NONE) + continue; - if (dev->type != IDE_NONE) { - dev->buffer = (uint16_t *) malloc(65536 * sizeof(uint16_t)); - memset(dev->buffer, 0, 65536 * sizeof(uint16_t)); - } + ide_allocate_buffer(dev); ide_set_signature(dev); - max = ide_get_max(dev, TYPE_PIO); - dev->mdma_mode = (1 << max); + dev->mdma_mode = (1 << ide_get_max(dev, TYPE_PIO)); dev->error = 1; dev->cfg_spt = dev->cfg_hpc = 0; } @@ -1102,8 +950,6 @@ ide_set_callback(uint8_t board, int64_t callback) void ide_write_data(ide_t *ide, uint32_t val, int length) { - int ch = ide->channel; - uint8_t *idebufferb = (uint8_t *) ide->buffer; uint16_t *idebufferw = ide->buffer; uint32_t *idebufferl = (uint32_t *) ide->buffer; @@ -1111,13 +957,11 @@ ide_write_data(ide_t *ide, uint32_t val, int length) if (ide->command == WIN_PACKETCMD) { ide->pos = 0; - if (!ide_drive_is_zip(ide) && !ide_drive_is_cdrom(ide)) + if (!ide_drive_is_atapi(ide)) return; - if (ide_drive_is_zip(ide)) - zip_write(ch, val, length); - else - cdrom_write(ch, val, length); + if (ide_drive_is_atapi(ide)) + ide->packet_write(ide->p, val, length); return; } else { switch(length) { @@ -1208,6 +1052,7 @@ void ide_write_devctl(uint16_t addr, uint8_t val, void *priv) { ide_board_t *dev = (ide_board_t *) priv; + scsi_device_data_t *atapi; ide_t *ide, *ide_other; int ch; @@ -1219,11 +1064,11 @@ ide_write_devctl(uint16_t addr, uint8_t val, void *priv) ide_log("ide_write_devctl %04X %02X from %04X(%08X):%08X\n", addr, val, CS, cs, cpu_state.pc); if ((ide->fdisk & 4) && !(val&4) && (ide->type != IDE_NONE || ide_other->type != IDE_NONE)) { + atapi = (scsi_device_data_t *) ide->p; + timer_process(); - if (ide_drive_is_zip(ide)) - zip[atapi_zip_drives[ide->channel]]->callback = 0LL; - else if (ide_drive_is_cdrom(ide)) - cdrom[atapi_cdrom_drives[ide->channel]]->callback = 0LL; + if (ide_drive_is_atapi(ide)) + atapi->callback = 0LL; ide_set_callback(ide->board, 500LL * IDE_TIME); timer_update_outstanding(); @@ -1231,10 +1076,8 @@ ide_write_devctl(uint16_t addr, uint8_t val, void *priv) ide->reset = 1; if (ide_other->type != IDE_NONE) ide->reset = 1; - if (ide_drive_is_zip(ide)) - zip[atapi_zip_drives[ide->channel]]->status = BSY_STAT; - else if (ide_drive_is_cdrom(ide)) - cdrom[atapi_cdrom_drives[ide->channel]]->status = BSY_STAT; + if (ide_drive_is_atapi(ide)) + atapi->status = BSY_STAT; ide->atastat = ide_other->atastat = BSY_STAT; } @@ -1254,6 +1097,7 @@ void ide_writeb(uint16_t addr, uint8_t val, void *priv) { ide_board_t *dev = (ide_board_t *) priv; + scsi_device_data_t *atapi, *atapi_other; ide_t *ide, *ide_other; int ch; @@ -1269,6 +1113,9 @@ ide_writeb(uint16_t addr, uint8_t val, void *priv) if ((ide->type == IDE_NONE) && ((addr == 0x0) || (addr == 0x7))) return; + atapi = (scsi_device_data_t *) ide->p; + atapi_other = (scsi_device_data_t *) ide_other->p; + switch (addr) { case 0x0: /* Data */ ide_write_data(ide, val | (val << 8), 2); @@ -1276,38 +1123,27 @@ ide_writeb(uint16_t addr, uint8_t val, void *priv) /* Note to self: for ATAPI, bit 0 of this is DMA if set, PIO if clear. */ case 0x1: /* Features */ - if (ide_drive_is_zip(ide)) { + if (ide_drive_is_atapi(ide)) { ide_log("ATAPI transfer mode: %s\n", (val & 1) ? "DMA" : "PIO"); - zip[atapi_zip_drives[ch]]->features = val; - } else if (ide_drive_is_cdrom(ide)) { - ide_log("ATAPI transfer mode: %s\n", (val & 1) ? "DMA" : "PIO"); - cdrom[atapi_cdrom_drives[ch]]->features = val; + atapi->features = val; } ide->cylprecomp = val; - if (ide_drive_is_zip(ide_other)) - zip[atapi_zip_drives[ch ^ 1]]->features = val; - else if (ide_drive_is_cdrom(ide_other)) - cdrom[atapi_cdrom_drives[ch ^ 1]]->features = val; + if (ide_drive_is_atapi(ide_other)) + atapi_other->features = val; ide_other->cylprecomp = val; return; case 0x2: /* Sector count */ - if (ide_drive_is_zip(ide)) { + if (ide_drive_is_atapi(ide)) { ide_log("Sector count write: %i\n", val); - zip[atapi_zip_drives[ch]]->phase = val; - } else if (ide_drive_is_cdrom(ide)) { - ide_log("Sector count write: %i\n", val); - cdrom[atapi_cdrom_drives[ch]]->phase = val; + atapi->phase = val; } ide->secount = val; - if (ide_drive_is_zip(ide_other)) { + if (ide_drive_is_atapi(ide_other)) { ide_log("Other sector count write: %i\n", val); - zip[atapi_zip_drives[ch ^ 1]]->phase = val; - } else if (ide_drive_is_cdrom(ide_other)) { - ide_log("Other sector count write: %i\n", val); - cdrom[atapi_cdrom_drives[ch ^ 1]]->phase = val; + atapi_other->phase = val; } ide_other->secount = val; return; @@ -1320,44 +1156,32 @@ ide_writeb(uint16_t addr, uint8_t val, void *priv) return; case 0x4: /* Cylinder low */ - if (ide_drive_is_zip(ide)) { - zip[atapi_zip_drives[ch]]->request_length &= 0xFF00; - zip[atapi_zip_drives[ch]]->request_length |= val; - } else if (ide_drive_is_cdrom(ide)) { - cdrom[atapi_cdrom_drives[ch]]->request_length &= 0xFF00; - cdrom[atapi_cdrom_drives[ch]]->request_length |= val; + if (ide_drive_is_atapi(ide)) { + atapi->request_length &= 0xFF00; + atapi->request_length |= val; } ide->cylinder = (ide->cylinder & 0xFF00) | val; ide->lba_addr = (ide->lba_addr & 0xFFF00FF) | (val << 8); - if (ide_drive_is_zip(ide_other)) { - zip[atapi_zip_drives[ch ^ 1]]->request_length &= 0xFF00; - zip[atapi_zip_drives[ch ^ 1]]->request_length |= val; - } else if (ide_drive_is_cdrom(ide_other)) { - cdrom[atapi_cdrom_drives[ch ^ 1]]->request_length &= 0xFF00; - cdrom[atapi_cdrom_drives[ch ^ 1]]->request_length |= val; + if (ide_drive_is_atapi(ide_other)) { + atapi_other->request_length &= 0xFF00; + atapi_other->request_length |= val; } ide_other->cylinder = (ide_other->cylinder & 0xFF00) | val; ide_other->lba_addr = (ide_other->lba_addr & 0xFFF00FF) | (val << 8); return; case 0x5: /* Cylinder high */ - if (ide_drive_is_zip(ide)) { - zip[atapi_zip_drives[ch]]->request_length &= 0xFF; - zip[atapi_zip_drives[ch]]->request_length |= (val << 8); - } else if (ide_drive_is_cdrom(ide)) { - cdrom[atapi_cdrom_drives[ch]]->request_length &= 0xFF; - cdrom[atapi_cdrom_drives[ch]]->request_length |= (val << 8); + if (ide_drive_is_atapi(ide)) { + atapi->request_length &= 0xFF; + atapi->request_length |= (val << 8); } ide->cylinder = (ide->cylinder & 0xFF) | (val << 8); ide->lba_addr = (ide->lba_addr & 0xF00FFFF) | (val << 16); - if (ide_drive_is_zip(ide_other)) { - zip[atapi_zip_drives[ch ^ 1]]->request_length &= 0xFF; - zip[atapi_zip_drives[ch ^ 1]]->request_length |= (val << 8); - } else if (ide_drive_is_cdrom(ide_other)) { - cdrom[atapi_cdrom_drives[ch ^ 1]]->request_length &= 0xFF; - cdrom[atapi_cdrom_drives[ch ^ 1]]->request_length |= (val << 8); + if (ide_drive_is_atapi(ide_other)) { + atapi_other->request_length &= 0xFF; + atapi_other->request_length |= (val << 8); } ide_other->cylinder = (ide_other->cylinder & 0xFF) | (val << 8); ide_other->lba_addr = (ide_other->lba_addr & 0xF00FFFF) | (val << 16); @@ -1377,35 +1201,21 @@ ide_writeb(uint16_t addr, uint8_t val, void *priv) ide->cylinder = ide_other->cylinder = 0; ide->reset = ide_other->reset = 0; - if (ide_drive_is_zip(ide)) { - zip[atapi_zip_drives[ide->channel]]->status = DRDY_STAT | DSC_STAT; - zip[atapi_zip_drives[ide->channel]]->error = 1; - zip[atapi_zip_drives[ide->channel]]->phase = 1; - zip[atapi_zip_drives[ide->channel]]->request_length = 0xEB14; - zip[atapi_zip_drives[ide->channel]]->callback = 0LL; - ide->cylinder = 0xEB14; - } else if (ide_drive_is_cdrom(ide)) { - cdrom[atapi_cdrom_drives[ide->channel]]->status = DRDY_STAT | DSC_STAT; - cdrom[atapi_cdrom_drives[ide->channel]]->error = 1; - cdrom[atapi_cdrom_drives[ide->channel]]->phase = 1; - cdrom[atapi_cdrom_drives[ide->channel]]->request_length = 0xEB14; - cdrom[atapi_cdrom_drives[ide->channel]]->callback = 0LL; + if (ide_drive_is_atapi(ide)) { + atapi->status = DRDY_STAT | DSC_STAT; + atapi->error = 1; + atapi->phase = 1; + atapi->request_length = 0xEB14; + atapi->callback = 0LL; ide->cylinder = 0xEB14; } - if (ide_drive_is_zip(ide_other)) { - zip[atapi_zip_drives[ide_other->channel]]->status = DRDY_STAT | DSC_STAT; - zip[atapi_zip_drives[ide_other->channel]]->error = 1; - zip[atapi_zip_drives[ide_other->channel]]->phase = 1; - zip[atapi_zip_drives[ide_other->channel]]->request_length = 0xEB14; - zip[atapi_zip_drives[ide_other->channel]]->callback = 0LL; - ide->cylinder = 0xEB14; - } else if (ide_drive_is_cdrom(ide_other)) { - cdrom[atapi_cdrom_drives[ide_other->channel]]->status = DRDY_STAT | DSC_STAT; - cdrom[atapi_cdrom_drives[ide_other->channel]]->error = 1; - cdrom[atapi_cdrom_drives[ide_other->channel]]->phase = 1; - cdrom[atapi_cdrom_drives[ide_other->channel]]->request_length = 0xEB14; - cdrom[atapi_cdrom_drives[ide_other->channel]]->callback = 0LL; + if (ide_drive_is_atapi(ide_other)) { + atapi_other->status = DRDY_STAT | DSC_STAT; + atapi_other->error = 1; + atapi_other->phase = 1; + atapi_other->request_length = 0xEB14; + atapi_other->callback = 0LL; ide->cylinder = 0xEB14; } @@ -1434,24 +1244,18 @@ ide_writeb(uint16_t addr, uint8_t val, void *priv) ide->command=val; ide->error=0; - if (ide_drive_is_zip(ide)) - zip[atapi_zip_drives[ide->channel]]->error = 0; - else if (ide_drive_is_cdrom(ide)) - cdrom[atapi_cdrom_drives[ide->channel]]->error = 0; + if (ide_drive_is_atapi(ide)) + atapi->error = 0; if (((val >= WIN_RECAL) && (val <= 0x1F)) || ((val >= WIN_SEEK) && (val <= 0x7F))) { - if (ide_drive_is_zip(ide)) - zip[atapi_zip_drives[ide->channel]]->status = DRDY_STAT; - else if (ide_drive_is_cdrom(ide)) - cdrom[atapi_cdrom_drives[ide->channel]]->status = DRDY_STAT; + if (ide_drive_is_atapi(ide)) + atapi->status = DRDY_STAT; else ide->atastat = BSY_STAT; timer_process(); - if (ide_drive_is_zip(ide)) - zip[atapi_zip_drives[ide->channel]]->callback = 100LL*IDE_TIME; - else if (ide_drive_is_cdrom(ide)) - cdrom[atapi_cdrom_drives[ide->channel]]->callback = 100LL*IDE_TIME; + if (ide_drive_is_atapi(ide)) + atapi->callback = 100LL * IDE_TIME; ide_set_callback(ide->board, 100LL * IDE_TIME); timer_update_outstanding(); return; @@ -1459,18 +1263,14 @@ ide_writeb(uint16_t addr, uint8_t val, void *priv) switch (val) { case WIN_SRST: /* ATAPI Device Reset */ - if (ide_drive_is_zip(ide)) - zip[atapi_zip_drives[ide->channel]]->status = BSY_STAT; - else if (ide_drive_is_cdrom(ide)) - cdrom[atapi_cdrom_drives[ide->channel]]->status = BSY_STAT; + if (ide_drive_is_atapi(ide)) + atapi->status = BSY_STAT; else ide->atastat = DRDY_STAT; timer_process(); - if (ide_drive_is_zip(ide)) - zip[atapi_zip_drives[ide->channel]]->callback = 100LL*IDE_TIME; - else if (ide_drive_is_cdrom(ide)) - cdrom[atapi_cdrom_drives[ide->channel]]->callback = 100LL*IDE_TIME; + if (ide_drive_is_atapi(ide)) + atapi->callback = 100LL * IDE_TIME; ide_set_callback(ide->board, 100LL * IDE_TIME); timer_update_outstanding(); return; @@ -1490,18 +1290,15 @@ ide_writeb(uint16_t addr, uint8_t val, void *priv) case WIN_READ_NORETRY: case WIN_READ_DMA: case WIN_READ_DMA_ALT: - if (ide_drive_is_zip(ide)) - zip[atapi_zip_drives[ide->channel]]->status = BSY_STAT; - else if (ide_drive_is_cdrom(ide)) - cdrom[atapi_cdrom_drives[ide->channel]]->status = BSY_STAT; + if (ide_drive_is_atapi(ide)) + atapi->status = BSY_STAT; else ide->atastat = BSY_STAT; timer_process(); - if (ide_drive_is_zip(ide)) - zip[atapi_zip_drives[ide->channel]]->callback = 200LL*IDE_TIME; - else if (ide_drive_is_cdrom(ide)) - cdrom[atapi_cdrom_drives[ide->channel]]->callback = 200LL*IDE_TIME; + if (ide_drive_is_atapi(ide)) + atapi->callback = 200LL * IDE_TIME; + if (ide->type == IDE_HDD) { if ((val == WIN_READ_DMA) || (val == WIN_READ_DMA_ALT)) { if (ide->secount) @@ -1517,7 +1314,7 @@ ide_writeb(uint16_t addr, uint8_t val, void *priv) return; case WIN_WRITE_MULTIPLE: - if (!ide->blocksize && !ide_drive_is_zip(ide) && !ide_drive_is_cdrom(ide)) + if (!ide->blocksize && !ide_drive_is_atapi(ide)) fatal("Write_MULTIPLE - blocksize = 0\n"); ide->blockcount = 0; /* Turn on the activity indicator *here* so that it gets turned on @@ -1526,12 +1323,9 @@ ide_writeb(uint16_t addr, uint8_t val, void *priv) case WIN_WRITE: case WIN_WRITE_NORETRY: - if (ide_drive_is_zip(ide)) { - zip[atapi_zip_drives[ide->channel]]->status = DRQ_STAT | DSC_STAT | DRDY_STAT; - zip[atapi_zip_drives[ide->channel]]->pos = 0; - } else if (ide_drive_is_cdrom(ide)) { - cdrom[atapi_cdrom_drives[ide->channel]]->status = DRQ_STAT | DSC_STAT | DRDY_STAT; - cdrom[atapi_cdrom_drives[ide->channel]]->pos = 0; + if (ide_drive_is_atapi(ide)) { + atapi->status = DRQ_STAT | DSC_STAT | DRDY_STAT; + atapi->pos = 0; } else { ide->atastat = DRQ_STAT | DSC_STAT | DRDY_STAT; ide->pos=0; @@ -1545,18 +1339,14 @@ ide_writeb(uint16_t addr, uint8_t val, void *priv) case WIN_IDENTIFY: /* Identify Device */ case WIN_SET_FEATURES: /* Set Features */ case WIN_READ_NATIVE_MAX: - if (ide_drive_is_zip(ide)) - zip[atapi_zip_drives[ide->channel]]->status = BSY_STAT; - else if (ide_drive_is_cdrom(ide)) - cdrom[atapi_cdrom_drives[ide->channel]]->status = BSY_STAT; + if (ide_drive_is_atapi(ide)) + atapi->status = BSY_STAT; else ide->atastat = BSY_STAT; timer_process(); - if (ide_drive_is_zip(ide)) - zip[atapi_zip_drives[ide->channel]]->callback = 200LL*IDE_TIME; - else if (ide_drive_is_cdrom(ide)) - cdrom[atapi_cdrom_drives[ide->channel]]->callback = 200LL*IDE_TIME; + if (ide_drive_is_atapi(ide)) + atapi->callback = 200LL * IDE_TIME; if ((ide->type == IDE_HDD) && ((val == WIN_WRITE_DMA) || (val == WIN_WRITE_DMA_ALT))) { if (ide->secount) @@ -1572,7 +1362,7 @@ ide_writeb(uint16_t addr, uint8_t val, void *priv) return; case WIN_FORMAT: - if (ide_drive_is_zip(ide) || ide_drive_is_cdrom(ide)) + if (ide_drive_is_atapi(ide)) goto ide_bad_command; else { ide->atastat = DRQ_STAT; @@ -1581,42 +1371,32 @@ ide_writeb(uint16_t addr, uint8_t val, void *priv) return; case WIN_SPECIFY: /* Initialize Drive Parameters */ - if (ide_drive_is_zip(ide)) - zip[atapi_zip_drives[ide->channel]]->status = BSY_STAT; - else if (ide_drive_is_cdrom(ide)) - cdrom[atapi_cdrom_drives[ide->channel]]->status = BSY_STAT; + if (ide_drive_is_atapi(ide)) + atapi->status = BSY_STAT; else ide->atastat = BSY_STAT; timer_process(); - if (ide_drive_is_zip(ide)) - zip[atapi_zip_drives[ide->channel]]->callback = 30LL*IDE_TIME; - else if (ide_drive_is_cdrom(ide)) - cdrom[atapi_cdrom_drives[ide->channel]]->callback = 30LL*IDE_TIME; + if (ide_drive_is_atapi(ide)) + atapi->callback = 30LL * IDE_TIME; ide_set_callback(ide->board, 30LL * IDE_TIME); timer_update_outstanding(); return; case WIN_DRIVE_DIAGNOSTICS: /* Execute Drive Diagnostics */ - if (ide_drive_is_zip(ide)) - zip[atapi_zip_drives[ide->channel]]->status = BSY_STAT; - else if (ide_drive_is_cdrom(ide)) - cdrom[atapi_cdrom_drives[ide->channel]]->status = BSY_STAT; + if (ide_drive_is_atapi(ide)) + atapi->status = BSY_STAT; else ide->atastat = BSY_STAT; - if (ide_drive_is_zip(ide_other)) - zip[atapi_zip_drives[ide_other->channel]]->status = BSY_STAT; - else if (ide_drive_is_cdrom(ide_other)) - cdrom[atapi_cdrom_drives[ide_other->channel]]->status = BSY_STAT; + if (ide_drive_is_atapi(ide_other)) + atapi_other->status = BSY_STAT; else ide_other->atastat = BSY_STAT; timer_process(); - if (ide_drive_is_zip(ide)) - zip[atapi_zip_drives[ide->channel]]->callback = 200LL * IDE_TIME; - else if (ide_drive_is_cdrom(ide)) - cdrom[atapi_cdrom_drives[ide->channel]]->callback = 200LL * IDE_TIME; + if (ide_drive_is_atapi(ide)) + atapi->callback = 200LL * IDE_TIME; ide_set_callback(ide->board, 200LL * IDE_TIME); timer_update_outstanding(); return; @@ -1629,10 +1409,8 @@ ide_writeb(uint16_t addr, uint8_t val, void *priv) case WIN_SETIDLE1: /* Idle */ case WIN_CHECKPOWERMODE1: case WIN_SLEEP1: - if (ide_drive_is_zip(ide)) - zip[atapi_zip_drives[ide->channel]]->status = BSY_STAT; - else if (ide_drive_is_cdrom(ide)) - cdrom[atapi_cdrom_drives[ide->channel]]->status = BSY_STAT; + if (ide_drive_is_atapi(ide)) + atapi->status = BSY_STAT; else ide->atastat = BSY_STAT; timer_process(); @@ -1642,17 +1420,13 @@ ide_writeb(uint16_t addr, uint8_t val, void *priv) case WIN_PACKETCMD: /* ATAPI Packet */ /* Skip the command callback wait, and process immediately. */ - if (ide_drive_is_zip(ide)) { - zip[atapi_zip_drives[ide->channel]]->packet_status = ZIP_PHASE_IDLE; - zip[atapi_zip_drives[ide->channel]]->pos=0; - zip[atapi_zip_drives[ide->channel]]->phase = 1; - zip[atapi_zip_drives[ide->channel]]->status = DRDY_STAT | DRQ_STAT; - ide_irq_raise(ide); /* Interrupt DRQ, requires IRQ on any DRQ. */ - } else if (ide_drive_is_cdrom(ide)) { - cdrom[atapi_cdrom_drives[ide->channel]]->packet_status = CDROM_PHASE_IDLE; - cdrom[atapi_cdrom_drives[ide->channel]]->pos=0; - cdrom[atapi_cdrom_drives[ide->channel]]->phase = 1; - cdrom[atapi_cdrom_drives[ide->channel]]->status = DRDY_STAT | DRQ_STAT; + if (ide_drive_is_atapi(ide)) { + atapi->packet_status = PHASE_IDLE; + atapi->pos = 0; + atapi->phase = 1; + atapi->status = DRDY_STAT | DRQ_STAT; + if (ide->interrupt_drq) + ide_irq_raise(ide); /* Interrupt DRQ, requires IRQ on any DRQ. */ } else { ide->atastat = BSY_STAT; timer_process(); @@ -1665,12 +1439,9 @@ ide_writeb(uint16_t addr, uint8_t val, void *priv) case 0xF0: default: ide_bad_command: - if (ide_drive_is_zip(ide)) { - zip[atapi_zip_drives[ide->channel]]->status = DRDY_STAT | ERR_STAT | DSC_STAT; - zip[atapi_zip_drives[ide->channel]]->error = ABRT_ERR; - } else if (ide_drive_is_cdrom(ide)) { - cdrom[atapi_cdrom_drives[ide->channel]]->status = DRDY_STAT | ERR_STAT | DSC_STAT; - cdrom[atapi_cdrom_drives[ide->channel]]->error = ABRT_ERR; + if (ide_drive_is_atapi(ide)) { + atapi->status = DRDY_STAT | ERR_STAT | DSC_STAT; + atapi->error = ABRT_ERR; } else { ide->atastat = DRDY_STAT | ERR_STAT | DSC_STAT; ide->error = ABRT_ERR; @@ -1686,7 +1457,7 @@ ide_bad_command: static uint32_t ide_read_data(ide_t *ide, int length) { - int ch = ide->channel; + scsi_device_data_t *atapi = (scsi_device_data_t *) ide->p; uint32_t temp; if (!ide->buffer) { @@ -1708,14 +1479,12 @@ ide_read_data(ide_t *ide, int length) if (ide->command == WIN_PACKETCMD) { ide->pos = 0; - if (!ide_drive_is_zip(ide) && !ide_drive_is_cdrom(ide)) { - ide_log("Drive not ZIP or CD-ROM (position: %i)\n", ide->pos); + if (!ide_drive_is_atapi(ide)) { + ide_log("Drive not ATAPI (position: %i)\n", ide->pos); return 0; } - if (ide_drive_is_zip(ide)) - temp = zip_read(ch, length); - else - temp = cdrom_read(ch, length); + if (ide_drive_is_atapi(ide)) + temp = ide->packet_read(ide->p, length); } else { switch (length) { case 1: @@ -1734,17 +1503,14 @@ ide_read_data(ide_t *ide, int length) return 0; } } - if (ide->pos>=512 && ide->command != WIN_PACKETCMD) { - ide->pos=0; + if ((ide->pos >= 512) && (ide->command != WIN_PACKETCMD)) { + ide->pos = 0; ide->atastat = DRDY_STAT | DSC_STAT; - if (ide_drive_is_zip(ide)) { - zip[atapi_zip_drives[ch]]->status = DRDY_STAT | DSC_STAT; - zip[atapi_zip_drives[ch]]->packet_status = ZIP_PHASE_IDLE; - } else if (ide_drive_is_cdrom(ide)) { - cdrom[atapi_cdrom_drives[ch]]->status = DRDY_STAT | DSC_STAT; - cdrom[atapi_cdrom_drives[ch]]->packet_status = CDROM_PHASE_IDLE; + if (ide_drive_is_atapi(ide)) { + atapi->status = DRDY_STAT | DSC_STAT; + atapi->packet_status = PHASE_IDLE; } - if (ide->command == WIN_READ || ide->command == WIN_READ_NORETRY || ide->command == WIN_READ_MULTIPLE) { + if ((ide->command == WIN_READ) || (ide->command == WIN_READ_NORETRY) || (ide->command == WIN_READ_MULTIPLE)) { ide->secount = (ide->secount - 1) & 0xff; if (ide->secount) { ide_next_sector(ide); @@ -1769,13 +1535,13 @@ ide_read_data(ide_t *ide, int length) static uint8_t ide_status(ide_t *ide, int ch) { + scsi_device_data_t *atapi = (scsi_device_data_t *) ide->p; + if (ide->type == IDE_NONE) return 0; else { - if (ide_drive_is_zip(ide)) - return (zip[atapi_zip_drives[ch]]->status & ~DSC_STAT) | (ide->service ? SERVICE_STAT : 0); - else if (ide_drive_is_cdrom(ide)) - return (cdrom[atapi_cdrom_drives[ch]]->status & ~DSC_STAT) | (ide->service ? SERVICE_STAT : 0); + if (ide_drive_is_atapi(ide)) + return (atapi->status & ~DSC_STAT) | (ide->service ? SERVICE_STAT : 0); else return ide->atastat; } @@ -1785,6 +1551,7 @@ ide_status(ide_t *ide, int ch) uint8_t ide_readb(uint16_t addr, void *priv) { + scsi_device_data_t *atapi; ide_board_t *dev = (ide_board_t *) priv; int ch; @@ -1792,6 +1559,7 @@ ide_readb(uint16_t addr, void *priv) ch = dev->cur_dev; ide = ide_drives[ch]; + atapi = (scsi_device_data_t *) ide->p; uint8_t temp = 0xff; uint16_t tempw; @@ -1812,10 +1580,8 @@ ide_readb(uint16_t addr, void *priv) if (ide->type == IDE_NONE) temp = 0; else { - if (ide_drive_is_zip(ide)) - temp = zip[atapi_zip_drives[ch]]->error; - else if (ide_drive_is_cdrom(ide)) - temp = cdrom[atapi_cdrom_drives[ch]]->error; + if (ide_drive_is_atapi(ide)) + temp = atapi->error; else temp = ide->error; } @@ -1835,10 +1601,8 @@ ide_readb(uint16_t addr, void *priv) 0 1 0 Data from host 1 0 1 Status. */ case 0x2: /* Sector count */ - if (ide_drive_is_zip(ide)) - temp = zip[atapi_zip_drives[ch]]->phase; - else if (ide_drive_is_cdrom(ide)) - temp = cdrom[atapi_cdrom_drives[ch]]->phase; + if (ide_drive_is_atapi(ide)) + temp = atapi->phase; else temp = ide->secount; break; @@ -1851,10 +1615,8 @@ ide_readb(uint16_t addr, void *priv) if (ide->type == IDE_NONE) temp = 0xFF; else { - if (ide_drive_is_zip(ide)) - temp = zip[atapi_zip_drives[ch]]->request_length & 0xff; - else if (ide_drive_is_cdrom(ide)) - temp = cdrom[atapi_cdrom_drives[ch]]->request_length & 0xff; + if (ide_drive_is_atapi(ide)) + temp = atapi->request_length & 0xff; else temp = ide->cylinder & 0xff; } @@ -1864,10 +1626,8 @@ ide_readb(uint16_t addr, void *priv) if (ide->type == IDE_NONE) temp = 0xFF; else { - if (ide_drive_is_zip(ide)) - temp = zip[atapi_zip_drives[ch]]->request_length >> 8; - else if (ide_drive_is_cdrom(ide)) - temp = cdrom[atapi_cdrom_drives[ch]]->request_length >> 8; + if (ide_drive_is_atapi(ide)) + temp = atapi->request_length >> 8; else temp = ide->cylinder >> 8; } @@ -1967,14 +1727,15 @@ ide_callback(void *priv) { ide_t *ide, *ide_other; int snum, ret, ch; - int cdrom_id, cdrom_id_other; - int zip_id, zip_id_other; ide_board_t *dev = (ide_board_t *) priv; + scsi_device_data_t *atapi, *atapi_other; ch = dev->cur_dev; ide = ide_drives[ch]; + atapi = (scsi_device_data_t *) ide->p; ide_other = ide_drives[ch ^ 1]; + atapi_other = (scsi_device_data_t *) ide_other->p; ide_set_callback(ide->board, 0LL); @@ -1994,29 +1755,19 @@ ide_callback(void *priv) ide->reset = ide_other->reset = 0; ide_set_signature(ide); - if (ide_drive_is_zip(ide)) { - zip_id = atapi_zip_drives[ch]; - zip[zip_id]->status = DRDY_STAT | DSC_STAT; - zip[zip_id]->error = 1; - } else if (ide_drive_is_cdrom(ide)) { - cdrom_id = atapi_cdrom_drives[ch]; - cdrom[cdrom_id]->status = DRDY_STAT | DSC_STAT; - cdrom[cdrom_id]->error = 1; - if (cdrom[cdrom_id]->handler->stop) - cdrom[cdrom_id]->handler->stop(cdrom_id); + if (ide_drive_is_atapi(ide)) { + atapi->status = DRDY_STAT | DSC_STAT; + atapi->error = 1; + if (ide->stop) + ide->stop(ide->p); } ide_set_signature(ide_other); - if (ide_drive_is_zip(ide_other)) { - zip_id_other = atapi_zip_drives[ch ^ 1]; - zip[zip_id_other]->status = DRDY_STAT | DSC_STAT; - zip[zip_id_other]->error = 1; - } else if (ide_drive_is_cdrom(ide_other)) { - cdrom_id_other = atapi_cdrom_drives[ch ^ 1]; - cdrom[cdrom_id_other]->status = DRDY_STAT | DSC_STAT; - cdrom[cdrom_id_other]->error = 1; - if (cdrom[cdrom_id_other]->handler->stop) - cdrom[cdrom_id_other]->handler->stop(cdrom_id_other); + if (ide_drive_is_atapi(ide_other)) { + atapi_other->status = DRDY_STAT | DSC_STAT; + atapi_other->error = 1; + if (ide_other->stop) + ide_other->stop(ide_other->p); } return; @@ -2024,12 +1775,6 @@ ide_callback(void *priv) ide_log("CALLBACK %02X %i %i\n", ide->command, ide->reset,ch); - cdrom_id = atapi_cdrom_drives[ch]; - cdrom_id_other = atapi_cdrom_drives[ch ^ 1]; - - zip_id = atapi_zip_drives[ch]; - zip_id_other = atapi_zip_drives[ch ^ 1]; - if (((ide->command >= WIN_RECAL) && (ide->command <= 0x1F)) || ((ide->command >= WIN_SEEK) && (ide->command <= 0x7F))) { if (ide->type != IDE_HDD) @@ -2056,17 +1801,14 @@ ide_callback(void *priv) ide_set_signature(ide); - if (ide_drive_is_zip(ide)) { - zip[zip_id]->status = DRDY_STAT | DSC_STAT; - zip[zip_id]->error = 1; - zip_reset(zip[zip_id]); - } else if (ide_drive_is_cdrom(ide)) { - cdrom[cdrom_id]->status = DRDY_STAT | DSC_STAT; - cdrom[cdrom_id]->error = 1; - cdrom_reset(cdrom[cdrom_id]); + if (ide_drive_is_atapi(ide)) { + atapi->status = DRDY_STAT | DSC_STAT; + atapi->error = 1; + if (ide->device_reset) + ide->device_reset(ide->p); } ide_irq_raise(ide); - if (ide_drive_is_zip(ide) || ide_drive_is_cdrom(ide)) + if (ide_drive_is_atapi(ide)) ide->service = 0; return; @@ -2074,10 +1816,8 @@ ide_callback(void *priv) case WIN_STANDBYNOW1: case WIN_IDLENOW1: case WIN_SETIDLE1: - if (ide_drive_is_zip(ide)) - zip[zip_id]->status = DRDY_STAT | DSC_STAT; - else if (ide_drive_is_cdrom(ide)) - cdrom[cdrom_id]->status = DRDY_STAT | DSC_STAT; + if (ide_drive_is_atapi(ide)) + atapi->status = DRDY_STAT | DSC_STAT; else ide->atastat = DRDY_STAT | DSC_STAT; ide_irq_raise(ide); @@ -2085,12 +1825,9 @@ ide_callback(void *priv) case WIN_CHECKPOWERMODE1: case WIN_SLEEP1: - if (ide_drive_is_zip(ide)) { - zip[zip_id]->phase = 0xFF; - zip[zip_id]->status = DRDY_STAT | DSC_STAT; - } else if (ide_drive_is_cdrom(ide)) { - cdrom[cdrom_id]->phase = 0xFF; - cdrom[cdrom_id]->status = DRDY_STAT | DSC_STAT; + if (ide_drive_is_atapi(ide)) { + atapi->phase = 0xFF; + atapi->status = DRDY_STAT | DSC_STAT; } ide->secount = 0xFF; ide->atastat = DRDY_STAT | DSC_STAT; @@ -2099,7 +1836,7 @@ ide_callback(void *priv) case WIN_READ: case WIN_READ_NORETRY: - if (ide_drive_is_zip(ide) || ide_drive_is_cdrom(ide)) { + if (ide_drive_is_atapi(ide)) { ide_set_signature(ide); goto abort_cmd; } @@ -2129,7 +1866,7 @@ ide_callback(void *priv) case WIN_READ_DMA: case WIN_READ_DMA_ALT: - if (ide_drive_is_zip(ide) || ide_drive_is_cdrom(ide) || (ide->board >= 2)) { + if (ide_drive_is_atapi(ide) || !IDE_PCI || (ide->board >= 2)) { ide_log("IDE %i: DMA read aborted (bad device or board)\n", ide->channel); goto abort_cmd; } @@ -2183,7 +1920,7 @@ ide_callback(void *priv) command has been executed or when Read Multiple commands are disabled, the Read Multiple operation is rejected with an Aborted Com- mand error. */ - if (ide_drive_is_zip(ide) || ide_drive_is_cdrom(ide) || !ide->blocksize) + if (ide_drive_is_atapi(ide) || !ide->blocksize) goto abort_cmd; if (ide->cfg_spt == 0) goto id_not_found; @@ -2212,7 +1949,7 @@ ide_callback(void *priv) case WIN_WRITE: case WIN_WRITE_NORETRY: - if (ide_drive_is_zip(ide) || ide_drive_is_cdrom(ide)) + if (ide_drive_is_atapi(ide)) goto abort_cmd; if (ide->cfg_spt == 0) goto id_not_found; @@ -2232,7 +1969,7 @@ ide_callback(void *priv) case WIN_WRITE_DMA: case WIN_WRITE_DMA_ALT: - if (ide_drive_is_zip(ide) || ide_drive_is_cdrom(ide) || (ide->board >= 2)) { + if (ide_drive_is_atapi(ide) || !IDE_PCI || (ide->board >= 2)) { ide_log("IDE %i: DMA write aborted (bad device type or board)\n", ide->channel); goto abort_cmd; } @@ -2279,7 +2016,7 @@ ide_callback(void *priv) return; case WIN_WRITE_MULTIPLE: - if (ide_drive_is_zip(ide) || ide_drive_is_cdrom(ide)) + if (ide_drive_is_atapi(ide)) goto abort_cmd; if (ide->cfg_spt == 0) goto id_not_found; @@ -2302,7 +2039,7 @@ ide_callback(void *priv) case WIN_VERIFY: case WIN_VERIFY_ONCE: - if (ide_drive_is_zip(ide) || ide_drive_is_cdrom(ide)) + if (ide_drive_is_atapi(ide)) goto abort_cmd; if (ide->cfg_spt == 0) goto id_not_found; @@ -2313,7 +2050,7 @@ ide_callback(void *priv) return; case WIN_FORMAT: - if (ide_drive_is_zip(ide) || ide_drive_is_cdrom(ide)) + if (ide_drive_is_atapi(ide)) goto abort_cmd; if (ide->cfg_spt == 0) goto id_not_found; @@ -2329,13 +2066,9 @@ ide_callback(void *priv) ide_set_signature(ide); ide->error=1; /*No error detected*/ - if (ide_drive_is_zip(ide)) { - zip[zip_id]->status = 0; - zip[zip_id]->error = 1; - ide_irq_raise(ide); - } else if (ide_drive_is_cdrom(ide)) { - cdrom[cdrom_id]->status = 0; - cdrom[cdrom_id]->error = 1; + if (ide_drive_is_atapi(ide)) { + atapi->status = 0; + atapi->error = 1; ide_irq_raise(ide); } else { ide->atastat = DRDY_STAT | DSC_STAT; @@ -2346,12 +2079,9 @@ ide_callback(void *priv) ide_set_signature(ide_other); ide_other->error=1; /*No error detected*/ - if (ide_drive_is_zip(ide_other)) { - zip[zip_id_other]->status = 0; - zip[zip_id_other]->error = 1; - } else if (ide_drive_is_cdrom(ide_other)) { - cdrom[cdrom_id_other]->status = 0; - cdrom[cdrom_id_other]->error = 1; + if (ide_drive_is_atapi(ide_other)) { + atapi_other->status = 0; + atapi_other->error = 1; } else { ide_other->atastat = DRDY_STAT | DSC_STAT; ide_other->error = 1; @@ -2362,7 +2092,7 @@ ide_callback(void *priv) return; case WIN_SPECIFY: /* Initialize Drive Parameters */ - if (ide_drive_is_zip(ide) || ide_drive_is_cdrom(ide)) + if (ide_drive_is_atapi(ide)) goto abort_cmd; if (ide->cfg_spt == 0) { /* Only accept after RESET or DIAG. */ @@ -2376,29 +2106,20 @@ ide_callback(void *priv) return; case WIN_PIDENTIFY: /* Identify Packet Device */ - if (ide_drive_is_zip(ide)) { + if (ide_drive_is_atapi(ide)) { ide_identify(ide); ide->pos = 0; - zip[zip_id]->phase = 2; - zip[zip_id]->pos = 0; - zip[zip_id]->error = 0; - zip[zip_id]->status = DRQ_STAT | DRDY_STAT | DSC_STAT; - ide_irq_raise(ide); - return; - } else if (ide_drive_is_cdrom(ide)) { - ide_identify(ide); - ide->pos = 0; - cdrom[cdrom_id]->phase = 2; - cdrom[cdrom_id]->pos = 0; - cdrom[cdrom_id]->error = 0; - cdrom[cdrom_id]->status = DRQ_STAT | DRDY_STAT | DSC_STAT; + atapi->phase = 2; + atapi->pos = 0; + atapi->error = 0; + atapi->status = DRQ_STAT | DRDY_STAT | DSC_STAT; ide_irq_raise(ide); return; } goto abort_cmd; case WIN_SET_MULTIPLE_MODE: - if (ide_drive_is_zip(ide) || ide_drive_is_cdrom(ide)) + if (ide_drive_is_atapi(ide)) goto abort_cmd; ide->blocksize = ide->secount; ide->atastat = DRDY_STAT | DSC_STAT; @@ -2412,12 +2133,9 @@ ide_callback(void *priv) if (!ide_set_features(ide)) goto abort_cmd; else { - if (ide_drive_is_zip(ide)) { - zip[zip_id]->status = DRDY_STAT | DSC_STAT; - zip[zip_id]->pos = 0; - } else if (ide_drive_is_cdrom(ide)) { - cdrom[cdrom_id]->status = DRDY_STAT | DSC_STAT; - cdrom[cdrom_id]->pos = 0; + if (ide_drive_is_atapi(ide)) { + atapi->status = DRDY_STAT | DSC_STAT; + atapi->pos = 0; } ide->atastat = DRDY_STAT | DSC_STAT; ide_irq_raise(ide); @@ -2448,13 +2166,10 @@ ide_callback(void *priv) return; case WIN_PACKETCMD: /* ATAPI Packet */ - if (!ide_drive_is_zip(ide) && !ide_drive_is_cdrom(ide)) + if (!ide_drive_is_atapi(ide) || !ide->packet_callback) goto abort_cmd; - if (ide_drive_is_zip(ide)) - zip_phase_callback(zip[atapi_zip_drives[ch]]); - else - cdrom_phase_callback(cdrom[atapi_cdrom_drives[ch]]); + ide->packet_callback(ide->p); return; case 0xFF: @@ -2463,14 +2178,10 @@ ide_callback(void *priv) abort_cmd: ide->command = 0; - if (ide_drive_is_zip(ide)) { - zip[zip_id]->status = DRDY_STAT | ERR_STAT | DSC_STAT; - zip[zip_id]->error = ABRT_ERR; - zip[zip_id]->pos = 0; - } else if (ide_drive_is_cdrom(ide)) { - cdrom[cdrom_id]->status = DRDY_STAT | ERR_STAT | DSC_STAT; - cdrom[cdrom_id]->error = ABRT_ERR; - cdrom[cdrom_id]->pos = 0; + if (ide_drive_is_atapi(ide)) { + atapi->status = DRDY_STAT | ERR_STAT | DSC_STAT; + atapi->error = ABRT_ERR; + atapi->pos = 0; } else { ide->atastat = DRDY_STAT | ERR_STAT | DSC_STAT; ide->error = ABRT_ERR; diff --git a/src/disk/hdc_ide.h b/src/disk/hdc_ide.h index 69ede4604..89dd1c2ca 100644 --- a/src/disk/hdc_ide.h +++ b/src/disk/hdc_ide.h @@ -9,7 +9,7 @@ * Implementation of the IDE emulation for hard disks and ATAPI * CD-ROM devices. * - * Version: @(#)hdd_ide.h 1.0.11 2018/09/15 + * Version: @(#)hdd_ide.h 1.0.12 2018/10/10 * * Authors: Sarah Walker, * Miran Grca, @@ -20,28 +20,77 @@ # define EMU_IDE_H -typedef struct { - uint8_t atastat, error, - command, fdisk; - int type, board, - irqstat, service, - blocksize, blockcount, - hdd_num, channel, - pos, sector_pos, - lba, skip512, - reset, mdma_mode, - do_initial_read; - uint32_t secount, sector, - cylinder, head, - drive, cylprecomp, - cfg_spt, cfg_hpc, - lba_addr, tracks, - spt, hpc; +enum +{ + IDE_NONE = 0, + IDE_HDD, + IDE_ATAPI +}; - uint16_t *buffer; - uint8_t *sector_buffer; +typedef struct { + uint8_t atastat, error, + command, fdisk; + int type, board, + irqstat, service, + blocksize, blockcount, + hdd_num, channel, + pos, sector_pos, + lba, skip512, + reset, mdma_mode, + do_initial_read; + uint32_t secount, sector, + cylinder, head, + drive, cylprecomp, + cfg_spt, cfg_hpc, + lba_addr, tracks, + spt, hpc; + + uint16_t *buffer; + uint8_t *sector_buffer; + + /* Stuff mostly used by ATAPI */ + void *p; + int interrupt_drq; + + int (*get_max)(int ide_has_dma, int type); + int (*get_timings)(int ide_has_dma, int type); + void (*identify)(void *p, int ide_has_dma); + void (*set_signature)(void *p); + void (*packet_write)(void *p, uint32_t val, int length); + uint32_t (*packet_read)(void *p, int length); + void (*stop)(void *p); + void (*packet_callback)(void *p); + void (*device_reset)(void *p); } ide_t; +/* Type: + 0 = PIO, + 1 = SDMA, + 2 = MDMA, + 3 = UDMA + Return: + -1 = Not supported, + Anything else = maximum mode + + This will eventually be hookable. */ +enum { + TYPE_PIO = 0, + TYPE_SDMA, + TYPE_MDMA, + TYPE_UDMA +}; + +/* Return: + 0 = Not supported, + Anything else = timings + + This will eventually be hookable. */ +enum { + TIMINGS_DMA = 0, + TIMINGS_PIO, + TIMINGS_PIO_FC +}; + extern int ideboard; extern int ide_ter_enabled, ide_qua_enabled; @@ -82,6 +131,7 @@ extern void ide_sec_disable(void); extern void ide_set_callback(uint8_t channel, int64_t callback); extern void secondary_ide_check(void); +extern void ide_padstr(char *str, const char *src, int len); extern void ide_padstr8(uint8_t *buf, int buf_size, const char *src); extern int (*ide_bus_master_read)(int channel, uint8_t *data, int transfer_length, void *priv); @@ -90,6 +140,8 @@ extern void (*ide_bus_master_set_irq)(int channel, void *priv); extern void *ide_bus_master_priv[2]; extern void ide_enable_pio_override(void); +extern void ide_allocate_buffer(ide_t *dev); +extern void ide_atapi_attach(ide_t *dev); #endif /*EMU_IDE_H*/ diff --git a/src/disk/zip.c b/src/disk/zip.c index 7452b4008..bf7a173e8 100644 --- a/src/disk/zip.c +++ b/src/disk/zip.c @@ -51,11 +51,8 @@ #define zipbufferb dev->buffer -zip_t *zip[ZIP_NUM]; +zip_t *zip[ZIP_NUM] = { NULL, NULL, NULL, NULL }; zip_drive_t zip_drives[ZIP_NUM]; -uint8_t atapi_zip_drives[8] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; -uint8_t scsi_zip_drives[16] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; /* Table of all SCSI commands and their flags, needed for the new disc change / not ready handler. */ @@ -456,7 +453,7 @@ static const mode_sense_pages_t zip_250_mode_sense_pages_changeable = static void zip_command_complete(zip_t *dev); static void zip_init(zip_t *dev); -void zip_phase_callback(zip_t *dev); +static void zip_callback(void *p); #ifdef ENABLE_ZIP_LOG @@ -581,43 +578,6 @@ zip_disk_close(zip_t *dev) } -void -build_atapi_zip_map() -{ - uint8_t i = 0; - - memset(atapi_zip_drives, 0xff, 8); - - for (i = 0; i < 8; i++) - atapi_zip_drives[i] = find_zip_for_channel(i); -} - - -int -find_zip_for_scsi_id(uint8_t scsi_id) -{ - uint8_t i = 0; - - for (i = 0; i < ZIP_NUM; i++) { - if ((zip_drives[i].bus_type == ZIP_BUS_SCSI) && (zip_drives[i].scsi_device_id == scsi_id)) - return i; - } - return 0xff; -} - - -void -build_scsi_zip_map() -{ - uint8_t i = 0; - - memset(scsi_zip_drives, 0xff, 16); - - for (i = 0; i < 16; i++) - scsi_zip_drives[i] = find_zip_for_scsi_id(i); -} - - static void zip_set_callback(zip_t *dev) { @@ -626,9 +586,11 @@ zip_set_callback(zip_t *dev) } -void -zip_set_signature(zip_t *dev) +static void +zip_set_signature(void *p) { + zip_t *dev = (zip_t *) p; + if (dev->id >= ZIP_NUM) return; dev->phase = 1; @@ -696,9 +658,11 @@ zip_current_mode(zip_t *dev) /* Translates ATAPI status (ERR_STAT flag) to SCSI status. */ -int -zip_ZIP_PHASE_to_scsi(zip_t *dev) +static int +zip_err_stat_to_scsi(void *p) { + zip_t *dev = (zip_t *) p; + if (dev->status & ERR_STAT) return SCSI_STATUS_CHECK_CONDITION; else @@ -795,9 +759,10 @@ zip_mode_sense_save(zip_t *dev) } -int -zip_read_capacity(zip_t *dev, uint8_t *cdb, uint8_t *buffer, uint32_t *len) +static int +zip_read_capacity(void *p, uint8_t *cdb, uint8_t *buffer, uint32_t *len) { + zip_t *dev = (zip_t *) p; int size = 0; if (dev->drv->is_250) @@ -855,10 +820,10 @@ zip_mode_sense_read(zip_t *dev, uint8_t page_control, uint8_t page, uint8_t pos) static uint32_t -zip_mode_sense(zip_t *dev, uint8_t *buf, uint32_t pos, uint8_t type, uint8_t block_descriptor_len) +zip_mode_sense(zip_t *dev, uint8_t *buf, uint32_t pos, uint8_t page, uint8_t block_descriptor_len) { uint64_t pf; - uint8_t page_control = (type >> 6) & 3; + uint8_t page_control = (page >> 6) & 3; if (dev->drv->is_250) pf = zip_250_mode_sense_page_flags; @@ -870,7 +835,7 @@ zip_mode_sense(zip_t *dev, uint8_t *buf, uint32_t pos, uint8_t type, uint8_t blo uint8_t msplen; - type &= 0x3f; + page &= 0x3f; if (block_descriptor_len) { if (dev->drv->is_250) { @@ -891,8 +856,8 @@ zip_mode_sense(zip_t *dev, uint8_t *buf, uint32_t pos, uint8_t type, uint8_t blo } for (i = 0; i < 0x40; i++) { - if ((type == GPMODE_ALL_PAGES) || (type == i)) { - if (pf & (1LL << dev->current_page_code)) { + if ((page == GPMODE_ALL_PAGES) || (page == i)) { + if (pf & (1LL << ((uint64_t) page))) { buf[pos++] = zip_mode_sense_read(dev, page_control, i, 0); msplen = zip_mode_sense_read(dev, page_control, i, 1); buf[pos++] = msplen; @@ -976,8 +941,8 @@ zip_command_common(zip_t *dev) dev->status = BUSY_STAT; dev->phase = 1; dev->pos = 0; - if (dev->packet_status == ZIP_PHASE_COMPLETE) { - zip_phase_callback(dev); + if (dev->packet_status == PHASE_COMPLETE) { + zip_callback((void *) dev); dev->callback = 0LL; } else { if (dev->drv->bus_type == ZIP_BUS_SCSI) { @@ -1003,7 +968,7 @@ zip_command_common(zip_t *dev) static void zip_command_complete(zip_t *dev) { - dev->packet_status = ZIP_PHASE_COMPLETE; + dev->packet_status = PHASE_COMPLETE; zip_command_common(dev); } @@ -1011,25 +976,23 @@ zip_command_complete(zip_t *dev) static void zip_command_read(zip_t *dev) { - dev->packet_status = ZIP_PHASE_DATA_IN; + dev->packet_status = PHASE_DATA_IN; zip_command_common(dev); - dev->total_read = 0; } static void zip_command_read_dma(zip_t *dev) { - dev->packet_status = ZIP_PHASE_DATA_IN_DMA; + dev->packet_status = PHASE_DATA_IN_DMA; zip_command_common(dev); - dev->total_read = 0; } static void zip_command_write(zip_t *dev) { - dev->packet_status = ZIP_PHASE_DATA_OUT; + dev->packet_status = PHASE_DATA_OUT; zip_command_common(dev); } @@ -1037,7 +1000,7 @@ zip_command_write(zip_t *dev) static void zip_command_write_dma(zip_t *dev) { - dev->packet_status = ZIP_PHASE_DATA_OUT_DMA; + dev->packet_status = PHASE_DATA_OUT_DMA; zip_command_common(dev); } @@ -1088,7 +1051,6 @@ zip_data_command_finish(zip_t *dev, int len, int block_len, int alloc_len, int d static void zip_sense_clear(zip_t *dev, int command) { - dev->previous_command = command; zip_sense_key = zip_asc = zip_ascq = 0; } @@ -1101,7 +1063,7 @@ zip_set_phase(zip_t *dev, uint8_t phase) if (dev->drv->bus_type != ZIP_BUS_SCSI) return; - SCSIDevices[scsi_id].Phase = phase; + scsi_devices[scsi_id].phase = phase; } @@ -1232,8 +1194,6 @@ zip_data_phase_error(zip_t *dev) static int zip_blocks(zip_t *dev, int32_t *len, int first_batch, int out) { - dev->data_pos = 0; - *len = 0; if (!dev->sector_len) { @@ -1348,11 +1308,6 @@ zip_pre_execution_check(zip_t *dev, uint8_t *cdb) zip_sense_clear(dev, cdb[0]); /* Next it's time for NOT READY. */ - if (!ready) - dev->media_status = MEC_MEDIA_REMOVAL; - else - dev->media_status = (dev->unit_attention) ? MEC_NEW_MEDIA : MEC_NO_CHANGE; - if ((zip_command_flags[cdb[0]] & CHECK_READY) && !ready) { zip_log("ZIP %i: Not ready (%02X)\n", dev->id, cdb[0]); zip_not_ready(dev); @@ -1382,8 +1337,10 @@ zip_rezero(zip_t *dev) void -zip_reset(zip_t *dev) +zip_reset(void *p) { + zip_t *dev = (zip_t *) p; + zip_rezero(dev); dev->status = 0; dev->callback = 0LL; @@ -1429,9 +1386,10 @@ zip_request_sense(zip_t *dev, uint8_t *buffer, uint8_t alloc_length, int desc) } -void -zip_request_sense_for_scsi(zip_t *dev, uint8_t *buffer, uint8_t alloc_length) +static void +zip_request_sense_for_scsi(void *p, uint8_t *buffer, uint8_t alloc_length) { + zip_t *dev = (zip_t *) p; int ready = 0; ready = (dev->drv->f != NULL); @@ -1483,9 +1441,10 @@ zip_buf_free(zip_t *dev) } -void -zip_command(zip_t *dev, uint8_t *cdb) +static void +zip_command(void *p, uint8_t *cdb) { + zip_t *dev = (zip_t *) p; int pos = 0, block_desc = 0; int ret; int32_t len, max_len; @@ -1497,7 +1456,7 @@ zip_command(zip_t *dev, uint8_t *cdb) int32_t *BufLen; if (dev->drv->bus_type == ZIP_BUS_SCSI) { - BufLen = &SCSIDevices[dev->drv->scsi_device_id].BufferLength; + BufLen = &scsi_devices[dev->drv->scsi_device_id].buffer_length; dev->status &= ~ERR_STAT; } else { BufLen = &blen; @@ -1507,8 +1466,6 @@ zip_command(zip_t *dev, uint8_t *cdb) dev->packet_len = 0; dev->request_pos = 0; - dev->data_pos = 0; - memcpy(dev->current_cdb, cdb, 12); if (cdb[0] != 0) { @@ -1597,7 +1554,7 @@ zip_command(zip_t *dev, uint8_t *cdb) if (!max_len) { zip_set_phase(dev, SCSI_PHASE_STATUS); - dev->packet_status = ZIP_PHASE_COMPLETE; + dev->packet_status = PHASE_COMPLETE; dev->callback = 20LL * ZIP_TIME; zip_set_callback(dev); break; @@ -1650,7 +1607,7 @@ zip_command(zip_t *dev, uint8_t *cdb) if (!dev->sector_len) { zip_set_phase(dev, SCSI_PHASE_STATUS); /* zip_log("ZIP %i: All done - callback set\n", dev->id); */ - dev->packet_status = ZIP_PHASE_COMPLETE; + dev->packet_status = PHASE_COMPLETE; dev->callback = 20LL * ZIP_TIME; zip_set_callback(dev); break; @@ -1677,8 +1634,7 @@ zip_command(zip_t *dev, uint8_t *cdb) zip_data_command_finish(dev, alloc_length, 512, alloc_length, 0); - dev->all_blocks_total = dev->block_total; - if (dev->packet_status != ZIP_PHASE_COMPLETE) + if (dev->packet_status != PHASE_COMPLETE) ui_sb_update_icon(SB_ZIP | dev->id, 1); else ui_sb_update_icon(SB_ZIP | dev->id, 0); @@ -1743,7 +1699,7 @@ zip_command(zip_t *dev, uint8_t *cdb) if (!dev->sector_len) { zip_set_phase(dev, SCSI_PHASE_STATUS); /* zip_log("ZIP %i: All done - callback set\n", dev->id); */ - dev->packet_status = ZIP_PHASE_COMPLETE; + dev->packet_status = PHASE_COMPLETE; dev->callback = 20LL * ZIP_TIME; zip_set_callback(dev); break; @@ -1764,8 +1720,7 @@ zip_command(zip_t *dev, uint8_t *cdb) zip_data_command_finish(dev, dev->packet_len, 512, dev->packet_len, 1); - dev->all_blocks_total = dev->block_total; - if (dev->packet_status != ZIP_PHASE_COMPLETE) + if (dev->packet_status != PHASE_COMPLETE) ui_sb_update_icon(SB_ZIP | dev->id, 1); else ui_sb_update_icon(SB_ZIP | dev->id, 0); @@ -1805,7 +1760,7 @@ zip_command(zip_t *dev, uint8_t *cdb) if (!dev->sector_len) { zip_set_phase(dev, SCSI_PHASE_STATUS); /* zip_log("ZIP %i: All done - callback set\n", dev->id); */ - dev->packet_status = ZIP_PHASE_COMPLETE; + dev->packet_status = PHASE_COMPLETE; dev->callback = 20LL * ZIP_TIME; zip_set_callback(dev); break; @@ -1826,8 +1781,7 @@ zip_command(zip_t *dev, uint8_t *cdb) zip_data_command_finish(dev, dev->packet_len, 512, dev->packet_len, 1); - dev->all_blocks_total = dev->block_total; - if (dev->packet_status != ZIP_PHASE_COMPLETE) + if (dev->packet_status != PHASE_COMPLETE) ui_sb_update_icon(SB_ZIP | dev->id, 1); else ui_sb_update_icon(SB_ZIP | dev->id, 0); @@ -1850,10 +1804,7 @@ zip_command(zip_t *dev, uint8_t *cdb) zip_buf_alloc(dev, 65536); } - dev->current_page_code = cdb[2] & 0x3F; - zip_log("Mode sense page: %02X\n", dev->current_page_code); - - if (!(zip_mode_sense_page_flags & (1LL << dev->current_page_code))) { + if (!(zip_mode_sense_page_flags & (1LL << (uint64_t) (cdb[2] & 0x3f)))) { zip_invalid_field(dev); zip_buf_free(dev); return; @@ -1905,8 +1856,6 @@ zip_command(zip_t *dev, uint8_t *cdb) dev->total_length = len; dev->do_page_save = cdb[1] & 1; - dev->current_page_pos = 0; - zip_data_command_finish(dev, len, len, len, 1); return; @@ -2335,11 +2284,11 @@ zip_pio_request(zip_t *dev, uint8_t out) zip_log("ZIP %i: Packet length %i, request length %i\n", dev->id, dev->packet_len, dev->max_transfer_len); - dev->packet_status = out ? ZIP_PHASE_DATA_OUT : ZIP_PHASE_DATA_IN; + dev->packet_status = out ? PHASE_DATA_OUT : PHASE_DATA_IN; dev->status = BUSY_STAT; dev->phase = 1; - zip_phase_callback(dev); + zip_callback((void *) dev); dev->callback = 0LL; zip_set_callback(dev); @@ -2349,22 +2298,17 @@ zip_pio_request(zip_t *dev, uint8_t out) static int -zip_read_from_ide_dma(uint8_t channel) +zip_read_from_ide_dma(zip_t *dev) { - zip_t *dev; - - uint8_t id = atapi_zip_drives[channel]; int ret; - if (id > ZIP_NUM) + if (!dev) return 0; - dev = zip[id]; - if (ide_bus_master_write) { - ret = ide_bus_master_write(channel >> 1, + ret = ide_bus_master_write(dev->drv->ide_channel >> 1, zipbufferb, dev->packet_len, - ide_bus_master_priv[channel >> 1]); + ide_bus_master_priv[dev->drv->ide_channel >> 1]); if (ret == 2) /* DMA not enabled, wait for it to be enabled. */ return 2; else if (ret == 1) { /* DMA error. */ @@ -2380,18 +2324,14 @@ zip_read_from_ide_dma(uint8_t channel) static int zip_read_from_scsi_dma(uint8_t scsi_id) { - zip_t *dev; + zip_t *dev = (zip_t *) scsi_devices[scsi_id].p; + int32_t *BufLen = &scsi_devices[scsi_id].buffer_length; - uint8_t id = scsi_zip_drives[scsi_id]; - int32_t *BufLen = &SCSIDevices[scsi_id].BufferLength; - - if (id > ZIP_NUM) + if (!dev) return 0; - dev = zip[id]; - zip_log("Reading from SCSI DMA: SCSI ID %02X, init length %i\n", scsi_id, *BufLen); - memcpy(zipbufferb, SCSIDevices[scsi_id].CmdBuffer, *BufLen); + memcpy(zipbufferb, scsi_devices[scsi_id].cmd_buffer, *BufLen); return 1; } @@ -2407,13 +2347,13 @@ zip_irq_raise(zip_t *dev) static int zip_read_from_dma(zip_t *dev) { - int32_t *BufLen = &SCSIDevices[dev->drv->scsi_device_id].BufferLength; + int32_t *BufLen = &scsi_devices[dev->drv->scsi_device_id].buffer_length; int ret = 0; if (dev->drv->bus_type == ZIP_BUS_SCSI) ret = zip_read_from_scsi_dma(dev->drv->scsi_device_id); else - ret = zip_read_from_ide_dma(dev->drv->ide_channel); + ret = zip_read_from_ide_dma(dev); if (ret != 1) return ret; @@ -2433,24 +2373,17 @@ zip_read_from_dma(zip_t *dev) static int -zip_write_to_ide_dma(uint8_t channel) +zip_write_to_ide_dma(zip_t *dev) { - zip_t *dev; - - uint8_t id = atapi_zip_drives[channel]; int ret; - if (id > ZIP_NUM) { - zip_log("ZIP %i: Drive not found\n", id); + if (!dev) return 0; - } - - dev = zip[id]; if (ide_bus_master_read) { - ret = ide_bus_master_read(channel >> 1, + ret = ide_bus_master_read(dev->drv->ide_channel >> 1, zipbufferb, dev->packet_len, - ide_bus_master_priv[channel >> 1]); + ide_bus_master_priv[dev->drv->ide_channel >> 1]); if (ret == 2) /* DMA not enabled, wait for it to be enabled. */ return 2; else if (ret == 1) { /* DMA error. */ @@ -2466,26 +2399,17 @@ zip_write_to_ide_dma(uint8_t channel) static int zip_write_to_scsi_dma(uint8_t scsi_id) { - zip_t *dev; + zip_t *dev = (zip_t *) scsi_devices[scsi_id].p; + int32_t *BufLen = &scsi_devices[scsi_id].buffer_length; - uint8_t id = scsi_zip_drives[scsi_id]; - int32_t *BufLen = &SCSIDevices[scsi_id].BufferLength; - - if (id > ZIP_NUM) + if (!dev) return 0; - dev = zip[id]; - zip_log("Writing to SCSI DMA: SCSI ID %02X, init length %i\n", scsi_id, *BufLen); - memcpy(SCSIDevices[scsi_id].CmdBuffer, zipbufferb, *BufLen); - zip_log("ZIP %i: Data from CD buffer: %02X %02X %02X %02X %02X %02X %02X %02X\n", id, + memcpy(scsi_devices[scsi_id].cmd_buffer, zipbufferb, *BufLen); + zip_log("ZIP %i: Data from CD buffer: %02X %02X %02X %02X %02X %02X %02X %02X\n", dev->id, zipbufferb[0], zipbufferb[1], zipbufferb[2], zipbufferb[3], zipbufferb[4], zipbufferb[5], zipbufferb[6], zipbufferb[7]); - zip_log("ZIP %i: Data from SCSI DMA : %02X %02X %02X %02X %02X %02X %02X %02X\n", id, - SCSIDevices[scsi_id].CmdBuffer[0], SCSIDevices[scsi_id].CmdBuffer[1], - SCSIDevices[scsi_id].CmdBuffer[2], SCSIDevices[scsi_id].CmdBuffer[3], - SCSIDevices[scsi_id].CmdBuffer[4], SCSIDevices[scsi_id].CmdBuffer[5], - SCSIDevices[scsi_id].CmdBuffer[6], SCSIDevices[scsi_id].CmdBuffer[7]); return 1; } @@ -2493,14 +2417,14 @@ zip_write_to_scsi_dma(uint8_t scsi_id) static int zip_write_to_dma(zip_t *dev) { - int32_t *BufLen = &SCSIDevices[dev->drv->scsi_device_id].BufferLength; + int32_t *BufLen = &scsi_devices[dev->drv->scsi_device_id].buffer_length; int ret = 0; if (dev->drv->bus_type == ZIP_BUS_SCSI) { zip_log("Write to SCSI DMA: (ID %02X)\n", dev->drv->scsi_device_id); ret = zip_write_to_scsi_dma(dev->drv->scsi_device_id); } else - ret = zip_write_to_ide_dma(dev->drv->ide_channel); + ret = zip_write_to_ide_dma(dev); if (dev->drv->bus_type == ZIP_BUS_SCSI) zip_log("ZIP %i: SCSI Output data length: %i\n", dev->id, *BufLen); @@ -2511,40 +2435,41 @@ zip_write_to_dma(zip_t *dev) } -void -zip_phase_callback(zip_t *dev) +static void +zip_callback(void *p) { + zip_t *dev = (zip_t *) p; int ret; switch(dev->packet_status) { - case ZIP_PHASE_IDLE: - zip_log("ZIP %i: ZIP_PHASE_IDLE\n", dev->id); + case PHASE_IDLE: + zip_log("ZIP %i: PHASE_IDLE\n", dev->id); dev->pos = 0; dev->phase = 1; dev->status = READY_STAT | DRQ_STAT | (dev->status & ERR_STAT); return; - case ZIP_PHASE_COMMAND: - zip_log("ZIP %i: ZIP_PHASE_COMMAND\n", dev->id); + case PHASE_COMMAND: + zip_log("ZIP %i: PHASE_COMMAND\n", dev->id); dev->status = BUSY_STAT | (dev->status & ERR_STAT); memcpy(dev->atapi_cdb, zipbufferb, 12); zip_command(dev, dev->atapi_cdb); return; - case ZIP_PHASE_COMPLETE: - zip_log("ZIP %i: ZIP_PHASE_COMPLETE\n", dev->id); + case PHASE_COMPLETE: + zip_log("ZIP %i: PHASE_COMPLETE\n", dev->id); dev->status = READY_STAT; dev->phase = 3; dev->packet_status = 0xFF; ui_sb_update_icon(SB_ZIP | dev->id, 0); zip_irq_raise(dev); return; - case ZIP_PHASE_DATA_OUT: - zip_log("ZIP %i: ZIP_PHASE_DATA_OUT\n", dev->id); + case PHASE_DATA_OUT: + zip_log("ZIP %i: PHASE_DATA_OUT\n", dev->id); dev->status = READY_STAT | DRQ_STAT | (dev->status & ERR_STAT); dev->phase = 0; zip_irq_raise(dev); return; - case ZIP_PHASE_DATA_OUT_DMA: - zip_log("ZIP %i: ZIP_PHASE_DATA_OUT_DMA\n", dev->id); + case PHASE_DATA_OUT_DMA: + zip_log("ZIP %i: PHASE_DATA_OUT_DMA\n", dev->id); ret = zip_read_from_dma(dev); if ((ret == 1) || (dev->drv->bus_type == ZIP_BUS_SCSI)) { @@ -2559,14 +2484,14 @@ zip_phase_callback(zip_t *dev) zip_buf_free(dev); } return; - case ZIP_PHASE_DATA_IN: - zip_log("ZIP %i: ZIP_PHASE_DATA_IN\n", dev->id); + case PHASE_DATA_IN: + zip_log("ZIP %i: PHASE_DATA_IN\n", dev->id); dev->status = READY_STAT | DRQ_STAT | (dev->status & ERR_STAT); dev->phase = 2; zip_irq_raise(dev); return; - case ZIP_PHASE_DATA_IN_DMA: - zip_log("ZIP %i: ZIP_PHASE_DATA_IN_DMA\n", dev->id); + case PHASE_DATA_IN_DMA: + zip_log("ZIP %i: PHASE_DATA_IN_DMA\n", dev->id); ret = zip_write_to_dma(dev); if ((ret == 1) || (dev->drv->bus_type == ZIP_BUS_SCSI)) { @@ -2581,8 +2506,8 @@ zip_phase_callback(zip_t *dev) zip_buf_free(dev); } return; - case ZIP_PHASE_ERROR: - zip_log("ZIP %i: ZIP_PHASE_ERROR\n", dev->id); + case PHASE_ERROR: + zip_log("ZIP %i: PHASE_ERROR\n", dev->id); dev->status = READY_STAT | ERR_STAT; dev->phase = 3; dev->packet_status = 0xFF; @@ -2593,23 +2518,19 @@ zip_phase_callback(zip_t *dev) } -uint32_t -zip_read(uint8_t channel, int length) +static uint32_t +zip_packet_read(void *p, int length) { - zip_t *dev; + zip_t *dev = (zip_t *) p; uint16_t *zipbufferw; uint32_t *zipbufferl; - uint8_t id = atapi_zip_drives[channel]; - uint32_t temp = 0; - if (id > ZIP_NUM) + if (!dev) return 0; - dev = zip[id]; - zipbufferw = (uint16_t *) zipbufferb; zipbufferl = (uint32_t *) zipbufferb; @@ -2639,39 +2560,29 @@ zip_read(uint8_t channel, int length) return 0; } - if (dev->packet_status == ZIP_PHASE_DATA_IN) { - zip_log("ZIP %i: Returning: %04X (buffer position: %05i, request position: %05i)\n", - id, temp, (dev->pos - 2) & 0xffff, (dev->request_pos - 2) & 0xffff); + if (dev->packet_status == PHASE_DATA_IN) { if ((dev->request_pos >= dev->max_transfer_len) || (dev->pos >= dev->packet_len)) { /* Time for a DRQ. */ - zip_log("ZIP %i: Issuing read callback\n", id); zip_pio_request(dev, 0); } return temp; - } else { - zip_log("ZIP %i: Returning: 0000 (buffer position: %05i, request position: %05i)\n", - id, (dev->pos - 2) & 0xffff, (dev->request_pos - 2) & 0xffff); + } else return 0; - } } -void -zip_write(uint8_t channel, uint32_t val, int length) +static void +zip_packet_write(void *p, uint32_t val, int length) { - zip_t *dev; + zip_t *dev = (zip_t *) p; uint16_t *zipbufferw; uint32_t *zipbufferl; - uint8_t id = atapi_zip_drives[channel]; - - if (id > ZIP_NUM) + if (!dev) return; - dev = zip[id]; - - if (dev->packet_status == ZIP_PHASE_IDLE) { + if (dev->packet_status == PHASE_IDLE) { if (!zipbufferb) zip_buf_alloc(dev, 12); } @@ -2702,19 +2613,19 @@ zip_write(uint8_t channel, uint32_t val, int length) return; } - if (dev->packet_status == ZIP_PHASE_DATA_OUT) { + if (dev->packet_status == PHASE_DATA_OUT) { if ((dev->request_pos >= dev->max_transfer_len) || (dev->pos >= dev->packet_len)) { /* Time for a DRQ. */ zip_pio_request(dev, 1); } return; - } else if (dev->packet_status == ZIP_PHASE_IDLE) { + } else if (dev->packet_status == PHASE_IDLE) { if (dev->pos >= 12) { dev->pos = 0; dev->status = BUSY_STAT; - dev->packet_status = ZIP_PHASE_COMMAND; + dev->packet_status = PHASE_COMMAND; timer_process(); - zip_phase_callback(dev); + zip_callback((void *) dev); timer_update_outstanding(); } return; @@ -2732,19 +2643,168 @@ zip_global_init(void) } +static void +zip_100_identify(ide_t *ide) +{ + ide_padstr((char *) (ide->buffer + 23), "E.08", 8); /* Firmware */ + ide_padstr((char *) (ide->buffer + 27), "IOMEGA ZIP 100 ATAPI", 40); /* Model */ +} + + +static void +zip_250_identify(ide_t *ide, int ide_has_dma) +{ + ide_padstr((char *) (ide->buffer + 23), "42.S", 8); /* Firmware */ + ide_padstr((char *) (ide->buffer + 27), "IOMEGA ZIP 250 ATAPI", 40); /* Model */ + + if (ide_has_dma) { + ide->buffer[80] = 0x30; /*Supported ATA versions : ATA/ATAPI-4 ATA/ATAPI-5*/ + ide->buffer[81] = 0x15; /*Maximum ATA revision supported : ATA/ATAPI-5 T13 1321D revision 1*/ + } +} + + +static int +zip_get_max(int ide_has_dma, int type) +{ + int ret; + + switch(type) { + case TYPE_PIO: + ret = ide_has_dma ? 3 : 0; + break; + case TYPE_SDMA: + default: + ret = -1; + break; + case TYPE_MDMA: + ret = ide_has_dma ? -1 : 1; + break; + case TYPE_UDMA: + ret = ide_has_dma ? -1 : 2; + break; + } + + return ret; +} + + +static int +zip_get_timings(int ide_has_dma, int type) +{ + int ret; + + switch(type) { + case TIMINGS_DMA: + ret = ide_has_dma ? 0x96 : 0; + break; + case TIMINGS_PIO: + ret = ide_has_dma ? 0xb4 : 0; + break; + case TIMINGS_PIO_FC: + ret = ide_has_dma ? 0xb4 : 0; + break; + default: + ret = 0; + break; + } + + return ret; +} + + +static void +zip_identify(void *p, int ide_has_dma) +{ + ide_t *ide = (ide_t *) p; + zip_t *zip; + + zip = (zip_t *) ide->p; + + /* Using (2<<5) below makes the ASUS P/I-P54TP4XE misdentify the ZIP drive + as a LS-120. */ + ide->buffer[0] = 0x8000 | (0<<8) | 0x80 | (1<<5); /* ATAPI device, direct-access device, removable media, interrupt DRQ */ + ide_padstr((char *) (ide->buffer + 10), "", 20); /* Serial Number */ + ide->buffer[49] = 0x200; /* LBA supported */ + ide->buffer[126] = 0xfffe; /* Interpret zero byte count limit as maximum length */ + + if (zip_drives[zip->id].is_250) + zip_250_identify(ide, ide_has_dma); + else + zip_100_identify(ide); +} + + +static zip_t * +zip_drive_reset(int c) +{ + scsi_device_t *sd; + ide_t *id; + + if (!zip[c]) { + zip[c] = (zip_t *) malloc(sizeof(zip_t)); + memset(zip[c], 0, sizeof(zip_t)); + } + + zip[c]->id = c; + + if (zip_drives[c].bus_type == ZIP_BUS_SCSI) { + /* SCSI ZIP, attach to the SCSI bus. */ + sd = &scsi_devices[zip_drives[c].scsi_device_id]; + + sd->p = zip[c]; + sd->command = zip_command; + sd->callback = zip_callback; + sd->err_stat_to_scsi = zip_err_stat_to_scsi; + sd->request_sense = zip_request_sense_for_scsi; + sd->reset = zip_reset; + sd->read_capacity = zip_read_capacity; + sd->type = SCSI_REMOVABLE_DISK; + } else if (zip_drives[c].bus_type == ZIP_BUS_ATAPI) { + /* ATAPI CD-ROM, attach to the IDE bus. */ + id = ide_drives[zip_drives[c].ide_channel]; + /* If the IDE channel is initialized, we attach to it, + otherwise, we do nothing - it's going to be a drive + that's not attached to anything. */ + if (id) { + id->p = zip[c]; + id->get_max = zip_get_max; + id->get_timings = zip_get_timings; + id->identify = zip_identify; + id->set_signature = zip_set_signature; + id->packet_write = zip_packet_write; + id->packet_read = zip_packet_read; + id->stop = NULL; + id->packet_callback = zip_callback; + id->device_reset = zip_reset; + id->interrupt_drq = 1; + + ide_atapi_attach(id); + } + } + + return zip[c]; +} + + void zip_hard_reset(void) { int c; for (c = 0; c < ZIP_NUM; c++) { - if (zip_drives[c].bus_type) { + if ((zip_drives[c].bus_type == ZIP_BUS_ATAPI) || (zip_drives[c].bus_type == ZIP_BUS_SCSI)) { zip_log("ZIP hard_reset drive=%d\n", c); - if (!zip[c]) { - zip[c] = (zip_t *) malloc(sizeof(zip_t)); - memset(zip[c], 0, sizeof(zip_t)); - } + /* Make sure to ignore any SCSI ZIP drive that has an out of range ID. */ + if ((zip_drives[c].bus_type == ZIP_BUS_SCSI) && (zip_drives[c].scsi_device_id > SCSI_ID_MAX)) + continue; + + /* Make sure to ignore any ATAPI ZIP drive that has an out of range IDE channel. */ + if ((zip_drives[c].bus_type == ZIP_BUS_ATAPI) && (zip_drives[c].ide_channel > 7)) + continue; + + zip[c] = zip_drive_reset(c); zip[c]->id = c; zip[c]->drv = &zip_drives[c]; @@ -2755,10 +2815,13 @@ zip_hard_reset(void) zip_load(zip[c], zip_drives[c].image_path); zip_mode_sense_load(zip[c]); + + if (zip_drives[c].bus_type == ZIP_BUS_SCSI) + zip_log("SCSI ZIP drive %i attached to SCSI ID %i\n", c, zip_drives[c].scsi_device_id); + else if (zip_drives[c].bus_type == ZIP_BUS_ATAPI) + zip_log("ATAPI ZIP drive %i attached to IDE channel %i\n", c, zip_drives[c].ide_channel); } } - - build_atapi_zip_map(); } diff --git a/src/disk/zip.h b/src/disk/zip.h index 67be6797b..6c7fd16a3 100644 --- a/src/disk/zip.h +++ b/src/disk/zip.h @@ -21,15 +21,6 @@ #define ZIP_NUM 4 -#define ZIP_PHASE_IDLE 0x00 -#define ZIP_PHASE_COMMAND 0x01 -#define ZIP_PHASE_COMPLETE 0x02 -#define ZIP_PHASE_DATA_IN 0x03 -#define ZIP_PHASE_DATA_IN_DMA 0x04 -#define ZIP_PHASE_DATA_OUT 0x05 -#define ZIP_PHASE_DATA_OUT_DMA 0x06 -#define ZIP_PHASE_ERROR 0x80 - #define BUF_SIZE 32768 #define ZIP_TIME (5LL * 100LL * (1LL << TIMER_SHIFT)) @@ -70,34 +61,30 @@ typedef struct { zip_drive_t *drv; - uint8_t previous_command, - error, features, - status, phase, - id, *buffer, + uint8_t *buffer, atapi_cdb[16], current_cdb[16], sense[256]; + uint8_t status, phase, + error, id, + features, pad0, + pad1, pad2; + uint16_t request_length, max_transfer_len; - int toctimes, media_status, - is_dma, requested_blocks, - current_page_len, current_page_pos, - total_length, written_length, - mode_select_phase, do_page_save, - callback, data_pos, - packet_status, unit_attention, - cdb_len_setting, cdb_len, - request_pos, total_read, - block_total, all_blocks_total, - old_len, block_descriptor_len, - init_length; + int requested_blocks, packet_status, + total_length, do_page_save, + unit_attention; uint32_t sector_pos, sector_len, - packet_len, pos, - seek_pos; + packet_len, pos; - uint64_t current_page_code; + int64_t callback; + + int request_pos, old_len; + + uint32_t seek_pos; } zip_t; @@ -121,29 +108,14 @@ extern int (*ide_bus_master_write)(int channel, uint8_t *data, int transfer_leng extern void (*ide_bus_master_set_irq)(int channel, void *priv); extern void *ide_bus_master_priv[2]; -extern void build_atapi_zip_map(void); -extern void build_scsi_zip_map(void); -extern int zip_ZIP_PHASE_to_scsi(zip_t *dev); -extern int zip_atapi_phase_to_scsi(zip_t *dev); -extern void zip_command(zip_t *dev, uint8_t *cdb); -extern void zip_phase_callback(zip_t *dev); -extern uint32_t zip_read(uint8_t channel, int length); -extern void zip_write(uint8_t channel, uint32_t val, int length); - extern void zip_disk_close(zip_t *dev); extern void zip_disk_reload(zip_t *dev); -extern void zip_reset(zip_t *dev); -extern void zip_set_signature(zip_t *dev); -extern void zip_request_sense_for_scsi(zip_t *dev, uint8_t *buffer, uint8_t alloc_length); -extern void zip_update_cdb(uint8_t *cdb, int lba_pos, int number_of_blocks); extern void zip_insert(zip_t *dev); -extern int find_zip_for_scsi_id(uint8_t scsi_id); -extern int zip_read_capacity(zip_t *dev, uint8_t *cdb, uint8_t *buffer, uint32_t *len); - extern void zip_global_init(void); extern void zip_hard_reset(void); +extern void zip_reset(void *p); extern int zip_load(zip_t *dev, wchar_t *fn); extern void zip_close(); diff --git a/src/intel_piix.c b/src/intel_piix.c index 41f44b029..877605aeb 100644 --- a/src/intel_piix.c +++ b/src/intel_piix.c @@ -26,8 +26,9 @@ #include #define HAVE_STDARG_H #include "86box.h" -#include "scsi/scsi_device.h" #include "cdrom/cdrom.h" +#include "scsi/scsi_device.h" +#include "scsi/scsi_cdrom.h" #include "dma.h" #include "io.h" #include "device.h" @@ -825,7 +826,7 @@ piix_reset(void *p) for (i = 0; i < CDROM_NUM; i++) { if (cdrom_drives[i].bus_type == CDROM_BUS_ATAPI) - cdrom_reset(cdrom[i]); + scsi_cdrom_reset(scsi_cdrom[i]); } for (i = 0; i < ZIP_NUM; i++) { if (zip_drives[i].bus_type == ZIP_BUS_ATAPI) diff --git a/src/pc.c b/src/pc.c index 90ff5177e..e44571ba5 100644 --- a/src/pc.c +++ b/src/pc.c @@ -8,7 +8,7 @@ * * Main emulator module where most things are controlled. * - * Version: @(#)pc.c 1.0.80 2018/10/02 + * Version: @(#)pc.c 1.0.81 2018/10/10 * * Authors: Sarah Walker, * Miran Grca, @@ -665,14 +665,15 @@ again2: hdc_init(hdc_name); + scsi_card_init(); + + /* These now come after as they now attach to the bus. */ + scsi_disk_hard_reset(); + cdrom_hard_reset(); zip_hard_reset(); - scsi_disk_hard_reset(); - - scsi_card_init(); - pc_full_speed(); shadowbios = 0; @@ -736,6 +737,10 @@ pc_reset_hard_close(void) cdrom_close(); + zip_close(); + + scsi_disk_close(); + closeal(); } @@ -766,15 +771,12 @@ pc_reset_hard_init(void) /* This is needed to initialize the serial timer. */ serial_init(); - cdrom_hard_reset(); - - zip_hard_reset(); - - scsi_disk_hard_reset(); - /* Initialize the actual machine and its basic modules. */ machine_init(); + /* Reset and reconfigure the Sound Card layer. */ + sound_card_reset(); + /* Reset any ISA memory cards. */ isamem_reset(); @@ -811,8 +813,11 @@ pc_reset_hard_init(void) /* Reset and reconfigure the SCSI layer. */ scsi_card_init(); - /* Reset and reconfigure the Sound Card layer. */ - sound_card_reset(); + cdrom_hard_reset(); + + zip_hard_reset(); + + scsi_disk_hard_reset(); /* Reset and reconfigure the Network Card layer. */ network_reset(); @@ -917,6 +922,7 @@ pc_close(thread_t *ptr) network_close(); sound_cd_thread_end(); + cdrom_close(); zip_close(); diff --git a/src/scsi/scsi.c b/src/scsi/scsi.c index d0dcd34f3..bea9e7310 100644 --- a/src/scsi/scsi.c +++ b/src/scsi/scsi.c @@ -8,7 +8,7 @@ * * Handling of the SCSI controllers. * - * Version: @(#)scsi.c 1.0.21 2018/10/02 + * Version: @(#)scsi.c 1.0.22 2018/10/10 * * Authors: Miran Grca, * Fred N. van Kempen, @@ -43,15 +43,9 @@ #endif -scsi_device_t SCSIDevices[SCSI_ID_MAX]; -char scsi_fn[SCSI_NUM][512]; -uint16_t scsi_disk_location[SCSI_NUM]; - int scsi_card_current = 0; int scsi_card_last = 0; -uint32_t SCSI_BufferLength; - typedef const struct { const char *name; @@ -83,26 +77,6 @@ static SCSI_CARD scsi_cards[] = { }; -#ifdef ENABLE_SCSI_LOG -int scsi_do_log = ENABLE_SCSI_LOG; -#endif - - -static void -scsi_log(const char *fmt, ...) -{ -#ifdef ENABLE_SCSI_LOG - va_list ap; - - if (scsi_do_log) { - va_start(ap, fmt); - pclog_ex(fmt, ap); - va_end(ap); - } -#endif -} - - int scsi_card_available(int card) { if (scsi_cards[card].device) @@ -159,25 +133,13 @@ void scsi_card_init(void) if (!scsi_cards[scsi_card_current].device) return; - scsi_log("Building SCSI hard disk map...\n"); - build_scsi_disk_map(); - scsi_log("Building SCSI CD-ROM map...\n"); - build_scsi_cdrom_map(); - scsi_log("Building SCSI ZIP map...\n"); - build_scsi_zip_map(); + for (i = 0; i < SCSI_ID_MAX; i++) { + if (scsi_devices[i].cmd_buffer) + free(scsi_devices[i].cmd_buffer); + scsi_devices[i].cmd_buffer = NULL; - for (i=0; i * Miran Grca, @@ -556,6 +556,7 @@ BuslogicSCSIBIOSDMATransfer(ESCMD *ESCSICmd, uint8_t TargetID, int dir) int DataLength = ESCSICmd->DataLength; uint32_t Address; uint32_t TransferLength; + scsi_device_t *dev = &scsi_devices[TargetID]; if (ESCSICmd->DataDirection == 0x03) { /* Non-data command. */ @@ -567,16 +568,16 @@ BuslogicSCSIBIOSDMATransfer(ESCMD *ESCSICmd, uint8_t TargetID, int dir) /* If the control byte is 0x00, it means that the transfer direction is set up by the SCSI command without checking its length, so do this procedure for both read/write commands. */ - if ((DataLength > 0) && (SCSIDevices[TargetID].BufferLength > 0)) { + if ((DataLength > 0) && (dev->buffer_length > 0)) { Address = DataPointer; - TransferLength = MIN(DataLength, SCSIDevices[TargetID].BufferLength); + TransferLength = MIN(DataLength, dev->buffer_length); if (dir && ((ESCSICmd->DataDirection == CCB_DATA_XFER_OUT) || (ESCSICmd->DataDirection == 0x00))) { buslogic_log("BusLogic BIOS DMA: Reading %i bytes from %08X\n", TransferLength, Address); - DMAPageRead(Address, (uint8_t *)SCSIDevices[TargetID].CmdBuffer, TransferLength); + DMAPageRead(Address, (uint8_t *)dev->cmd_buffer, TransferLength); } else if (!dir && ((ESCSICmd->DataDirection == CCB_DATA_XFER_IN) || (ESCSICmd->DataDirection == 0x00))) { buslogic_log("BusLogic BIOS DMA: Writing %i bytes at %08X\n", TransferLength, Address); - DMAPageWrite(Address, (uint8_t *)SCSIDevices[TargetID].CmdBuffer, TransferLength); + DMAPageWrite(Address, (uint8_t *)dev->cmd_buffer, TransferLength); } } } @@ -591,6 +592,7 @@ BuslogicSCSIBIOSRequestSetup(x54x_t *dev, uint8_t *CmdBuf, uint8_t *DataInBuf, u int target_cdb_len = 12; uint8_t target_id = 0; int phase; + scsi_device_t *sd = &scsi_devices[ESCSICmd->TargetId]; DataInBuf[0] = DataInBuf[1] = 0; @@ -602,9 +604,9 @@ BuslogicSCSIBIOSRequestSetup(x54x_t *dev, uint8_t *CmdBuf, uint8_t *DataInBuf, u buslogic_log("Scanning SCSI Target ID %i\n", ESCSICmd->TargetId); - SCSIDevices[ESCSICmd->TargetId].Status = SCSI_STATUS_OK; + sd->status = SCSI_STATUS_OK; - if (!scsi_device_present(ESCSICmd->TargetId)) { + if (!scsi_device_present(sd)) { buslogic_log("SCSI Target ID %i has no device attached\n", ESCSICmd->TargetId); DataInBuf[2] = CCB_SELECTION_TIMEOUT; DataInBuf[3] = SCSI_STATUS_OK; @@ -623,7 +625,7 @@ BuslogicSCSIBIOSRequestSetup(x54x_t *dev, uint8_t *CmdBuf, uint8_t *DataInBuf, u target_cdb_len = 12; - if (!scsi_device_valid(ESCSICmd->TargetId)) fatal("SCSI target on ID %02i has disappeared\n", ESCSICmd->TargetId); + if (!scsi_device_valid(sd)) fatal("SCSI target on ID %02i has disappeared\n", ESCSICmd->TargetId); buslogic_log("SCSI target command being executed on: SCSI ID %i, SCSI LUN %i, Target %i\n", ESCSICmd->TargetId, ESCSICmd->LogicalUnit, target_id); @@ -639,26 +641,26 @@ BuslogicSCSIBIOSRequestSetup(x54x_t *dev, uint8_t *CmdBuf, uint8_t *DataInBuf, u memcpy(temp_cdb, ESCSICmd->CDB, target_cdb_len); } - SCSIDevices[ESCSICmd->TargetId].BufferLength = ESCSICmd->DataLength; - scsi_device_command_phase0(ESCSICmd->TargetId, temp_cdb); + sd->buffer_length = ESCSICmd->DataLength; + scsi_device_command_phase0(sd, temp_cdb); - phase = SCSIDevices[ESCSICmd->TargetId].Phase; + phase = sd->phase; if (phase != SCSI_PHASE_STATUS) { if (phase == SCSI_PHASE_DATA_IN) - scsi_device_command_phase1(ESCSICmd->TargetId); + scsi_device_command_phase1(sd); BuslogicSCSIBIOSDMATransfer(ESCSICmd, ESCSICmd->TargetId, (phase == SCSI_PHASE_DATA_OUT)); if (phase == SCSI_PHASE_DATA_OUT) - scsi_device_command_phase1(ESCSICmd->TargetId); + scsi_device_command_phase1(sd); } x54x_buf_free(ESCSICmd->TargetId); buslogic_log("BIOS Request complete\n"); - if (SCSIDevices[ESCSICmd->TargetId].Status == SCSI_STATUS_OK) { + if (sd->status == SCSI_STATUS_OK) { DataInBuf[2] = CCB_COMPLETE; DataInBuf[3] = SCSI_STATUS_OK; - } else if (SCSIDevices[ESCSICmd->TargetId].Status == SCSI_STATUS_CHECK_CONDITION) { + } else if (scsi_devices[ESCSICmd->TargetId].status == SCSI_STATUS_CHECK_CONDITION) { DataInBuf[2] = CCB_COMPLETE; DataInBuf[3] = SCSI_STATUS_CHECK_CONDITION; } @@ -697,15 +699,15 @@ buslogic_cmds(void *p) case 0x23: memset(dev->DataBuf, 0, 8); for (i = 8; i < 15; i++) { - dev->DataBuf[i-8] = 0; - if (scsi_device_present(i) && (i != buslogic_get_host_id(dev))) - dev->DataBuf[i-8] |= 1; + dev->DataBuf[i - 8] = 0; + if (scsi_device_present(&scsi_devices[i]) && (i != buslogic_get_host_id(dev))) + dev->DataBuf[i - 8] |= 1; } dev->DataReplyLeft = 8; break; case 0x24: - for (i=0; i<15; i++) { - if (scsi_device_present(i) && (i != buslogic_get_host_id(dev))) + for (i = 0; i < 15; i++) { + if (scsi_device_present(&scsi_devices[i]) && (i != buslogic_get_host_id(dev))) TargetsPresentMask |= (1 << i); } dev->DataBuf[0] = TargetsPresentMask & 0xFF; diff --git a/src/scsi/scsi_cdrom.c b/src/scsi/scsi_cdrom.c new file mode 100644 index 000000000..4b0c70352 --- /dev/null +++ b/src/scsi/scsi_cdrom.c @@ -0,0 +1,3091 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * Implementation of the CD-ROM drive with SCSI(-like) + * commands, for both ATAPI and SCSI usage. + * + * Version: @(#)scsi_cdrom.c 1.0.52 2018/10/09 + * + * Author: Miran Grca, + * + * Copyright 2016-2018 Miran Grca. + */ +#include +#include +#include +#include +#include +#include +#include +#define HAVE_STDARG_H +#include "../86box.h" +#include "../config.h" +#include "../timer.h" +#include "../device.h" +#include "../piix.h" +#include "../scsi/scsi_device.h" +#include "../nvr.h" +#include "../disk/hdc.h" +#include "../disk/hdc_ide.h" +#include "../plat.h" +#include "../sound/sound.h" +#include "../ui.h" +#include "../cdrom/cdrom.h" +#include "../cdrom/cdrom_image.h" +#include "../cdrom/cdrom_null.h" +#include "scsi_cdrom.h" + + +/* Bits of 'status' */ +#define ERR_STAT 0x01 +#define DRQ_STAT 0x08 /* Data request */ +#define DSC_STAT 0x10 +#define SERVICE_STAT 0x10 +#define READY_STAT 0x40 +#define BUSY_STAT 0x80 + +/* Bits of 'error' */ +#define ABRT_ERR 0x04 /* Command aborted */ +#define MCR_ERR 0x08 /* Media change request */ + +#define cdbufferb dev->buffer + + +scsi_cdrom_t *scsi_cdrom[CDROM_NUM] = { NULL, NULL, NULL, NULL }; + + +#pragma pack(push,1) +typedef struct +{ + uint8_t opcode; + uint8_t polled; + uint8_t reserved2[2]; + uint8_t class; + uint8_t reserved3[2]; + uint16_t len; + uint8_t control; +} gesn_cdb_t; +#pragma pack(pop) + +#pragma pack(push,1) +typedef struct +{ + uint16_t len; + uint8_t notification_class; + uint8_t supported_events; +} gesn_event_header_t; +#pragma pack(pop) + + +/* Table of all SCSI commands and their flags, needed for the new disc change / not ready handler. */ +const uint8_t scsi_cdrom_command_flags[0x100] = +{ + IMPLEMENTED | CHECK_READY | NONDATA, /* 0x00 */ + IMPLEMENTED | ALLOW_UA | NONDATA | SCSI_ONLY, /* 0x01 */ + 0, /* 0x02 */ + IMPLEMENTED | ALLOW_UA, /* 0x03 */ + 0, 0, 0, 0, /* 0x04-0x07 */ + IMPLEMENTED | CHECK_READY, /* 0x08 */ + 0, 0, /* 0x09-0x0A */ + IMPLEMENTED | CHECK_READY | NONDATA, /* 0x0B */ + 0, 0, 0, 0, 0, 0, /* 0x0C-0x11 */ + IMPLEMENTED | ALLOW_UA, /* 0x12 */ + IMPLEMENTED | CHECK_READY | NONDATA | SCSI_ONLY, /* 0x13 */ + 0, /* 0x14 */ + IMPLEMENTED, /* 0x15 */ + 0, 0, 0, 0, /* 0x16-0x19 */ + IMPLEMENTED, /* 0x1A */ + IMPLEMENTED | CHECK_READY, /* 0x1B */ + 0, 0, /* 0x1C-0x1D */ + IMPLEMENTED | CHECK_READY, /* 0x1E */ + 0, 0, 0, 0, 0, 0, /* 0x1F-0x24 */ + IMPLEMENTED | CHECK_READY, /* 0x25 */ + 0, 0, /* 0x26-0x27 */ + IMPLEMENTED | CHECK_READY, /* 0x28 */ + 0, 0, /* 0x29-0x2A */ + IMPLEMENTED | CHECK_READY | NONDATA, /* 0x2B */ + 0, 0, 0, /* 0x2C-0x2E */ + IMPLEMENTED | CHECK_READY | NONDATA | SCSI_ONLY, /* 0x2F */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x30-0x3F */ + 0, 0, /* 0x40-0x41 */ + IMPLEMENTED | CHECK_READY, /* 0x42 */ + IMPLEMENTED | CHECK_READY, /* 0x43 - Read TOC - can get through UNIT_ATTENTION, per VIDE-CDD.SYS + NOTE: The ATAPI reference says otherwise, but I think this is a question of + interpreting things right - the UNIT ATTENTION condition we have here + is a tradition from not ready to ready, by definition the drive + eventually becomes ready, make the condition go away. */ + IMPLEMENTED | CHECK_READY, /* 0x44 */ + IMPLEMENTED | CHECK_READY, /* 0x45 */ + IMPLEMENTED | ALLOW_UA, /* 0x46 */ + IMPLEMENTED | CHECK_READY, /* 0x47 */ + IMPLEMENTED | CHECK_READY, /* 0x48 */ + 0, /* 0x49 */ + IMPLEMENTED | ALLOW_UA, /* 0x4A */ + IMPLEMENTED | CHECK_READY, /* 0x4B */ + 0, 0, /* 0x4C-0x4D */ + IMPLEMENTED | CHECK_READY, /* 0x4E */ + 0, 0, /* 0x4F-0x50 */ + IMPLEMENTED | CHECK_READY, /* 0x51 */ + IMPLEMENTED | CHECK_READY, /* 0x52 */ + 0, 0, /* 0x53-0x54 */ + IMPLEMENTED, /* 0x55 */ + 0, 0, 0, 0, /* 0x56-0x59 */ + IMPLEMENTED, /* 0x5A */ + 0, 0, 0, 0, 0, /* 0x5B-0x5F */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x60-0x6F */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x70-0x7F */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x80-0x8F */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x90-0x9F */ + 0, 0, 0, 0, 0, /* 0xA0-0xA4 */ + IMPLEMENTED | CHECK_READY, /* 0xA5 */ + 0, 0, /* 0xA6-0xA7 */ + IMPLEMENTED | CHECK_READY, /* 0xA8 */ + 0, 0, 0, 0, /* 0xA9-0xAC */ + IMPLEMENTED | CHECK_READY, /* 0xAD */ + 0, /* 0xAE */ + IMPLEMENTED | CHECK_READY | NONDATA | SCSI_ONLY, /* 0xAF */ + 0, 0, 0, 0, /* 0xB0-0xB3 */ + IMPLEMENTED | CHECK_READY | ATAPI_ONLY, /* 0xB4 */ + 0, 0, 0, /* 0xB5-0xB7 */ + IMPLEMENTED | CHECK_READY | ATAPI_ONLY, /* 0xB8 */ + IMPLEMENTED | CHECK_READY, /* 0xB9 */ + IMPLEMENTED | CHECK_READY, /* 0xBA */ + IMPLEMENTED, /* 0xBB */ + IMPLEMENTED | CHECK_READY, /* 0xBC */ + IMPLEMENTED, /* 0xBD */ + IMPLEMENTED | CHECK_READY, /* 0xBE */ + IMPLEMENTED | CHECK_READY, /* 0xBF */ + 0, 0, /* 0xC0-0xC1 */ + IMPLEMENTED | CHECK_READY | SCSI_ONLY, /* 0xC2 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xC3-0xCC */ + IMPLEMENTED | CHECK_READY | SCSI_ONLY, /* 0xCD */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xCE-0xD9 */ + IMPLEMENTED | SCSI_ONLY, /* 0xDA */ + 0, 0, 0, 0, 0, /* 0xDB-0xDF */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xE0-0xEF */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 /* 0xF0-0xFF */ +}; + +static uint64_t scsi_cdrom_mode_sense_page_flags = (GPMODEP_R_W_ERROR_PAGE | + GPMODEP_CDROM_PAGE | + GPMODEP_CDROM_AUDIO_PAGE | + GPMODEP_CAPABILITIES_PAGE | + GPMODEP_ALL_PAGES); + +static const mode_sense_pages_t scsi_cdrom_mode_sense_pages_default = +{ { + { 0, 0 }, + { GPMODE_R_W_ERROR_PAGE, 6, 0, 5, 0, 0, 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { GPMODE_CDROM_PAGE, 6, 0, 1, 0, 60, 0, 75 }, + { 0x8E, 0xE, 4, 0, 0, 0, 0, 75, 1, 255, 2, 255, 0, 0, 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { GPMODE_CAPABILITIES_PAGE, 0x12, 0, 0, 1, 0, 0, 0, 2, 0xC2, 1, 0, 0, 0, 2, 0xC2, 0, 0, 0, 0 } +} }; + +static const mode_sense_pages_t scsi_cdrom_mode_sense_pages_default_scsi = +{ { + { 0, 0 }, + { GPMODE_R_W_ERROR_PAGE, 6, 0, 5, 0, 0, 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { GPMODE_CDROM_PAGE, 6, 0, 1, 0, 60, 0, 75 }, + { 0x8E, 0xE, 5, 4, 0,128, 0, 75, 1, 255, 2, 255, 0, 0, 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { GPMODE_CAPABILITIES_PAGE, 0x12, 0, 0, 1, 0, 0, 0, 2, 0xC2, 1, 0, 0, 0, 2, 0xC2, 0, 0, 0, 0 } +} }; + +static const mode_sense_pages_t scsi_cdrom_mode_sense_pages_changeable = +{ { + { 0, 0 }, + { GPMODE_R_W_ERROR_PAGE, 6, 0xFF, 0xFF, 0, 0, 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { GPMODE_CDROM_PAGE, 6, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, + { 0x8E, 0xE, 0xFF, 0, 0, 0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { GPMODE_CAPABILITIES_PAGE, 0x12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } +} }; + +uint8_t scsi_cdrom_read_capacity_cdb[12] = {0x25, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + +static gesn_cdb_t *gesn_cdb; +static gesn_event_header_t *gesn_event_header; + + +static void scsi_cdrom_command_complete(scsi_cdrom_t *dev); + +static void scsi_cdrom_mode_sense_load(scsi_cdrom_t *dev); + +static void scsi_cdrom_init(scsi_cdrom_t *dev); + +static void scsi_cdrom_callback(void *p); + + +#ifdef ENABLE_SCSI_CDROM_LOG +int scsi_cdrom_do_log = ENABLE_SCSI_CDROM_LOG; +#endif + + +static void +scsi_cdrom_log(const char *format, ...) +{ +#ifdef ENABLE_SCSI_CDROM_LOG + va_list ap; + + if (scsi_cdrom_do_log) { + va_start(ap, format); + pclog_ex(format, ap); + va_end(ap); + } +#endif +} + + +static void +scsi_cdrom_set_callback(scsi_cdrom_t *dev) +{ + if (dev && dev->drv && (dev->drv->bus_type != CDROM_BUS_SCSI)) + ide_set_callback(dev->drv->ide_channel >> 1, dev->callback); +} + + +static void +scsi_cdrom_set_signature(void *p) +{ + scsi_cdrom_t *dev = (scsi_cdrom_t *) p; + + if (!dev) + return; + dev->phase = 1; + dev->request_length = 0xEB14; +} + + +static void +scsi_cdrom_init(scsi_cdrom_t *dev) +{ + if (!dev) + return; + + /* Tell the scsi_cdrom_t struct what cdrom_drives element corresponds to it. */ + dev->drv = &(cdrom_drives[dev->id]); + + /* Do a reset (which will also rezero it). */ + scsi_cdrom_reset(dev); + + /* Configure the drive. */ + dev->requested_blocks = 1; + + dev->drv->bus_mode = 0; + if (dev->drv->bus_type >= CDROM_BUS_ATAPI) + dev->drv->bus_mode |= 2; + if (dev->drv->bus_type < CDROM_BUS_SCSI) + dev->drv->bus_mode |= 1; + scsi_cdrom_log("CD-ROM %i: Bus type %i, bus mode %i\n", dev->id, dev->drv->bus_type, dev->drv->bus_mode); + + dev->sense[0] = 0xf0; + dev->sense[7] = 10; + dev->status = READY_STAT | DSC_STAT; + dev->pos = 0; + dev->packet_status = 0xff; + scsi_cdrom_sense_key = scsi_cdrom_asc = scsi_cdrom_ascq = dev->unit_attention = 0; + dev->drv->cur_speed = dev->drv->speed; + scsi_cdrom_mode_sense_load(dev); +} + + +/* Returns: 0 for none, 1 for PIO, 2 for DMA. */ +static int +scsi_cdrom_current_mode(scsi_cdrom_t *dev) +{ + if (dev->drv->bus_type == CDROM_BUS_SCSI) + return 2; + else if (dev->drv->bus_type == CDROM_BUS_ATAPI) { + scsi_cdrom_log("CD-ROM %i: ATAPI drive, setting to %s\n", dev->id, + (dev->features & 1) ? "DMA" : "PIO", + dev->id); + return (dev->features & 1) ? 2 : 1; + } + + return 0; +} + + +/* Translates ATAPI status (ERR_STAT flag) to SCSI status. */ +int +scsi_cdrom_err_stat_to_scsi(void *p) +{ + scsi_cdrom_t *dev = (scsi_cdrom_t *) p; + + if (dev->status & ERR_STAT) + return SCSI_STATUS_CHECK_CONDITION; + else + return SCSI_STATUS_OK; +} + + +/* Translates ATAPI phase (DRQ, I/O, C/D) to SCSI phase (MSG, C/D, I/O). */ +int +scsi_cdrom_atapi_phase_to_scsi(scsi_cdrom_t *dev) +{ + if (dev->status & 8) { + switch (dev->phase & 3) { + case 0: + return 0; + case 1: + return 2; + case 2: + return 1; + case 3: + return 7; + } + } else { + if ((dev->phase & 3) == 3) + return 3; + else + return 4; + } + + return 0; +} + + +static uint32_t +scsi_cdrom_get_channel(void *p, int channel) +{ + scsi_cdrom_t *dev = (scsi_cdrom_t *) p; + if (!dev) + return channel + 1; + + return dev->ms_pages_saved.pages[GPMODE_CDROM_AUDIO_PAGE][channel ? 10 : 8]; +} + + +static uint32_t +scsi_cdrom_get_volume(void *p, int channel) +{ + scsi_cdrom_t *dev = (scsi_cdrom_t *) p; + if (!dev) + return 255; + + return dev->ms_pages_saved.pages[GPMODE_CDROM_AUDIO_PAGE][channel ? 11 : 9]; +} + + +static void +scsi_cdrom_mode_sense_load(scsi_cdrom_t *dev) +{ + FILE *f; + wchar_t file_name[512]; + int i; + + memset(&dev->ms_pages_saved, 0, sizeof(mode_sense_pages_t)); + for (i = 0; i < 0x3f; i++) { + if (scsi_cdrom_mode_sense_pages_default.pages[i][1] != 0) { + if (dev->drv->bus_type == CDROM_BUS_SCSI) + memcpy(dev->ms_pages_saved.pages[i], + scsi_cdrom_mode_sense_pages_default_scsi.pages[i], + scsi_cdrom_mode_sense_pages_default_scsi.pages[i][1] + 2); + else + memcpy(dev->ms_pages_saved.pages[i], + scsi_cdrom_mode_sense_pages_default.pages[i], + scsi_cdrom_mode_sense_pages_default.pages[i][1] + 2); + } + } + memset(file_name, 0, 512 * sizeof(wchar_t)); + if (dev->drv->bus_type == CDROM_BUS_SCSI) + swprintf(file_name, 512, L"scsi_cdrom_%02i_mode_sense_bin", dev->id); + else + swprintf(file_name, 512, L"cdrom_%02i_mode_sense_bin", dev->id); + f = plat_fopen(nvr_path(file_name), L"rb"); + if (f) { + fread(dev->ms_pages_saved.pages[GPMODE_CDROM_AUDIO_PAGE], 1, 0x10, f); + fclose(f); + } +} + + +static void +scsi_cdrom_mode_sense_save(scsi_cdrom_t *dev) +{ + FILE *f; + wchar_t file_name[512]; + + memset(file_name, 0, 512 * sizeof(wchar_t)); + if (dev->drv->bus_type == CDROM_BUS_SCSI) + swprintf(file_name, 512, L"scsi_cdrom_%02i_mode_sense_bin", dev->id); + else + swprintf(file_name, 512, L"cdrom_%02i_mode_sense_bin", dev->id); + f = plat_fopen(nvr_path(file_name), L"wb"); + if (f) { + fwrite(dev->ms_pages_saved.pages[GPMODE_CDROM_AUDIO_PAGE], 1, 0x10, f); + fclose(f); + } +} + + +int +scsi_cdrom_read_capacity(void *p, uint8_t *cdb, uint8_t *buffer, uint32_t *len) +{ + scsi_cdrom_t *dev = (scsi_cdrom_t *) p; + int size = 0; + + size = dev->drv->handler->size(dev->id) - 1; /* IMPORTANT: What's returned is the last LBA block. */ + memset(buffer, 0, 8); + buffer[0] = (size >> 24) & 0xff; + buffer[1] = (size >> 16) & 0xff; + buffer[2] = (size >> 8) & 0xff; + buffer[3] = size & 0xff; + buffer[6] = 8; /* 2048 = 0x0800 */ + *len = 8; + + return 1; +} + + +/*SCSI Mode Sense 6/10*/ +static uint8_t +scsi_cdrom_mode_sense_read(scsi_cdrom_t *dev, uint8_t page_control, uint8_t page, uint8_t pos) +{ + switch (page_control) { + case 0: + case 3: + return dev->ms_pages_saved.pages[page][pos]; + break; + case 1: + return scsi_cdrom_mode_sense_pages_changeable.pages[page][pos]; + break; + case 2: + if (dev->drv->bus_type == CDROM_BUS_SCSI) + return scsi_cdrom_mode_sense_pages_default_scsi.pages[page][pos]; + else + return scsi_cdrom_mode_sense_pages_default.pages[page][pos]; + break; + } + + return 0; +} + + +static uint32_t +scsi_cdrom_mode_sense(scsi_cdrom_t *dev, uint8_t *buf, uint32_t pos, uint8_t page, uint8_t block_descriptor_len) +{ + uint8_t page_control = (page >> 6) & 3; + int i = 0, j = 0; + + uint8_t msplen; + + page &= 0x3f; + + if (block_descriptor_len) { + buf[pos++] = 1; /* Density code. */ + buf[pos++] = 0; /* Number of blocks (0 = all). */ + buf[pos++] = 0; + buf[pos++] = 0; + buf[pos++] = 0; /* Reserved. */ + buf[pos++] = 0; /* Block length (0x800 = 2048 bytes). */ + buf[pos++] = 8; + buf[pos++] = 0; + } + + for (i = 0; i < 0x40; i++) { + if ((page == GPMODE_ALL_PAGES) || (page == i)) { + if (scsi_cdrom_mode_sense_page_flags & (1LL << ((uint64_t) (page & 0x3f)))) { + buf[pos++] = scsi_cdrom_mode_sense_read(dev, page_control, i, 0); + msplen = scsi_cdrom_mode_sense_read(dev, page_control, i, 1); + buf[pos++] = msplen; + scsi_cdrom_log("CD-ROM %i: MODE SENSE: Page [%02X] length %i\n", dev->id, i, msplen); + for (j = 0; j < msplen; j++) { + if ((i == GPMODE_CAPABILITIES_PAGE) && (j >= 6) && (j <= 7)) { + if (j & 1) + buf[pos++] = ((dev->drv->speed * 176) & 0xff); + else + buf[pos++] = ((dev->drv->speed * 176) >> 8); + } else if ((i == GPMODE_CAPABILITIES_PAGE) && (j >= 12) && (j <= 13)) { + if (j & 1) + buf[pos++] = ((dev->drv->cur_speed * 176) & 0xff); + else + buf[pos++] = ((dev->drv->cur_speed * 176) >> 8); + } else + buf[pos++] = scsi_cdrom_mode_sense_read(dev, page_control, i, 2 + j); + } + } + } + } + + return pos; +} + + +static void +scsi_cdrom_update_request_length(scsi_cdrom_t *dev, int len, int block_len) +{ + int32_t bt, min_len = 0; + + dev->max_transfer_len = dev->request_length; + + /* For media access commands, make sure the requested DRQ length matches the block length. */ + switch (dev->current_cdb[0]) { + case 0x08: + case 0x28: + case 0xa8: + case 0xb9: + case 0xbe: + /* Make sure total length is not bigger than sum of the lengths of + all the requested blocks. */ + bt = (dev->requested_blocks * block_len); + if (len > bt) + len = bt; + + min_len = block_len; + + if (len <= block_len) { + /* Total length is less or equal to block length. */ + if (dev->max_transfer_len < block_len) { + /* Transfer a minimum of (block size) bytes. */ + dev->max_transfer_len = block_len; + dev->packet_len = block_len; + break; + } + } + default: + dev->packet_len = len; + break; + } + /* If the DRQ length is odd, and the total remaining length is bigger, make sure it's even. */ + if ((dev->max_transfer_len & 1) && (dev->max_transfer_len < len)) + dev->max_transfer_len &= 0xfffe; + /* If the DRQ length is smaller or equal in size to the total remaining length, set it to that. */ + if (!dev->max_transfer_len) + dev->max_transfer_len = 65534; + + if ((len <= dev->max_transfer_len) && (len >= min_len)) + dev->request_length = dev->max_transfer_len = len; + else if (len > dev->max_transfer_len) + dev->request_length = dev->max_transfer_len; + + return; +} + + +static double +scsi_cdrom_bus_speed(scsi_cdrom_t *dev) +{ + if (dev->drv->bus_type == CDROM_BUS_SCSI) { + dev->callback = -1LL; /* Speed depends on SCSI controller */ + return 0.0; + } else { + /* TODO: Get the actual selected speed from IDE. */ + if (scsi_cdrom_current_mode(dev) == 2) + return 66666666.666666666666666; /* 66 MB/s MDMA-2 speed */ + else + return 8333333.333333333333333; /* 8.3 MB/s PIO-2 speed */ + } +} + + +static void +scsi_cdrom_command_bus(scsi_cdrom_t *dev) +{ + dev->status = BUSY_STAT; + dev->phase = 1; + dev->pos = 0; + dev->callback = 1LL * CDROM_TIME; + scsi_cdrom_set_callback(dev); +} + + +static void +scsi_cdrom_command_common(scsi_cdrom_t *dev) +{ + double bytes_per_second, period; + double dusec; + + dev->status = BUSY_STAT; + dev->phase = 1; + dev->pos = 0; + dev->callback = 0LL; + + scsi_cdrom_log("CD-ROM %i: Current speed: %ix\n", dev->id, dev->drv->cur_speed); + + if (dev->packet_status == PHASE_COMPLETE) { + scsi_cdrom_callback(dev); + dev->callback = 0LL; + } else { + switch(dev->current_cdb[0]) { + case GPCMD_REZERO_UNIT: + case 0x0b: + case 0x2b: + /* Seek time is in us. */ + period = cdrom_seek_time(dev->drv); + scsi_cdrom_log("CD-ROM %i: Seek period: %" PRIu64 " us\n", + dev->id, (int64_t) period); + period = period * ((double) TIMER_USEC); + dev->callback += ((int64_t) period); + scsi_cdrom_set_callback(dev); + return; + case 0x08: + case 0x28: + case 0xa8: + /* Seek time is in us. */ + period = cdrom_seek_time(dev->drv); + scsi_cdrom_log("CD-ROM %i: Seek period: %" PRIu64 " us\n", + dev->id, (int64_t) period); + period = period * ((double) TIMER_USEC); + dev->callback += ((int64_t) period); + case 0x25: + case 0x42: + case 0x43: + case 0x44: + case 0x51: + case 0x52: + case 0xad: + case 0xb8: + case 0xb9: + case 0xbe: + if (dev->current_cdb[0] == 0x42) + dev->callback += 200LL * CDROM_TIME; + /* Account for seek time. */ + bytes_per_second = 176.0 * 1024.0; + bytes_per_second *= (double) dev->drv->cur_speed; + break; + default: + bytes_per_second = scsi_cdrom_bus_speed(dev); + if (bytes_per_second == 0.0) { + dev->callback = -1LL; /* Speed depends on SCSI controller */ + return; + } + break; + } + + period = 1000000.0 / bytes_per_second; + scsi_cdrom_log("CD-ROM %i: Byte transfer period: %" PRIu64 " us\n", dev->id, (int64_t) period); + period = period * (double) (dev->packet_len); + scsi_cdrom_log("CD-ROM %i: Sector transfer period: %" PRIu64 " us\n", dev->id, (int64_t) period); + dusec = period * ((double) TIMER_USEC); + dev->callback += ((int64_t) dusec); + } + scsi_cdrom_set_callback(dev); +} + + +static void +scsi_cdrom_command_complete(scsi_cdrom_t *dev) +{ + dev->packet_status = PHASE_COMPLETE; + scsi_cdrom_command_common(dev); +} + + +static void +scsi_cdrom_command_read(scsi_cdrom_t *dev) +{ + dev->packet_status = PHASE_DATA_IN; + scsi_cdrom_command_common(dev); + dev->total_read = 0; +} + + +static void +scsi_cdrom_command_read_dma(scsi_cdrom_t *dev) +{ + dev->packet_status = PHASE_DATA_IN_DMA; + scsi_cdrom_command_common(dev); + dev->total_read = 0; +} + + +static void +scsi_cdrom_command_write(scsi_cdrom_t *dev) +{ + dev->packet_status = PHASE_DATA_OUT; + scsi_cdrom_command_common(dev); +} + + +static void scsi_cdrom_command_write_dma(scsi_cdrom_t *dev) +{ + dev->packet_status = PHASE_DATA_OUT_DMA; + scsi_cdrom_command_common(dev); +} + + +/* id = Current CD-ROM device ID; + len = Total transfer length; + block_len = Length of a single block (it matters because media access commands on ATAPI); + alloc_len = Allocated transfer length; + direction = Transfer direction (0 = read from host, 1 = write to host). */ +static void scsi_cdrom_data_command_finish(scsi_cdrom_t *dev, int len, int block_len, int alloc_len, int direction) +{ + scsi_cdrom_log("CD-ROM %i: Finishing command (%02X): %i, %i, %i, %i, %i\n", + dev->id, dev->current_cdb[0], len, block_len, alloc_len, direction, dev->request_length); + dev->pos = 0; + if (alloc_len >= 0) { + if (alloc_len < len) + len = alloc_len; + } + if ((len == 0) || (scsi_cdrom_current_mode(dev) == 0)) { + if (dev->drv->bus_type != CDROM_BUS_SCSI) + dev->packet_len = 0; + + scsi_cdrom_command_complete(dev); + } else { + if (scsi_cdrom_current_mode(dev) == 2) { + if (dev->drv->bus_type != CDROM_BUS_SCSI) + dev->packet_len = alloc_len; + + if (direction == 0) + scsi_cdrom_command_read_dma(dev); + else + scsi_cdrom_command_write_dma(dev); + } else { + scsi_cdrom_update_request_length(dev, len, block_len); + if (direction == 0) + scsi_cdrom_command_read(dev); + else + scsi_cdrom_command_write(dev); + } + } + + scsi_cdrom_log("CD-ROM %i: Status: %i, cylinder %i, packet length: %i, position: %i, phase: %i\n", + dev->id, dev->packet_status, dev->request_length, dev->packet_len, dev->pos, dev->phase); +} + + +static void +scsi_cdrom_sense_clear(scsi_cdrom_t *dev, int command) +{ + dev->previous_command = command; + scsi_cdrom_sense_key = scsi_cdrom_asc = scsi_cdrom_ascq = 0; +} + + +static void +scsi_cdrom_set_phase(scsi_cdrom_t *dev, uint8_t phase) +{ + uint8_t scsi_id = dev->drv->scsi_device_id; + + if (dev->drv->bus_type != CDROM_BUS_SCSI) + return; + + scsi_devices[scsi_id].phase = phase; +} + + +static void +scsi_cdrom_cmd_error(scsi_cdrom_t *dev) +{ + scsi_cdrom_set_phase(dev, SCSI_PHASE_STATUS); + dev->error = ((scsi_cdrom_sense_key & 0xf) << 4) | ABRT_ERR; + if (dev->unit_attention) + dev->error |= MCR_ERR; + dev->status = READY_STAT | ERR_STAT; + dev->phase = 3; + dev->pos = 0; + dev->packet_status = 0x80; + dev->callback = 50LL * CDROM_TIME; + scsi_cdrom_set_callback(dev); + scsi_cdrom_log("CD-ROM %i: ERROR: %02X/%02X/%02X\n", dev->id, scsi_cdrom_sense_key, scsi_cdrom_asc, scsi_cdrom_ascq); +} + + +static void +scsi_cdrom_unit_attention(scsi_cdrom_t *dev) +{ + scsi_cdrom_set_phase(dev, SCSI_PHASE_STATUS); + dev->error = (SENSE_UNIT_ATTENTION << 4) | ABRT_ERR; + if (dev->unit_attention) + dev->error |= MCR_ERR; + dev->status = READY_STAT | ERR_STAT; + dev->phase = 3; + dev->pos = 0; + dev->packet_status = 0x80; + dev->callback = 50LL * CDROM_TIME; + scsi_cdrom_set_callback(dev); + scsi_cdrom_log("CD-ROM %i: UNIT ATTENTION\n", dev->id); +} + + +static void +scsi_cdrom_bus_master_error(scsi_cdrom_t *dev) +{ + scsi_cdrom_sense_key = scsi_cdrom_asc = scsi_cdrom_ascq = 0; + scsi_cdrom_cmd_error(dev); +} + + +static void +scsi_cdrom_not_ready(scsi_cdrom_t *dev) +{ + scsi_cdrom_sense_key = SENSE_NOT_READY; + scsi_cdrom_asc = ASC_MEDIUM_NOT_PRESENT; + scsi_cdrom_ascq = 0; + scsi_cdrom_cmd_error(dev); +} + + +static void +scsi_cdrom_invalid_lun(scsi_cdrom_t *dev) +{ + scsi_cdrom_sense_key = SENSE_ILLEGAL_REQUEST; + scsi_cdrom_asc = ASC_INV_LUN; + scsi_cdrom_ascq = 0; + scsi_cdrom_cmd_error(dev); +} + + +static void +scsi_cdrom_illegal_opcode(scsi_cdrom_t *dev) +{ + scsi_cdrom_sense_key = SENSE_ILLEGAL_REQUEST; + scsi_cdrom_asc = ASC_ILLEGAL_OPCODE; + scsi_cdrom_ascq = 0; + scsi_cdrom_cmd_error(dev); +} + + +static void +scsi_cdrom_lba_out_of_range(scsi_cdrom_t *dev) +{ + scsi_cdrom_sense_key = SENSE_ILLEGAL_REQUEST; + scsi_cdrom_asc = ASC_LBA_OUT_OF_RANGE; + scsi_cdrom_ascq = 0; + scsi_cdrom_cmd_error(dev); +} + + +static void +scsi_cdrom_invalid_field(scsi_cdrom_t *dev) +{ + scsi_cdrom_sense_key = SENSE_ILLEGAL_REQUEST; + scsi_cdrom_asc = ASC_INV_FIELD_IN_CMD_PACKET; + scsi_cdrom_ascq = 0; + scsi_cdrom_cmd_error(dev); + dev->status = 0x53; +} + + +static void +scsi_cdrom_invalid_field_pl(scsi_cdrom_t *dev) +{ + scsi_cdrom_sense_key = SENSE_ILLEGAL_REQUEST; + scsi_cdrom_asc = ASC_INV_FIELD_IN_PARAMETER_LIST; + scsi_cdrom_ascq = 0; + scsi_cdrom_cmd_error(dev); + dev->status = 0x53; +} + + +static void +scsi_cdrom_illegal_mode(scsi_cdrom_t *dev) +{ + scsi_cdrom_sense_key = SENSE_ILLEGAL_REQUEST; + scsi_cdrom_asc = ASC_ILLEGAL_MODE_FOR_THIS_TRACK; + scsi_cdrom_ascq = 0; + scsi_cdrom_cmd_error(dev); +} + + +static void +scsi_cdrom_incompatible_format(scsi_cdrom_t *dev) +{ + scsi_cdrom_sense_key = SENSE_ILLEGAL_REQUEST; + scsi_cdrom_asc = ASC_INCOMPATIBLE_FORMAT; + scsi_cdrom_ascq = 2; + scsi_cdrom_cmd_error(dev); +} + + +static void +scsi_cdrom_data_phase_error(scsi_cdrom_t *dev) +{ + scsi_cdrom_sense_key = SENSE_ILLEGAL_REQUEST; + scsi_cdrom_asc = ASC_DATA_PHASE_ERROR; + scsi_cdrom_ascq = 0; + scsi_cdrom_cmd_error(dev); +} + + +void +scsi_cdrom_update_cdb(uint8_t *cdb, int lba_pos, int number_of_blocks) +{ + int temp = 0; + + switch(cdb[0]) { + case GPCMD_READ_6: + cdb[1] = (lba_pos >> 16) & 0xff; + cdb[2] = (lba_pos >> 8) & 0xff; + cdb[3] = lba_pos & 0xff; + break; + + case GPCMD_READ_10: + cdb[2] = (lba_pos >> 24) & 0xff; + cdb[3] = (lba_pos >> 16) & 0xff; + cdb[4] = (lba_pos >> 8) & 0xff; + cdb[5] = lba_pos & 0xff; + cdb[7] = (number_of_blocks >> 8) & 0xff; + cdb[8] = number_of_blocks & 0xff; + break; + + case GPCMD_READ_12: + cdb[2] = (lba_pos >> 24) & 0xff; + cdb[3] = (lba_pos >> 16) & 0xff; + cdb[4] = (lba_pos >> 8) & 0xff; + cdb[5] = lba_pos & 0xff; + cdb[6] = (number_of_blocks >> 24) & 0xff; + cdb[7] = (number_of_blocks >> 16) & 0xff; + cdb[8] = (number_of_blocks >> 8) & 0xff; + cdb[9] = number_of_blocks & 0xff; + break; + + case GPCMD_READ_CD_MSF: + temp = cdrom_lba_to_msf_accurate(lba_pos); + cdb[3] = (temp >> 16) & 0xff; + cdb[4] = (temp >> 8) & 0xff; + cdb[5] = temp & 0xff; + + temp = cdrom_lba_to_msf_accurate(lba_pos + number_of_blocks - 1); + cdb[6] = (temp >> 16) & 0xff; + cdb[7] = (temp >> 8) & 0xff; + cdb[8] = temp & 0xff; + break; + + case GPCMD_READ_CD: + cdb[2] = (lba_pos >> 24) & 0xff; + cdb[3] = (lba_pos >> 16) & 0xff; + cdb[4] = (lba_pos >> 8) & 0xff; + cdb[5] = lba_pos & 0xff; + cdb[6] = (number_of_blocks >> 16) & 0xff; + cdb[7] = (number_of_blocks >> 8) & 0xff; + cdb[8] = number_of_blocks & 0xff; + break; + } +} + + +static int +scsi_cdrom_read_data(scsi_cdrom_t *dev, int msf, int type, int flags, int32_t *len) +{ + int ret = 0; + uint32_t cdsize = 0; + + int i = 0; + int temp_len = 0; + + cdsize = dev->drv->handler->size(dev->id); + + if (dev->sector_pos >= cdsize) { + scsi_cdrom_log("CD-ROM %i: Trying to read from beyond the end of disc (%i >= %i)\n", dev->id, + dev->sector_pos, cdsize); + scsi_cdrom_lba_out_of_range(dev); + return 0; + } + + if ((dev->sector_pos + dev->sector_len - 1) >= cdsize) { + scsi_cdrom_log("CD-ROM %i: Trying to read to beyond the end of disc (%i >= %i)\n", dev->id, + (dev->sector_pos + dev->sector_len - 1), cdsize); + scsi_cdrom_lba_out_of_range(dev); + return 0; + } + + dev->old_len = 0; + *len = 0; + + for (i = 0; i < dev->requested_blocks; i++) { + ret = dev->drv->handler->readsector_raw(dev->id, cdbufferb + dev->data_pos, dev->sector_pos + i, + msf, type, flags, &temp_len); + + dev->data_pos += temp_len; + dev->old_len += temp_len; + + *len += temp_len; + + if (!ret) { + scsi_cdrom_illegal_mode(dev); + return 0; + } + } + + return 1; +} + + +static int +scsi_cdrom_read_blocks(scsi_cdrom_t *dev, int32_t *len, int first_batch) +{ + int ret = 0, msf = 0; + int type = 0, flags = 0; + + if (dev->current_cdb[0] == GPCMD_READ_CD_MSF) + msf = 1; + + if ((dev->current_cdb[0] == GPCMD_READ_CD_MSF) || (dev->current_cdb[0] == GPCMD_READ_CD)) { + type = (dev->current_cdb[1] >> 2) & 7; + flags = dev->current_cdb[9] | (((uint32_t) dev->current_cdb[10]) << 8); + } else { + type = 8; + flags = 0x10; + } + + dev->data_pos = 0; + + if (!dev->sector_len) { + scsi_cdrom_command_complete(dev); + return -1; + } + + scsi_cdrom_log("Reading %i blocks starting from %i...\n", dev->requested_blocks, dev->sector_pos); + + scsi_cdrom_update_cdb(dev->current_cdb, dev->sector_pos, dev->requested_blocks); + + ret = scsi_cdrom_read_data(dev, msf, type, flags, len); + + scsi_cdrom_log("Read %i bytes of blocks...\n", *len); + + if (!ret || ((dev->old_len != *len) && !first_batch)) { + if ((dev->old_len != *len) && !first_batch) + scsi_cdrom_illegal_mode(dev); + + return 0; + } + + dev->sector_pos += dev->requested_blocks; + dev->sector_len -= dev->requested_blocks; + + return 1; +} + + +/*SCSI Read DVD Structure*/ +static int +scsi_cdrom_read_dvd_structure(scsi_cdrom_t *dev, int format, const uint8_t *packet, uint8_t *buf) +{ + int layer = packet[6]; + uint64_t total_sectors; + + switch (format) { + case 0x00: /* Physical format information */ + total_sectors = (uint64_t) dev->drv->handler->size(dev->id); + + if (layer != 0) { + scsi_cdrom_invalid_field(dev); + return 0; + } + + total_sectors >>= 2; + if (total_sectors == 0) { + /* return -ASC_MEDIUM_NOT_PRESENT; */ + scsi_cdrom_not_ready(dev); + return 0; + } + + buf[4] = 1; /* DVD-ROM, part version 1 */ + buf[5] = 0xf; /* 120mm disc, minimum rate unspecified */ + buf[6] = 1; /* one layer, read-only (per MMC-2 spec) */ + buf[7] = 0; /* default densities */ + + /* FIXME: 0x30000 per spec? */ + buf[8] = buf[9] = buf[10] = buf[11] = 0; /* start sector */ + buf[12] = (total_sectors >> 24) & 0xff; /* end sector */ + buf[13] = (total_sectors >> 16) & 0xff; + buf[14] = (total_sectors >> 8) & 0xff; + buf[15] = total_sectors & 0xff; + + buf[16] = (total_sectors >> 24) & 0xff; /* l0 end sector */ + buf[17] = (total_sectors >> 16) & 0xff; + buf[18] = (total_sectors >> 8) & 0xff; + buf[19] = total_sectors & 0xff; + + /* Size of buffer, not including 2 byte size field */ + buf[0] = ((2048 +2 ) >> 8) & 0xff; + buf[1] = (2048 + 2) & 0xff; + + /* 2k data + 4 byte header */ + return (2048 + 4); + + case 0x01: /* DVD copyright information */ + buf[4] = 0; /* no copyright data */ + buf[5] = 0; /* no region restrictions */ + + /* Size of buffer, not including 2 byte size field */ + buf[0] = ((4 + 2) >> 8) & 0xff; + buf[1] = (4 + 2) & 0xff; + + /* 4 byte header + 4 byte data */ + return (4 + 4); + + case 0x03: /* BCA information - invalid field for no BCA info */ + scsi_cdrom_invalid_field(dev); + return 0; + + case 0x04: /* DVD disc manufacturing information */ + /* Size of buffer, not including 2 byte size field */ + buf[0] = ((2048 + 2) >> 8) & 0xff; + buf[1] = (2048 + 2) & 0xff; + + /* 2k data + 4 byte header */ + return (2048 + 4); + + case 0xff: + /* + * This lists all the command capabilities above. Add new ones + * in order and update the length and buffer return values. + */ + + buf[4] = 0x00; /* Physical format */ + buf[5] = 0x40; /* Not writable, is readable */ + buf[6] = ((2048 + 4) >> 8) & 0xff; + buf[7] = (2048 + 4) & 0xff; + + buf[8] = 0x01; /* Copyright info */ + buf[9] = 0x40; /* Not writable, is readable */ + buf[10] = ((4 + 4) >> 8) & 0xff; + buf[11] = (4 + 4) & 0xff; + + buf[12] = 0x03; /* BCA info */ + buf[13] = 0x40; /* Not writable, is readable */ + buf[14] = ((188 + 4) >> 8) & 0xff; + buf[15] = (188 + 4) & 0xff; + + buf[16] = 0x04; /* Manufacturing info */ + buf[17] = 0x40; /* Not writable, is readable */ + buf[18] = ((2048 + 4) >> 8) & 0xff; + buf[19] = (2048 + 4) & 0xff; + + /* Size of buffer, not including 2 byte size field */ + buf[6] = ((16 + 2) >> 8) & 0xff; + buf[7] = (16 + 2) & 0xff; + + /* data written + 4 byte header */ + return (16 + 4); + + default: /* TODO: formats beyond DVD-ROM requires */ + scsi_cdrom_invalid_field(dev); + return 0; + } +} + + +static void +scsi_cdrom_insert(void *p) +{ + scsi_cdrom_t *dev = (scsi_cdrom_t *) p; + + if (!dev) + return; + + dev->unit_attention = 1; + scsi_cdrom_log("CD-ROM %i: Media insert\n", dev->id); +} + + +static int +scsi_cdrom_pre_execution_check(scsi_cdrom_t *dev, uint8_t *cdb) +{ + int ready = 0, status = 0; + + if (dev->drv->bus_type == CDROM_BUS_SCSI) { + if ((cdb[0] != GPCMD_REQUEST_SENSE) && (cdb[1] & 0xe0)) { + scsi_cdrom_log("CD-ROM %i: Attempting to execute a unknown command targeted at SCSI LUN %i\n", + dev->id, ((dev->request_length >> 5) & 7)); + scsi_cdrom_invalid_lun(dev); + return 0; + } + } + + if (!(scsi_cdrom_command_flags[cdb[0]] & IMPLEMENTED)) { + scsi_cdrom_log("CD-ROM %i: Attempting to execute unknown command %02X over %s\n", dev->id, cdb[0], + (dev->drv->bus_type == CDROM_BUS_SCSI) ? "SCSI" : "ATAPI"); + + scsi_cdrom_illegal_opcode(dev); + return 0; + } + + if ((dev->drv->bus_type < CDROM_BUS_SCSI) && (scsi_cdrom_command_flags[cdb[0]] & SCSI_ONLY)) { + scsi_cdrom_log("CD-ROM %i: Attempting to execute SCSI-only command %02X over ATAPI\n", dev->id, cdb[0]); + scsi_cdrom_illegal_opcode(dev); + return 0; + } + + if ((dev->drv->bus_type == CDROM_BUS_SCSI) && (scsi_cdrom_command_flags[cdb[0]] & ATAPI_ONLY)) { + scsi_cdrom_log("CD-ROM %i: Attempting to execute ATAPI-only command %02X over SCSI\n", dev->id, cdb[0]); + scsi_cdrom_illegal_opcode(dev); + return 0; + } + + status = dev->drv->handler->status(dev->id); + + if ((status == CD_STATUS_PLAYING) || (status == CD_STATUS_PAUSED)) { + ready = 1; + goto skip_ready_check; + } + + if (dev->drv->handler->medium_changed(dev->id)) + scsi_cdrom_insert((void *) dev); + + ready = dev->drv->handler->ready(dev->id); + +skip_ready_check: + /* If the drive is not ready, there is no reason to keep the + UNIT ATTENTION condition present, as we only use it to mark + disc changes. */ + if (!ready && dev->unit_attention) + dev->unit_attention = 0; + + /* If the UNIT ATTENTION condition is set and the command does not allow + execution under it, error out and report the condition. */ + if (dev->unit_attention == 1) { + /* Only increment the unit attention phase if the command can not pass through it. */ + if (!(scsi_cdrom_command_flags[cdb[0]] & ALLOW_UA)) { + /* scsi_cdrom_log("CD-ROM %i: Unit attention now 2\n", dev->id); */ + dev->unit_attention++; + scsi_cdrom_log("CD-ROM %i: UNIT ATTENTION: Command %02X not allowed to pass through\n", + dev->id, cdb[0]); + scsi_cdrom_unit_attention(dev); + return 0; + } + } else if (dev->unit_attention == 2) { + if (cdb[0] != GPCMD_REQUEST_SENSE) { + /* scsi_cdrom_log("CD-ROM %i: Unit attention now 0\n", dev->id); */ + dev->unit_attention = 0; + } + } + + /* Unless the command is REQUEST SENSE, clear the sense. This will *NOT* + the UNIT ATTENTION condition if it's set. */ + if (cdb[0] != GPCMD_REQUEST_SENSE) + scsi_cdrom_sense_clear(dev, cdb[0]); + + /* Next it's time for NOT READY. */ + if (!ready) + dev->media_status = MEC_MEDIA_REMOVAL; + else + dev->media_status = (dev->unit_attention) ? MEC_NEW_MEDIA : MEC_NO_CHANGE; + + if ((scsi_cdrom_command_flags[cdb[0]] & CHECK_READY) && !ready) { + scsi_cdrom_log("CD-ROM %i: Not ready (%02X)\n", dev->id, cdb[0]); + scsi_cdrom_not_ready(dev); + return 0; + } + + scsi_cdrom_log("CD-ROM %i: Continuing with command %02X\n", dev->id, cdb[0]); + + return 1; +} + + +static void +scsi_cdrom_rezero(scsi_cdrom_t *dev) +{ + dev->sector_pos = dev->sector_len = 0; + cdrom_seek(dev->drv, 0); +} + + +void +scsi_cdrom_reset(void *p) +{ + scsi_cdrom_t *dev = (scsi_cdrom_t *) p; + + if (!dev) + return; + + scsi_cdrom_rezero(dev); + dev->status = 0; + dev->callback = 0LL; + scsi_cdrom_set_callback(dev); + dev->packet_status = 0xff; + dev->unit_attention = 0xff; +} + + +static void +scsi_cdrom_request_sense(scsi_cdrom_t *dev, uint8_t *buffer, uint8_t alloc_length) +{ + int status = dev->drv->cd_status; + + /*Will return 18 bytes of 0*/ + if (alloc_length != 0) { + memset(buffer, 0, alloc_length); + memcpy(buffer, dev->sense, alloc_length); + } + + buffer[0] = 0x70; + + if ((scsi_cdrom_sense_key > 0) && ((status < CD_STATUS_PLAYING) || + (status == CD_STATUS_STOPPED)) && cdrom_playing_completed(dev->drv)) { + buffer[2]=SENSE_ILLEGAL_REQUEST; + buffer[12]=ASC_AUDIO_PLAY_OPERATION; + buffer[13]=ASCQ_AUDIO_PLAY_OPERATION_COMPLETED; + } else if ((scsi_cdrom_sense_key == 0) && (status >= CD_STATUS_PLAYING) && + (status != CD_STATUS_STOPPED)) { + buffer[2]=SENSE_ILLEGAL_REQUEST; + buffer[12]=ASC_AUDIO_PLAY_OPERATION; + buffer[13]=(status == CD_STATUS_PLAYING) ? ASCQ_AUDIO_PLAY_OPERATION_IN_PROGRESS : ASCQ_AUDIO_PLAY_OPERATION_PAUSED; + } else { + if (dev->unit_attention && (scsi_cdrom_sense_key == 0)) { + buffer[2]=SENSE_UNIT_ATTENTION; + buffer[12]=ASC_MEDIUM_MAY_HAVE_CHANGED; + buffer[13]=0; + } + } + + scsi_cdrom_log("CD-ROM %i: Reporting sense: %02X %02X %02X\n", dev->id, buffer[2], buffer[12], buffer[13]); + + if (buffer[2] == SENSE_UNIT_ATTENTION) { + /* If the last remaining sense is unit attention, clear + that condition. */ + dev->unit_attention = 0; + } + + /* Clear the sense stuff as per the spec. */ + scsi_cdrom_sense_clear(dev, GPCMD_REQUEST_SENSE); +} + + +void +scsi_cdrom_request_sense_for_scsi(void *p, uint8_t *buffer, uint8_t alloc_length) +{ + scsi_cdrom_t *dev = (scsi_cdrom_t *) p; + int ready = 0; + + if (dev->drv->handler->medium_changed(dev->id)) + scsi_cdrom_insert((void *) dev); + + ready = dev->drv->handler->ready(dev->id); + + if (!ready && dev->unit_attention) { + /* If the drive is not ready, there is no reason to keep the + UNIT ATTENTION condition present, as we only use it to mark + disc changes. */ + dev->unit_attention = 0; + } + + /* Do *NOT* advance the unit attention phase. */ + scsi_cdrom_request_sense(dev, buffer, alloc_length); +} + + +static void +scsi_cdrom_set_buf_len(scsi_cdrom_t *dev, int32_t *BufLen, int32_t *src_len) +{ + if (dev->drv->bus_type == CDROM_BUS_SCSI) { + if (*BufLen == -1) + *BufLen = *src_len; + else { + *BufLen = MIN(*src_len, *BufLen); + *src_len = *BufLen; + } + scsi_cdrom_log("CD-ROM %i: Actual transfer length: %i\n", dev->id, *BufLen); + } +} + + +static void +scsi_cdrom_buf_alloc(scsi_cdrom_t *dev, uint32_t len) +{ + scsi_cdrom_log("CD-ROM %i: Allocated buffer length: %i\n", dev->id, len); + cdbufferb = (uint8_t *) malloc(len); +} + + +static void +scsi_cdrom_buf_free(scsi_cdrom_t *dev) +{ + if (cdbufferb) { + scsi_cdrom_log("CD-ROM %i: Freeing buffer...\n", dev->id); + free(cdbufferb); + cdbufferb = NULL; + } +} + + +void +scsi_cdrom_command(void *p, uint8_t *cdb) +{ + scsi_cdrom_t *dev = (scsi_cdrom_t *) p; + int len, max_len, used_len, alloc_length, msf; + int pos = 0, i= 0, size_idx, idx = 0; + uint32_t feature; + unsigned preamble_len; + int toc_format, block_desc = 0; + int ret, format = 0; + int real_pos, track = 0; + char device_identify[9] = { '8', '6', 'B', '_', 'C', 'D', '0', '0', 0 }; + char device_identify_ex[15] = { '8', '6', 'B', '_', 'C', 'D', '0', '0', ' ', 'v', '1', '.', '0', '0', 0 }; + int32_t blen = 0, *BufLen; + uint8_t *b; + uint32_t profiles[2] = { MMC_PROFILE_CD_ROM, MMC_PROFILE_DVD_ROM }; + + if (dev->drv->bus_type == CDROM_BUS_SCSI) { + BufLen = &scsi_devices[dev->drv->scsi_device_id].buffer_length; + dev->status &= ~ERR_STAT; + } else { + BufLen = &blen; + dev->error = 0; + } + + dev->packet_len = 0; + dev->request_pos = 0; + + device_identify[7] = dev->id + 0x30; + + device_identify_ex[7] = dev->id + 0x30; + device_identify_ex[10] = EMU_VERSION[0]; + device_identify_ex[12] = EMU_VERSION[2]; + device_identify_ex[13] = EMU_VERSION[3]; + + dev->data_pos = 0; + + memcpy(dev->current_cdb, cdb, 12); + + dev->drv->cd_status = dev->drv->handler->status(dev->id); + + if (cdb[0] != 0) { + scsi_cdrom_log("CD-ROM %i: Command 0x%02X, Sense Key %02X, Asc %02X, Ascq %02X, Unit attention: %i\n", + dev->id, cdb[0], scsi_cdrom_sense_key, scsi_cdrom_asc, scsi_cdrom_ascq, dev->unit_attention); + scsi_cdrom_log("CD-ROM %i: Request length: %04X\n", dev->id, dev->request_length); + + scsi_cdrom_log("CD-ROM %i: CDB: %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X\n", dev->id, + cdb[0], cdb[1], cdb[2], cdb[3], cdb[4], cdb[5], cdb[6], cdb[7], + cdb[8], cdb[9], cdb[10], cdb[11]); + } + + msf = cdb[1] & 2; + dev->sector_len = 0; + + scsi_cdrom_set_phase(dev, SCSI_PHASE_STATUS); + + /* This handles the Not Ready/Unit Attention check if it has to be handled at this point. */ + if (scsi_cdrom_pre_execution_check(dev, cdb) == 0) + return; + + switch (cdb[0]) { + case GPCMD_TEST_UNIT_READY: + scsi_cdrom_set_phase(dev, SCSI_PHASE_STATUS); + scsi_cdrom_command_complete(dev); + break; + + case GPCMD_REZERO_UNIT: + if (dev->drv->handler->stop) + dev->drv->handler->stop(dev->id); + dev->sector_pos = dev->sector_len = 0; + dev->drv->seek_diff = dev->drv->seek_pos; + cdrom_seek(dev->drv, 0); + scsi_cdrom_set_phase(dev, SCSI_PHASE_STATUS); + break; + + case GPCMD_REQUEST_SENSE: + /* If there's a unit attention condition and there's a buffered not ready, a standalone REQUEST SENSE + should forget about the not ready, and report unit attention straight away. */ + scsi_cdrom_set_phase(dev, SCSI_PHASE_DATA_IN); + max_len = cdb[4]; + + if (!max_len) { + scsi_cdrom_set_phase(dev, SCSI_PHASE_STATUS); + dev->packet_status = PHASE_COMPLETE; + dev->callback = 20LL * CDROM_TIME; + scsi_cdrom_set_callback(dev); + break; + } + + scsi_cdrom_buf_alloc(dev, 256); + scsi_cdrom_set_buf_len(dev, BufLen, &max_len); + scsi_cdrom_request_sense(dev, cdbufferb, max_len); + scsi_cdrom_data_command_finish(dev, 18, 18, cdb[4], 0); + break; + + case GPCMD_SET_SPEED: + case GPCMD_SET_SPEED_ALT: + dev->drv->cur_speed = (cdb[3] | (cdb[2] << 8)) / 176; + if (dev->drv->cur_speed < 1) + dev->drv->cur_speed = 1; + else if (dev->drv->cur_speed > dev->drv->speed) + dev->drv->cur_speed = dev->drv->speed; + scsi_cdrom_set_phase(dev, SCSI_PHASE_STATUS); + scsi_cdrom_command_complete(dev); + break; + + case GPCMD_MECHANISM_STATUS: + scsi_cdrom_set_phase(dev, SCSI_PHASE_DATA_IN); + len = (cdb[7] << 16) | (cdb[8] << 8) | cdb[9]; + + scsi_cdrom_buf_alloc(dev, 8); + + scsi_cdrom_set_buf_len(dev, BufLen, &len); + + memset(cdbufferb, 0, 8); + cdbufferb[5] = 1; + + scsi_cdrom_data_command_finish(dev, 8, 8, len, 0); + break; + + case GPCMD_READ_TOC_PMA_ATIP: + scsi_cdrom_set_phase(dev, SCSI_PHASE_DATA_IN); + + max_len = cdb[7]; + max_len <<= 8; + max_len |= cdb[8]; + + scsi_cdrom_buf_alloc(dev, 65536); + + toc_format = cdb[2] & 0xf; + + if (toc_format == 0) + toc_format = (cdb[9] >> 6) & 3; + + switch (toc_format) { + case 0: /*Normal*/ + len = dev->drv->handler->readtoc(dev->id, cdbufferb, cdb[6], msf, max_len, + 0); + break; + case 1: /*Multi session*/ + len = dev->drv->handler->readtoc_session(dev->id, cdbufferb, msf, max_len); + cdbufferb[0] = 0; cdbufferb[1] = 0xA; + break; + case 2: /*Raw*/ + len = dev->drv->handler->readtoc_raw(dev->id, cdbufferb, max_len); + break; + default: + scsi_cdrom_invalid_field(dev); + scsi_cdrom_buf_free(dev); + return; + } + + if (len > max_len) { + len = max_len; + + cdbufferb[0] = ((len - 2) >> 8) & 0xff; + cdbufferb[1] = (len - 2) & 0xff; + } + + scsi_cdrom_set_buf_len(dev, BufLen, &len); + + scsi_cdrom_data_command_finish(dev, len, len, len, 0); + /* scsi_cdrom_log("CD-ROM %i: READ_TOC_PMA_ATIP format %02X, length %i (%i)\n", dev->id, + toc_format, ide->cylinder, cdbufferb[1]); */ + return; + + case GPCMD_READ_CD_OLD: + /* IMPORTANT: Convert the command to new read CD + for pass through purposes. */ + dev->current_cdb[0] = 0xbe; + case GPCMD_READ_6: + case GPCMD_READ_10: + case GPCMD_READ_12: + case GPCMD_READ_CD: + case GPCMD_READ_CD_MSF: + scsi_cdrom_set_phase(dev, SCSI_PHASE_DATA_IN); + alloc_length = 2048; + + switch(cdb[0]) { + case GPCMD_READ_6: + dev->sector_len = cdb[4]; + dev->sector_pos = ((((uint32_t) cdb[1]) & 0x1f) << 16) | (((uint32_t) cdb[2]) << 8) | ((uint32_t) cdb[3]); + msf = 0; + break; + case GPCMD_READ_10: + dev->sector_len = (cdb[7] << 8) | cdb[8]; + dev->sector_pos = (cdb[2] << 24) | (cdb[3] << 16) | (cdb[4] << 8) | cdb[5]; + scsi_cdrom_log("CD-ROM %i: Length: %i, LBA: %i\n", dev->id, dev->sector_len, + dev->sector_pos); + msf = 0; + break; + case GPCMD_READ_12: + dev->sector_len = (((uint32_t) cdb[6]) << 24) | (((uint32_t) cdb[7]) << 16) | (((uint32_t) cdb[8]) << 8) | ((uint32_t) cdb[9]); + dev->sector_pos = (((uint32_t) cdb[2]) << 24) | (((uint32_t) cdb[3]) << 16) | (((uint32_t) cdb[4]) << 8) | ((uint32_t) cdb[5]); + scsi_cdrom_log("CD-ROM %i: Length: %i, LBA: %i\n", dev->id, dev->sector_len, + dev->sector_pos); + msf = 0; + break; + case GPCMD_READ_CD_MSF: + alloc_length = 2856; + dev->sector_len = MSFtoLBA(cdb[6], cdb[7], cdb[8]); + dev->sector_pos = MSFtoLBA(cdb[3], cdb[4], cdb[5]); + + dev->sector_len -= dev->sector_pos; + dev->sector_len++; + msf = 1; + break; + case GPCMD_READ_CD_OLD: + case GPCMD_READ_CD: + alloc_length = 2856; + dev->sector_len = (cdb[6] << 16) | (cdb[7] << 8) | cdb[8]; + dev->sector_pos = (cdb[2] << 24) | (cdb[3] << 16) | (cdb[4] << 8) | cdb[5]; + + msf = 0; + break; + } + + dev->drv->seek_diff = ABS((int) (pos - dev->drv->seek_pos)); + dev->drv->seek_pos = dev->sector_pos; + + if (!dev->sector_len) { + scsi_cdrom_set_phase(dev, SCSI_PHASE_STATUS); + /* scsi_cdrom_log("CD-ROM %i: All done - callback set\n", dev->id); */ + dev->packet_status = PHASE_COMPLETE; + dev->callback = 20LL * CDROM_TIME; + scsi_cdrom_set_callback(dev); + break; + } + + max_len = dev->sector_len; + dev->requested_blocks = max_len; /* If we're reading all blocks in one go for DMA, why not also for PIO, it should NOT + matter anyway, this step should be identical and only the way the read dat is + transferred to the host should be different. */ + + dev->packet_len = max_len * alloc_length; + scsi_cdrom_buf_alloc(dev, dev->packet_len); + + ret = scsi_cdrom_read_blocks(dev, &alloc_length, 1); + if (ret <= 0) { + scsi_cdrom_buf_free(dev); + return; + } + + dev->requested_blocks = max_len; + dev->packet_len = alloc_length; + + scsi_cdrom_set_buf_len(dev, BufLen, (int32_t *) &dev->packet_len); + + scsi_cdrom_data_command_finish(dev, alloc_length, alloc_length / dev->requested_blocks, + alloc_length, 0); + + if (dev->packet_status != PHASE_COMPLETE) + ui_sb_update_icon(SB_CDROM | dev->id, 1); + else + ui_sb_update_icon(SB_CDROM | dev->id, 0); + return; + + case GPCMD_READ_HEADER: + scsi_cdrom_set_phase(dev, SCSI_PHASE_DATA_IN); + + alloc_length = ((cdb[7] << 8) | cdb[8]); + scsi_cdrom_buf_alloc(dev, 8); + + dev->sector_len = 1; + dev->sector_pos = (cdb[2] << 24) | (cdb[3] << 16) | (cdb[4]<<8) | cdb[5]; + if (msf) + real_pos = cdrom_lba_to_msf_accurate(dev->sector_pos); + else + real_pos = dev->sector_pos; + cdbufferb[0] = 1; /*2048 bytes user data*/ + cdbufferb[1] = cdbufferb[2] = cdbufferb[3] = 0; + cdbufferb[4] = (real_pos >> 24); + cdbufferb[5] = ((real_pos >> 16) & 0xff); + cdbufferb[6] = ((real_pos >> 8) & 0xff); + cdbufferb[7] = real_pos & 0xff; + + len = 8; + len = MIN(len, alloc_length); + + scsi_cdrom_set_buf_len(dev, BufLen, &len); + + scsi_cdrom_data_command_finish(dev, len, len, len, 0); + return; + + case GPCMD_MODE_SENSE_6: + case GPCMD_MODE_SENSE_10: + scsi_cdrom_set_phase(dev, SCSI_PHASE_DATA_IN); + + if (dev->drv->bus_type == CDROM_BUS_SCSI) + block_desc = ((cdb[1] >> 3) & 1) ? 0 : 1; + else + block_desc = 0; + + if (cdb[0] == GPCMD_MODE_SENSE_6) { + len = cdb[4]; + scsi_cdrom_buf_alloc(dev, 256); + } else { + len = (cdb[8] | (cdb[7] << 8)); + scsi_cdrom_buf_alloc(dev, 65536); + } + + if (!(scsi_cdrom_mode_sense_page_flags & (1LL << (uint64_t) (cdb[2] & 0x3f)))) { + scsi_cdrom_invalid_field(dev); + scsi_cdrom_buf_free(dev); + return; + } + + memset(cdbufferb, 0, len); + alloc_length = len; + + if (cdb[0] == GPCMD_MODE_SENSE_6) { + len = scsi_cdrom_mode_sense(dev, cdbufferb, 4, cdb[2], block_desc); + len = MIN(len, alloc_length); + cdbufferb[0] = len - 1; + cdbufferb[1] = dev->drv->handler->media_type_id(dev->id); + if (block_desc) + cdbufferb[3] = 8; + } else { + len = scsi_cdrom_mode_sense(dev, cdbufferb, 8, cdb[2], block_desc); + len = MIN(len, alloc_length); + cdbufferb[0]=(len - 2) >> 8; + cdbufferb[1]=(len - 2) & 255; + cdbufferb[2] = dev->drv->handler->media_type_id(dev->id); + if (block_desc) { + cdbufferb[6] = 0; + cdbufferb[7] = 8; + } + } + + scsi_cdrom_set_buf_len(dev, BufLen, &len); + + scsi_cdrom_log("CD-ROM %i: Reading mode page: %02X...\n", dev->id, cdb[2]); + + scsi_cdrom_data_command_finish(dev, len, len, alloc_length, 0); + return; + + case GPCMD_MODE_SELECT_6: + case GPCMD_MODE_SELECT_10: + scsi_cdrom_set_phase(dev, SCSI_PHASE_DATA_OUT); + + if (cdb[0] == GPCMD_MODE_SELECT_6) { + len = cdb[4]; + scsi_cdrom_buf_alloc(dev, 256); + } else { + len = (cdb[7] << 8) | cdb[8]; + scsi_cdrom_buf_alloc(dev, 65536); + } + + scsi_cdrom_set_buf_len(dev, BufLen, &len); + + dev->total_length = len; + dev->do_page_save = cdb[1] & 1; + + scsi_cdrom_data_command_finish(dev, len, len, len, 1); + return; + + case GPCMD_GET_CONFIGURATION: + scsi_cdrom_set_phase(dev, SCSI_PHASE_DATA_IN); + + /* XXX: could result in alignment problems in some architectures */ + feature = (cdb[2] << 8) | cdb[3]; + max_len = (cdb[7] << 8) | cdb[8]; + + /* only feature 0 is supported */ + if ((cdb[2] != 0) || (cdb[3] > 2)) { + scsi_cdrom_invalid_field(dev); + scsi_cdrom_buf_free(dev); + return; + } + + scsi_cdrom_buf_alloc(dev, 65536); + memset(cdbufferb, 0, max_len); + + alloc_length = 0; + b = cdbufferb; + + /* + * the number of sectors from the media tells us which profile + * to use as current. 0 means there is no media + */ + if (dev->drv->handler->ready(dev->id)) { + len = dev->drv->handler->size(dev->id); + if (len > CD_MAX_SECTORS) { + b[6] = (MMC_PROFILE_DVD_ROM >> 8) & 0xff; + b[7] = MMC_PROFILE_DVD_ROM & 0xff; + ret = 1; + } else { + b[6] = (MMC_PROFILE_CD_ROM >> 8) & 0xff; + b[7] = MMC_PROFILE_CD_ROM & 0xff; + ret = 0; + } + } else + ret = 2; + + alloc_length = 8; + b += 8; + + if ((feature == 0) || ((cdb[1] & 3) < 2)) { + b[2] = (0 << 2) | 0x02 | 0x01; /* persistent and current */ + b[3] = 8; + + alloc_length += 4; + b += 4; + + for (i = 0; i < 2; i++) { + b[0] = (profiles[i] >> 8) & 0xff; + b[1] = profiles[i] & 0xff; + + if (ret == i) + b[2] |= 1; + + alloc_length += 4; + b += 4; + } + } + if ((feature == 1) || ((cdb[1] & 3) < 2)) { + b[1] = 1; + b[2] = (2 << 2) | 0x02 | 0x01; /* persistent and current */ + b[3] = 8; + + if (dev->drv->bus_type == CDROM_BUS_SCSI) + b[7] = 1; + else + b[7] = 2; + b[8] = 1; + + alloc_length += 12; + b += 12; + } + if ((feature == 2) || ((cdb[1] & 3) < 2)) { + b[1] = 2; + b[2] = (1 << 2) | 0x02 | 0x01; /* persistent and current */ + b[3] = 4; + + b[4] = 2; + + alloc_length += 8; + b += 8; + } + + cdbufferb[0] = ((alloc_length - 4) >> 24) & 0xff; + cdbufferb[1] = ((alloc_length - 4) >> 16) & 0xff; + cdbufferb[2] = ((alloc_length - 4) >> 8) & 0xff; + cdbufferb[3] = (alloc_length - 4) & 0xff; + + alloc_length = MIN(alloc_length, max_len); + + scsi_cdrom_set_buf_len(dev, BufLen, &alloc_length); + + scsi_cdrom_data_command_finish(dev, alloc_length, alloc_length, alloc_length, 0); + break; + + case GPCMD_GET_EVENT_STATUS_NOTIFICATION: + scsi_cdrom_set_phase(dev, SCSI_PHASE_DATA_IN); + + scsi_cdrom_buf_alloc(dev, 8 + sizeof(gesn_event_header_t)); + + gesn_cdb = (void *) cdb; + gesn_event_header = (void *) cdbufferb; + + /* It is fine by the MMC spec to not support async mode operations. */ + if (!(gesn_cdb->polled & 0x01)) { + /* asynchronous mode */ + /* Only polling is supported, asynchronous mode is not. */ + scsi_cdrom_invalid_field(dev); + scsi_cdrom_buf_free(dev); + return; + } + + /* + * These are the supported events. + * + * We currently only support requests of the 'media' type. + * Notification class requests and supported event classes are bitmasks, + * but they are built from the same values as the "notification class" + * field. + */ + gesn_event_header->supported_events = 1 << GESN_MEDIA; + + /* + * We use |= below to set the class field; other bits in this byte + * are reserved now but this is useful to do if we have to use the + * reserved fields later. + */ + gesn_event_header->notification_class = 0; + + /* + * Responses to requests are to be based on request priority. The + * notification_class_request_type enum above specifies the + * priority: upper elements are higher prio than lower ones. + */ + if (gesn_cdb->class & (1 << GESN_MEDIA)) { + gesn_event_header->notification_class |= GESN_MEDIA; + + cdbufferb[4] = dev->media_status; /* Bits 7-4 = Reserved, Bits 4-1 = Media Status */ + cdbufferb[5] = 1; /* Power Status (1 = Active) */ + cdbufferb[6] = 0; + cdbufferb[7] = 0; + used_len = 8; + } else { + gesn_event_header->notification_class = 0x80; /* No event available */ + used_len = sizeof(*gesn_event_header); + } + gesn_event_header->len = used_len - sizeof(*gesn_event_header); + + memcpy(cdbufferb, gesn_event_header, 4); + + scsi_cdrom_set_buf_len(dev, BufLen, &used_len); + + scsi_cdrom_data_command_finish(dev, used_len, used_len, used_len, 0); + break; + + case GPCMD_READ_DISC_INFORMATION: + scsi_cdrom_set_phase(dev, SCSI_PHASE_DATA_IN); + + max_len = cdb[7]; + max_len <<= 8; + max_len |= cdb[8]; + + scsi_cdrom_buf_alloc(dev, 65536); + + memset(cdbufferb, 0, 34); + memset(cdbufferb, 1, 9); + cdbufferb[0] = 0; + cdbufferb[1] = 32; + cdbufferb[2] = 0xe; /* last session complete, disc finalized */ + cdbufferb[7] = 0x20; /* unrestricted use */ + cdbufferb[8] = 0x00; /* CD-ROM */ + + len=34; + len = MIN(len, max_len); + + scsi_cdrom_set_buf_len(dev, BufLen, &len); + + scsi_cdrom_data_command_finish(dev, len, len, len, 0); + break; + + case GPCMD_READ_TRACK_INFORMATION: + scsi_cdrom_set_phase(dev, SCSI_PHASE_DATA_IN); + + max_len = cdb[7]; + max_len <<= 8; + max_len |= cdb[8]; + + scsi_cdrom_buf_alloc(dev, 65536); + + track = ((uint32_t) cdb[2]) << 24; + track |= ((uint32_t) cdb[3]) << 16; + track |= ((uint32_t) cdb[4]) << 8; + track |= (uint32_t) cdb[5]; + + if (((cdb[1] & 0x03) != 1) || (track != 1)) { + scsi_cdrom_invalid_field(dev); + scsi_cdrom_buf_free(dev); + return; + } + + len = 36; + + memset(cdbufferb, 0, 36); + cdbufferb[0] = 0; + cdbufferb[1] = 34; + cdbufferb[2] = 1; /* track number (LSB) */ + cdbufferb[3] = 1; /* session number (LSB) */ + cdbufferb[5] = (0 << 5) | (0 << 4) | (4 << 0); /* not damaged, primary copy, data track */ + cdbufferb[6] = (0 << 7) | (0 << 6) | (0 << 5) | (0 << 6) | (1 << 0); /* not reserved track, not blank, not packet writing, not fixed packet, data mode 1 */ + cdbufferb[7] = (0 << 1) | (0 << 0); /* last recorded address not valid, next recordable address not valid */ + cdbufferb[24] = (dev->drv->handler->size(dev->id) >> 24) & 0xff; /* track size */ + cdbufferb[25] = (dev->drv->handler->size(dev->id) >> 16) & 0xff; /* track size */ + cdbufferb[26] = (dev->drv->handler->size(dev->id) >> 8) & 0xff; /* track size */ + cdbufferb[27] = dev->drv->handler->size(dev->id) & 0xff; /* track size */ + + if (len > max_len) { + len = max_len; + cdbufferb[0] = ((max_len - 2) >> 8) & 0xff; + cdbufferb[1] = (max_len - 2) & 0xff; + } + + scsi_cdrom_set_buf_len(dev, BufLen, &len); + + scsi_cdrom_data_command_finish(dev, len, len, max_len, 0); + break; + + case GPCMD_PLAY_AUDIO_10: + case GPCMD_PLAY_AUDIO_12: + case GPCMD_PLAY_AUDIO_MSF: + case GPCMD_PLAY_AUDIO_TRACK_INDEX: + scsi_cdrom_set_phase(dev, SCSI_PHASE_STATUS); + + switch(cdb[0]) { + case GPCMD_PLAY_AUDIO_10: + msf = 0; + pos = (cdb[2] << 24) | (cdb[3] << 16) | (cdb[4] << 8) | cdb[5]; + len = (cdb[7] << 8) | cdb[8]; + break; + case GPCMD_PLAY_AUDIO_12: + msf = 0; + pos = (cdb[2] << 24) | (cdb[3] << 16) | (cdb[4] << 8) | cdb[5]; + len = (cdb[6] << 24) | (cdb[7] << 16) | (cdb[8] << 8) | cdb[9]; + break; + case GPCMD_PLAY_AUDIO_MSF: + /* This is apparently deprecated in the ATAPI spec, and apparently + has been since 1995 (!). Hence I'm having to guess most of it. */ + msf = 1; + pos = (cdb[3] << 16) | (cdb[4] << 8) | cdb[5]; + len = (cdb[6] << 16) | (cdb[7] << 8) | cdb[8]; + break; + case GPCMD_PLAY_AUDIO_TRACK_INDEX: + msf = 2; + pos = (cdb[4] << 8) | cdb[5]; + len = (cdb[7] << 8) | cdb[8]; + break; + } + + if ((dev->drv->host_drive < 1) || (dev->drv->cd_status <= CD_STATUS_DATA_ONLY)) { + scsi_cdrom_illegal_mode(dev); + break; + } + + if (dev->drv->handler->playaudio) + ret = dev->drv->handler->playaudio(dev->id, pos, len, msf); + else + ret = 0; + + if (ret) + scsi_cdrom_command_complete(dev); + else + scsi_cdrom_illegal_mode(dev); + break; + + case GPCMD_READ_SUBCHANNEL: + scsi_cdrom_set_phase(dev, SCSI_PHASE_DATA_IN); + + max_len = cdb[7]; + max_len <<= 8; + max_len |= cdb[8]; + msf = (cdb[1] >> 1) & 1; + + scsi_cdrom_buf_alloc(dev, 32); + + scsi_cdrom_log("CD-ROM %i: Getting page %i (%s)\n", dev->id, cdb[3], msf ? "MSF" : "LBA"); + + if (cdb[3] > 3) { + /* scsi_cdrom_log("CD-ROM %i: Read subchannel check condition %02X\n", dev->id, + cdb[3]); */ + scsi_cdrom_invalid_field(dev); + scsi_cdrom_buf_free(dev); + return; + } + + switch(cdb[3]) { + case 0: + alloc_length = 4; + break; + case 1: + alloc_length = 16; + break; + default: + alloc_length = 24; + break; + } + + memset(cdbufferb, 0, 24); + pos = 0; + cdbufferb[pos++] = 0; + cdbufferb[pos++] = 0; /*Audio status*/ + cdbufferb[pos++] = 0; cdbufferb[pos++] = 0; /*Subchannel length*/ + cdbufferb[pos++] = cdb[3] & 3; /*Format code*/ + if (cdb[3] == 1) { + cdbufferb[1] = dev->drv->handler->getcurrentsubchannel(dev->id, &cdbufferb[5], msf); + switch(dev->drv->cd_status) { + case CD_STATUS_PLAYING: + cdbufferb[1] = 0x11; + break; + case CD_STATUS_PAUSED: + cdbufferb[1] = 0x12; + break; + case CD_STATUS_DATA_ONLY: + cdbufferb[1] = 0x15; + break; + default: + cdbufferb[1] = 0x13; + break; + } + } + + if (!(cdb[2] & 0x40) || (cdb[3] == 0)) + len = 4; + else + len = alloc_length; + + len = MIN(len, max_len); + scsi_cdrom_set_buf_len(dev, BufLen, &len); + + scsi_cdrom_data_command_finish(dev, len, len, len, 0); + break; + + case GPCMD_READ_DVD_STRUCTURE: + scsi_cdrom_set_phase(dev, SCSI_PHASE_DATA_IN); + + alloc_length = (((uint32_t) cdb[8]) << 8) | ((uint32_t) cdb[9]); + + scsi_cdrom_buf_alloc(dev, alloc_length); + + len = dev->drv->handler->size(dev->id); + + if ((cdb[7] < 0xc0) && (len <= CD_MAX_SECTORS)) { + scsi_cdrom_incompatible_format(dev); + scsi_cdrom_buf_free(dev); + return; + } + + memset(cdbufferb, 0, alloc_length); + + if ((cdb[7] <= 0x7f) || (cdb[7] == 0xff)) { + if (cdb[1] == 0) { + ret = scsi_cdrom_read_dvd_structure(dev, format, cdb, cdbufferb); + if (ret) { + scsi_cdrom_set_buf_len(dev, BufLen, &alloc_length); + scsi_cdrom_data_command_finish(dev, alloc_length, alloc_length, + len, 0); + } else + scsi_cdrom_buf_free(dev); + return; + } + } else { + scsi_cdrom_invalid_field(dev); + scsi_cdrom_buf_free(dev); + return; + } + break; + + case GPCMD_START_STOP_UNIT: + scsi_cdrom_set_phase(dev, SCSI_PHASE_STATUS); + + switch(cdb[4] & 3) { + case 0: /* Stop the disc. */ + if (dev->drv->handler->stop) + dev->drv->handler->stop(dev->id); + break; + case 1: /* Start the disc and read the TOC. */ + dev->drv->handler->medium_changed(dev->id); /* This causes a TOC reload. */ + break; + case 2: /* Eject the disc if possible. */ + if (dev->drv->handler->stop) + dev->drv->handler->stop(dev->id); + cdrom_eject(dev->id); + break; + case 3: /* Load the disc (close tray). */ + cdrom_reload(dev->id); + break; + } + + scsi_cdrom_command_complete(dev); + break; + + case GPCMD_INQUIRY: + scsi_cdrom_set_phase(dev, SCSI_PHASE_DATA_IN); + + max_len = cdb[3]; + max_len <<= 8; + max_len |= cdb[4]; + + scsi_cdrom_buf_alloc(dev, 65536); + + if (cdb[1] & 1) { + preamble_len = 4; + size_idx = 3; + + cdbufferb[idx++] = 05; + cdbufferb[idx++] = cdb[2]; + cdbufferb[idx++] = 0; + + idx++; + + switch (cdb[2]) { + case 0x00: + cdbufferb[idx++] = 0x00; + cdbufferb[idx++] = 0x83; + break; + case 0x83: + if (idx + 24 > max_len) { + scsi_cdrom_data_phase_error(dev); + scsi_cdrom_buf_free(dev); + return; + } + + cdbufferb[idx++] = 0x02; + cdbufferb[idx++] = 0x00; + cdbufferb[idx++] = 0x00; + cdbufferb[idx++] = 20; + ide_padstr8(cdbufferb + idx, 20, "53R141"); /* Serial */ + idx += 20; + + if (idx + 72 > cdb[4]) + goto atapi_out; + cdbufferb[idx++] = 0x02; + cdbufferb[idx++] = 0x01; + cdbufferb[idx++] = 0x00; + cdbufferb[idx++] = 68; + ide_padstr8(cdbufferb + idx, 8, EMU_NAME); /* Vendor */ + idx += 8; + ide_padstr8(cdbufferb + idx, 40, device_identify_ex); /* Product */ + idx += 40; + ide_padstr8(cdbufferb + idx, 20, "53R141"); /* Product */ + idx += 20; + break; + default: + scsi_cdrom_log("INQUIRY: Invalid page: %02X\n", cdb[2]); + scsi_cdrom_invalid_field(dev); + scsi_cdrom_buf_free(dev); + return; + } + } else { + preamble_len = 5; + size_idx = 4; + + memset(cdbufferb, 0, 8); + cdbufferb[0] = 5; /*CD-ROM*/ + cdbufferb[1] = 0x80; /*Removable*/ + cdbufferb[2] = (dev->drv->bus_type == CDROM_BUS_SCSI) ? 0x02 : 0x00; /*SCSI-2 compliant*/ + cdbufferb[3] = (dev->drv->bus_type == CDROM_BUS_SCSI) ? 0x12 : 0x21; + cdbufferb[4] = 31; + if (dev->drv->bus_type == CDROM_BUS_SCSI) { + cdbufferb[6] = 1; /* 16-bit transfers supported */ + cdbufferb[7] = 0x20; /* Wide bus supported */ + } + + ide_padstr8(cdbufferb + 8, 8, EMU_NAME); /* Vendor */ + ide_padstr8(cdbufferb + 16, 16, device_identify); /* Product */ + ide_padstr8(cdbufferb + 32, 4, EMU_VERSION); /* Revision */ + idx = 36; + + if (max_len == 96) { + cdbufferb[4] = 91; + idx = 96; + } + } + +atapi_out: + cdbufferb[size_idx] = idx - preamble_len; + len=idx; + + len = MIN(len, max_len); + scsi_cdrom_set_buf_len(dev, BufLen, &len); + + scsi_cdrom_data_command_finish(dev, len, len, max_len, 0); + break; + + case GPCMD_PREVENT_REMOVAL: + scsi_cdrom_set_phase(dev, SCSI_PHASE_STATUS); + scsi_cdrom_command_complete(dev); + break; + + case GPCMD_PAUSE_RESUME_ALT: + case GPCMD_PAUSE_RESUME: + scsi_cdrom_set_phase(dev, SCSI_PHASE_STATUS); + + if (cdb[8] & 1) { + if (dev->drv->handler->resume) + dev->drv->handler->resume(dev->id); + else { + scsi_cdrom_illegal_mode(dev); + break; + } + } else { + if (dev->drv->handler->pause) + dev->drv->handler->pause(dev->id); + else { + scsi_cdrom_illegal_mode(dev); + break; + } + } + scsi_cdrom_command_complete(dev); + break; + + case GPCMD_SEEK_6: + case GPCMD_SEEK_10: + scsi_cdrom_set_phase(dev, SCSI_PHASE_STATUS); + + switch(cdb[0]) { + case GPCMD_SEEK_6: + pos = (cdb[2] << 8) | cdb[3]; + break; + case GPCMD_SEEK_10: + pos = (cdb[2] << 24) | (cdb[3]<<16) | (cdb[4]<<8) | cdb[5]; + break; + } + dev->drv->seek_diff = ABS((int) (pos - dev->drv->seek_pos)); + cdrom_seek(dev->drv, pos); + scsi_cdrom_command_complete(dev); + break; + + case GPCMD_READ_CDROM_CAPACITY: + scsi_cdrom_set_phase(dev, SCSI_PHASE_DATA_IN); + + scsi_cdrom_buf_alloc(dev, 8); + + if (scsi_cdrom_read_capacity(dev, dev->current_cdb, cdbufferb, (uint32_t *) &len) == 0) { + scsi_cdrom_buf_free(dev); + return; + } + + scsi_cdrom_set_buf_len(dev, BufLen, &len); + + scsi_cdrom_data_command_finish(dev, len, len, len, 0); + break; + + case GPCMD_STOP_PLAY_SCAN: + scsi_cdrom_set_phase(dev, SCSI_PHASE_STATUS); + + if (dev->drv->handler->stop) + dev->drv->handler->stop(dev->id); + else { + scsi_cdrom_illegal_mode(dev); + break; + } + scsi_cdrom_command_complete(dev); + break; + + default: + scsi_cdrom_illegal_opcode(dev); + break; + } + + /* scsi_cdrom_log("CD-ROM %i: Phase: %02X, request length: %i\n", dev->phase, dev->request_length); */ + + if (scsi_cdrom_atapi_phase_to_scsi(dev) == SCSI_PHASE_STATUS) + scsi_cdrom_buf_free(dev); +} + + +/* The command second phase function, needed for Mode Select. */ +static uint8_t +scsi_cdrom_phase_data_out(scsi_cdrom_t *dev) +{ + uint16_t block_desc_len, pos; + uint16_t i = 0; + + uint8_t error = 0; + uint8_t page, page_len, hdr_len, val, old_val, ch; + + switch(dev->current_cdb[0]) { + case GPCMD_MODE_SELECT_6: + case GPCMD_MODE_SELECT_10: + if (dev->current_cdb[0] == GPCMD_MODE_SELECT_10) + hdr_len = 8; + else + hdr_len = 4; + + if (dev->drv->bus_type == CDROM_BUS_SCSI) { + if (dev->current_cdb[0] == GPCMD_MODE_SELECT_6) { + block_desc_len = cdbufferb[2]; + block_desc_len <<= 8; + block_desc_len |= cdbufferb[3]; + } else { + block_desc_len = cdbufferb[6]; + block_desc_len <<= 8; + block_desc_len |= cdbufferb[7]; + } + } else + block_desc_len = 0; + + pos = hdr_len + block_desc_len; + + while(1) { + page = cdbufferb[pos] & 0x3F; + page_len = cdbufferb[pos + 1]; + + pos += 2; + + if (!(scsi_cdrom_mode_sense_page_flags & (1LL << ((uint64_t) page)))) { + scsi_cdrom_log("Unimplemented page %02X\n", page); + error |= 1; + } else { + for (i = 0; i < page_len; i++) { + ch = scsi_cdrom_mode_sense_pages_changeable.pages[page][i + 2]; + val = cdbufferb[pos + i]; + old_val = dev->ms_pages_saved.pages[page][i + 2]; + if (val != old_val) { + if (ch) + dev->ms_pages_saved.pages[page][i + 2] = val; + else { + scsi_cdrom_log("Unchangeable value on position %02X on page %02X\n", i + 2, page); + error |= 1; + } + } + } + } + + pos += page_len; + + if (dev->drv->bus_type == CDROM_BUS_SCSI) + val = scsi_cdrom_mode_sense_pages_default_scsi.pages[page][0] & 0x80; + else + val = scsi_cdrom_mode_sense_pages_default.pages[page][0] & 0x80; + + if (dev->do_page_save && val) + scsi_cdrom_mode_sense_save(dev); + + if (pos >= dev->total_length) + break; + } + + if (error) { + scsi_cdrom_invalid_field_pl(dev); + return 0; + } + break; + } + + return 1; +} + + +/* This is the general ATAPI PIO request function. */ +static void +scsi_cdrom_pio_request(scsi_cdrom_t *dev, uint8_t out) +{ + int ret = 0; + + if (dev->drv->bus_type < CDROM_BUS_SCSI) { + scsi_cdrom_log("CD-ROM %i: Lowering IDE IRQ\n", dev->id); + ide_irq_lower(ide_drives[dev->drv->ide_channel]); + } + + dev->status = BUSY_STAT; + + if (dev->pos >= dev->packet_len) { + scsi_cdrom_log("CD-ROM %i: %i bytes %s, command done\n", dev->id, dev->pos, out ? "written" : "read"); + + dev->pos = dev->request_pos = 0; + if (out) { + ret = scsi_cdrom_phase_data_out(dev); + /* If ret = 0 (phase 1 error), then we do not do anything else other than + free the buffer, as the phase and callback have already been set by the + error function. */ + if (ret) + scsi_cdrom_command_complete(dev); + } else + scsi_cdrom_command_complete(dev); + scsi_cdrom_buf_free(dev); + } else { + scsi_cdrom_log("CD-ROM %i: %i bytes %s, %i bytes are still left\n", dev->id, dev->pos, + out ? "written" : "read", dev->packet_len - dev->pos); + + /* If less than (packet length) bytes are remaining, update packet length + accordingly. */ + if ((dev->packet_len - dev->pos) < (dev->max_transfer_len)) + dev->max_transfer_len = dev->packet_len - dev->pos; + scsi_cdrom_log("CD-ROM %i: Packet length %i, request length %i\n", dev->id, dev->packet_len, + dev->max_transfer_len); + + dev->packet_status = out ? PHASE_DATA_OUT : PHASE_DATA_IN; + + dev->status = BUSY_STAT; + dev->phase = 1; + scsi_cdrom_callback(dev); + dev->callback = 0LL; + scsi_cdrom_set_callback(dev); + + dev->request_pos = 0; + } +} + + +static int +scsi_cdrom_read_from_ide_dma(scsi_cdrom_t *dev) +{ + int ret; + + if (!dev) + return 0; + + if (ide_bus_master_write) { + ret = ide_bus_master_write(dev->drv->ide_channel >> 1, + cdbufferb, dev->packet_len, + ide_bus_master_priv[dev->drv->ide_channel >> 1]); + if (ret == 2) /* DMA not enabled, wait for it to be enabled. */ + return 2; + else if (ret == 1) { /* DMA error. */ + scsi_cdrom_bus_master_error(dev); + return 0; + } else + return 1; + } else + return 0; + + return 0; +} + + +static int +scsi_cdrom_read_from_scsi_dma(uint8_t scsi_id) +{ + scsi_cdrom_t *dev = scsi_devices[scsi_id].p; + int32_t *BufLen = &scsi_devices[scsi_id].buffer_length; + + if (dev) + return 0; + + scsi_cdrom_log("Reading from SCSI DMA: SCSI ID %02X, init length %i\n", scsi_id, *BufLen); + memcpy(cdbufferb, scsi_devices[scsi_id].cmd_buffer, *BufLen); + return 1; +} + + +static void +scsi_cdrom_irq_raise(scsi_cdrom_t *dev) +{ + if (dev->drv->bus_type < CDROM_BUS_SCSI) + ide_irq_raise(ide_drives[dev->drv->ide_channel]); +} + + +static int +scsi_cdrom_read_from_dma(scsi_cdrom_t *dev) +{ + int32_t *BufLen = &scsi_devices[dev->drv->scsi_device_id].buffer_length; + int ret = 0; + + if (dev->drv->bus_type == CDROM_BUS_SCSI) + ret = scsi_cdrom_read_from_scsi_dma(dev->drv->scsi_device_id); + else + ret = scsi_cdrom_read_from_ide_dma(dev); + + if (ret != 1) + return ret; + + if (dev->drv->bus_type == CDROM_BUS_SCSI) + scsi_cdrom_log("CD-ROM %i: SCSI Input data length: %i\n", dev->id, *BufLen); + else + scsi_cdrom_log("CD-ROM %i: ATAPI Input data length: %i\n", dev->id, dev->packet_len); + + ret = scsi_cdrom_phase_data_out(dev); + + if (ret) + return 1; + else + return 0; +} + + +static int +scsi_cdrom_write_to_ide_dma(scsi_cdrom_t *dev) +{ + int ret; + + if (!dev) + return 0; + + if (ide_bus_master_read) { + ret = ide_bus_master_read(dev->drv->ide_channel >> 1, + cdbufferb, dev->packet_len, + ide_bus_master_priv[dev->drv->ide_channel >> 1]); + if (ret == 2) /* DMA not enabled, wait for it to be enabled. */ + return 2; + else if (ret == 1) { /* DMA error. */ + scsi_cdrom_bus_master_error(dev); + return 0; + } else + return 1; + } else + return 0; +} + + +static int +scsi_cdrom_write_to_scsi_dma(uint8_t scsi_id) +{ + scsi_cdrom_t *dev = scsi_devices[scsi_id].p; + int32_t *BufLen = &scsi_devices[scsi_id].buffer_length; + + if (!dev) + return 0; + + scsi_cdrom_log("Writing to SCSI DMA: SCSI ID %02X, init length %i\n", scsi_id, *BufLen); + memcpy(scsi_devices[scsi_id].cmd_buffer, cdbufferb, *BufLen); + scsi_cdrom_log("CD-ROM %i: Data from CD buffer: %02X %02X %02X %02X %02X %02X %02X %02X\n", dev->id, + cdbufferb[0], cdbufferb[1], cdbufferb[2], cdbufferb[3], cdbufferb[4], cdbufferb[5], + cdbufferb[6], cdbufferb[7]); + return 1; +} + + +static int +scsi_cdrom_write_to_dma(scsi_cdrom_t *dev) +{ + int32_t *BufLen = &scsi_devices[dev->drv->scsi_device_id].buffer_length; + int ret = 0; + + if (dev->drv->bus_type == CDROM_BUS_SCSI) { + scsi_cdrom_log("Write to SCSI DMA: (ID %02X)\n", dev->drv->scsi_device_id); + ret = scsi_cdrom_write_to_scsi_dma(dev->drv->scsi_device_id); + } else + ret = scsi_cdrom_write_to_ide_dma(dev); + + if (dev->drv->bus_type == CDROM_BUS_SCSI) + scsi_cdrom_log("CD-ROM %i: SCSI Output data length: %i\n", dev->id, *BufLen); + else + scsi_cdrom_log("CD-ROM %i: ATAPI Output data length: %i\n", dev->id, dev->packet_len); + + return ret; +} + + +static void +scsi_cdrom_callback(void *p) +{ + scsi_cdrom_t *dev = (scsi_cdrom_t *) p; + int ret; + + switch(dev->packet_status) { + case PHASE_IDLE: + scsi_cdrom_log("CD-ROM %i: PHASE_IDLE\n", dev->id); + dev->pos = 0; + dev->phase = 1; + dev->status = READY_STAT | DRQ_STAT | (dev->status & ERR_STAT); + return; + case PHASE_COMMAND: + scsi_cdrom_log("CD-ROM %i: PHASE_COMMAND\n", dev->id); + dev->status = BUSY_STAT | (dev->status & ERR_STAT); + memcpy(dev->atapi_cdb, cdbufferb, 12); + scsi_cdrom_command(dev, dev->atapi_cdb); + return; + case PHASE_COMPLETE: + scsi_cdrom_log("CD-ROM %i: PHASE_COMPLETE\n", dev->id); + dev->status = READY_STAT; + dev->phase = 3; + dev->packet_status = 0xFF; + ui_sb_update_icon(SB_CDROM | dev->id, 0); + scsi_cdrom_irq_raise(dev); + return; + case PHASE_DATA_OUT: + scsi_cdrom_log("CD-ROM %i: PHASE_DATA_OUT\n", dev->id); + dev->status = READY_STAT | DRQ_STAT | (dev->status & ERR_STAT); + dev->phase = 0; + scsi_cdrom_irq_raise(dev); + return; + case PHASE_DATA_OUT_DMA: + scsi_cdrom_log("CD-ROM %i: PHASE_DATA_OUT_DMA\n", dev->id); + ret = scsi_cdrom_read_from_dma(dev); + + if ((ret == 1) || (dev->drv->bus_type == CDROM_BUS_SCSI)) { + scsi_cdrom_log("CD-ROM %i: DMA data out phase done\n"); + scsi_cdrom_buf_free(dev); + scsi_cdrom_command_complete(dev); + } else if (ret == 2) { + scsi_cdrom_log("CD-ROM %i: DMA out not enabled, wait\n"); + scsi_cdrom_command_bus(dev); + } else { + scsi_cdrom_log("CD-ROM %i: DMA data out phase failure\n"); + scsi_cdrom_buf_free(dev); + } + return; + case PHASE_DATA_IN: + scsi_cdrom_log("CD-ROM %i: PHASE_DATA_IN\n", dev->id); + dev->status = READY_STAT | DRQ_STAT | (dev->status & ERR_STAT); + dev->phase = 2; + scsi_cdrom_irq_raise(dev); + return; + case PHASE_DATA_IN_DMA: + scsi_cdrom_log("CD-ROM %i: PHASE_DATA_IN_DMA\n", dev->id); + ret = scsi_cdrom_write_to_dma(dev); + + if ((ret == 1) || (dev->drv->bus_type == CDROM_BUS_SCSI)) { + scsi_cdrom_log("CD-ROM %i: DMA data in phase done\n", dev->id); + scsi_cdrom_buf_free(dev); + scsi_cdrom_command_complete(dev); + } else if (ret == 2) { + scsi_cdrom_log("CD-ROM %i: DMA in not enabled, wait\n", dev->id); + scsi_cdrom_command_bus(dev); + } else { + scsi_cdrom_log("CD-ROM %i: DMA data in phase failure\n", dev->id); + scsi_cdrom_buf_free(dev); + } + return; + case PHASE_ERROR: + scsi_cdrom_log("CD-ROM %i: PHASE_ERROR\n", dev->id); + dev->status = READY_STAT | ERR_STAT; + dev->phase = 3; + scsi_cdrom_irq_raise(dev); + ui_sb_update_icon(SB_CDROM | dev->id, 0); + return; + } +} + + +static uint32_t +scsi_cdrom_packet_read(void *p, int length) +{ + scsi_cdrom_t *dev = (scsi_cdrom_t *) p; + + uint16_t *cdbufferw; + uint32_t *cdbufferl; + + uint32_t temp = 0; + + if (!dev) + return 0; + + cdbufferw = (uint16_t *) cdbufferb; + cdbufferl = (uint32_t *) cdbufferb; + + if (!cdbufferb) + return 0; + + /* Make sure we return a 0 and don't attempt to read from the buffer if we're transferring bytes beyond it, + which can happen when issuing media access commands with an allocated length below minimum request length + (which is 1 sector = 2048 bytes). */ + switch(length) { + case 1: + temp = (dev->pos < dev->packet_len) ? cdbufferb[dev->pos] : 0; + dev->pos++; + dev->request_pos++; + break; + case 2: + temp = (dev->pos < dev->packet_len) ? cdbufferw[dev->pos >> 1] : 0; + dev->pos += 2; + dev->request_pos += 2; + break; + case 4: + temp = (dev->pos < dev->packet_len) ? cdbufferl[dev->pos >> 2] : 0; + dev->pos += 4; + dev->request_pos += 4; + break; + default: + return 0; + } + + if (dev->packet_status == PHASE_DATA_IN) { + if ((dev->request_pos >= dev->max_transfer_len) || (dev->pos >= dev->packet_len)) { + /* Time for a DRQ. */ + scsi_cdrom_pio_request(dev, 0); + } + return temp; + } else + return 0; +} + + +static void +scsi_cdrom_packet_write(void *p, uint32_t val, int length) +{ + scsi_cdrom_t *dev = (scsi_cdrom_t *) p; + + uint16_t *cdbufferw; + uint32_t *cdbufferl; + + if (!dev) + return; + + if ((dev->packet_status == PHASE_IDLE) && !cdbufferb) + scsi_cdrom_buf_alloc(dev, 12); + + cdbufferw = (uint16_t *) cdbufferb; + cdbufferl = (uint32_t *) cdbufferb; + + if (!cdbufferb) + return; + + switch(length) { + case 1: + cdbufferb[dev->pos] = val & 0xff; + dev->pos++; + dev->request_pos++; + break; + case 2: + cdbufferw[dev->pos >> 1] = val & 0xffff; + dev->pos += 2; + dev->request_pos += 2; + break; + case 4: + cdbufferl[dev->pos >> 2] = val; + dev->pos += 4; + dev->request_pos += 4; + break; + default: + return; + } + + if (dev->packet_status == PHASE_DATA_OUT) { + if ((dev->request_pos >= dev->max_transfer_len) || (dev->pos >= dev->packet_len)) { + /* Time for a DRQ. */ + scsi_cdrom_pio_request(dev, 1); + } + return; + } else if (dev->packet_status == PHASE_IDLE) { + if (dev->pos >= 12) { + dev->pos = 0; + dev->status = BUSY_STAT; + dev->packet_status = PHASE_COMMAND; + timer_process(); + scsi_cdrom_callback(dev); + timer_update_outstanding(); + } + return; + } +} + + +static void +scsi_cdrom_close(void *p) +{ + scsi_cdrom_t *dev = (scsi_cdrom_t *) p; + + if (dev) { + free(scsi_cdrom[dev->id]); + scsi_cdrom[dev->id] = NULL; + } +} + + +static void +scsi_cdrom_stop(void *p) +{ + scsi_cdrom_t *dev = (scsi_cdrom_t *) p; + + if (dev->drv->handler->stop) + dev->drv->handler->stop(dev->id); +} + + +static int +scsi_cdrom_get_max(int ide_has_dma, int type) +{ + int ret; + + switch(type) { + case TYPE_PIO: + ret = ide_has_dma ? 4 : 0; + break; + case TYPE_SDMA: + ret = ide_has_dma ? -1 : 2; + break; + case TYPE_MDMA: + ret = ide_has_dma ? -1 : 2; + break; + case TYPE_UDMA: + ret = ide_has_dma ? -1 : 2; + break; + default: + ret = -1; + break; + } + + return ret; +} + + +static int +scsi_cdrom_get_timings(int ide_has_dma, int type) +{ + int ret; + + switch(type) { + case TIMINGS_DMA: + ret = ide_has_dma ? 120 : 0; + break; + case TIMINGS_PIO: + ret = ide_has_dma ? 120 : 0; + break; + case TIMINGS_PIO_FC: + ret = 0; + break; + default: + ret = 0; + break; + } + + return ret; +} + + +/** + * Fill in ide->buffer with the output of the "IDENTIFY PACKET DEVICE" command + */ +static void +scsi_cdrom_identify(void *p, int ide_has_dma) +{ + ide_t *ide = (ide_t *) p; + scsi_cdrom_t *dev; + char device_identify[9] = { '8', '6', 'B', '_', 'C', 'D', '0', '0', 0 }; + + dev = (scsi_cdrom_t *) ide->p; + + device_identify[7] = dev->id + 0x30; + scsi_cdrom_log("ATAPI Identify: %s\n", device_identify); + + ide->buffer[0] = 0x8000 | (5<<8) | 0x80 | (2<<5); /* ATAPI device, CD-ROM drive, removable media, accelerated DRQ */ + ide_padstr((char *) (ide->buffer + 10), "", 20); /* Serial Number */ +#if 0 + ide_padstr((char *) (ide->buffer + 23), EMU_VERSION, 8); /* Firmware */ + ide_padstr((char *) (ide->buffer + 27), device_identify, 40); /* Model */ +#else + ide_padstr((char *) (ide->buffer + 23), "4.20 ", 8); /* Firmware */ + ide_padstr((char *) (ide->buffer + 27), "NEC CD-ROM DRIVE:273 ", 40); /* Model */ +#endif + ide->buffer[49] = 0x200; /* LBA supported */ + ide->buffer[126] = 0xfffe; /* Interpret zero byte count limit as maximum length */ + + if (ide_has_dma) { + ide->buffer[71] = 30; + ide->buffer[72] = 30; + } +} + + +void +scsi_cdrom_drive_reset(int c) +{ + cdrom_drive_t *drv = &cdrom_drives[c]; + scsi_device_t *sd; + ide_t *id; + + /* Make sure to ignore any SCSI CD-ROM drive that has an out of range ID. */ + if ((drv->bus_type == CDROM_BUS_SCSI) && (drv->scsi_device_id > SCSI_ID_MAX)) + return; + + /* Make sure to ignore any ATAPI CD-ROM drive that has an out of range IDE channel. */ + if ((drv->bus_type == CDROM_BUS_ATAPI) && (drv->ide_channel > 7)) + return; + + if (!scsi_cdrom[c]) { + scsi_cdrom[c] = (scsi_cdrom_t *) malloc(sizeof(scsi_cdrom_t)); + memset(scsi_cdrom[c], 0, sizeof(scsi_cdrom_t)); + } + + scsi_cdrom[c]->id = c; + scsi_cdrom[c]->drv = drv; + drv->p = scsi_cdrom[c]; + drv->insert = scsi_cdrom_insert; + drv->get_volume = scsi_cdrom_get_volume; + drv->get_channel = scsi_cdrom_get_channel; + drv->close = scsi_cdrom_close; + + scsi_cdrom_init(scsi_cdrom[c]); + + if (drv->bus_type == CDROM_BUS_SCSI) { + /* SCSI CD-ROM, attach to the SCSI bus. */ + sd = &scsi_devices[drv->scsi_device_id]; + + sd->p = scsi_cdrom[c]; + sd->command = scsi_cdrom_command; + sd->callback = scsi_cdrom_callback; + sd->err_stat_to_scsi = scsi_cdrom_err_stat_to_scsi; + sd->request_sense = scsi_cdrom_request_sense_for_scsi; + sd->reset = scsi_cdrom_reset; + sd->read_capacity = scsi_cdrom_read_capacity; + sd->type = SCSI_REMOVABLE_CDROM; + + scsi_cdrom_log("SCSI CD-ROM drive %i attached to SCSI ID %i\n", c, cdrom_drives[c].scsi_device_id); + } else if (drv->bus_type == CDROM_BUS_ATAPI) { + /* ATAPI CD-ROM, attach to the IDE bus. */ + id = ide_drives[drv->ide_channel]; + /* If the IDE channel is initialized, we attach to it, + otherwise, we do nothing - it's going to be a drive + that's not attached to anything. */ + if (id) { + id->p = scsi_cdrom[c]; + id->get_max = scsi_cdrom_get_max; + id->get_timings = scsi_cdrom_get_timings; + id->identify = scsi_cdrom_identify; + id->set_signature = scsi_cdrom_set_signature; + id->packet_write = scsi_cdrom_packet_write; + id->packet_read = scsi_cdrom_packet_read; + id->stop = scsi_cdrom_stop; + id->packet_callback = scsi_cdrom_callback; + id->device_reset = scsi_cdrom_reset; + id->interrupt_drq = 0; + + ide_atapi_attach(id); + } + + scsi_cdrom_log("ATAPI CD-ROM drive %i attached to IDE channel %i\n", c, cdrom_drives[c].ide_channel); + } +} diff --git a/src/scsi/scsi_cdrom.h b/src/scsi/scsi_cdrom.h new file mode 100644 index 000000000..a1741ac15 --- /dev/null +++ b/src/scsi/scsi_cdrom.h @@ -0,0 +1,75 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * Implementation of the CD-ROM drive with SCSI(-like) + * commands, for both ATAPI and SCSI usage. + * + * Version: @(#)scsi_cdrom.h 1.0.0 2018/10/09 + * + * Author: Miran Grca, + * + * Copyright 2018 Miran Grca. + */ +#ifndef EMU_SCSI_CDROM_H +#define EMU_SCSI_CDROM_H + + +#define CDROM_TIME (5LL * 100LL * (1LL << TIMER_SHIFT)) + + +#ifdef SCSI_DEVICE_H +typedef struct { + /* Common block. */ + mode_sense_pages_t ms_pages_saved; + + cdrom_drive_t *drv; + + uint8_t *buffer, + atapi_cdb[16], + current_cdb[16], + sense[256]; + + uint8_t status, phase, + error, id, + features, pad0, + pad1, pad2; + + uint16_t request_length, max_transfer_len; + + int requested_blocks, packet_status, + total_length, do_page_save, + unit_attention; + + uint32_t sector_pos, sector_len, + packet_len, pos; + + int64_t callback; + + int media_status, data_pos, + request_pos, total_read, + old_len; + + uint8_t previous_command, + pad3, pad4, pad5; +} scsi_cdrom_t; +#endif + + +extern scsi_cdrom_t *scsi_cdrom[CDROM_NUM]; + +#define scsi_cdrom_sense_error dev->sense[0] +#define scsi_cdrom_sense_key dev->sense[2] +#define scsi_cdrom_asc dev->sense[12] +#define scsi_cdrom_ascq dev->sense[13] +#define scsi_cdrom_drive cdrom_drives[id].host_drive + + +extern void scsi_cdrom_reset(void *p); + + +#endif /*EMU_SCSI_CDROM_H*/ diff --git a/src/scsi/scsi_device.c b/src/scsi/scsi_device.c index f5567cb74..54c8b53e0 100644 --- a/src/scsi/scsi_device.c +++ b/src/scsi/scsi_device.c @@ -8,7 +8,7 @@ * * The generic SCSI device command handler. * - * Version: @(#)scsi_device.c 1.0.17 2018/06/02 + * Version: @(#)scsi_device.c 1.0.18 2018/10/10 * * Authors: Miran Grca, * Fred N. van Kempen, @@ -25,325 +25,153 @@ #include "../disk/hdd.h" #include "scsi.h" #include "scsi_device.h" -#include "../cdrom/cdrom.h" -#include "../disk/zip.h" -#include "scsi_disk.h" +scsi_device_t scsi_devices[SCSI_ID_MAX]; + uint8_t scsi_null_device_sense[18] = { 0x70,0,SENSE_ILLEGAL_REQUEST,0,0,0,0,0,0,0,0,0,ASC_INV_LUN,0,0,0,0,0 }; static uint8_t -scsi_device_target_command(int lun_type, uint8_t id, uint8_t *cdb) +scsi_device_target_command(scsi_device_t *dev, uint8_t *cdb) { - switch(lun_type) { - case SCSI_DISK: - scsi_disk_command(scsi_disk[id], cdb); - return scsi_disk_err_stat_to_scsi(scsi_disk[id]); - case SCSI_CDROM: - cdrom_command(cdrom[id], cdb); - return cdrom_CDROM_PHASE_to_scsi(cdrom[id]); - case SCSI_ZIP: - zip_command(zip[id], cdb); - return zip_ZIP_PHASE_to_scsi(zip[id]); - default: - return SCSI_STATUS_CHECK_CONDITION; - } + if (dev->command && dev->err_stat_to_scsi) { + dev->command(dev->p, cdb); + return dev->err_stat_to_scsi(dev->p); + } else + return SCSI_STATUS_CHECK_CONDITION; } -static void scsi_device_target_phase_callback(int lun_type, uint8_t id) +static void scsi_device_target_callback(scsi_device_t *dev) { - switch(lun_type) { - case SCSI_DISK: - scsi_disk_callback(scsi_disk[id]); - break; - case SCSI_CDROM: - cdrom_phase_callback(cdrom[id]); - break; - case SCSI_ZIP: - zip_phase_callback(zip[id]); - break; - } + if (dev->callback) + dev->callback(dev->p); + return; } -static int scsi_device_target_err_stat_to_scsi(int lun_type, uint8_t id) +static int scsi_device_target_err_stat_to_scsi(scsi_device_t *dev) { - switch(lun_type) { - case SCSI_DISK: - return scsi_disk_err_stat_to_scsi(scsi_disk[id]); - case SCSI_CDROM: - return cdrom_CDROM_PHASE_to_scsi(cdrom[id]); - case SCSI_ZIP: - return zip_ZIP_PHASE_to_scsi(zip[id]); - default: - return SCSI_STATUS_CHECK_CONDITION; - } + if (dev->err_stat_to_scsi) + return dev->err_stat_to_scsi(dev->p); + else + return SCSI_STATUS_CHECK_CONDITION; } -int64_t scsi_device_get_callback(uint8_t scsi_id) +int64_t scsi_device_get_callback(scsi_device_t *dev) { - uint8_t lun_type = SCSIDevices[scsi_id].LunType; + scsi_device_data_t *sdd = (scsi_device_data_t *) dev->p; - uint8_t id = 0; - - switch (lun_type) - { - case SCSI_DISK: - id = scsi_disks[scsi_id]; - return scsi_disk[id]->callback; - break; - case SCSI_CDROM: - id = scsi_cdrom_drives[scsi_id]; - return cdrom[id]->callback; - break; - case SCSI_ZIP: - id = scsi_zip_drives[scsi_id]; - return zip[id]->callback; - break; - default: - return -1LL; - break; - } + if (sdd) + return sdd->callback; + else + return -1LL; } -uint8_t *scsi_device_sense(uint8_t scsi_id) +uint8_t *scsi_device_sense(scsi_device_t *dev) { - uint8_t lun_type = SCSIDevices[scsi_id].LunType; + scsi_device_data_t *sdd = (scsi_device_data_t *) dev->p; - uint8_t id = 0; - - switch (lun_type) - { - case SCSI_DISK: - id = scsi_disks[scsi_id]; - return scsi_disk[id]->sense; - break; - case SCSI_CDROM: - id = scsi_cdrom_drives[scsi_id]; - return cdrom[id]->sense; - break; - case SCSI_ZIP: - id = scsi_zip_drives[scsi_id]; - return zip[id]->sense; - break; - default: - return scsi_null_device_sense; - break; - } + if (sdd) + return sdd->sense; + else + return scsi_null_device_sense; } -void scsi_device_request_sense(uint8_t scsi_id, uint8_t *buffer, uint8_t alloc_length) +void scsi_device_request_sense(scsi_device_t *dev, uint8_t *buffer, uint8_t alloc_length) { - uint8_t lun_type = SCSIDevices[scsi_id].LunType; - - uint8_t id = 0; - - switch (lun_type) - { - case SCSI_DISK: - id = scsi_disks[scsi_id]; - scsi_disk_request_sense_for_scsi(scsi_disk[id], buffer, alloc_length); - break; - case SCSI_CDROM: - id = scsi_cdrom_drives[scsi_id]; - cdrom_request_sense_for_scsi(cdrom[id], buffer, alloc_length); - break; - case SCSI_ZIP: - id = scsi_zip_drives[scsi_id]; - zip_request_sense_for_scsi(zip[id], buffer, alloc_length); - break; - default: - memcpy(buffer, scsi_null_device_sense, alloc_length); - break; - } + if (dev->request_sense) + dev->request_sense(dev, buffer, alloc_length); + else + memcpy(buffer, scsi_null_device_sense, alloc_length); } -void scsi_device_reset(uint8_t scsi_id) +void scsi_device_reset(scsi_device_t *dev) { - uint8_t lun_type = SCSIDevices[scsi_id].LunType; - - uint8_t id = 0; - - switch (lun_type) - { - case SCSI_DISK: - id = scsi_disks[scsi_id]; - scsi_disk_reset(scsi_disk[id]); - break; - case SCSI_CDROM: - id = scsi_cdrom_drives[scsi_id]; - cdrom_reset(cdrom[id]); - break; - case SCSI_ZIP: - id = scsi_zip_drives[scsi_id]; - zip_reset(zip[id]); - break; - } + if (dev->reset) + dev->reset(dev->p); } -void scsi_device_type_data(uint8_t scsi_id, uint8_t *type, uint8_t *rmb) +void scsi_device_type_data(scsi_device_t *dev, uint8_t *type, uint8_t *rmb) { - uint8_t lun_type = SCSIDevices[scsi_id].LunType; - - switch (lun_type) - { - case SCSI_DISK: - *type = *rmb = 0x00; - break; - case SCSI_CDROM: - *type = 0x05; - *rmb = 0x80; - break; - case SCSI_ZIP: - *type = 0x00; - *rmb = 0x80; - break; - default: - *type = *rmb = 0xff; - break; - } + *rmb = dev->type >> 8; + *type = dev->type & 0xff; } -int scsi_device_read_capacity(uint8_t scsi_id, uint8_t *cdb, uint8_t *buffer, uint32_t *len) +int scsi_device_read_capacity(scsi_device_t *dev, uint8_t *cdb, uint8_t *buffer, uint32_t *len) { - uint8_t lun_type = SCSIDevices[scsi_id].LunType; - - uint8_t id = 0; - - switch (lun_type) - { - case SCSI_DISK: - id = scsi_disks[scsi_id]; - return scsi_disk_read_capacity(scsi_disk[id], cdb, buffer, len); - case SCSI_CDROM: - id = scsi_cdrom_drives[scsi_id]; - return cdrom_read_capacity(cdrom[id], cdb, buffer, len); - case SCSI_ZIP: - id = scsi_zip_drives[scsi_id]; - return zip_read_capacity(zip[id], cdb, buffer, len); - default: - return 0; - } + if (dev->read_capacity) + return dev->read_capacity(dev->p, cdb, buffer, len); + else + return 0; } -int scsi_device_present(uint8_t scsi_id) +int scsi_device_present(scsi_device_t *dev) { - uint8_t lun_type = SCSIDevices[scsi_id].LunType; - - switch (lun_type) - { - case SCSI_NONE: - return 0; - default: - return 1; - } + if (dev->type == SCSI_NONE) + return 0; + else + return 1; } -int scsi_device_valid(uint8_t scsi_id) +int scsi_device_valid(scsi_device_t *dev) { - uint8_t lun_type = SCSIDevices[scsi_id].LunType; - - uint8_t id = 0; - - switch (lun_type) - { - case SCSI_DISK: - id = scsi_disks[scsi_id]; - break; - case SCSI_CDROM: - id = scsi_cdrom_drives[scsi_id]; - break; - case SCSI_ZIP: - id = scsi_zip_drives[scsi_id]; - break; - default: - id = 0; - break; - } - - return (id == 0xFF) ? 0 : 1; + if (dev->p) + return 0; + else + return 1; } -int scsi_device_cdb_length(uint8_t scsi_id) +int scsi_device_cdb_length(scsi_device_t *dev) { /* Right now, it's 12 for all devices. */ return 12; } -void scsi_device_command_phase0(uint8_t scsi_id, uint8_t *cdb) +void scsi_device_command_phase0(scsi_device_t *dev, uint8_t *cdb) { - uint8_t id = 0; - uint8_t lun_type = SCSIDevices[scsi_id].LunType; - - switch (lun_type) { - case SCSI_DISK: - id = scsi_disks[scsi_id]; - break; - case SCSI_CDROM: - id = scsi_cdrom_drives[scsi_id]; - break; - case SCSI_ZIP: - id = scsi_zip_drives[scsi_id]; - break; - default: - id = 0; - SCSIDevices[scsi_id].Phase = SCSI_PHASE_STATUS; - SCSIDevices[scsi_id].Status = SCSI_STATUS_CHECK_CONDITION; - return; + if (!dev->p) { + dev->phase = SCSI_PHASE_STATUS; + dev->status = SCSI_STATUS_CHECK_CONDITION; + return; } /* Finally, execute the SCSI command immediately and get the transfer length. */ - SCSIDevices[scsi_id].Phase = SCSI_PHASE_COMMAND; - SCSIDevices[scsi_id].Status = scsi_device_target_command(lun_type, id, cdb); + dev->phase = SCSI_PHASE_COMMAND; + dev->status = scsi_device_target_command(dev, cdb); - if (SCSIDevices[scsi_id].Phase == SCSI_PHASE_STATUS) { + if (dev->phase == SCSI_PHASE_STATUS) { /* Command completed (either OK or error) - call the phase callback to complete the command. */ - scsi_device_target_phase_callback(lun_type, id); + scsi_device_target_callback(dev); } /* If the phase is DATA IN or DATA OUT, finish this here. */ } -void scsi_device_command_phase1(uint8_t scsi_id) +void scsi_device_command_phase1(scsi_device_t *dev) { - uint8_t id = 0; - uint8_t lun_type = SCSIDevices[scsi_id].LunType; - - switch (lun_type) { - case SCSI_DISK: - id = scsi_disks[scsi_id]; - break; - case SCSI_CDROM: - id = scsi_cdrom_drives[scsi_id]; - break; - case SCSI_ZIP: - id = scsi_zip_drives[scsi_id]; - break; - default: - id = 0; - return; - } + if (!dev->p) + return; /* Call the second phase. */ - scsi_device_target_phase_callback(lun_type, id); - SCSIDevices[scsi_id].Status = scsi_device_target_err_stat_to_scsi(lun_type, id); + scsi_device_target_callback(dev); + dev->status = scsi_device_target_err_stat_to_scsi(dev); /* Command second phase complete - call the callback to complete the command. */ - scsi_device_target_phase_callback(lun_type, id); + scsi_device_target_callback(dev); } -int32_t *scsi_device_get_buf_len(uint8_t scsi_id) +int32_t *scsi_device_get_buf_len(scsi_device_t *dev) { - return &SCSIDevices[scsi_id].BufferLength; + return &dev->buffer_length; } diff --git a/src/scsi/scsi_device.h b/src/scsi/scsi_device.h index 87678902a..8455a080d 100644 --- a/src/scsi/scsi_device.h +++ b/src/scsi/scsi_device.h @@ -8,7 +8,7 @@ * * Definitions for the generic SCSI device command handler. * - * Version: @(#)scsi_device.h 1.0.10 2018/10/07 + * Version: @(#)scsi_device.h 1.0.11 2018/10/09 * * Authors: Miran Grca, * Fred N. van Kempen, @@ -250,6 +250,15 @@ #define BUS_IDLE (1 << 31) +#define PHASE_IDLE 0x00 +#define PHASE_COMMAND 0x01 +#define PHASE_COMPLETE 0x02 +#define PHASE_DATA_IN 0x03 +#define PHASE_DATA_IN_DMA 0x04 +#define PHASE_DATA_OUT 0x05 +#define PHASE_DATA_OUT_DMA 0x06 +#define PHASE_ERROR 0x80 + #define SCSI_PHASE_DATA_OUT 0 #define SCSI_PHASE_DATA_IN BUS_IO #define SCSI_PHASE_COMMAND BUS_CD @@ -264,28 +273,38 @@ #define MODE_SELECT_PHASE_PAGE 4 +/* This is probably no longer needed. */ +#if 0 typedef struct { - int state; - int new_state; - int clear_req; - uint32_t bus_in, bus_out; - int dev_id; + uint8_t command[20]; - int command_pos; - uint8_t command[20]; - int data_pos; - - int change_state_delay; - int new_req_delay; + int state, new_state, + clear_req, dev_id, + command_pos, data_pos, + change_state_delay, + new_req_delay; + + uint32_t bus_in, bus_out; } scsi_bus_t; +#endif typedef struct { - uint8_t *CmdBuffer; - int LunType; - int32_t BufferLength; - uint8_t Status; - uint8_t Phase; + uint8_t *cmd_buffer; + + int32_t buffer_length; + + uint8_t status, phase; + uint16_t type; + + void *p; + + void (*command)(void *p, uint8_t *cdb); + void (*callback)(void *p); + int (*err_stat_to_scsi)(void *p); + void (*request_sense)(void *p, uint8_t *buffer, uint8_t alloc_length); + void (*reset)(void *p); + int (*read_capacity)(void *p, uint8_t *cdb, uint8_t *buffer, uint32_t *len); } scsi_device_t; #pragma pack(push,1) @@ -294,15 +313,43 @@ typedef struct { } mode_sense_pages_t; #pragma pack(pop) -enum { - SCSI_NONE = 0, - SCSI_DISK, - SCSI_CDROM, - SCSI_ZIP -}; +/* This is so we can access the common elements to all SCSI device structs + without knowing the device type. */ +typedef struct { + mode_sense_pages_t ms_pages_saved; + void *p; -extern scsi_device_t SCSIDevices[SCSI_ID_MAX]; + uint8_t *temp_buffer, + pad[16], /* This is atapi_cdb in ATAPI-supporting devices, + and pad in SCSI-only devices. */ + current_cdb[16], + sense[256]; + + uint8_t status, phase, + error, id, + features, pad0, + pad1, pad2; + + uint16_t request_length, max_transfer_len; + + int requested_blocks, packet_status, + total_length, do_page_save, + unit_attention; + + uint32_t sector_pos, sector_len, + packet_len, pos; + + int64_t callback; +} scsi_device_data_t; + +/* These are based on the INQUIRY values. */ +#define SCSI_NONE 0x0060 +#define SCSI_FIXED_DISK 0x0000 +#define SCSI_REMOVABLE_DISK 0x8000 +#define SCSI_REMOVABLE_CDROM 0x8005 + +extern scsi_device_t scsi_devices[SCSI_ID_MAX]; extern int cdrom_add_error_and_subchannel(uint8_t *b, int real_sector_type); @@ -312,20 +359,19 @@ extern int mode_select_init(uint8_t command, uint16_t pl_length, uint8_t do_save extern int mode_select_terminate(int force); extern int mode_select_write(uint8_t val); -extern uint8_t *scsi_device_sense(uint8_t id); -extern void scsi_device_type_data(uint8_t id, uint8_t *type, uint8_t *rmb); -extern int64_t scsi_device_get_callback(uint8_t scsi_id); -extern void scsi_device_request_sense(uint8_t scsi_id, uint8_t *buffer, +extern uint8_t *scsi_device_sense(scsi_device_t *dev); +extern void scsi_device_type_data(scsi_device_t *dev, uint8_t *type, uint8_t *rmb); +extern int64_t scsi_device_get_callback(scsi_device_t *dev); +extern void scsi_device_request_sense(scsi_device_t *dev, uint8_t *buffer, uint8_t alloc_length); -extern void scsi_device_reset(uint8_t scsi_id); -extern int scsi_device_read_capacity(uint8_t id, uint8_t *cdb, +extern void scsi_device_reset(scsi_device_t *dev); +extern int scsi_device_read_capacity(scsi_device_t *dev, uint8_t *cdb, uint8_t *buffer, uint32_t *len); -extern int scsi_device_present(uint8_t id); -extern int scsi_device_valid(uint8_t id); -extern int scsi_device_cdb_length(uint8_t id); -extern void scsi_device_command(uint8_t id, int cdb_len, uint8_t *cdb); -extern void scsi_device_command_phase0(uint8_t scsi_id, uint8_t *cdb); -extern void scsi_device_command_phase1(uint8_t scsi_id); -extern int32_t *scsi_device_get_buf_len(uint8_t scsi_id); +extern int scsi_device_present(scsi_device_t *dev); +extern int scsi_device_valid(scsi_device_t *dev); +extern int scsi_device_cdb_length(scsi_device_t *dev); +extern void scsi_device_command_phase0(scsi_device_t *dev, uint8_t *cdb); +extern void scsi_device_command_phase1(scsi_device_t *dev); +extern int32_t *scsi_device_get_buf_len(scsi_device_t *dev); #endif /*SCSI_DEVICE_H*/ diff --git a/src/scsi/scsi_disk.c b/src/scsi/scsi_disk.c index faa88e143..d7518cf81 100644 --- a/src/scsi/scsi_disk.c +++ b/src/scsi/scsi_disk.c @@ -30,7 +30,6 @@ #include "../plat.h" #include "../ui.h" #include "scsi_device.h" -#include "../cdrom/cdrom.h" #include "scsi_disk.h" @@ -54,12 +53,8 @@ #define scsi_disk_ascq dev->sense[13] -scsi_disk_t *scsi_disk[HDD_NUM]; - -uint8_t scsi_disks[16] = { - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF -}; +scsi_disk_t *scsi_disk[HDD_NUM] = { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL }; /* Table of all SCSI commands and their flags, needed for the new disc change / not ready handler. */ @@ -145,6 +140,9 @@ static const mode_sense_pages_t scsi_disk_mode_sense_pages_changeable = } }; +static void scsi_disk_callback(void *p); + + #ifdef ENABLE_SCSI_DISK_LOG int scsi_disk_do_log = ENABLE_SCSI_DISK_LOG; #endif @@ -166,9 +164,11 @@ scsi_disk_log(const char *fmt, ...) /* Translates ATAPI status (ERR_STAT flag) to SCSI status. */ -int -scsi_disk_err_stat_to_scsi(scsi_disk_t *dev) +static int +scsi_disk_err_stat_to_scsi(void *p) { + scsi_disk_t *dev = (scsi_disk_t *) p; + if (dev->status & ERR_STAT) return SCSI_STATUS_CHECK_CONDITION; else @@ -176,48 +176,6 @@ scsi_disk_err_stat_to_scsi(scsi_disk_t *dev) } -int -find_hdd_for_scsi_id(uint8_t scsi_id) -{ - uint8_t i = 0; - - for (i = 0; i < HDD_NUM; i++) { - if (wcslen(hdd[i].fn) == 0) - continue; - if ((hdd[i].spt == 0) || (hdd[i].hpc == 0) || (hdd[i].tracks == 0)) - continue; - if ((hdd[i].bus == HDD_BUS_SCSI) && (hdd[i].scsi_id == scsi_id)) - return i; - } - return 0xff; -} - - -void -scsi_loadhd(int scsi_id, int id) -{ - if (! hdd_image_load(id)) - scsi_disks[scsi_id] = 0xff; -} - - -void -build_scsi_disk_map(void) -{ - uint8_t i = 0; - - memset(scsi_disks, 0xff, 16); - - for (i = 0; i < 16; i++) { - scsi_disks[i] = find_hdd_for_scsi_id(i); - if (scsi_disks[i] != 0xff) { - if (wcslen(hdd[scsi_disks[i]].fn) > 0) - scsi_loadhd(i, scsi_disks[i]); - } - } -} - - void scsi_disk_mode_sense_load(scsi_disk_t *dev) { @@ -256,9 +214,10 @@ scsi_disk_mode_sense_save(scsi_disk_t *dev) } -int -scsi_disk_read_capacity(scsi_disk_t *dev, uint8_t *cdb, uint8_t *buffer, uint32_t *len) +static int +scsi_disk_read_capacity(void *p, uint8_t *cdb, uint8_t *buffer, uint32_t *len) { + scsi_disk_t *dev = (scsi_disk_t *) p; int size = 0; size = hdd_image_get_last_sector(dev->id); @@ -296,14 +255,14 @@ scsi_disk_mode_sense_read(scsi_disk_t *dev, uint8_t page_control, uint8_t page, uint32_t -scsi_disk_mode_sense(scsi_disk_t *dev, uint8_t *buf, uint32_t pos, uint8_t type, uint8_t block_descriptor_len) +scsi_disk_mode_sense(scsi_disk_t *dev, uint8_t *buf, uint32_t pos, uint8_t page, uint8_t block_descriptor_len) { - uint8_t msplen, page_control = (type >> 6) & 3; + uint8_t msplen, page_control = (page >> 6) & 3; int i = 0, j = 0; int size = 0; - type &= 0x3f; + page &= 0x3f; size = hdd_image_get_last_sector(dev->id); @@ -319,8 +278,8 @@ scsi_disk_mode_sense(scsi_disk_t *dev, uint8_t *buf, uint32_t pos, uint8_t type, } for (i = 0; i < 0x40; i++) { - if ((type == GPMODE_ALL_PAGES) || (type == i)) { - if (scsi_disk_mode_sense_page_flags & (1LL << dev->current_page_code)) { + if ((page == GPMODE_ALL_PAGES) || (page == i)) { + if (scsi_disk_mode_sense_page_flags & (1LL << (uint64_t) page)) { buf[pos++] = scsi_disk_mode_sense_read(dev, page_control, i, 0); msplen = scsi_disk_mode_sense_read(dev, page_control, i, 1); buf[pos++] = msplen; @@ -340,8 +299,8 @@ scsi_disk_command_common(scsi_disk_t *dev) { dev->status = BUSY_STAT; dev->phase = 1; - if (dev->packet_status == CDROM_PHASE_COMPLETE) { - scsi_disk_callback(dev); + if (dev->packet_status == PHASE_COMPLETE) { + scsi_disk_callback((void *) dev); dev->callback = 0LL; } else dev->callback = -1LL; /* Speed depends on SCSI controller */ @@ -351,7 +310,7 @@ scsi_disk_command_common(scsi_disk_t *dev) static void scsi_disk_command_complete(scsi_disk_t *dev) { - dev->packet_status = CDROM_PHASE_COMPLETE; + dev->packet_status = PHASE_COMPLETE; scsi_disk_command_common(dev); } @@ -359,7 +318,7 @@ scsi_disk_command_complete(scsi_disk_t *dev) static void scsi_disk_command_read_dma(scsi_disk_t *dev) { - dev->packet_status = CDROM_PHASE_DATA_IN_DMA; + dev->packet_status = PHASE_DATA_IN_DMA; scsi_disk_command_common(dev); } @@ -367,7 +326,7 @@ scsi_disk_command_read_dma(scsi_disk_t *dev) static void scsi_disk_command_write_dma(scsi_disk_t *dev) { - dev->packet_status = CDROM_PHASE_DATA_OUT_DMA; + dev->packet_status = PHASE_DATA_OUT_DMA; scsi_disk_command_common(dev); } @@ -407,7 +366,7 @@ scsi_disk_set_phase(scsi_disk_t *dev, uint8_t phase) if (dev->drv->bus != HDD_BUS_SCSI) return; - SCSIDevices[scsi_id].Phase = phase; + scsi_devices[scsi_id].phase = phase; } @@ -533,9 +492,11 @@ scsi_disk_rezero(scsi_disk_t *dev) } -void -scsi_disk_reset(scsi_disk_t *dev) +static void +scsi_disk_reset(void *p) { + scsi_disk_t *dev = (scsi_disk_t *) p; + scsi_disk_rezero(dev); dev->status = 0; dev->callback = 0; @@ -568,9 +529,11 @@ scsi_disk_request_sense(scsi_disk_t *dev, uint8_t *buffer, uint8_t alloc_length, } -void -scsi_disk_request_sense_for_scsi(scsi_disk_t *dev, uint8_t *buffer, uint8_t alloc_length) +static void +scsi_disk_request_sense_for_scsi(void *p, uint8_t *buffer, uint8_t alloc_length) { + scsi_disk_t *dev = (scsi_disk_t *) p; + scsi_disk_request_sense(dev, buffer, alloc_length, 0); } @@ -588,9 +551,10 @@ scsi_disk_set_buf_len(scsi_disk_t *dev, int32_t *BufLen, int32_t *src_len) } -void -scsi_disk_command(scsi_disk_t *dev, uint8_t *cdb) +static void +scsi_disk_command(void *p, uint8_t *cdb) { + scsi_disk_t *dev = (scsi_disk_t *) p; uint8_t *hdbufferb; int32_t *BufLen; int32_t len, max_len, alloc_length; @@ -602,8 +566,8 @@ scsi_disk_command(scsi_disk_t *dev, uint8_t *cdb) char device_identify_ex[15] = { '8', '6', 'B', '_', 'H', 'D', '0', '0', ' ', 'v', '1', '.', '0', '0', 0 }; int block_desc = 0; - hdbufferb = SCSIDevices[dev->drv->scsi_id].CmdBuffer; - BufLen = &SCSIDevices[dev->drv->scsi_id].BufferLength; + hdbufferb = scsi_devices[dev->drv->scsi_id].cmd_buffer; + BufLen = &scsi_devices[dev->drv->scsi_id].buffer_length; last_sector = hdd_image_get_last_sector(dev->id); @@ -666,7 +630,7 @@ scsi_disk_command(scsi_disk_t *dev, uint8_t *cdb) if (!len) { scsi_disk_set_phase(dev, SCSI_PHASE_STATUS); - dev->packet_status = CDROM_PHASE_COMPLETE; + dev->packet_status = PHASE_COMPLETE; dev->callback = 20 * SCSI_TIME; break; } @@ -715,7 +679,7 @@ scsi_disk_command(scsi_disk_t *dev, uint8_t *cdb) if ((!dev->sector_len) || (*BufLen == 0)) { scsi_disk_set_phase(dev, SCSI_PHASE_STATUS); scsi_disk_log("SCSI HD %i: All done - callback set\n", dev); - dev->packet_status = CDROM_PHASE_COMPLETE; + dev->packet_status = PHASE_COMPLETE; dev->callback = 20 * SCSI_TIME; break; } @@ -779,7 +743,7 @@ scsi_disk_command(scsi_disk_t *dev, uint8_t *cdb) if ((!dev->sector_len) || (*BufLen == 0)) { scsi_disk_set_phase(dev, SCSI_PHASE_STATUS); scsi_disk_log("SCSI HD %i: All done - callback set\n", dev->id); - dev->packet_status = CDROM_PHASE_COMPLETE; + dev->packet_status = PHASE_COMPLETE; dev->callback = 20 * SCSI_TIME; break; } @@ -817,7 +781,7 @@ scsi_disk_command(scsi_disk_t *dev, uint8_t *cdb) if ((!dev->sector_len) || (*BufLen == 0)) { scsi_disk_set_phase(dev, SCSI_PHASE_STATUS); scsi_disk_log("SCSI HD %i: All done - callback set\n", dev->id); - dev->packet_status = CDROM_PHASE_COMPLETE; + dev->packet_status = PHASE_COMPLETE; dev->callback = 20 * SCSI_TIME; break; } @@ -847,8 +811,6 @@ scsi_disk_command(scsi_disk_t *dev, uint8_t *cdb) else len = (cdb[8] | (cdb[7] << 8)); - dev->current_page_code = cdb[2] & 0x3F; - alloc_length = len; dev->temp_buffer = (uint8_t *) malloc(65536); @@ -909,7 +871,7 @@ scsi_disk_command(scsi_disk_t *dev, uint8_t *cdb) if ((!max_len) || (*BufLen == 0)) { scsi_disk_set_phase(dev, SCSI_PHASE_STATUS); /* scsi_disk_log("SCSI HD %i: All done - callback set\n", dev->id); */ - dev->packet_status = CDROM_PHASE_COMPLETE; + dev->packet_status = PHASE_COMPLETE; dev->callback = 20 * SCSI_TIME; break; } @@ -1055,8 +1017,8 @@ atapi_out: static void scsi_disk_phase_data_in(scsi_disk_t *dev) { - uint8_t *hdbufferb = SCSIDevices[dev->drv->scsi_id].CmdBuffer; - int32_t *BufLen = &SCSIDevices[dev->drv->scsi_id].BufferLength; + uint8_t *hdbufferb = scsi_devices[dev->drv->scsi_id].cmd_buffer; + int32_t *BufLen = &scsi_devices[dev->drv->scsi_id].buffer_length; if (!*BufLen) { scsi_disk_log("scsi_disk_phase_data_in(): Buffer length is 0\n"); @@ -1108,9 +1070,9 @@ scsi_disk_phase_data_in(scsi_disk_t *dev) static void scsi_disk_phase_data_out(scsi_disk_t *dev) { - uint8_t *hdbufferb = SCSIDevices[dev->drv->scsi_id].CmdBuffer; + uint8_t *hdbufferb = scsi_devices[dev->drv->scsi_id].cmd_buffer; int i; - int32_t *BufLen = &SCSIDevices[dev->drv->scsi_id].BufferLength; + int32_t *BufLen = &scsi_devices[dev->drv->scsi_id].buffer_length; uint32_t last_sector = hdd_image_get_last_sector(dev->id); uint32_t c, h, s, last_to_write = 0; uint16_t block_desc_len, pos; @@ -1232,36 +1194,38 @@ scsi_disk_phase_data_out(scsi_disk_t *dev) /* If the result is 1, issue an IRQ, otherwise not. */ -void -scsi_disk_callback(scsi_disk_t *dev) +static void +scsi_disk_callback(void *p) { + scsi_disk_t *dev = (scsi_disk_t *) p; + switch(dev->packet_status) { - case CDROM_PHASE_IDLE: + case PHASE_IDLE: scsi_disk_log("SCSI HD %i: PHASE_IDLE\n", dev->id); dev->phase = 1; dev->status = READY_STAT | DRQ_STAT | (dev->status & ERR_STAT); return; - case CDROM_PHASE_COMPLETE: + case PHASE_COMPLETE: scsi_disk_log("SCSI HD %i: PHASE_COMPLETE\n", dev->id); dev->status = READY_STAT; dev->phase = 3; dev->packet_status = 0xFF; return; - case CDROM_PHASE_DATA_OUT_DMA: + case PHASE_DATA_OUT_DMA: scsi_disk_log("SCSI HD %i: PHASE_DATA_OUT_DMA\n", dev->id); scsi_disk_phase_data_out(dev); - dev->packet_status = CDROM_PHASE_COMPLETE; + dev->packet_status = PHASE_COMPLETE; dev->status = READY_STAT; dev->phase = 3; return; - case CDROM_PHASE_DATA_IN_DMA: + case PHASE_DATA_IN_DMA: scsi_disk_log("SCSI HD %i: PHASE_DATA_IN_DMA\n", dev->id); scsi_disk_phase_data_in(dev); - dev->packet_status = CDROM_PHASE_COMPLETE; + dev->packet_status = PHASE_COMPLETE; dev->status = READY_STAT; dev->phase = 3; return; - case CDROM_PHASE_ERROR: + case PHASE_ERROR: scsi_disk_log("SCSI HD %i: PHASE_ERROR\n", dev->id); dev->status = READY_STAT | ERR_STAT; dev->phase = 3; @@ -1283,20 +1247,47 @@ void scsi_disk_hard_reset(void) { int c; + scsi_device_t *sd; for (c = 0; c < HDD_NUM; c++) { if (hdd[c].bus == HDD_BUS_SCSI) { scsi_disk_log("SCSI disk hard_reset drive=%d\n", c); + /* Make sure to ignore any SCSI disk that has an out of range ID. */ + if (hdd[c].scsi_id > SCSI_ID_MAX) + continue; + + /* Make sure to ignore any SCSI disk whose image file name is empty. */ + if (wcslen(hdd[c].fn) == 0) + continue; + + /* Make sure to ignore any SCSI disk whose image fails to load. */ + if (! hdd_image_load(c)) + continue; + if (!scsi_disk[c]) { scsi_disk[c] = (scsi_disk_t *) malloc(sizeof(scsi_disk_t)); memset(scsi_disk[c], 0, sizeof(scsi_disk_t)); } + /* SCSI disk, attach to the SCSI bus. */ + sd = &scsi_devices[hdd[c].scsi_id]; + + sd->p = scsi_disk[c]; + sd->command = scsi_disk_command; + sd->callback = scsi_disk_callback; + sd->err_stat_to_scsi = scsi_disk_err_stat_to_scsi; + sd->request_sense = scsi_disk_request_sense_for_scsi; + sd->reset = scsi_disk_reset; + sd->read_capacity = scsi_disk_read_capacity; + sd->type = SCSI_FIXED_DISK; + scsi_disk[c]->id = c; scsi_disk[c]->drv = &hdd[c]; scsi_disk_mode_sense_load(scsi_disk[c]); + + scsi_disk_log("SCSI disk %i attached to SCSI ID %i\n", c, hdd[c].scsi_id); } } } diff --git a/src/scsi/scsi_disk.h b/src/scsi/scsi_disk.h index 36898f266..fdba9bb7e 100644 --- a/src/scsi/scsi_disk.h +++ b/src/scsi/scsi_disk.h @@ -6,7 +6,7 @@ * * Emulation of SCSI fixed and removable disks. * - * Version: @(#)scsi_disk.h 1.0.5 2018/06/02 + * Version: @(#)scsi_disk.h 1.0.6 2018/10/10 * * Author: Miran Grca, * Copyright 2017,2018 Miran Grca. @@ -18,43 +18,33 @@ typedef struct { hard_disk_t *drv; - /* Stuff for SCSI hard disks. */ - uint8_t status, phase, - error, id, + uint8_t *temp_buffer, + pad[16], /* This is atapi_cdb in ATAPI-supporting devices, + and pad in SCSI-only devices. */ current_cdb[16], sense[256]; - uint16_t request_length; + uint8_t status, phase, + error, id, + pad0, pad1, + pad2, pad3; - int requested_blocks, block_total, - packet_status, callback, - block_descriptor_len, - total_length, do_page_save; + uint16_t request_length, pad4; + + int requested_blocks, packet_status, + total_length, do_page_save, + unit_attention; uint32_t sector_pos, sector_len, - packet_len; + packet_len, pos; - uint64_t current_page_code; - - uint8_t *temp_buffer; + int64_t callback; } scsi_disk_t; extern scsi_disk_t *scsi_disk[HDD_NUM]; -extern uint8_t scsi_disks[16]; -extern void scsi_loadhd(int scsi_id, int id); extern void scsi_disk_global_init(void); extern void scsi_disk_hard_reset(void); extern void scsi_disk_close(void); - -extern int scsi_disk_read_capacity(scsi_disk_t *dev, uint8_t *cdb, uint8_t *buffer, uint32_t *len); -extern int scsi_disk_err_stat_to_scsi(scsi_disk_t *dev); -extern int scsi_disk_phase_to_scsi(scsi_disk_t *dev); -extern int find_hdd_for_scsi_id(uint8_t scsi_id); -extern void build_scsi_disk_map(void); -extern void scsi_disk_reset(scsi_disk_t *dev); -extern void scsi_disk_request_sense_for_scsi(scsi_disk_t *dev, uint8_t *buffer, uint8_t alloc_length); -extern void scsi_disk_command(scsi_disk_t *dev, uint8_t *cdb); -extern void scsi_disk_callback(scsi_disk_t *dev); diff --git a/src/scsi/scsi_ncr5380.c b/src/scsi/scsi_ncr5380.c index e26352b04..e09e64992 100644 --- a/src/scsi/scsi_ncr5380.c +++ b/src/scsi/scsi_ncr5380.c @@ -9,7 +9,7 @@ * Implementation of the NCR 5380 series of SCSI Host Adapters * made by NCR. These controllers were designed for the ISA bus. * - * Version: @(#)scsi_ncr5380.c 1.0.20 2018/10/08 + * Version: @(#)scsi_ncr5380.c 1.0.22 2018/10/09 * * Authors: Sarah Walker, * TheCollector1995, @@ -280,19 +280,19 @@ ncr_wait_process(ncr5380_t *ncr_dev) if (ncr->wait_data) { ncr->wait_data--; if (!ncr->wait_data) { - dev = &SCSIDevices[ncr->target_id]; + dev = &scsi_devices[ncr->target_id]; SET_BUS_STATE(ncr, ncr->new_phase); if (ncr->new_phase == SCSI_PHASE_DATA_IN) { ncr_log("Data In bus phase\n"); - ncr->tx_data = dev->CmdBuffer[ncr->data_pos++]; + ncr->tx_data = dev->cmd_buffer[ncr->data_pos++]; ncr->state = STATE_DATAIN; ncr->cur_bus = (ncr->cur_bus & ~BUS_DATAMASK) | BUS_SETDATA(ncr->tx_data) | BUS_DBP; } else if (ncr->new_phase == SCSI_PHASE_STATUS) { ncr_log("Status bus phase\n"); ncr->cur_bus |= BUS_REQ; ncr->state = STATE_STATUS; - ncr->cur_bus = (ncr->cur_bus & ~BUS_DATAMASK) | BUS_SETDATA(dev->Status) | BUS_DBP; + ncr->cur_bus = (ncr->cur_bus & ~BUS_DATAMASK) | BUS_SETDATA(dev->status) | BUS_DBP; } else if (ncr->new_phase == SCSI_PHASE_MESSAGE_IN) { ncr_log("Message In bus phase\n"); ncr->state = STATE_MESSAGEIN; @@ -799,7 +799,7 @@ scsiat_out(uint16_t port, uint8_t val, void *priv) { ncr5380_t *ncr_dev = (ncr5380_t *)priv; ncr_t *ncr = &ncr_dev->ncr; - scsi_device_t *dev = &SCSIDevices[ncr->target_id]; + scsi_device_t *dev = &scsi_devices[ncr->target_id]; ncr_log("SCSI AT write=0x%03x, val=%02x\n", port, val); switch (port & 0x0f) { @@ -852,7 +852,7 @@ scsiat_out(uint16_t port, uint8_t val, void *priv) if (ncr->unk_08 & 0x01) { ncr_dev->block_count_loaded = 1; - ncr_dev->block_count = dev->BufferLength / 128; + ncr_dev->block_count = dev->buffer_length / 128; } break; @@ -875,8 +875,8 @@ ncr_callback(void *priv) { ncr5380_t *ncr_dev = (ncr5380_t *)priv; ncr_t *ncr = &ncr_dev->ncr; - scsi_device_t *dev = &SCSIDevices[ncr->target_id]; - int c = 0; + scsi_device_t *dev = &scsi_devices[ncr->target_id]; + int req_len, c = 0; int64_t p; uint8_t temp, data; @@ -887,7 +887,7 @@ ncr_callback(void *priv) if (((ncr->state == STATE_DATAIN) || (ncr->state == STATE_DATAOUT)) && (ncr->dma_mode != DMA_IDLE)) ncr_dev->timer_period = (int64_t) ncr_dev->period; else - ncr_dev->timer_period += 10LL * TIMER_USEC; + ncr_dev->timer_period += 40LL * TIMER_USEC; if (ncr->dma_mode == DMA_IDLE) { ncr->bus_host = get_bus_host(ncr); @@ -909,7 +909,7 @@ ncr_callback(void *priv) ncr_log("Select - target ID = %i\n", ncr->target_id); /*Once the device has been found and selected, mark it as busy*/ - if ((ncr->target_id != -1) && scsi_device_present(ncr->target_id)) { + if ((ncr->target_id != -1) && scsi_device_present(&scsi_devices[ncr->target_id])) { ncr->cur_bus |= BUS_BSY; ncr_log("Device found at ID %i\n", ncr->target_id); ncr_log("Current Bus BSY=%02x\n", ncr->cur_bus); @@ -943,35 +943,36 @@ ncr_callback(void *priv) /*Reset data position to default*/ ncr->data_pos = 0; - dev = &SCSIDevices[ncr->target_id]; + dev = &scsi_devices[ncr->target_id]; - ncr_log("SCSI Command 0x%02X for ID %d, status code=%02x\n", ncr->command[0], ncr->target_id, dev->Status); + ncr_log("SCSI Command 0x%02X for ID %d, status code=%02x\n", ncr->command[0], ncr->target_id, dev->status); - dev->BufferLength = -1; + dev->buffer_length = -1; /*Now, execute the given SCSI command*/ - scsi_device_command_phase0(ncr->target_id, ncr->command); + scsi_device_command_phase0(dev, ncr->command); - ncr_log("SCSI ID %i: Command %02X: Buffer Length %i, SCSI Phase %02X\n", ncr->target_id, ncr->command[0], dev->BufferLength, dev->Phase); + ncr_log("SCSI ID %i: Command %02X: Buffer Length %i, SCSI Phase %02X\n", ncr->target_id, ncr->command[0], dev->buffer_length, dev->phase); - if (dev->Status != SCSI_STATUS_OK) { + if (dev->status != SCSI_STATUS_OK) { ncr->new_phase = SCSI_PHASE_STATUS; ncr->wait_data = 4; return; } /*If the SCSI phase is Data In or Data Out, allocate the SCSI buffer based on the transfer length of the command*/ - if (dev->BufferLength && (dev->Phase == SCSI_PHASE_DATA_IN || dev->Phase == SCSI_PHASE_DATA_OUT)) { - dev->CmdBuffer = (uint8_t *) malloc(dev->BufferLength); + if (dev->buffer_length && (dev->phase == SCSI_PHASE_DATA_IN || dev->phase == SCSI_PHASE_DATA_OUT)) { + dev->cmd_buffer = (uint8_t *) malloc(dev->buffer_length); - p = scsi_device_get_callback(ncr->target_id); + p = scsi_device_get_callback(dev); + req_len = MIN(64, dev->buffer_length); if (p <= 0LL) - ncr_dev->period = 0.2 * ((double) TIMER_USEC) * ((double) MIN(64, dev->BufferLength)); + ncr_dev->period = 0.2 * ((double) TIMER_USEC) * ((double) req_len); else - ncr_dev->period = (p / ((double) dev->BufferLength)) * ((double) MIN(64, dev->BufferLength)); + ncr_dev->period = (p / ((double) dev->buffer_length)) * ((double) req_len); } - if (dev->Phase == SCSI_PHASE_DATA_OUT) { + if (dev->phase == SCSI_PHASE_DATA_OUT) { /* Write direction commands have delayed execution - only execute them after the bus has gotten all the data from the host. */ ncr_log("Next state is data out\n"); ncr->new_phase = SCSI_PHASE_DATA_OUT; @@ -979,23 +980,23 @@ ncr_callback(void *priv) ncr->clear_req = 4; } else { /* Other command - execute immediately. */ - ncr->new_phase = dev->Phase; + ncr->new_phase = dev->phase; if (ncr->new_phase == SCSI_PHASE_DATA_IN) - scsi_device_command_phase1(ncr->target_id); + scsi_device_command_phase1(dev); ncr->wait_data = 4; } } } } else if (ncr->state == STATE_DATAIN) { - dev = &SCSIDevices[ncr->target_id]; + dev = &scsi_devices[ncr->target_id]; ncr_log("Data In ACK=%02x\n", ncr->bus_host & BUS_ACK); if (ncr->bus_host & BUS_ACK) { - if (ncr->data_pos >= dev->BufferLength) { - if (dev->CmdBuffer != NULL) { - free(dev->CmdBuffer); - dev->CmdBuffer = NULL; + if (ncr->data_pos >= dev->buffer_length) { + if (dev->cmd_buffer != NULL) { + free(dev->cmd_buffer); + dev->cmd_buffer = NULL; } ncr->cur_bus &= ~BUS_REQ; @@ -1003,7 +1004,7 @@ ncr_callback(void *priv) ncr->wait_data = 4; ncr->wait_complete = 8; } else { - ncr->tx_data = dev->CmdBuffer[ncr->data_pos++]; + ncr->tx_data = dev->cmd_buffer[ncr->data_pos++]; ncr->cur_bus = (ncr->cur_bus & ~BUS_DATAMASK) | BUS_SETDATA(ncr->tx_data) | BUS_DBP | BUS_REQ; ncr->clear_req = 3; ncr->cur_bus &= ~BUS_REQ; @@ -1011,18 +1012,18 @@ ncr_callback(void *priv) } } } else if (ncr->state == STATE_DATAOUT) { - dev = &SCSIDevices[ncr->target_id]; + dev = &scsi_devices[ncr->target_id]; ncr_log("Data Out ACK=%02x\n", ncr->bus_host & BUS_ACK); if (ncr->bus_host & BUS_ACK) { - dev->CmdBuffer[ncr->data_pos++] = BUS_GETDATA(ncr->bus_host); + dev->cmd_buffer[ncr->data_pos++] = BUS_GETDATA(ncr->bus_host); - if (ncr->data_pos >= dev->BufferLength) { - scsi_device_command_phase1(ncr->target_id); + if (ncr->data_pos >= dev->buffer_length) { + scsi_device_command_phase1(dev); - if (dev->CmdBuffer != NULL) { - free(dev->CmdBuffer); - dev->CmdBuffer = NULL; + if (dev->cmd_buffer != NULL) { + free(dev->cmd_buffer); + dev->cmd_buffer = NULL; } ncr->cur_bus &= ~BUS_REQ; @@ -1073,10 +1074,10 @@ ncr_callback(void *priv) temp = BUS_GETDATA(ncr->bus_host); ncr->bus_host = get_bus_host(ncr); - if (ncr->data_pos >= dev->BufferLength) { - if (dev->CmdBuffer != NULL) { - free(dev->CmdBuffer); - dev->CmdBuffer = NULL; + if (ncr->data_pos >= dev->buffer_length) { + if (dev->cmd_buffer != NULL) { + free(dev->cmd_buffer); + dev->cmd_buffer = NULL; } ncr->cur_bus &= ~BUS_REQ; @@ -1084,7 +1085,7 @@ ncr_callback(void *priv) ncr->wait_data = 4; ncr->wait_complete = 8; } else { - ncr->tx_data = dev->CmdBuffer[ncr->data_pos++]; + ncr->tx_data = dev->cmd_buffer[ncr->data_pos++]; ncr->cur_bus = (ncr->cur_bus & ~BUS_DATAMASK) | BUS_SETDATA(ncr->tx_data) | BUS_DBP | BUS_REQ; ncr->clear_req = 3; ncr->cur_bus &= ~BUS_REQ; @@ -1139,14 +1140,14 @@ ncr_callback(void *priv) ncr->bus_host = get_bus_host(ncr) & ~BUS_DATAMASK; ncr->bus_host |= BUS_SETDATA(data); - dev->CmdBuffer[ncr->data_pos++] = BUS_GETDATA(ncr->bus_host); + dev->cmd_buffer[ncr->data_pos++] = BUS_GETDATA(ncr->bus_host); - if (ncr->data_pos >= dev->BufferLength) { - scsi_device_command_phase1(ncr->target_id); + if (ncr->data_pos >= dev->buffer_length) { + scsi_device_command_phase1(dev); - if (dev->CmdBuffer != NULL) { - free(dev->CmdBuffer); - dev->CmdBuffer = NULL; + if (dev->cmd_buffer != NULL) { + free(dev->cmd_buffer); + dev->cmd_buffer = NULL; } ncr->cur_bus &= ~BUS_REQ; @@ -1196,10 +1197,10 @@ ncr_callback(void *priv) temp = BUS_GETDATA(ncr->bus_host); ncr->bus_host = get_bus_host(ncr); - if (ncr->data_pos >= dev->BufferLength) { - if (dev->CmdBuffer != NULL) { - free(dev->CmdBuffer); - dev->CmdBuffer = NULL; + if (ncr->data_pos >= dev->buffer_length) { + if (dev->cmd_buffer != NULL) { + free(dev->cmd_buffer); + dev->cmd_buffer = NULL; } ncr->cur_bus &= ~BUS_REQ; @@ -1207,7 +1208,7 @@ ncr_callback(void *priv) ncr->wait_data = 4; ncr->wait_complete = 8; } else { - ncr->tx_data = dev->CmdBuffer[ncr->data_pos++]; + ncr->tx_data = dev->cmd_buffer[ncr->data_pos++]; ncr->cur_bus = (ncr->cur_bus & ~BUS_DATAMASK) | BUS_SETDATA(ncr->tx_data) | BUS_DBP | BUS_REQ; ncr->clear_req = 3; ncr->cur_bus &= ~BUS_REQ; @@ -1248,14 +1249,14 @@ ncr_callback(void *priv) ncr->bus_host = get_bus_host(ncr) & ~BUS_DATAMASK; ncr->bus_host |= BUS_SETDATA(data); - dev->CmdBuffer[ncr->data_pos++] = BUS_GETDATA(ncr->bus_host); + dev->cmd_buffer[ncr->data_pos++] = BUS_GETDATA(ncr->bus_host); - if (ncr->data_pos >= dev->BufferLength) { - scsi_device_command_phase1(ncr->target_id); + if (ncr->data_pos >= dev->buffer_length) { + scsi_device_command_phase1(dev); - if (dev->CmdBuffer != NULL) { - free(dev->CmdBuffer); - dev->CmdBuffer = NULL; + if (dev->cmd_buffer != NULL) { + free(dev->cmd_buffer); + dev->cmd_buffer = NULL; } ncr->cur_bus &= ~BUS_REQ; diff --git a/src/scsi/scsi_ncr53c810.c b/src/scsi/scsi_ncr53c810.c index 459ca28fd..4ac48f67f 100644 --- a/src/scsi/scsi_ncr53c810.c +++ b/src/scsi/scsi_ncr53c810.c @@ -10,7 +10,7 @@ * NCR and later Symbios and LSI. This controller was designed * for the PCI bus. * - * Version: @(#)scsi_ncr53c810.c 1.0.14 2018/05/28 + * Version: @(#)scsi_ncr53c810.c 1.0.15 2018/10/09 * * Authors: Paul Brook (QEMU) * Artyom Tarasenko (QEMU) @@ -391,8 +391,10 @@ ncr53c810_soft_reset(ncr53c810_t *dev) dev->gpreg0 = 0; dev->sstop = 1; - for (i = 0; i < 16; i++) - scsi_device_reset(i); + /* This is *NOT* a wide SCSI controller, so do not touch + SCSI devices with ID's >= 8. */ + for (i = 0; i < 8; i++) + scsi_device_reset(&scsi_devices[i]); } @@ -595,11 +597,9 @@ ncr53c810_do_dma(ncr53c810_t *dev, int out, uint8_t id) uint32_t addr, tdbc; int count; - scsi_device_t *sd; + scsi_device_t *sd = &scsi_devices[id]; - sd = &SCSIDevices[id]; - - if ((!scsi_device_present(id))) { + if ((!scsi_device_present(sd))) { ncr53c810_log("(ID=%02i LUN=%02i) SCSI Command 0x%02x: Device not present when attempting to do DMA\n", id, dev->current_lun, dev->last_command); return; } @@ -610,7 +610,7 @@ ncr53c810_do_dma(ncr53c810_t *dev, int out, uint8_t id) return; } - /* Make sure count is never bigger than BufferLength. */ + /* Make sure count is never bigger than buffer_length. */ count = tdbc = dev->dbc; if (count > dev->temp_buf_len) count = dev->temp_buf_len; @@ -622,13 +622,13 @@ ncr53c810_do_dma(ncr53c810_t *dev, int out, uint8_t id) dev->dbc -= count; if (out) - ncr53c810_read(dev, addr, sd->CmdBuffer+dev->buffer_pos, count); + ncr53c810_read(dev, addr, sd->cmd_buffer + dev->buffer_pos, count); else { if (!dev->buffer_pos) { ncr53c810_log("(ID=%02i LUN=%02i) SCSI Command 0x%02x: SCSI Command Phase 1 on PHASE_DI\n", id, dev->current_lun, dev->last_command); - scsi_device_command_phase1(dev->current->tag); + scsi_device_command_phase1(&scsi_devices[dev->current->tag]); } - ncr53c810_write(dev, addr, sd->CmdBuffer+dev->buffer_pos, count); + ncr53c810_write(dev, addr, sd->cmd_buffer + dev->buffer_pos, count); } dev->temp_buf_len -= count; @@ -637,13 +637,13 @@ ncr53c810_do_dma(ncr53c810_t *dev, int out, uint8_t id) if (dev->temp_buf_len <= 0) { if (out) { ncr53c810_log("(ID=%02i LUN=%02i) SCSI Command 0x%02x: SCSI Command Phase 1 on PHASE_DO\n", id, dev->current_lun, dev->last_command); - scsi_device_command_phase1(id); + scsi_device_command_phase1(&scsi_devices[id]); } - if (sd->CmdBuffer != NULL) { - free(sd->CmdBuffer); - sd->CmdBuffer = NULL; + if (sd->cmd_buffer != NULL) { + free(sd->cmd_buffer); + sd->cmd_buffer = NULL; } - ncr53c810_command_complete(dev, sd->Status); + ncr53c810_command_complete(dev, sd->status); } else { ncr53c810_log("(ID=%02i LUN=%02i) SCSI Command 0x%02x: Resume SCRIPTS\n", id, dev->current_lun, dev->last_command); dev->sstop = 0; @@ -683,8 +683,8 @@ ncr53c810_do_command(ncr53c810_t *dev, uint8_t id) dev->sfbr = buf[0]; dev->command_complete = 0; - sd = &SCSIDevices[id]; - if (!scsi_device_present(id)) { + sd = &scsi_devices[id]; + if (!scsi_device_present(sd)) { ncr53c810_log("(ID=%02i LUN=%02i) SCSI Command 0x%02x: Bad Selection\n", id, dev->current_lun, buf[0]); ncr53c810_bad_selection(dev, id); return 0; @@ -693,46 +693,46 @@ ncr53c810_do_command(ncr53c810_t *dev, uint8_t id) dev->current = (ncr53c810_request*)malloc(sizeof(ncr53c810_request)); dev->current->tag = id; - sd->BufferLength = -1; + sd->buffer_length = -1; ncr53c810_log("(ID=%02i LUN=%02i) SCSI Command 0x%02x: DBC=%i\n", id, dev->current_lun, buf[0], dev->dbc); dev->last_command = buf[0]; - scsi_device_command_phase0(dev->current->tag, buf); + scsi_device_command_phase0(&scsi_devices[dev->current->tag], buf); dev->hba_private = (void *)dev->current; dev->waiting = 0; dev->buffer_pos = 0; - dev->temp_buf_len = sd->BufferLength; + dev->temp_buf_len = sd->buffer_length; - if (sd->BufferLength > 0) { - sd->CmdBuffer = (uint8_t *)malloc(sd->BufferLength); - dev->current->dma_len = sd->BufferLength; + if (sd->buffer_length > 0) { + sd->cmd_buffer = (uint8_t *)malloc(sd->buffer_length); + dev->current->dma_len = sd->buffer_length; } - if ((sd->Phase == SCSI_PHASE_DATA_IN) && (sd->BufferLength > 0)) { + if ((sd->phase == SCSI_PHASE_DATA_IN) && (sd->buffer_length > 0)) { ncr53c810_log("(ID=%02i LUN=%02i) SCSI Command 0x%02x: PHASE_DI\n", id, dev->current_lun, buf[0]); ncr53c810_set_phase(dev, PHASE_DI); - p = scsi_device_get_callback(dev->current->tag); + p = scsi_device_get_callback(&scsi_devices[dev->current->tag]); if (p <= 0LL) { - period = ((double) sd->BufferLength) * 0.1 * ((double) TIMER_USEC); /* Fast SCSI: 10000000 bytes per second */ + period = ((double) sd->buffer_length) * 0.1 * ((double) TIMER_USEC); /* Fast SCSI: 10000000 bytes per second */ dev->timer_period += (int64_t) period; } else dev->timer_period += p; return 1; - } else if ((sd->Phase == SCSI_PHASE_DATA_OUT) && (sd->BufferLength > 0)) { + } else if ((sd->phase == SCSI_PHASE_DATA_OUT) && (sd->buffer_length > 0)) { ncr53c810_log("(ID=%02i LUN=%02i) SCSI Command 0x%02x: PHASE_DO\n", id, buf[0]); ncr53c810_set_phase(dev, PHASE_DO); - p = scsi_device_get_callback(dev->current->tag); + p = scsi_device_get_callback(&scsi_devices[dev->current->tag]); if (p <= 0LL) { - period = ((double) sd->BufferLength) * 0.1 * ((double) TIMER_USEC); /* Fast SCSI: 10000000 bytes per second */ + period = ((double) sd->buffer_length) * 0.1 * ((double) TIMER_USEC); /* Fast SCSI: 10000000 bytes per second */ dev->timer_period += (int64_t) period; } else dev->timer_period += p; return 1; } else { - ncr53c810_command_complete(dev, sd->Status); + ncr53c810_command_complete(dev, sd->status); return 0; } } @@ -832,7 +832,7 @@ ncr53c810_do_msgout(ncr53c810_t *dev, uint8_t id) uint32_t current_tag; scsi_device_t *sd; - sd = &SCSIDevices[id]; + sd = &scsi_devices[id]; current_tag = id; @@ -884,9 +884,9 @@ ncr53c810_do_msgout(ncr53c810_t *dev, uint8_t id) case 0x0d: /* The ABORT TAG message clears the current I/O process only. */ ncr53c810_log("MSG: ABORT TAG tag=0x%x\n", current_tag); - if (sd->CmdBuffer) { - free(sd->CmdBuffer); - sd->CmdBuffer = NULL; + if (sd->cmd_buffer) { + free(sd->cmd_buffer); + sd->cmd_buffer = NULL; } ncr53c810_disconnect(dev); break; @@ -907,9 +907,9 @@ ncr53c810_do_msgout(ncr53c810_t *dev, uint8_t id) ncr53c810_log("MSG: BUS DEVICE RESET tag=0x%x\n", current_tag); /* clear the current I/O process */ - if (sd->CmdBuffer) { - free(sd->CmdBuffer); - sd->CmdBuffer = NULL; + if (sd->cmd_buffer) { + free(sd->cmd_buffer); + sd->cmd_buffer = NULL; } ncr53c810_disconnect(dev); break; @@ -1078,7 +1078,7 @@ again: } dev->sstat0 |= NCR_SSTAT0_WOA; dev->scntl1 &= ~NCR_SCNTL1_IARB; - if (!scsi_device_present(id)) { + if (!scsi_device_present(&scsi_devices[id])) { ncr53c810_bad_selection(dev, id); break; } diff --git a/src/scsi/scsi_x54x.c b/src/scsi/scsi_x54x.c index 6be8820b1..7ad642075 100644 --- a/src/scsi/scsi_x54x.c +++ b/src/scsi/scsi_x54x.c @@ -11,7 +11,7 @@ * series of SCSI Host Adapters made by Mylex. * These controllers were designed for various buses. * - * Version: @(#)scsi_x54x.c 1.0.22 2018/10/02 + * Version: @(#)scsi_x54x.c 1.0.23 2018/10/09 * * Authors: TheCollector1995, * Miran Grca, @@ -155,9 +155,8 @@ clear_irq(x54x_t *dev) static void target_check(uint8_t id) { - if (! scsi_device_valid(id)) { + if (! scsi_device_valid(&scsi_devices[id])) fatal("BIOS INT13 device on ID %02i has disappeared\n", id); - } } @@ -237,9 +236,10 @@ x54x_bios_command_08(uint8_t id, uint8_t *buffer) uint8_t rcbuf[8] = { 0,0,0,0,0,0,0,0 }; uint32_t len = 0; int i, ret, sc; + scsi_device_t *sd = &scsi_devices[id]; - ret = scsi_device_read_capacity(id, cdb, rcbuf, &len); - sc = completion_code(scsi_device_sense(id)); + ret = scsi_device_read_capacity(sd, cdb, rcbuf, &len); + sc = completion_code(scsi_device_sense(sd)); if (ret == 0) return(sc); memset(buffer, 0x00, 6); @@ -261,15 +261,16 @@ x54x_bios_command_15(uint8_t id, uint8_t *buffer) uint8_t rcbuf[8] = { 0,0,0,0,0,0,0,0 }; uint32_t len = 0; int i, ret, sc; + scsi_device_t *sd = &scsi_devices[id]; - ret = scsi_device_read_capacity(id, cdb, rcbuf, &len); - sc = completion_code(scsi_device_sense(id)); + ret = scsi_device_read_capacity(sd, cdb, rcbuf, &len); + sc = completion_code(scsi_device_sense(sd)); memset(buffer, 0x00, 6); for (i=0; i<4; i++) buffer[i] = (ret == 0) ? 0 : rcbuf[i]; - scsi_device_type_data(id, &(buffer[4]), &(buffer[5])); + scsi_device_type_data(sd, &(buffer[4]), &(buffer[5])); x54x_log("BIOS Command 0x15: %02X %02X %02X %02X %02X %02X\n", buffer[0], buffer[1], buffer[2], buffer[3], buffer[4], buffer[5]); @@ -308,15 +309,15 @@ x54x_bios_command(x54x_t *x54x, uint8_t max_id, BIOSCMD *cmd, int8_t islba) } /* Get pointer to selected device. */ - dev = &SCSIDevices[cmd->id]; - dev->BufferLength = 0; + dev = &scsi_devices[cmd->id]; + dev->buffer_length = 0; - if (! scsi_device_present(cmd->id)) { + if (! scsi_device_present(dev)) { x54x_log("BIOS Target ID %i has no device attached\n", cmd->id); return(0x80); } - if ((dev->LunType == SCSI_CDROM) && !x54x->cdrom_boot) { + if ((dev->type == SCSI_REMOVABLE_CDROM) && !x54x->cdrom_boot) { x54x_log("BIOS Target ID %i is CD-ROM on unsupported BIOS\n", cmd->id); return(0x80); } @@ -326,9 +327,9 @@ x54x_bios_command(x54x_t *x54x, uint8_t max_id, BIOSCMD *cmd, int8_t islba) x54x_log("BIOS Data Buffer write: length %d, pointer 0x%04X\n", sector_len, dma_address); - if (dev->CmdBuffer != NULL) { - free(dev->CmdBuffer); - dev->CmdBuffer = NULL; + if (dev->cmd_buffer != NULL) { + free(dev->cmd_buffer); + dev->cmd_buffer = NULL; } switch(cmd->command) { @@ -343,20 +344,20 @@ x54x_bios_command(x54x_t *x54x, uint8_t max_id, BIOSCMD *cmd, int8_t islba) * length for SCSI sense, and no command-specific * indication is given. */ - dev->BufferLength = 14; - dev->CmdBuffer = (uint8_t *)malloc(14); - memset(dev->CmdBuffer, 0x00, 14); + dev->buffer_length = 14; + dev->cmd_buffer = (uint8_t *)malloc(14); + memset(dev->cmd_buffer, 0x00, 14); if (sector_len > 0) { x54x_log("BIOS DMA: Reading 14 bytes at %08X\n", dma_address); DMAPageWrite(dma_address, - scsi_device_sense(cmd->id), 14); + scsi_device_sense(dev), 14); } - if (dev->CmdBuffer != NULL) { - free(dev->CmdBuffer); - dev->CmdBuffer = NULL; + if (dev->cmd_buffer != NULL) { + free(dev->cmd_buffer); + dev->cmd_buffer = NULL; } return(0); @@ -364,7 +365,7 @@ x54x_bios_command(x54x_t *x54x, uint8_t max_id, BIOSCMD *cmd, int8_t islba) case 0x02: /* Read Desired Sectors to Memory */ target_check(cmd->id); - dev->BufferLength = -1; + dev->buffer_length = -1; cdb[0] = GPCMD_READ_10; cdb[1] = (cmd->lun & 7) << 5; @@ -378,33 +379,33 @@ x54x_bios_command(x54x_t *x54x, uint8_t max_id, BIOSCMD *cmd, int8_t islba) x54x_log("BIOS CMD(READ, %08lx, %d)\n", lba, cmd->secount); #endif - scsi_device_command_phase0(cmd->id, cdb); + scsi_device_command_phase0(dev, cdb); - if (dev->Phase == SCSI_PHASE_STATUS) + if (dev->phase == SCSI_PHASE_STATUS) goto skip_read_phase1; - dev->CmdBuffer = (uint8_t *)malloc(dev->BufferLength); + dev->cmd_buffer = (uint8_t *)malloc(dev->buffer_length); - scsi_device_command_phase1(cmd->id); + scsi_device_command_phase1(dev); if (sector_len > 0) { x54x_log("BIOS DMA: Reading %i bytes at %08X\n", - dev->BufferLength, dma_address); + dev->buffer_length, dma_address); DMAPageWrite(dma_address, - dev->CmdBuffer, dev->BufferLength); + dev->cmd_buffer, dev->buffer_length); } skip_read_phase1: - if (dev->CmdBuffer != NULL) { - free(dev->CmdBuffer); - dev->CmdBuffer = NULL; + if (dev->cmd_buffer != NULL) { + free(dev->cmd_buffer); + dev->cmd_buffer = NULL; } - return(completion_code(scsi_device_sense(cmd->id))); + return(completion_code(scsi_device_sense(dev))); case 0x03: /* Write Desired Sectors from Memory */ target_check(cmd->id); - dev->BufferLength = -1; + dev->buffer_length = -1; cdb[0] = GPCMD_WRITE_10; cdb[1] = (cmd->lun & 7) << 5; @@ -418,29 +419,29 @@ skip_read_phase1: x54x_log("BIOS CMD(WRITE, %08lx, %d)\n", lba, cmd->secount); #endif - scsi_device_command_phase0(cmd->id, cdb); + scsi_device_command_phase0(dev, cdb); - if (dev->Phase == SCSI_PHASE_STATUS) + if (dev->phase == SCSI_PHASE_STATUS) goto skip_write_phase1; - dev->CmdBuffer = (uint8_t *)malloc(dev->BufferLength); + dev->cmd_buffer = (uint8_t *)malloc(dev->buffer_length); if (sector_len > 0) { x54x_log("BIOS DMA: Reading %i bytes at %08X\n", - dev->BufferLength, dma_address); + dev->buffer_length, dma_address); DMAPageRead(dma_address, - dev->CmdBuffer, dev->BufferLength); + dev->cmd_buffer, dev->buffer_length); } - scsi_device_command_phase1(cmd->id); + scsi_device_command_phase1(dev); skip_write_phase1: - if (dev->CmdBuffer != NULL) { - free(dev->CmdBuffer); - dev->CmdBuffer = NULL; + if (dev->cmd_buffer != NULL) { + free(dev->cmd_buffer); + dev->cmd_buffer = NULL; } - return(completion_code(scsi_device_sense(cmd->id))); + return(completion_code(scsi_device_sense(dev))); case 0x04: /* Verify Desired Sectors */ target_check(cmd->id); @@ -454,9 +455,9 @@ skip_write_phase1: cdb[7] = 0; cdb[8] = sector_len; - scsi_device_command_phase0(cmd->id, cdb); + scsi_device_command_phase0(dev, cdb); - return(completion_code(scsi_device_sense(cmd->id))); + return(completion_code(scsi_device_sense(dev))); case 0x05: /* Format Track, invalid since SCSI has no tracks */ //FIXME: add a longer delay here --FvK @@ -472,26 +473,26 @@ skip_write_phase1: cdb[0] = GPCMD_FORMAT_UNIT; cdb[1] = (cmd->lun & 7) << 5; - scsi_device_command_phase0(cmd->id, cdb); + scsi_device_command_phase0(dev, cdb); - return(completion_code(scsi_device_sense(cmd->id))); + return(completion_code(scsi_device_sense(dev))); case 0x08: /* Read Drive Parameters */ target_check(cmd->id); - dev->BufferLength = 6; - dev->CmdBuffer = (uint8_t *)malloc(dev->BufferLength); - memset(dev->CmdBuffer, 0x00, dev->BufferLength); + dev->buffer_length = 6; + dev->cmd_buffer = (uint8_t *)malloc(dev->buffer_length); + memset(dev->cmd_buffer, 0x00, dev->buffer_length); - ret = x54x_bios_command_08(cmd->id, dev->CmdBuffer); + ret = x54x_bios_command_08(cmd->id, dev->cmd_buffer); x54x_log("BIOS DMA: Reading 6 bytes at %08X\n", dma_address); DMAPageWrite(dma_address, - dev->CmdBuffer, 4 /* dev->BufferLength */); + dev->cmd_buffer, 4 /* dev->buffer_length */); - if (dev->CmdBuffer != NULL) { - free(dev->CmdBuffer); - dev->CmdBuffer = NULL; + if (dev->cmd_buffer != NULL) { + free(dev->cmd_buffer); + dev->cmd_buffer = NULL; } return(ret); @@ -510,9 +511,9 @@ skip_write_phase1: cdb[4] = (lba >> 8) & 0xff; cdb[5] = lba & 0xff; - scsi_device_command_phase0(cmd->id, cdb); + scsi_device_command_phase0(dev, cdb); - return((dev->Status == SCSI_STATUS_OK) ? 1 : 0); + return((dev->status == SCSI_STATUS_OK) ? 1 : 0); case 0x0d: /* Alternate Disk Reset, in practice it's a nop */ //FIXME: add a longer delay here --FvK @@ -524,9 +525,9 @@ skip_write_phase1: cdb[0] = GPCMD_TEST_UNIT_READY; cdb[1] = (cmd->lun & 7) << 5; - scsi_device_command_phase0(cmd->id, cdb); + scsi_device_command_phase0(dev, cdb); - return(completion_code(scsi_device_sense(cmd->id))); + return(completion_code(scsi_device_sense(dev))); case 0x11: /* Recalibrate */ target_check(cmd->id); @@ -534,9 +535,9 @@ skip_write_phase1: cdb[0] = GPCMD_REZERO_UNIT; cdb[1] = (cmd->lun & 7) << 5; - scsi_device_command_phase0(cmd->id, cdb); + scsi_device_command_phase0(dev, cdb); - return(completion_code(scsi_device_sense(cmd->id))); + return(completion_code(scsi_device_sense(dev))); case 0x14: /* Controller Diagnostic */ //FIXME: add a longer delay here --FvK @@ -545,19 +546,19 @@ skip_write_phase1: case 0x15: /* Read DASD Type */ target_check(cmd->id); - dev->BufferLength = 6; - dev->CmdBuffer = (uint8_t *)malloc(dev->BufferLength); - memset(dev->CmdBuffer, 0x00, dev->BufferLength); + dev->buffer_length = 6; + dev->cmd_buffer = (uint8_t *)malloc(dev->buffer_length); + memset(dev->cmd_buffer, 0x00, dev->buffer_length); - ret = x54x_bios_command_15(cmd->id, dev->CmdBuffer); + ret = x54x_bios_command_15(cmd->id, dev->cmd_buffer); x54x_log("BIOS DMA: Reading 6 bytes at %08X\n", dma_address); DMAPageWrite(dma_address, - dev->CmdBuffer, 4 /* dev->BufferLength */); + dev->cmd_buffer, 4 /* dev->buffer_length */); - if (dev->CmdBuffer != NULL) { - free(dev->CmdBuffer); - dev->CmdBuffer = NULL; + if (dev->cmd_buffer != NULL) { + free(dev->cmd_buffer); + dev->cmd_buffer = NULL; } return(ret); @@ -761,7 +762,7 @@ x54x_set_residue(Req_t *req, int32_t TransferLength) { uint32_t Residue = 0; addr24 Residue24; - int32_t BufLen = SCSIDevices[req->TargetID].BufferLength; + int32_t BufLen = scsi_devices[req->TargetID].buffer_length; if ((req->CmdBlock.common.Opcode == SCSI_INITIATOR_COMMAND_RES) || (req->CmdBlock.common.Opcode == SCATTER_GATHER_COMMAND_RES)) { @@ -792,7 +793,7 @@ x54x_buf_dma_transfer(Req_t *req, int Is24bit, int TransferLength, int dir) uint32_t DataPointer, DataLength; uint32_t SGEntryLength = (Is24bit ? sizeof(SGE) : sizeof(SGE32)); uint32_t Address, i; - int32_t BufLen = SCSIDevices[req->TargetID].BufferLength; + int32_t BufLen = scsi_devices[req->TargetID].buffer_length; uint8_t read_from_host = (dir && ((req->CmdBlock.common.ControlByte == CCB_DATA_XFER_OUT) || (req->CmdBlock.common.ControlByte == 0x00))); uint8_t write_to_host = (!dir && ((req->CmdBlock.common.ControlByte == CCB_DATA_XFER_IN) || (req->CmdBlock.common.ControlByte == 0x00))); int sg_pos = 0; @@ -824,11 +825,11 @@ x54x_buf_dma_transfer(Req_t *req, int Is24bit, int TransferLength, int dir) if (read_from_host && DataToTransfer) { x54x_log("Reading S/G segment %i: length %i, pointer %08X\n", i, DataToTransfer, Address); - DMAPageRead(Address, &(SCSIDevices[req->TargetID].CmdBuffer[sg_pos]), DataToTransfer); + DMAPageRead(Address, &(scsi_devices[req->TargetID].cmd_buffer[sg_pos]), DataToTransfer); } else if (write_to_host && DataToTransfer) { x54x_log("Writing S/G segment %i: length %i, pointer %08X\n", i, DataToTransfer, Address); - DMAPageWrite(Address, &(SCSIDevices[req->TargetID].CmdBuffer[sg_pos]), DataToTransfer); + DMAPageWrite(Address, &(scsi_devices[req->TargetID].cmd_buffer[sg_pos]), DataToTransfer); } else x54x_log("No action on S/G segment %i: length %i, pointer %08X\n", i, DataToTransfer, Address); @@ -848,9 +849,9 @@ x54x_buf_dma_transfer(Req_t *req, int Is24bit, int TransferLength, int dir) if ((DataLength > 0) && (BufLen > 0) && (req->CmdBlock.common.ControlByte < 0x03)) { if (read_from_host) - DMAPageRead(Address, SCSIDevices[req->TargetID].CmdBuffer, MIN(BufLen, (int) DataLength)); + DMAPageRead(Address, scsi_devices[req->TargetID].cmd_buffer, MIN(BufLen, (int) DataLength)); else if (write_to_host) - DMAPageWrite(Address, SCSIDevices[req->TargetID].CmdBuffer, MIN(BufLen, (int) DataLength)); + DMAPageWrite(Address, scsi_devices[req->TargetID].cmd_buffer, MIN(BufLen, (int) DataLength)); } } } @@ -860,23 +861,23 @@ x54x_buf_dma_transfer(Req_t *req, int Is24bit, int TransferLength, int dir) void x54x_buf_alloc(uint8_t id, int length) { - if (SCSIDevices[id].CmdBuffer != NULL) { - free(SCSIDevices[id].CmdBuffer); - SCSIDevices[id].CmdBuffer = NULL; + if (scsi_devices[id].cmd_buffer != NULL) { + free(scsi_devices[id].cmd_buffer); + scsi_devices[id].cmd_buffer = NULL; } x54x_log("Allocating data buffer (%i bytes)\n", length); - SCSIDevices[id].CmdBuffer = (uint8_t *) malloc(length); - memset(SCSIDevices[id].CmdBuffer, 0, length); + scsi_devices[id].cmd_buffer = (uint8_t *) malloc(length); + memset(scsi_devices[id].cmd_buffer, 0, length); } void x54x_buf_free(uint8_t id) { - if (SCSIDevices[id].CmdBuffer != NULL) { - free(SCSIDevices[id].CmdBuffer); - SCSIDevices[id].CmdBuffer = NULL; + if (scsi_devices[id].cmd_buffer != NULL) { + free(scsi_devices[id].cmd_buffer); + scsi_devices[id].cmd_buffer = NULL; } } @@ -920,7 +921,7 @@ SenseBufferFree(Req_t *req, int Copy) uint8_t temp_sense[256]; if (SenseLength && Copy) { - scsi_device_request_sense(req->TargetID, temp_sense, SenseLength); + scsi_device_request_sense(&scsi_devices[req->TargetID], temp_sense, SenseLength); /* * The sense address, in 32-bit mode, is located in the @@ -945,24 +946,22 @@ static void x54x_scsi_cmd(x54x_t *dev) { Req_t *req = &dev->Req; - uint8_t id, lun; + uint8_t id, lun, phase, bit24 = !!req->Is24bit; uint8_t temp_cdb[12]; - uint32_t i; - int target_cdb_len = 12; - int target_data_len; - uint8_t bit24 = !!req->Is24bit; + uint32_t i, SenseBufferAddress; + int target_data_len, target_cdb_len = 12; int32_t *BufLen; - uint8_t phase; - uint32_t SenseBufferAddress; int64_t p; + scsi_device_t *sd; id = req->TargetID; + sd = &scsi_devices[id]; lun = req->LUN; target_cdb_len = 12; target_data_len = x54x_get_length(req, bit24); - if (!scsi_device_valid(id)) + if (!scsi_device_valid(sd)) fatal("SCSI target on %02i has disappeared\n", id); x54x_log("target_data_len = %i\n", target_data_len); @@ -985,14 +984,14 @@ x54x_scsi_cmd(x54x_t *dev) dev->Residue = 0; - BufLen = scsi_device_get_buf_len(id); + BufLen = scsi_device_get_buf_len(sd); *BufLen = target_data_len; - x54x_log("Command buffer: %08X\n", SCSIDevices[id].CmdBuffer); + x54x_log("Command buffer: %08X\n", scsi_devices[id].cmd_buffer); - scsi_device_command_phase0(id, temp_cdb); + scsi_device_command_phase0(sd, temp_cdb); - phase = SCSIDevices[id].Phase; + phase = sd->phase; x54x_log("Control byte: %02X\n", (req->CmdBlock.common.ControlByte == 0x03)); @@ -1001,14 +1000,14 @@ x54x_scsi_cmd(x54x_t *dev) /* Request sense in non-data mode - sense goes to sense buffer. */ *BufLen = ConvertSenseLength(req->CmdBlock.common.RequestSenseLength); x54x_buf_alloc(id, *BufLen); - scsi_device_command_phase1(id); - if ((SCSIDevices[id].Status != SCSI_STATUS_OK) && (*BufLen > 0)) { + scsi_device_command_phase1(sd); + if ((sd->status != SCSI_STATUS_OK) && (*BufLen > 0)) { SenseBufferAddress = SenseBufferPointer(req); - DMAPageWrite(SenseBufferAddress, SCSIDevices[id].CmdBuffer, *BufLen); + DMAPageWrite(SenseBufferAddress, scsi_devices[id].cmd_buffer, *BufLen); x54x_add_to_period(*BufLen); } } else { - p = scsi_device_get_callback(id); + p = scsi_device_get_callback(sd); if (p <= 0LL) x54x_add_to_period(*BufLen); else @@ -1016,14 +1015,14 @@ x54x_scsi_cmd(x54x_t *dev) x54x_buf_alloc(id, MIN(target_data_len, *BufLen)); if (phase == SCSI_PHASE_DATA_OUT) x54x_buf_dma_transfer(req, bit24, target_data_len, 1); - scsi_device_command_phase1(id); + scsi_device_command_phase1(sd); if (phase == SCSI_PHASE_DATA_IN) x54x_buf_dma_transfer(req, bit24, target_data_len, 0); - SenseBufferFree(req, (SCSIDevices[id].Status != SCSI_STATUS_OK)); + SenseBufferFree(req, (sd->status != SCSI_STATUS_OK)); } } else - SenseBufferFree(req, (SCSIDevices[id].Status != SCSI_STATUS_OK)); + SenseBufferFree(req, (sd->status != SCSI_STATUS_OK)); x54x_set_residue(req, target_data_len); @@ -1031,15 +1030,15 @@ x54x_scsi_cmd(x54x_t *dev) x54x_log("Request complete\n"); - if (SCSIDevices[id].Status == SCSI_STATUS_OK) { + if (sd->status == SCSI_STATUS_OK) { x54x_mbi_setup(dev, req->CCBPointer, &req->CmdBlock, CCB_COMPLETE, SCSI_STATUS_OK, MBI_SUCCESS); - } else if (SCSIDevices[id].Status == SCSI_STATUS_CHECK_CONDITION) { + } else if (sd->status == SCSI_STATUS_CHECK_CONDITION) { x54x_mbi_setup(dev, req->CCBPointer, &req->CmdBlock, CCB_COMPLETE, SCSI_STATUS_CHECK_CONDITION, MBI_ERROR); } - x54x_log("SCSIDevices[%02i].Status = %02X\n", id, SCSIDevices[id].Status); + x54x_log("scsi_devices[%02i].Status = %02X\n", id, sd->status); } @@ -1058,6 +1057,7 @@ x54x_req_setup(x54x_t *dev, uint32_t CCBPointer, Mailbox32_t *Mailbox32) { Req_t *req = &dev->Req; uint8_t id, lun; + scsi_device_t *sd; /* Fetch data from the Command Control Block. */ DMAPageRead(CCBPointer, (uint8_t *)&req->CmdBlock, sizeof(CCB32)); @@ -1069,6 +1069,7 @@ x54x_req_setup(x54x_t *dev, uint32_t CCBPointer, Mailbox32_t *Mailbox32) req->LUN = dev->Mbx24bit ? req->CmdBlock.old.Lun : req->CmdBlock.new.Lun; id = req->TargetID; + sd = &scsi_devices[id]; lun = req->LUN; if ((id > dev->max_id) || (lun > 7)) { x54x_log("SCSI Target ID %i or LUN %i is not valid\n",id,lun); @@ -1081,10 +1082,10 @@ x54x_req_setup(x54x_t *dev, uint32_t CCBPointer, Mailbox32_t *Mailbox32) x54x_log("Scanning SCSI Target ID %i\n", id); - SCSIDevices[id].Status = SCSI_STATUS_OK; + sd->status = SCSI_STATUS_OK; /* If there is no device at ID:0, timeout the selection - the LUN is then checked later. */ - if (! scsi_device_present(id)) { + if (! scsi_device_present(sd)) { x54x_log("SCSI Target ID %i and LUN %i have no device attached\n",id,lun); x54x_mbi_setup(dev, CCBPointer, &req->CmdBlock, CCB_SELECTION_TIMEOUT, SCSI_STATUS_OK, MBI_ERROR); @@ -1106,7 +1107,7 @@ x54x_req_setup(x54x_t *dev, uint32_t CCBPointer, Mailbox32_t *Mailbox32) } if (req->CmdBlock.common.Opcode == 0x81) { x54x_log("Bus reset opcode\n"); - scsi_device_reset(id); + scsi_device_reset(sd); x54x_mbi_setup(dev, req->CCBPointer, &req->CmdBlock, CCB_COMPLETE, SCSI_STATUS_OK, MBI_SUCCESS); x54x_log("%s: Callback: Send incoming mailbox\n", dev->name); @@ -1443,7 +1444,7 @@ x54x_reset(x54x_t *dev) /* Reset all devices on controller reset. */ for (i = 0; i < 16; i++) - scsi_device_reset(i); + scsi_device_reset(&scsi_devices[i]); if (dev->ven_reset) dev->ven_reset(dev); @@ -1500,7 +1501,7 @@ x54x_out(uint16_t port, uint8_t val, void *priv) if (val & CTRL_SCRST) { /* Reset all devices on SCSI bus reset. */ for (i = 0; i < 16; i++) - scsi_device_reset(i); + scsi_device_reset(&scsi_devices[i]); } if (val & CTRL_IRST) { @@ -1677,7 +1678,7 @@ x54x_out(uint16_t port, uint8_t val, void *priv) if (i == host_id) continue; /* TODO: Query device for LUN's. */ - if (scsi_device_present(i)) + if (scsi_device_present(&scsi_devices[i])) dev->DataBuf[i] |= 1; } dev->DataReplyLeft = i; @@ -1685,9 +1686,9 @@ x54x_out(uint16_t port, uint8_t val, void *priv) case CMD_RETCONF: /* return Configuration */ if (dev->ven_get_dma) - dev->DataBuf[0] = (1<ven_get_dma(dev)); + dev->DataBuf[0] = (1 << dev->ven_get_dma(dev)); else - dev->DataBuf[0] = (1<DmaChannel); + dev->DataBuf[0] = (1 << dev->DmaChannel); if (dev->ven_get_irq) irq = dev->ven_get_irq(dev); diff --git a/src/sound/midi.c b/src/sound/midi.c index 197189de7..1f5f0ed47 100644 --- a/src/sound/midi.c +++ b/src/sound/midi.c @@ -8,7 +8,7 @@ * * MIDI device core module. * - * Version: @(#)midi.c 1.0.0 2018/09/06 + * Version: @(#)midi.c 1.0.1 2018/10/10 * * Authors: Sarah Walker, * Miran Grca, @@ -179,6 +179,11 @@ midi_init(midi_device_t* device) void midi_close(void) { + if (midi && midi->m_device) { + free(midi->m_device); + midi->m_device = NULL; + } + if (midi) { free(midi); midi = NULL; diff --git a/src/sound/midi_fluidsynth.c b/src/sound/midi_fluidsynth.c index 55a579faf..72c472584 100644 --- a/src/sound/midi_fluidsynth.c +++ b/src/sound/midi_fluidsynth.c @@ -61,7 +61,6 @@ static int (*f_fluid_synth_sysex)(void *synth, const char *data, int len, char static int (*f_fluid_synth_pitch_bend)(void *synth, int chan, int val); static int (*f_fluid_synth_program_change)(void *synth, int chan, int program); static int (*f_fluid_synth_sfload)(void *synth, const char *filename, int reset_presets); -static int (*f_fluid_synth_sfunload)(void *synth, unsigned int id, int reset_presets); static int (*f_fluid_synth_set_interp_method)(void *synth, int chan, int interp_method); static void (*f_fluid_synth_set_reverb)(void *synth, double roomsize, double damping, double width, double level); static void (*f_fluid_synth_set_reverb_on)(void *synth, int on); @@ -84,7 +83,6 @@ static dllimp_t fluidsynth_imports[] = { { "fluid_synth_pitch_bend", &f_fluid_synth_pitch_bend }, { "fluid_synth_program_change", &f_fluid_synth_program_change }, { "fluid_synth_sfload", &f_fluid_synth_sfload }, - { "fluid_synth_sfunload", &f_fluid_synth_sfunload }, { "fluid_synth_set_interp_method", &f_fluid_synth_set_interp_method }, { "fluid_synth_set_reverb", &f_fluid_synth_set_reverb }, { "fluid_synth_set_reverb_on", &f_fluid_synth_set_reverb_on }, @@ -104,13 +102,14 @@ typedef struct fluidsynth int samplerate; int sound_font; - thread_t* thread_h; - event_t* event; + thread_t *thread_h; + event_t *event, *start_event; int buf_size; float* buffer; int16_t* buffer_int16; int midi_pos; + int on; } fluidsynth_t; fluidsynth_t fsdev; @@ -136,9 +135,14 @@ static void fluidsynth_thread(void *param) fluidsynth_t* data = (fluidsynth_t*)param; int buf_pos = 0; int buf_size = data->buf_size / BUFFER_SEGMENTS; - while (1) + + thread_set_event(data->start_event); + + while (data->on) { thread_wait_event(data->event, -1); + thread_reset_event(data->event); + if (sound_is_float) { float *buf = (float*)((uint8_t*)data->buffer + buf_pos); @@ -237,6 +241,8 @@ void fluidsynth_sysex(uint8_t* data, unsigned int len) void* fluidsynth_init(const device_t *info) { fluidsynth_t* data = &fsdev; + midi_device_t* dev; + memset(data, 0, sizeof(fluidsynth_t)); /* Try loading the DLL. */ @@ -324,12 +330,10 @@ void* fluidsynth_init(const device_t *info) data->buffer = NULL; data->buffer_int16 = malloc(data->buf_size); } - data->event = thread_create_event(); - data->thread_h = thread_create(fluidsynth_thread, data); al_set_midi(data->samplerate, data->buf_size); - midi_device_t* dev = malloc(sizeof(midi_device_t)); + dev = malloc(sizeof(midi_device_t)); memset(dev, 0, sizeof(midi_device_t)); dev->play_msg = fluidsynth_msg; @@ -338,6 +342,16 @@ void* fluidsynth_init(const device_t *info) midi_init(dev); + data->on = 1; + + data->start_event = thread_create_event(); + + data->event = thread_create_event(); + data->thread_h = thread_create(fluidsynth_thread, data); + + thread_wait_event(data->start_event, -1); + thread_reset_event(data->start_event); + return dev; } @@ -347,10 +361,9 @@ void fluidsynth_close(void* p) fluidsynth_t* data = &fsdev; - if (data->sound_font != -1) { - f_fluid_synth_sfunload(data->synth, data->sound_font, 1); - data->sound_font = -1; - } + data->on = 0; + thread_set_event(data->event); + thread_wait(data->thread_h, -1); if (data->synth) { f_delete_fluid_synth(data->synth); @@ -362,8 +375,6 @@ void fluidsynth_close(void* p) data->settings = NULL; } - midi_close(); - if (data->buffer) { free(data->buffer); diff --git a/src/sound/midi_mt32.c b/src/sound/midi_mt32.c index 7903b2b05..c0b803119 100644 --- a/src/sound/midi_mt32.c +++ b/src/sound/midi_mt32.c @@ -83,6 +83,8 @@ int cm32l_available() static thread_t *thread_h = NULL; static event_t *event = NULL; +static event_t *start_event = NULL; +static int mt32_on = 0; #define RENDER_RATE 100 #define BUFFER_SEGMENTS 10 @@ -119,13 +121,19 @@ static void mt32_thread(void *param) { int buf_pos = 0; int bsize = buf_size / BUFFER_SEGMENTS; - while (1) + float *buf; + int16_t *buf16; + + thread_set_event(start_event); + + while (mt32_on) { thread_wait_event(event, -1); + thread_reset_event(event); if (sound_is_float) { - float *buf = (float *) ((uint8_t*)buffer + buf_pos); + buf = (float *) ((uint8_t*)buffer + buf_pos); memset(buf, 0, bsize); mt32_stream(buf, bsize / (2 * sizeof(float))); buf_pos += bsize; @@ -138,9 +146,9 @@ static void mt32_thread(void *param) } else { - int16_t *buf = (int16_t *) ((uint8_t*)buffer_int16 + buf_pos); - memset(buf, 0, bsize); - mt32_stream_int16(buf, bsize / (2 * sizeof(int16_t))); + buf16 = (int16_t *) ((uint8_t*)buffer_int16 + buf_pos); + memset(buf16, 0, bsize); + mt32_stream_int16(buf16, bsize / (2 * sizeof(int16_t))); buf_pos += bsize; if (buf_pos >= buf_size) { @@ -164,9 +172,12 @@ void mt32_sysex(uint8_t* data, unsigned int len) void* mt32emu_init(wchar_t *control_rom, wchar_t *pcm_rom) { + midi_device_t* dev; wchar_t s[512]; char fn[512]; + context = mt32emu_create_context(handler, NULL); + if (!rom_getfile(control_rom, s, 512)) return 0; wcstombs(fn, s, (wcslen(s) << 1) + 2); if (!mt32_check("mt32emu_add_rom_file", mt32emu_add_rom_file(context, fn), MT32EMU_RC_ADDED_CONTROL_ROM)) return 0; @@ -176,8 +187,6 @@ void* mt32emu_init(wchar_t *control_rom, wchar_t *pcm_rom) if (!mt32_check("mt32emu_open_synth", mt32emu_open_synth(context), MT32EMU_RC_OK)) return 0; - event = thread_create_event(); - thread_h = thread_create(mt32_thread, 0); samplerate = mt32emu_get_actual_stereo_output_samplerate(context); /* buf_size = samplerate/RENDER_RATE*2; */ if (sound_is_float) @@ -201,7 +210,7 @@ void* mt32emu_init(wchar_t *control_rom, wchar_t *pcm_rom) al_set_midi(samplerate, buf_size); - midi_device_t* dev = malloc(sizeof(midi_device_t)); + dev = malloc(sizeof(midi_device_t)); memset(dev, 0, sizeof(midi_device_t)); dev->play_msg = mt32_msg; @@ -210,6 +219,16 @@ void* mt32emu_init(wchar_t *control_rom, wchar_t *pcm_rom) midi_init(dev); + mt32_on = 1; + + start_event = thread_create_event(); + + event = thread_create_event(); + thread_h = thread_create(mt32_thread, 0); + + thread_wait_event(start_event, -1); + thread_reset_event(start_event); + return dev; } @@ -227,15 +246,15 @@ void mt32_close(void* p) { if (!p) return; - if (thread_h) - thread_kill(thread_h); - if (event) - thread_destroy_event(event); + mt32_on = 0; + thread_set_event(event); + thread_wait(thread_h, -1); + event = NULL; + start_event = NULL; thread_h = NULL; - if (context) - { + if (context) { mt32emu_close_synth(context); mt32emu_free_context(context); } @@ -248,10 +267,6 @@ void mt32_close(void* p) if (buffer_int16) free(buffer_int16); buffer_int16 = NULL; - - midi_close(); - - free((midi_device_t*)p); } static const device_config_t mt32_config[] = diff --git a/src/sound/sound.c b/src/sound/sound.c index ebae3610e..f797bda96 100644 --- a/src/sound/sound.c +++ b/src/sound/sound.c @@ -8,7 +8,7 @@ * * Sound emulation core. * - * Version: @(#)sound.c 1.0.20 2018/10/02 + * Version: @(#)sound.c 1.0.21 2018/10/09 * * Authors: Sarah Walker, * Miran Grca, @@ -26,7 +26,6 @@ #include "../86box.h" #include "../device.h" #include "../timer.h" -#include "../scsi/scsi_device.h" #include "../cdrom/cdrom.h" #include "../plat.h" #include "sound.h" @@ -188,68 +187,69 @@ void sound_set_cd_volume(unsigned int vol_l, unsigned int vol_r) static void sound_cd_thread(void *param) { - int i = 0; + int c, has_audio, d, r, i = 0; + int32_t audio_vol_l, audio_vol_r; + + int channel_select[2]; float cd_buffer_temp[2] = {0.0, 0.0}; float cd_buffer_temp2[2] = {0.0, 0.0}; int32_t cd_buffer_temp4[2] = {0, 0}; - int c, has_audio; - int d, r; - thread_set_event(sound_cd_start_event); - while (cdaudioon) - { + while (cdaudioon) { thread_wait_event(sound_cd_event, -1); thread_reset_event(sound_cd_event); + if (!soundon || !cdaudioon) return; - for (c = 0; c < CD_BUFLEN*2; c += 2) - { - if (sound_is_float) - { + + for (c = 0; c < CD_BUFLEN*2; c += 2) { + if (sound_is_float) { cd_out_buffer[c] = 0.0; cd_out_buffer[c+1] = 0.0; - } - else - { + } else { cd_out_buffer_int16[c] = 0; cd_out_buffer_int16[c+1] = 0; } } - for (i = 0; i < CDROM_NUM; i++) - { + + for (i = 0; i < CDROM_NUM; i++) { has_audio = 0; - if ((cdrom_drives[i].bus_type == CDROM_BUS_DISABLED) || !cdrom[i] || !cdrom[i]->handler) + if ((cdrom_drives[i].bus_type == CDROM_BUS_DISABLED) || !cdrom_drives[i].handler) continue; - if (cdrom[i]->handler->audio_callback) + if (cdrom_drives[i].handler->audio_callback) { - r = cdrom[i]->handler->audio_callback(i, cd_buffer[i], CD_BUFLEN*2); + r = cdrom_drives[i].handler->audio_callback(i, cd_buffer[i], CD_BUFLEN*2); has_audio = (cdrom_drives[i].bus_type && cdrom_drives[i].sound_on/* && r*/); } else continue; - if (soundon && has_audio) - { - int32_t audio_vol_l = cdrom_mode_sense_get_volume(cdrom[i], 0); - int32_t audio_vol_r = cdrom_mode_sense_get_volume(cdrom[i], 1); - int channel_select[2]; - channel_select[0] = cdrom_mode_sense_get_channel(cdrom[i], 0); - channel_select[1] = cdrom_mode_sense_get_channel(cdrom[i], 1); + if (soundon && has_audio) { + if (cdrom_drives[i].get_volume) { + audio_vol_l = cdrom_drives[i].get_volume(cdrom_drives[i].p, 0); + audio_vol_r = cdrom_drives[i].get_volume(cdrom_drives[i].p, 1); + } else { + audio_vol_l = 255; + audio_vol_r = 255; + } - if (!r) - { - for (c = 0; c < CD_BUFLEN*2; c += 2) - { - if (sound_is_float) - { + if (cdrom_drives[i].get_channel) { + channel_select[0] = cdrom_drives[i].get_channel(cdrom_drives[i].p, 0); + channel_select[1] = cdrom_drives[i].get_channel(cdrom_drives[i].p, 1); + } else { + channel_select[0] = 1; + channel_select[1] = 2; + } + + if (!r) { + for (c = 0; c < CD_BUFLEN*2; c += 2) { + if (sound_is_float) { cd_out_buffer[c] += 0.0; cd_out_buffer[c+1] += 0.0; - } - else - { + } else { cd_out_buffer_int16[c] += 0; cd_out_buffer_int16[c+1] += 0; } @@ -257,8 +257,7 @@ static void sound_cd_thread(void *param) continue; } - for (c = 0; c < CD_BUFLEN*2; c += 2) - { + for (c = 0; c < CD_BUFLEN*2; c += 2) { /* First, transfer the CD audio data to the temporary buffer. */ cd_buffer_temp[0] = (float) cd_buffer[i][c]; cd_buffer_temp[1] = (float) cd_buffer[i][c+1]; @@ -271,25 +270,17 @@ static void sound_cd_thread(void *param) /*Apply ATAPI channel select*/ cd_buffer_temp2[0] = cd_buffer_temp2[1] = 0.0; - if (channel_select[0] & 1) - { - cd_buffer_temp2[0] += cd_buffer_temp[0]; - } - if (channel_select[0] & 2) - { - cd_buffer_temp2[1] += cd_buffer_temp[0]; - } - if (channel_select[1] & 1) - { - cd_buffer_temp2[0] += cd_buffer_temp[1]; - } - if (channel_select[1] & 2) - { - cd_buffer_temp2[1] += cd_buffer_temp[1]; - } - if (sound_process_handlers_num) - { + if (channel_select[0] & 1) + cd_buffer_temp2[0] += cd_buffer_temp[0]; + if (channel_select[0] & 2) + cd_buffer_temp2[1] += cd_buffer_temp[0]; + if (channel_select[1] & 1) + cd_buffer_temp2[0] += cd_buffer_temp[1]; + if (channel_select[1] & 2) + cd_buffer_temp2[1] += cd_buffer_temp[1]; + + if (sound_process_handlers_num) { cd_buffer_temp4[0] = (int32_t) cd_buffer_temp2[0]; cd_buffer_temp4[1] = (int32_t) cd_buffer_temp2[1]; @@ -298,9 +289,7 @@ static void sound_cd_thread(void *param) cd_buffer_temp2[0] = (float) cd_buffer_temp4[0]; cd_buffer_temp2[1] = (float) cd_buffer_temp4[1]; - } - else - { + } else { /*Apply sound card CD volume*/ cd_buffer_temp2[0] *= (float) cd_vol_l; cd_buffer_temp2[0] /= 65535.0; @@ -309,13 +298,10 @@ static void sound_cd_thread(void *param) cd_buffer_temp2[1] /= 65535.0; } - if (sound_is_float) - { + if (sound_is_float) { cd_out_buffer[c] += (cd_buffer_temp2[0] / 32768.0); cd_out_buffer[c+1] += (cd_buffer_temp2[1] / 32768.0); - } - else - { + } else { if (cd_buffer_temp2[0] > 32767) cd_buffer_temp2[0] = 32767; if (cd_buffer_temp2[0] < -32768) @@ -331,6 +317,7 @@ static void sound_cd_thread(void *param) } } } + if (sound_is_float) givealbuffer_cd(cd_out_buffer); else @@ -540,21 +527,15 @@ void sound_cd_thread_reset(void) int i = 0; int available_cdrom_drives = 0; - for (i = 0; i < CDROM_NUM; i++) - { - if (cdrom[i] && cdrom[i]->handler && cdrom[i]->handler->audio_stop) - { - cdrom[i]->handler->audio_stop(i); - } + for (i = 0; i < CDROM_NUM; i++) { + if (cdrom_drives[i].handler && cdrom_drives[i].handler->audio_stop) + cdrom_drives[i].handler->audio_stop(i); - if ((cdrom_drives[i].bus_type != CDROM_BUS_DISABLED) && cdrom[i]) - { + if (cdrom_drives[i].bus_type != CDROM_BUS_DISABLED) available_cdrom_drives++; - } } - if (available_cdrom_drives && !cd_thread_enable) - { + if (available_cdrom_drives && !cd_thread_enable) { cdaudioon = 1; sound_cd_start_event = thread_create_event(); @@ -564,9 +545,7 @@ void sound_cd_thread_reset(void) thread_wait_event(sound_cd_start_event, -1); thread_reset_event(sound_cd_start_event); - } - else if (!available_cdrom_drives && cd_thread_enable) - { + } else if (!available_cdrom_drives && cd_thread_enable) { sound_cd_thread_end(); } diff --git a/src/win/Makefile.mingw b/src/win/Makefile.mingw index fc46ff2ed..374124e96 100644 --- a/src/win/Makefile.mingw +++ b/src/win/Makefile.mingw @@ -477,7 +477,7 @@ USBOBJ := usb.o endif SCSIOBJ := scsi.o scsi_device.o \ - scsi_disk.o \ + scsi_cdrom.o scsi_disk.o \ scsi_x54x.o \ scsi_aha154x.o scsi_buslogic.o \ scsi_ncr5380.o scsi_ncr53c810.o diff --git a/src/win/win.h b/src/win/win.h index 098cda60a..d252f429b 100644 --- a/src/win/win.h +++ b/src/win/win.h @@ -8,7 +8,7 @@ * * Platform support defintions for Win32. * - * Version: @(#)win.h 1.0.19 2018/07/19 + * Version: @(#)win.h 1.0.20 2018/10/10 * * Authors: Sarah Walker, * Miran Grca, @@ -50,6 +50,8 @@ #define WM_SHOWSETTINGS 0x8889 #define WM_PAUSE 0x8890 #define WM_SENDHWND 0x8891 +#define WM_HARDRESET 0x8892 +#define WM_SHUTDOWN 0x8893 #ifdef USE_VNC #define RENDERERS_NUM 5 diff --git a/src/win/win_cdrom.c b/src/win/win_cdrom.c index bf577aa86..cf54de328 100644 --- a/src/win/win_cdrom.c +++ b/src/win/win_cdrom.c @@ -8,7 +8,7 @@ * * Handle the platform-side of CDROM drives. * - * Version: @(#)win_cdrom.c 1.0.9 2018/10/02 + * Version: @(#)win_cdrom.c 1.0.10 2018/10/09 * * Authors: Sarah Walker, * Miran Grca, @@ -43,32 +43,35 @@ void cdrom_eject(uint8_t id) { - if (cdrom_drives[id].host_drive == 0) { + cdrom_drive_t *drv = &cdrom_drives[id]; + cdrom_image_t *img = &cdrom_image[id]; + + if (drv->host_drive == 0) { /* Switch from empty to empty. Do nothing. */ return; } - if (cdrom_image[id].prev_image_path) { - free(cdrom_image[id].prev_image_path); - cdrom_image[id].prev_image_path = NULL; + if (img->prev_image_path) { + free(img->prev_image_path); + img->prev_image_path = NULL; } - if (cdrom_drives[id].host_drive == 200) { - cdrom_image[id].prev_image_path = (wchar_t *) malloc(1024); - wcscpy(cdrom_image[id].prev_image_path, cdrom_image[id].image_path); + if (drv->host_drive == 200) { + img->prev_image_path = (wchar_t *) malloc(1024); + wcscpy(img->prev_image_path, img->image_path); } - cdrom_drives[id].prev_host_drive = cdrom_drives[id].host_drive; - cdrom[id]->handler->exit(id); + drv->prev_host_drive = drv->host_drive; + drv->handler->exit(id); cdrom_close_handler(id); - memset(cdrom_image[id].image_path, 0, 2048); + memset(img->image_path, 0, 2048); cdrom_null_open(id); - if (cdrom_drives[id].bus_type) { + if (drv->insert) { /* Signal disc change to the emulated machine. */ - cdrom_insert(cdrom[id]); + drv->insert(drv->p); } ui_sb_check_menu_item(SB_CDROM|id, IDM_CDROM_IMAGE | id, MF_UNCHECKED); - cdrom_drives[id].host_drive=0; + drv->host_drive=0; ui_sb_check_menu_item(SB_CDROM|id, IDM_CDROM_EMPTY | id, MF_CHECKED); ui_sb_update_icon_state(SB_CDROM|id, 1); ui_sb_enable_menu_item(SB_CDROM|id, IDM_CDROM_RELOAD | id, MF_BYCOMMAND | MF_ENABLED); @@ -81,31 +84,34 @@ cdrom_eject(uint8_t id) void cdrom_reload(uint8_t id) { - if ((cdrom_drives[id].host_drive == cdrom_drives[id].prev_host_drive) || (cdrom_drives[id].prev_host_drive == 0) || (cdrom_drives[id].host_drive != 0)) { + cdrom_drive_t *drv = &cdrom_drives[id]; + cdrom_image_t *img = &cdrom_image[id]; + + if ((drv->host_drive == drv->prev_host_drive) || !drv->prev_host_drive || drv->host_drive) { /* Switch from empty to empty. Do nothing. */ return; } cdrom_close_handler(id); - memset(cdrom_image[id].image_path, 0, 2048); + memset(img->image_path, 0, 2048); - if (cdrom_drives[id].prev_host_drive == 200) { - wcscpy(cdrom_image[id].image_path, cdrom_image[id].prev_image_path); - free(cdrom_image[id].prev_image_path); - cdrom_image[id].prev_image_path = NULL; - image_open(id, cdrom_image[id].image_path); - if (cdrom_drives[id].bus_type) { + if (drv->prev_host_drive == 200) { + wcscpy(img->image_path, img->prev_image_path); + free(img->prev_image_path); + img->prev_image_path = NULL; + image_open(id, img->image_path); + if (drv->insert) { /* Signal disc change to the emulated machine. */ - cdrom_insert(cdrom[id]); + drv->insert(drv->p); } - if (wcslen(cdrom_image[id].image_path) == 0) { + if (wcslen(img->image_path) == 0) { ui_sb_check_menu_item(SB_CDROM|id, IDM_CDROM_EMPTY | id, MF_CHECKED); - cdrom_drives[id].host_drive = 0; + drv->host_drive = 0; ui_sb_check_menu_item(SB_CDROM|id, IDM_CDROM_IMAGE | id, MF_UNCHECKED); ui_sb_update_icon_state(SB_CDROM|id, 1); } else { ui_sb_check_menu_item(SB_CDROM|id, IDM_CDROM_EMPTY | id, MF_UNCHECKED); - cdrom_drives[id].host_drive = 200; + drv->host_drive = 200; ui_sb_check_menu_item(SB_CDROM|id, IDM_CDROM_IMAGE | id, MF_CHECKED); ui_sb_update_icon_state(SB_CDROM|id, 0); } diff --git a/src/win/win_d3d.cpp b/src/win/win_d3d.cpp index fe18d587c..4f8a6fd4f 100644 --- a/src/win/win_d3d.cpp +++ b/src/win/win_d3d.cpp @@ -20,6 +20,7 @@ */ #include #include +#include #include "../86box.h" #include "../device.h" #include "../video/video.h" diff --git a/src/win/win_ddraw.cpp b/src/win/win_ddraw.cpp index 5168be9e2..f4e5fda00 100644 --- a/src/win/win_ddraw.cpp +++ b/src/win/win_ddraw.cpp @@ -11,7 +11,7 @@ * NOTES: This code should be re-merged into a single init() with a * 'fullscreen' argument, indicating FS mode is requested. * - * Version: @(#)win_ddraw.cpp 1.0.10 2018/07/17 + * Version: @(#)win_ddraw.cpp 1.0.11 2018/10/10 * * Authors: Sarah Walker, * Miran Grca, @@ -178,7 +178,8 @@ SavePNG(wchar_t *szFilename, HBITMAP hBitmap) bmpInfo.bmiHeader.biSizeImage = bmpInfo.bmiHeader.biWidth*abs(bmpInfo.bmiHeader.biHeight)*(bmpInfo.bmiHeader.biBitCount+7)/8; - if ((pBuf = malloc(bmpInfo.bmiHeader.biSizeImage)) == NULL) { + pBuf = malloc(bmpInfo.bmiHeader.biSizeImage); + if (pBuf == NULL) { ddraw_log("[SavePNG] Unable to Allocate Bitmap Memory"); fclose(fp); return; @@ -187,7 +188,8 @@ SavePNG(wchar_t *szFilename, HBITMAP hBitmap) if (ys2 <= 250) { bmpInfo.bmiHeader.biSizeImage <<= 1; - if ((pBuf2 = malloc(bmpInfo.bmiHeader.biSizeImage)) == NULL) { + pBuf2 = malloc(bmpInfo.bmiHeader.biSizeImage); + if (pBuf2 == NULL) { ddraw_log("[SavePNG] Unable to Allocate Secondary Bitmap Memory"); free(pBuf); fclose(fp); @@ -207,7 +209,8 @@ SavePNG(wchar_t *szFilename, HBITMAP hBitmap) 8, PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE); - if ((b_rgb = (png_bytep *) malloc(sizeof(png_bytep) * bmpInfo.bmiHeader.biHeight)) == NULL) { + b_rgb = (png_bytep *) malloc(sizeof(png_bytep) * bmpInfo.bmiHeader.biHeight); + if (b_rgb == NULL) { ddraw_log("[SavePNG] Unable to Allocate RGB Bitmap Memory"); free(pBuf2); free(pBuf); @@ -215,8 +218,9 @@ SavePNG(wchar_t *szFilename, HBITMAP hBitmap) return; } - for (i = 0; i < bmpInfo.bmiHeader.biHeight; i++) + for (i = 0; i < bmpInfo.bmiHeader.biHeight; i++) { b_rgb[i] = (png_byte *) malloc(png_get_rowbytes(png_ptr, info_ptr)); + } if (pBuf2) { DoubleLines((uint8_t *) pBuf2, (uint8_t *) pBuf); diff --git a/src/win/win_devconf.c b/src/win/win_devconf.c index 203fd2f32..ec6c71fe2 100644 --- a/src/win/win_devconf.c +++ b/src/win/win_devconf.c @@ -8,7 +8,7 @@ * * Windows device configuration dialog implementation. * - * Version: @(#)win_devconf.c 1.0.18 2018/04/01 + * Version: @(#)win_devconf.c 1.0.19 2018/10/10 * * Authors: Sarah Walker, * Miran Grca, @@ -18,6 +18,7 @@ */ #include #include +#include #include #include #include "../86box.h" @@ -459,10 +460,13 @@ deviceconfig_dlgproc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) uint8_t deviceconfig_open(HWND hwnd, const device_t *device) { const device_config_t *config = device->config; - uint16_t *data_block = malloc(16384); + uint16_t *data_block; uint16_t *data; - DLGTEMPLATE *dlg = (DLGTEMPLATE *)data_block; + DLGTEMPLATE *dlg; DLGITEMTEMPLATE *item; + + data_block = malloc(16384); + dlg = (DLGTEMPLATE *)data_block; int y = 10; int id = IDC_CONFIG_BASE; diff --git a/src/win/win_sdl.c b/src/win/win_sdl.c index 8fafd7e54..81a5a4434 100644 --- a/src/win/win_sdl.c +++ b/src/win/win_sdl.c @@ -12,7 +12,7 @@ * we will not use that, but, instead, use a new window which * coverrs the entire desktop. * - * Version: @(#)win_sdl.c 1.0.0 2018/05/26 + * Version: @(#)win_sdl.c 1.0.1 2018/10/10 * * Authors: Fred N. van Kempen, * Michael Drüing, @@ -551,7 +551,8 @@ sdl_take_screenshot(const wchar_t *fn) 8, PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE); - if ((rgba = (unsigned char *)malloc(width * height * 4)) == NULL) { + rgba = (unsigned char *) malloc(width * height * 4); + if (rgba == NULL) { sdl_log("[sdl_take_screenshot] Unable to Allocate RGBA Bitmap Memory"); fclose(fp); return; @@ -564,7 +565,8 @@ sdl_take_screenshot(const wchar_t *fn) return; } - if ((b_rgb = (png_bytep *) malloc(sizeof(png_bytep) * height)) == NULL) { + b_rgb = (png_bytep *) malloc(sizeof(png_bytep) * height); + if (b_rgb == NULL) { sdl_log("[sdl_take_screenshot] Unable to Allocate RGB Bitmap Memory"); free(rgba); fclose(fp); diff --git a/src/win/win_stbar.c b/src/win/win_stbar.c index 58bbadcb3..ca01be9e7 100644 --- a/src/win/win_stbar.c +++ b/src/win/win_stbar.c @@ -8,7 +8,7 @@ * * Implement the application's Status Bar. * - * Version: @(#)win_stbar.c 1.0.19 2018/10/02 + * Version: @(#)win_stbar.c 1.0.20 2018/10/09 * * Authors: Miran Grca, * Fred N. van Kempen, @@ -286,7 +286,7 @@ StatusBarCreateCdromTip(int part) free(sbTips[part]); sbTips[part] = NULL; } - sbTips[part] = (WCHAR *)malloc((wcslen(tempTip) << 1) + 2); + sbTips[part] = (WCHAR *)malloc((wcslen(tempTip) << 1) + 4); wcscpy(sbTips[part], tempTip); } @@ -882,12 +882,13 @@ StatusBarProcedure(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) if (!cdrom_image[id].prev_image_path) cdrom_image[id].prev_image_path = (wchar_t *) malloc(1024); wcscpy(cdrom_image[id].prev_image_path, cdrom_image[id].image_path); - cdrom[id]->handler->exit(id); + cdrom_drives[id].handler->exit(id); cdrom_close_handler(id); memset(cdrom_image[id].image_path, 0, 2048); image_open(id, temp_path); /* Signal media change to the emulated machine. */ - cdrom_insert(cdrom[id]); + if (cdrom_drives[id].insert) + cdrom_drives[id].insert(cdrom_drives[id].p); CheckMenuItem(sb_menu_handles[part], IDM_CDROM_EMPTY | id, MF_UNCHECKED); cdrom_drives[id].host_drive = (wcslen(cdrom_image[id].image_path) == 0) ? 0 : 200; if (cdrom_drives[id].host_drive == 200) { diff --git a/src/win/win_ui.c b/src/win/win_ui.c index 1b2991bb2..ca1e885bc 100644 --- a/src/win/win_ui.c +++ b/src/win/win_ui.c @@ -8,7 +8,7 @@ * * user Interface module for WinAPI on Windows. * - * Version: @(#)win_ui.c 1.0.31 2018/10/07 + * Version: @(#)win_ui.c 1.0.32 2018/10/10 * * Authors: Sarah Walker, * Miran Grca, @@ -644,6 +644,14 @@ MainWindowProcedure(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) CheckMenuItem(menuMain, IDM_ACTION_PAUSE, dopause ? MF_CHECKED : MF_UNCHECKED); break; + case WM_HARDRESET: + pc_reset(1); + break; + + case WM_SHUTDOWN: + PostQuitMessage(0); + break; + case WM_SYSCOMMAND: /* * Disable ALT key *ALWAYS*,