diff --git a/cmake/SourceFiles.cmake b/cmake/SourceFiles.cmake index 47220c1e1..511a45793 100644 --- a/cmake/SourceFiles.cmake +++ b/cmake/SourceFiles.cmake @@ -229,6 +229,7 @@ set(SOURCE_FILES src/osdep/amiberry_serial.cpp src/osdep/amiberry_uaenet.cpp src/osdep/amiberry_whdbooter.cpp + src/osdep/blkdev_ioctl.cpp src/osdep/ioport.cpp src/osdep/sigsegv_handler.cpp src/osdep/socket.cpp @@ -331,6 +332,7 @@ set(SOURCE_FILES src/osdep/gui/SelectFolder.cpp src/osdep/gui/SelectFile.cpp src/osdep/gui/CreateFilesysHardfile.cpp + src/osdep/gui/EditCDDrive.cpp src/osdep/gui/EditFilesysVirtual.cpp src/osdep/gui/EditFilesysHardfile.cpp src/osdep/gui/EditFilesysHardDrive.cpp diff --git a/src/blkdev.cpp b/src/blkdev.cpp index a054e4dac..e98284118 100644 --- a/src/blkdev.cpp +++ b/src/blkdev.cpp @@ -247,7 +247,11 @@ void blkdev_fix_prefs (struct uae_prefs *p) continue; if (p->cdslots[i].inuse || p->cdslots[i].name[0]) { TCHAR *name = p->cdslots[i].name; +#ifdef _WIN32 if (_tcslen (name) == 3 && name[1] == ':' && name[2] == '\\') { +#else + if (name[0] == '/' && name[1] == 'd' && name[2] == 'e' && name[3] == 'v' && name[4] == '/') { +#endif if (currprefs.scsi && (currprefs.uaescsimode == UAESCSI_SPTI || currprefs.uaescsimode == UAESCSI_SPTISCAN)) cdscsidevicetype[i] = SCSI_UNIT_SPTI; else diff --git a/src/expansion.cpp b/src/expansion.cpp index 22fc8096b..e67feffff 100644 --- a/src/expansion.cpp +++ b/src/expansion.cpp @@ -2429,6 +2429,10 @@ static uaecptr check_boot_rom (struct uae_prefs *p, int *boot_rom_type) #ifdef WIN32 if (p->win32_automount_drives || p->win32_automount_cddrives || p->win32_automount_netdrives || p->win32_automount_removable) return b; +#endif +#ifdef AMIBERRY + if (p->automount_cddrives || p->automount_removable) + return b; #endif if (p->socket_emu) return b; diff --git a/src/filesys.cpp b/src/filesys.cpp index 4dd1a706f..83a7cad63 100644 --- a/src/filesys.cpp +++ b/src/filesys.cpp @@ -1158,7 +1158,11 @@ static int set_filesys_unit (int nr, struct uaedev_config_info *ci, bool custom) return ret; } -static int add_filesys_unit (struct uaedev_config_info *ci, bool custom) +// we want to reference this from amiberry_filesys.cpp also +#ifndef AMIBERRY +static +#endif +int add_filesys_unit (struct uaedev_config_info *ci, bool custom) { int nr; diff --git a/src/include/uae.h b/src/include/uae.h index 9ba6c775b..9630bb3f4 100644 --- a/src/include/uae.h +++ b/src/include/uae.h @@ -107,5 +107,9 @@ extern void uaerandomizeseed(void); int get_guid_target (uae_u8 *out); void filesys_addexternals (void); +#ifdef AMIBERRY +extern std::vector get_cd_drives(); +extern int add_filesys_unit(struct uaedev_config_info* ci, bool custom); +#endif #endif /* UAE_UAE_H */ diff --git a/src/osdep/amiberry.cpp b/src/osdep/amiberry.cpp index 7494f0ebf..8005a8043 100644 --- a/src/osdep/amiberry.cpp +++ b/src/osdep/amiberry.cpp @@ -4902,6 +4902,25 @@ void read_controller_mapping_from_file(controller_mapping& input, const std::str in_file.close(); } +std::vector get_cd_drives() +{ + char path[MAX_DPATH]; + std::vector results{}; + + FILE* fp = popen("lsblk -o NAME,TYPE | grep 'rom' | awk '{print \"/dev/\" $1}'", "r"); + if (fp == nullptr) { + write_log("Failed to run 'lsblk' command, cannot auto-detect CD drives in system\n"); + return results; + } + + while (fgets(path, sizeof(path), fp) != nullptr) { + path[strcspn(path, "\n")] = 0; + results.emplace_back(path); + } + pclose(fp); + return results; +} + void target_setdefaultstatefilename(const TCHAR* name) { TCHAR path[MAX_DPATH]; @@ -4932,4 +4951,4 @@ void target_setdefaultstatefilename(const TCHAR* name) } } _tcscpy(savestate_fname, path); -} \ No newline at end of file +} diff --git a/src/osdep/amiberry_filesys.cpp b/src/osdep/amiberry_filesys.cpp index 1502462aa..94fea6521 100644 --- a/src/osdep/amiberry_filesys.cpp +++ b/src/osdep/amiberry_filesys.cpp @@ -7,6 +7,7 @@ #include "filesys.h" #include "zfile.h" #include +#include #include #include #include @@ -49,7 +50,7 @@ void utf8_to_latin1_string(std::string& input, std::string& output) std::string dst; auto* iconv_ = iconv_open("ISO-8859-1//TRANSLIT", "UTF-8"); - if (iconv_ == (iconv_t)-1) { + if (iconv_ == iconv_t(-1)) { if (!has_logged_iconv_fail) { write_log("iconv_open failed: will be copying directory entries verbatim\n"); has_logged_iconv_fail = true; @@ -61,7 +62,7 @@ void utf8_to_latin1_string(std::string& input, std::string& output) char* dst_ptr = buf.data(); size_t dst_size = buf.size(); size_t res = ::iconv(iconv_, &src_ptr, &src_size, &dst_ptr, &dst_size); - if (res == (size_t)-1) { + if (res == size_t(-1)) { if (errno != E2BIG) { // skip character ++src_ptr; @@ -142,7 +143,7 @@ std::string prefix_with_application_directory_path(std::string currentpath) } -std::string prefix_with_data_path(std::string filename) +std::string prefix_with_data_path(const std::string& filename) { #ifdef __MACH__ CFBundleRef mainBundle = CFBundleGetMainBundle(); @@ -172,7 +173,7 @@ std::string prefix_with_data_path(std::string filename) #endif } -std::string prefix_with_whdboot_path(std::string filename) +std::string prefix_with_whdboot_path(const std::string& filename) { #ifdef __MACH__ CFBundleRef mainBundle = CFBundleGetMainBundle(); @@ -828,8 +829,7 @@ int my_issamevolume(const TCHAR* path1, const TCHAR* path2, TCHAR* path) my_canonicalize_path(path2, p2, sizeof p2 / sizeof(TCHAR)); unsigned int len = _tcslen(p1); - if (len > _tcslen(p2)) - len = _tcslen(p2); + len = std::min(len, _tcslen(p2)); if (_tcsnicmp(p1, p2, len)) return 0; @@ -895,18 +895,36 @@ int target_get_volume_name(struct uaedev_mount_info* mtinf, struct uaedev_config bool copyfile(const char* target, const char* source, const bool replace) { #ifdef USE_OLDGCC - std::experimental::filesystem::copy_options options = {}; - options = replace ? experimental::filesystem::copy_options::overwrite_existing : experimental::filesystem::copy_options::none; + std::experimental::filesystem::copy_options options = replace + ? experimental::filesystem::copy_options::overwrite_existing + : experimental::filesystem::copy_options::none; #else - std::filesystem::copy_options options = {}; - options = replace ? filesystem::copy_options::overwrite_existing : filesystem::copy_options::none; + std::filesystem::copy_options options = replace + ? filesystem::copy_options::overwrite_existing + : filesystem::copy_options::none; #endif return copy_file(source, target, options); } void filesys_addexternals(void) { - // this would mount system drives on Windows + if (!currprefs.automount_cddrives) + return; + + const auto cd_drives = get_cd_drives(); + if (!cd_drives.empty()) + { + int drvnum = 0; + for (auto& drive : cd_drives) + { + struct uaedev_config_info ci = { 0 }; + _tcscpy(ci.rootdir, drive.c_str()); + ci.readonly = true; + ci.bootpri = -20 - drvnum; + add_filesys_unit(&ci, true); + drvnum++; + } + } } std::string my_get_sha1_of_file(const char* filepath) @@ -916,7 +934,7 @@ std::string my_get_sha1_of_file(const char* filepath) return ""; } - int fd = open(filepath, O_RDONLY); + const int fd = open(filepath, O_RDONLY); if (fd < 0) { write_log("my_get_sha1_of_file: open on file %s failed\n", filepath); return ""; diff --git a/src/osdep/amiberry_gui.cpp b/src/osdep/amiberry_gui.cpp index 80cd81566..d3ab87f66 100644 --- a/src/osdep/amiberry_gui.cpp +++ b/src/osdep/amiberry_gui.cpp @@ -1378,7 +1378,6 @@ void CreateDefaultDevicename(char* name) } } - int tweakbootpri(int bp, int ab, int dnm) { if (dnm) @@ -1601,6 +1600,9 @@ void new_cddrive(int entry) ci.device_emu_unit = 0; ci.controller_type = current_cddlg.ci.controller_type; ci.controller_unit = current_cddlg.ci.controller_unit; +#ifdef AMIBERRY + _tcscpy(ci.rootdir, current_cddlg.ci.rootdir); +#endif ci.type = UAEDEV_CD; ci.readonly = true; ci.blocksize = 2048; diff --git a/src/osdep/blkdev_ioctl.cpp b/src/osdep/blkdev_ioctl.cpp new file mode 100644 index 000000000..51a658ab0 --- /dev/null +++ b/src/osdep/blkdev_ioctl.cpp @@ -0,0 +1,1107 @@ +/* +* UAE - The Un*x Amiga Emulator +* +* CDROM/HD low level access code (IOCTL) +* +* Copyright 2024 Dimitris Panokostas +* Copyright 2002-2010 Toni Wilen +* +*/ + +#include "sysconfig.h" +#include "sysdeps.h" + +#include "options.h" +#include "traps.h" +#include "uae.h" +#include "threaddep/thread.h" +#include "blkdev.h" +#include "scsidev.h" +#include "gui.h" +#include "audio.h" + +#include +#include +#include +#include + +#ifdef __MACH__ +#include +#include +#include +#include +#include +#include +#include +#else +#include +#include +#include +#include +#endif + +#include +#include +#include + +#include "cda_play.h" +#ifdef RETROPLATFORM +#include "rp.h" +#endif + +#define IOCTL_DATA_BUFFER 8192 + +#ifdef WITH_SCSI_IOCTL + +struct dev_info_ioctl { + int fd; + uae_u8* tempbuffer; + TCHAR drvletter[30]; + TCHAR drvlettername[30]; + TCHAR devname[30]; + int type; + struct cdrom_tocentry cdromtoc; + uae_u8 trackmode[100]; + UINT errormode; + int fullaccess; + struct device_info di; + bool open; + bool usesptiread; + bool changed; + struct cda_play cda; +}; + +static struct dev_info_ioctl ciw32[MAX_TOTAL_SCSI_DEVICES]; +static int unittable[MAX_TOTAL_SCSI_DEVICES]; +static int bus_open; +static uae_sem_t play_sem; + +static int sys_cddev_open(struct dev_info_ioctl* ciw, int unitnum); +static void sys_cddev_close(struct dev_info_ioctl* ciw, int unitnum); + +static int getunitnum(struct dev_info_ioctl* ciw) +{ + if (!ciw) + return -1; + int idx = (int)(ciw - &ciw32[0]); + for (int i = 0; i < MAX_TOTAL_SCSI_DEVICES; i++) { + if (unittable[i] - 1 == idx) + return i; + } + return -1; +} + +static struct dev_info_ioctl* unitcheck(int unitnum) +{ + if (unitnum < 0 || unitnum >= MAX_TOTAL_SCSI_DEVICES) + return NULL; + if (unittable[unitnum] <= 0) + return NULL; + unitnum = unittable[unitnum] - 1; + if (ciw32[unitnum].drvletter == 0) + return NULL; + return &ciw32[unitnum]; +} + +static struct dev_info_ioctl* unitisopen(int unitnum) +{ + struct dev_info_ioctl* di = unitcheck(unitnum); + if (!di) + return NULL; + if (di->open == false) + return NULL; + return di; +} + +static int win32_error(struct dev_info_ioctl* ciw, int unitnum, const TCHAR* format, ...) +{ + va_list arglist; + TCHAR buf[1000]; + int err = errno; + + if (err == ENOMEDIUM) { + write_log(_T("IOCTL: media change, re-opening device\n")); + sys_cddev_close(ciw, unitnum); + if (sys_cddev_open(ciw, unitnum)) + write_log(_T("IOCTL: re-opening failed!\n")); + return -1; + } + va_start(arglist, format); + _vsntprintf(buf, sizeof buf / sizeof(TCHAR), format, arglist); + write_log(_T("IOCTL ERR: unit=%d,%s,%d: %s\n"), unitnum, buf, err, strerror(err)); + va_end(arglist); + return err; +} + +static int close_createfile(struct dev_info_ioctl* ciw) +{ + ciw->fullaccess = 0; + if (ciw->fd != -1) { + if (log_scsi) + write_log(_T("IOCTL: IOCTL close\n")); + close(ciw->fd); + if (log_scsi) + write_log(_T("IOCTL: IOCTL close completed\n")); + ciw->fd = -1; + return 1; + } + return 0; +} + +static int open_createfile(struct dev_info_ioctl* ciw, int fullaccess) +{ + if (ciw->fd != -1) { + //if (fullaccess && ciw->fullaccess == 0) { + close_createfile(ciw); + //} + // else { + // return 1; + // } + } + if (log_scsi) + write_log(_T("IOCTL: opening IOCTL %s\n"), ciw->devname); + ciw->fd = open(ciw->devname, fullaccess ? O_RDWR : O_RDONLY); + if (ciw->fd == -1) { + int err = errno; + write_log(_T("IOCTL: failed to open '%s', err=%d\n"), ciw->devname, err); + return 0; + } + ciw->fullaccess = fullaccess; + if (log_scsi) + write_log(_T("IOCTL: IOCTL open completed\n")); + return 1; +} + + +static int do_raw_scsi(struct dev_info_ioctl* ciw, int unitnum, unsigned char* cmd, int cmdlen, unsigned char* data, int datalen) { + struct sg_io_hdr io_hdr; + unsigned char sense_buffer[32]; + memset(&io_hdr, 0, sizeof(struct sg_io_hdr)); + io_hdr.interface_id = 'S'; + io_hdr.cmd_len = cmdlen; + io_hdr.mx_sb_len = sizeof(sense_buffer); + io_hdr.dxfer_direction = SG_DXFER_FROM_DEV; + io_hdr.dxfer_len = datalen; + io_hdr.dxferp = data; + io_hdr.cmdp = cmd; + io_hdr.sbp = sense_buffer; + io_hdr.timeout = 20000; // 20 seconds + + if (ioctl(ciw->fd, SG_IO, &io_hdr) < 0) { + perror("SG_IO"); + return 0; + } + return io_hdr.dxfer_len; +} + +static void sub_deinterleave(const uae_u8* s, uae_u8* d) +{ + for (int i = 0; i < 8 * 12; i++) { + int dmask = 0x80; + int smask = 1 << (7 - (i / 12)); + (*d) = 0; + for (int j = 0; j < 8; j++) { + (*d) |= (s[(i % 12) * 8 + j] & smask) ? dmask : 0; + dmask >>= 1; + } + d++; + } +} + +static int spti_read(struct dev_info_ioctl* ciw, int unitnum, uae_u8* data, int sector, int sectorsize) +{ + uae_u8 cmd[12] = { 0xbe, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0 }; + int tlen = sectorsize; + + write_log(_T("spti_read %d %d %d\n"), unitnum, sector, sectorsize); + + if (sectorsize == 2048 || sectorsize == 2336 || sectorsize == 2328) { + cmd[9] |= 1 << 4; // userdata + } + else if (sectorsize >= 2352) { + cmd[9] |= 1 << 4; // userdata + cmd[9] |= 1 << 3; // EDC&ECC + cmd[9] |= 1 << 7; // sync + cmd[9] |= 3 << 5; // header code + if (sectorsize > 2352) { + cmd[10] |= 1; // RAW P-W + } + if (sectorsize > 2352 + SUB_CHANNEL_SIZE) { + cmd[9] |= 0x2 << 1; // C2 + } + } + cmd[3] = (uae_u8)(sector >> 16); + cmd[4] = (uae_u8)(sector >> 8); + cmd[5] = (uae_u8)(sector >> 0); + if (unitnum >= 0) + gui_flicker_led(LED_CD, unitnum, LED_CD_ACTIVE); + int len = sizeof cmd; + return do_raw_scsi(ciw, unitnum, cmd, len, data, tlen); +} + +extern void encode_l2(uae_u8* p, int address); + +static int read2048(struct dev_info_ioctl* ciw, int sector) +{ + off_t offset = (off_t)sector * 2048; + + if (lseek(ciw->fd, offset, SEEK_SET) == (off_t)-1) { + return 0; + } + ssize_t dtotal = read(ciw->fd, ciw->tempbuffer, 2048); + return dtotal == 2048 ? 2048 : 0; +} + +static int read_block(struct dev_info_ioctl* ciw, int unitnum, uae_u8* data, int sector, int size, int sectorsize) +{ + uae_u8* p = ciw->tempbuffer; + int ret; + int origsize = size; + int origsector = sector; + uae_u8* origdata = data; + bool got; + +retry: + if (!open_createfile(ciw, ciw->usesptiread ? 1 : 0)) + return 0; + ret = 0; + while (size > 0) { + int track = cdtracknumber(&ciw->di.toc, sector); + if (track < 0) + return 0; + got = false; + if (!ciw->usesptiread && sectorsize == 2048 && ciw->trackmode[track] == 0) { + if (read2048(ciw, sector) == 2048) { + memcpy(data, p, 2048); + sector++; + data += sectorsize; + ret += sectorsize; + got = true; + } + } + if (!got && !ciw->usesptiread) { + int len = spti_read(ciw, unitnum, data, sector, sectorsize); + if (len) { + if (data) { + memcpy(data, p, sectorsize); + data += sectorsize; + ret += sectorsize; + } + got = true; + } + } + if (!got) { + int dtotal = read2048(ciw, sector); + if (dtotal != 2048) + return ret; + if (sectorsize >= 2352) { + memset(data, 0, 16); + memcpy(data + 16, p, 2048); + encode_l2(data, sector + 150); + if (sectorsize > 2352) + memset(data + 2352, 0, sectorsize - 2352); + sector++; + data += sectorsize; + ret += sectorsize; + } + else if (sectorsize == 2048) { + memcpy(data, p, 2048); + sector++; + data += sectorsize; + ret += sectorsize; + } + got = true; + } + sector++; + size--; + } + return ret; +} + +static int read_block_cda(struct cda_play* cda, int unitnum, uae_u8* data, int sector, int size, int sectorsize) +{ + return read_block(&ciw32[unitnum], unitnum, data, sector, size, sectorsize); +} + +/* pause/unpause CD audio */ +static int ioctl_command_pause(int unitnum, int paused) +{ + struct dev_info_ioctl* ciw = unitisopen(unitnum); + if (!ciw) + return -1; + int old = ciw->cda.cdda_paused; + if ((paused && ciw->cda.cdda_play) || !paused) + ciw->cda.cdda_paused = paused; + return old; +} + + +/* stop CD audio */ +static int ioctl_command_stop(int unitnum) +{ + struct dev_info_ioctl* ciw = unitisopen(unitnum); + if (!ciw) + return 0; + + ciw_cdda_stop(&ciw->cda); + + return 1; +} + +static uae_u32 ioctl_command_volume(int unitnum, uae_u16 volume_left, uae_u16 volume_right) +{ + struct dev_info_ioctl* ciw = unitisopen(unitnum); + if (!ciw) + return -1; + uae_u32 old = (ciw->cda.cdda_volume[1] << 16) | (ciw->cda.cdda_volume[0] << 0); + ciw->cda.cdda_volume[0] = volume_left; + ciw->cda.cdda_volume[1] = volume_right; + return old; +} + +/* play CD audio */ +static int ioctl_command_play(int unitnum, int startlsn, int endlsn, int scan, play_status_callback statusfunc, play_subchannel_callback subfunc) +{ + struct dev_info_ioctl* ciw = unitisopen(unitnum); + if (!ciw) + return 0; + + ciw->cda.di = &ciw->di; + ciw->cda.cdda_play_finished = 0; + ciw->cda.cdda_subfunc = subfunc; + ciw->cda.cdda_statusfunc = statusfunc; + ciw->cda.cdda_scan = scan > 0 ? 10 : (scan < 0 ? 10 : 0); + ciw->cda.cdda_delay = ciw_cdda_setstate(&ciw->cda, -1, -1); + ciw->cda.cdda_delay_frames = ciw_cdda_setstate(&ciw->cda, -2, -1); + ciw_cdda_setstate(&ciw->cda, AUDIO_STATUS_NOT_SUPPORTED, -1); + ciw->cda.read_block = read_block_cda; + + if (!open_createfile(ciw, 0)) { + ciw_cdda_setstate(&ciw->cda, AUDIO_STATUS_PLAY_ERROR, -1); + return 0; + } + if (!isaudiotrack(&ciw->di.toc, startlsn)) { + ciw_cdda_setstate(&ciw->cda, AUDIO_STATUS_PLAY_ERROR, -1); + return 0; + } + if (!ciw->cda.cdda_play) { + uae_start_thread(_T("ioctl_cdda_play"), ciw_cdda_play, &ciw->cda, NULL); + } + ciw->cda.cdda_start = startlsn; + ciw->cda.cdda_end = endlsn; + ciw->cda.cd_last_pos = ciw->cda.cdda_start; + ciw->cda.cdda_play++; + + return 1; +} + +/* read qcode */ +static int ioctl_command_qcode(int unitnum, uae_u8* buf, int sector, bool all) +{ + struct dev_info_ioctl* ciw = unitisopen(unitnum); + if (!ciw) + return 0; + + uae_u8* p; + int trk; + cdrom_tocentry* toc = &ciw->cdromtoc; + int pos; + int msf; + int start, end; + int status; + bool valid = false; + bool regenerate = true; + + if (all) + return 0; + + memset(buf, 0, SUBQ_SIZE); + p = buf; + + status = AUDIO_STATUS_NO_STATUS; + if (ciw->cda.cdda_play) { + status = AUDIO_STATUS_IN_PROGRESS; + if (ciw->cda.cdda_paused) + status = AUDIO_STATUS_PAUSED; + } + else if (ciw->cda.cdda_play_finished) { + status = AUDIO_STATUS_PLAY_COMPLETE; + } + + p[1] = status; + p[3] = 12; + + p = buf + 4; + + if (sector < 0) + pos = ciw->cda.cd_last_pos; + else + pos = sector; + + if (!regenerate) { + if (sector < 0 && ciw->cda.subcodevalid && ciw->cda.cdda_play) { + uae_sem_wait(&ciw->cda.sub_sem2); + uae_u8 subbuf[SUB_CHANNEL_SIZE]; + sub_deinterleave(ciw->cda.subcodebuf, subbuf); + memcpy(p, subbuf + 12, 12); + uae_sem_post(&ciw->cda.sub_sem2); + valid = true; + } + if (!valid && sector >= 0) { + unsigned int len; + uae_sem_wait(&ciw->cda.sub_sem); + struct cdrom_subchnl subchnl; + subchnl.cdsc_format = CDROM_MSF; + if (ioctl(ciw->fd, CDROMSUBCHNL, &subchnl) == -1) { + perror("CDROMSUBCHNL ioctl failed"); + } + uae_u8 subbuf[SUB_CHANNEL_SIZE]; + sub_deinterleave((uae_u8*)&subchnl, subbuf); + uae_sem_post(&ciw->cda.sub_sem); + memcpy(p, subbuf + 12, 12); + valid = true; + } + } + + if (!valid) { + start = end = 0; + struct cdrom_tocentry tocentry; + for (trk = 0; trk <= ciw->di.toc.last_track; trk++) { + tocentry.cdte_track = trk; + tocentry.cdte_format = CDROM_MSF; + if (ioctl(ciw->fd, CDROMREADTOCENTRY, &tocentry) == -1) { + perror("CDROMREADTOCENTRY ioctl failed"); + return 0; + } + start = msf2lsn((tocentry.cdte_addr.msf.minute << 16) | (tocentry.cdte_addr.msf.second << 8) | tocentry.cdte_addr.msf.frame); + if (trk < ciw->di.toc.last_track) { + tocentry.cdte_track = trk + 1; + if (ioctl(ciw->fd, CDROMREADTOCENTRY, &tocentry) == -1) { + perror("CDROMREADTOCENTRY ioctl failed"); + return 0; + } + end = msf2lsn((tocentry.cdte_addr.msf.minute << 16) | (tocentry.cdte_addr.msf.second << 8) | tocentry.cdte_addr.msf.frame); + } + else { + end = INT_MAX; + } + if (pos < start) + break; + if (pos >= start && pos < end) + break; + } + p[0] = (tocentry.cdte_ctrl << 4) | (tocentry.cdte_adr << 0); + p[1] = tobcd(trk + 1); + p[2] = tobcd(1); + msf = lsn2msf(pos); + tolongbcd(p + 7, msf); + msf = lsn2msf(pos - start - 150); + tolongbcd(p + 3, msf); + } + + return 1; +} + +static int ioctl_command_rawread(int unitnum, uae_u8* data, int sector, int size, int sectorsize, uae_u32 extra) +{ + struct dev_info_ioctl* ciw = unitisopen(unitnum); + if (!ciw) + return 0; + + uae_u8* p = ciw->tempbuffer; + int ret = 0; + + if (log_scsi) + write_log(_T("IOCTL rawread unit=%d sector=%d blocksize=%d\n"), unitnum, sector, sectorsize); + ciw_cdda_stop(&ciw->cda); + gui_flicker_led(LED_CD, unitnum, LED_CD_ACTIVE); + if (sectorsize > 0) { + if (sectorsize != 2336 && sectorsize != 2352 && sectorsize != 2048 && + sectorsize != 2336 + 96 && sectorsize != 2352 + 96 && sectorsize != 2048 + 96) + return 0; + while (size-- > 0) { + if (!read_block(ciw, unitnum, data, sector, 1, sectorsize)) + break; + ciw->cda.cd_last_pos = sector; + data += sectorsize; + ret += sectorsize; + sector++; + } + } + else { + uae_u8 sectortype = extra >> 16; + uae_u8 cmd9 = extra >> 8; + int sync = (cmd9 >> 7) & 1; + int headercodes = (cmd9 >> 5) & 3; + int userdata = (cmd9 >> 4) & 1; + int edcecc = (cmd9 >> 3) & 1; + int errorfield = (cmd9 >> 1) & 3; + uae_u8 subs = extra & 7; + if (subs != 0 && subs != 1 && subs != 2 && subs != 4) + return -1; + if (errorfield >= 3) + return -1; + uae_u8* d = data; + + if (isaudiotrack(&ciw->di.toc, sector)) { + + if (sectortype != 0 && sectortype != 1) + return -2; + + for (int i = 0; i < size; i++) { + uae_u8* odata = data; + int blocksize = errorfield == 0 ? 2352 : (errorfield == 1 ? 2352 + 294 : 2352 + 296); + int readblocksize = errorfield == 0 ? 2352 : 2352 + 296; + + if (!read_block(ciw, unitnum, NULL, sector, 1, readblocksize)) { + return ret; + } + ciw->cda.cd_last_pos = sector; + + if (subs == 0) { + memcpy(data, p, blocksize); + data += blocksize; + } + else if (subs == 4) { // all, de-interleaved + memcpy(data, p, blocksize); + data += blocksize; + sub_to_deinterleaved(p + readblocksize, data); + data += SUB_CHANNEL_SIZE; + } + else if (subs == 2) { // q-only + memcpy(data, p, blocksize); + data += blocksize; + uae_u8 subdata[SUB_CHANNEL_SIZE]; + sub_to_deinterleaved(p + readblocksize, subdata); + memcpy(data, subdata + SUB_ENTRY_SIZE, SUB_ENTRY_SIZE); + p += SUB_ENTRY_SIZE; + } + else if (subs == 1) { // all, interleaved + memcpy(data, p, blocksize); + memcpy(data + blocksize, p + readblocksize, SUB_CHANNEL_SIZE); + data += blocksize + SUB_CHANNEL_SIZE; + } + ret += (int)(data - odata); + sector++; + } + } + + + } + return ret; +} + +static int ioctl_command_readwrite(int unitnum, int sector, int size, int do_write, uae_u8* data) +{ + struct dev_info_ioctl* ciw = unitisopen(unitnum); + if (!ciw) + return 0; + + if (ciw->usesptiread) + return ioctl_command_rawread(unitnum, data, sector, size, 2048, 0); + + ciw_cdda_stop(&ciw->cda); + + ssize_t dtotal; + int cnt = 3; + uae_u8* p = ciw->tempbuffer; + int blocksize = ciw->di.bytespersector; + + if (!open_createfile(ciw, 0)) + return 0; + ciw->cda.cd_last_pos = sector; + while (cnt-- > 0) { + off_t offset = (off_t)sector * ciw->di.bytespersector; + gui_flicker_led(LED_CD, unitnum, LED_CD_ACTIVE); + if (lseek(ciw->fd, offset, SEEK_SET) == (off_t)-1) { + if (win32_error(ciw, unitnum, _T("SetFilePointer")) < 0) + continue; + return 0; + } + break; + } + while (size-- > 0) { + gui_flicker_led(LED_CD, unitnum, LED_CD_ACTIVE); + if (do_write) { + if (data) { + memcpy(p, data, blocksize); + data += blocksize; + } + if (write(ciw->fd, p, blocksize) != blocksize) { + int err; + err = win32_error(ciw, unitnum, _T("write")); + if (err < 0) + continue; + if (err == EROFS) + return -1; + return 0; + } + } + else { + dtotal = read(ciw->fd, p, blocksize); + if (dtotal != blocksize) { + if (win32_error(ciw, unitnum, _T("read")) < 0) + continue; + return 0; + } + if (dtotal == 0) { + static int reported; + /* ESS Mega (CDTV) "fake" data area returns zero bytes and no error.. */ + spti_read(ciw, unitnum, data, sector, 2048); + if (reported++ < 100) + write_log(_T("IOCTL unit %d, sector %d: read()==0. SPTI=%d\n"), unitnum, sector, errno); + return 1; + } + if (data) { + memcpy(data, p, blocksize); + data += blocksize; + } + } + gui_flicker_led(LED_CD, unitnum, LED_CD_ACTIVE); + } + return 1; + +} + +static int ioctl_command_write(int unitnum, uae_u8* data, int sector, int size) +{ + return ioctl_command_readwrite(unitnum, sector, size, 1, data); +} + +static int ioctl_command_read(int unitnum, uae_u8* data, int sector, int size) +{ + return ioctl_command_readwrite(unitnum, sector, size, 0, data); +} + +static int fetch_geometry(struct dev_info_ioctl* ciw, int unitnum, struct device_info* di) +{ + if (!open_createfile(ciw, 0)) + return 0; + uae_sem_wait(&ciw->cda.sub_sem); + + int status = ioctl(ciw->fd, CDROM_DRIVE_STATUS, CDSL_NONE); + if (status == -1) + { + perror("IOCTL: CDROM_DRIVE_STATUS"); + } + if (status != CDS_DISC_OK) + { + ciw->changed = true; + uae_sem_post(&ciw->cda.sub_sem); + return 0; + } + + uae_sem_post(&ciw->cda.sub_sem); + // if (di) { + // di->cylinders = geom.cylinders; + // di->sectorspertrack = geom.sectors; + // di->trackspercylinder = geom.heads; + // di->bytespersector = 2048; // Typical CD-ROM sector size + // } + return 1; +} + +static int ismedia(struct dev_info_ioctl* ciw, int unitnum) +{ + return fetch_geometry(ciw, unitnum, &ciw->di); +} + +static int eject(int unitnum, bool eject) +{ + struct dev_info_ioctl* ciw = unitisopen(unitnum); + + if (!ciw) + return 0; + if (!unitisopen(unitnum)) + return 0; + ciw_cdda_stop(&ciw->cda); + if (!open_createfile(ciw, 0)) + return 0; + int ret = 0; + if (ioctl(ciw->fd, eject ? CDROMEJECT : CDROMCLOSETRAY, 0) < 0) { + ret = 1; + } + return ret; +} + +static int ioctl_command_toc2(int unitnum, struct cd_toc_head* tocout, bool hide_errors) +{ + struct dev_info_ioctl* ciw = unitisopen(unitnum); + if (!ciw) + return 0; + + int len; + int i; + struct cd_toc_head* th = &ciw->di.toc; + struct cd_toc* t = th->toc; + int cnt = 3; + memset(ciw->trackmode, 0xff, sizeof(ciw->trackmode)); + struct cdrom_tochdr tochdr; + struct cdrom_tocentry tocentry; + + if (!unitisopen(unitnum)) + return 0; + + if (!open_createfile(ciw, 0)) + return 0; + while (cnt-- > 0) { + if (ioctl(ciw->fd, CDROMREADTOCHDR, &tochdr) == -1) { + int err = errno; + if (!hide_errors || (hide_errors && err == ENOMEDIUM)) { + if (win32_error(ciw, unitnum, _T("CDROMREADTOCHDR")) < 0) + continue; + } + return 0; + } + break; + } + + memset(th, 0, sizeof(struct cd_toc_head)); + th->first_track = tochdr.cdth_trk0; + th->last_track = tochdr.cdth_trk1; + th->tracks = th->last_track - th->first_track + 1; + th->points = th->tracks + 3; + th->firstaddress = 0; + th->lastaddress = msf2lsn((tocentry.cdte_addr.msf.minute << 16) | (tocentry.cdte_addr.msf.second << 8) | + (tocentry.cdte_addr.msf.frame << 0)); + + t->adr = 1; + t->point = 0xa0; + t->track = th->first_track; + t++; + + th->first_track_offset = 1; + for (i = 0; i < th->last_track; i++) { + tocentry.cdte_track = i + 1; + tocentry.cdte_format = CDROM_MSF; + if (ioctl(ciw->fd, CDROMREADTOCENTRY, &tocentry) == -1) { + return 0; + } + t->adr = tocentry.cdte_adr; + t->control = tocentry.cdte_ctrl; + t->paddress = msf2lsn((tocentry.cdte_addr.msf.minute << 16) | (tocentry.cdte_addr.msf.second << 8) | + (tocentry.cdte_addr.msf.frame << 0)); + t->point = t->track = i + 1; + t++; + } + + th->last_track_offset = th->last_track; + t->adr = 1; + t->point = 0xa1; + t->track = th->last_track; + t->paddress = th->lastaddress; + t++; + + t->adr = 1; + t->point = 0xa2; + t->paddress = th->lastaddress; + t++; + + for (i = th->first_track_offset; i <= th->last_track_offset + 1; i++) { + uae_u32 addr; + uae_u32 msf; + t = &th->toc[i]; + if (i <= th->last_track_offset) { + write_log(_T("%2d: "), t->track); + addr = t->paddress; + msf = lsn2msf(addr); + } + else { + write_log(_T(" ")); + addr = th->toc[th->last_track_offset + 2].paddress; + msf = lsn2msf(addr); + } + write_log(_T("%7d %02d:%02d:%02d"), + addr, (msf >> 16) & 0x7fff, (msf >> 8) & 0xff, (msf >> 0) & 0xff); + if (i <= th->last_track_offset) { + write_log(_T(" %s %x"), + (t->control & 4) ? _T("DATA ") : _T("CDA "), t->control); + } + write_log(_T("\n")); + } + + memcpy(tocout, th, sizeof(struct cd_toc_head)); + return 1; +} +static int ioctl_command_toc(int unitnum, struct cd_toc_head* tocout) +{ + return ioctl_command_toc2(unitnum, tocout, false); +} + +#ifdef AMIBERRY +#define DRIVE_UNKNOWN 0 +#define DRIVE_NO_ROOT_DIR 1 +#define DRIVE_REMOVABLE 2 +#define DRIVE_FIXED 3 +#define DRIVE_REMOTE 4 +#define DRIVE_CDROM 5 +#define DRIVE_RAMDISK 6 +#endif + +static void update_device_info(int unitnum) +{ + struct dev_info_ioctl* ciw = unitcheck(unitnum); + if (!ciw) + return; + struct device_info* di = &ciw->di; + di->bus = unitnum; + di->target = 0; + di->lun = 0; + di->media_inserted = 0; + di->bytespersector = 2048; + strncpy(di->mediapath, ciw->drvletter, sizeof(ciw->drvletter) - 1); + if (fetch_geometry(ciw, unitnum, di)) { // || ioctl_command_toc (unitnum)) + di->media_inserted = 1; + } + if (ciw->changed) { + ioctl_command_toc2(unitnum, &di->toc, true); + ciw->changed = false; + } + di->removable = ciw->type == DRIVE_CDROM ? 1 : 0; + di->write_protected = ciw->type == DRIVE_CDROM ? 1 : 0; + di->type = ciw->type == DRIVE_CDROM ? INQ_ROMD : INQ_DASD; + di->unitnum = unitnum + 1; + _tcscpy(di->label, ciw->drvlettername); + di->backend = _T("IOCTL"); +} + +static void trim(TCHAR* s) +{ + while (s[0] != '\0' && s[_tcslen(s) - 1] == ' ') + s[_tcslen(s) - 1] = 0; +} + +/* open device level access to cd rom drive */ +static int sys_cddev_open(struct dev_info_ioctl* ciw, int unitnum) +{ + ciw->cda.cdda_volume[0] = 0x7fff; + ciw->cda.cdda_volume[1] = 0x7fff; + ciw->tempbuffer = (unsigned char*)malloc(IOCTL_DATA_BUFFER); + if (!ciw->tempbuffer) { + write_log("IOCTL: Failed to allocate buffer\n"); + return 1; + } + + memset(ciw->di.vendorid, 0, sizeof(ciw->di.vendorid)); + memset(ciw->di.productid, 0, sizeof(ciw->di.productid)); + memset(ciw->di.revision, 0, sizeof(ciw->di.revision)); + _tcscpy(ciw->di.vendorid, _T("UAE")); + _stprintf(ciw->di.productid, _T("SCSI CD%d IMG"), unitnum); + _tcscpy(ciw->di.revision, _T("0.2")); + + if (!open_createfile(ciw, 0)) { + write_log("IOCTL: Failed to open '%s'\n", ciw->devname); + goto error; + } + + struct hd_driveid id; + if (ioctl(ciw->fd, HDIO_GET_IDENTITY, &id) == 0) { + strncpy(ciw->di.vendorid, (const char*)id.model, sizeof(ciw->di.vendorid) - 1); + strncpy(ciw->di.productid, (const char*)id.serial_no, sizeof(ciw->di.productid) - 1); + strncpy(ciw->di.revision, (const char*)id.fw_rev, sizeof(ciw->di.revision) - 1); + } + + write_log(_T("IOCTL: device '%s' (%s/%s/%s) opened successfully (unit=%d,media=%d)\n"), + ciw->devname, ciw->di.vendorid, ciw->di.productid, ciw->di.revision, + unitnum, ciw->di.media_inserted); + if (!_tcsicmp(ciw->di.vendorid, _T("iomega")) && !_tcsicmp(ciw->di.productid, _T("rrd"))) { + write_log(_T("Device blacklisted\n")); + goto error; + } + uae_sem_init(&ciw->cda.sub_sem, 0, 1); + uae_sem_init(&ciw->cda.sub_sem2, 0, 1); + ioctl_command_stop(unitnum); + update_device_info(unitnum); + ciw->open = true; + return 0; + +error: + win32_error(ciw, unitnum, _T("CreateFile")); + + free(ciw->tempbuffer); + ciw->tempbuffer = NULL; + close(ciw->fd); + ciw->fd = -1; + return -1; +} + +/* close device handle */ +static void sys_cddev_close(struct dev_info_ioctl* ciw, int unitnum) { + if (ciw->open == false) + return; + ciw_cdda_stop(&ciw->cda); + close_createfile(ciw); + free(ciw->tempbuffer); + ciw->tempbuffer = NULL; + uae_sem_destroy(&ciw->cda.sub_sem); + uae_sem_destroy(&ciw->cda.sub_sem2); + ciw->open = false; + write_log(_T("IOCTL: device '%s' closed\n"), ciw->devname, unitnum); +} + +static int open_device(int unitnum, const char* ident, int flags) +{ + struct dev_info_ioctl* ciw = NULL; + if (ident && ident[0]) { + for (int i = 0; i < MAX_TOTAL_SCSI_DEVICES; i++) { + ciw = &ciw32[i]; + if (unittable[i] == 0 && ciw->drvletter != 0) { + if (!strcmp(ciw->drvlettername, ident)) { + unittable[unitnum] = i + 1; + if (sys_cddev_open(ciw, unitnum) == 0) + return 1; + unittable[unitnum] = 0; + return 0; + } + } + } + return 0; + } + ciw = &ciw32[unitnum]; + for (int i = 0; i < MAX_TOTAL_SCSI_DEVICES; i++) { + if (unittable[i] == unitnum + 1) + return 0; + } + if (ciw->drvletter == 0) + return 0; + unittable[unitnum] = unitnum + 1; + if (sys_cddev_open(ciw, unitnum) == 0) + return 1; + unittable[unitnum] = 0; + blkdev_cd_change(unitnum, ciw->drvlettername); + return 0; +} + +static void close_device(int unitnum) +{ + struct dev_info_ioctl* ciw = unitcheck(unitnum); + if (!ciw) + return; + sys_cddev_close(ciw, unitnum); + blkdev_cd_change(unitnum, ciw->drvlettername); + unittable[unitnum] = 0; +} + +static int total_devices; + +static void close_bus(void) +{ + if (!bus_open) { + write_log(_T("IOCTL close_bus() when already closed!\n")); + return; + } + total_devices = 0; + for (int i = 0; i < MAX_TOTAL_SCSI_DEVICES; i++) { + sys_cddev_close(&ciw32[i], i); + memset(&ciw32[i], 0, sizeof(struct dev_info_ioctl)); + ciw32[i].fd = -1; + unittable[i] = 0; + } + bus_open = 0; + uae_sem_destroy(&play_sem); + write_log(_T("IOCTL driver closed.\n")); +} + +static int open_bus(int flags) +{ + if (bus_open) { + write_log(_T("IOCTL open_bus() more than once!\n")); + return 1; + } + total_devices = 0; + auto cd_drives = get_cd_drives(); + if (!cd_drives.empty()) + { + for (const auto& drive: cd_drives) + { + int fd = open(drive.c_str(), O_RDONLY | O_NONBLOCK); + if (fd != -1) { + struct stat st; + if (fstat(fd, &st) == 0 && S_ISBLK(st.st_mode)) { + strncpy(ciw32[total_devices].drvletter, drive.c_str(), sizeof(ciw32[total_devices].drvletter)); + strcpy(ciw32[total_devices].drvlettername, drive.c_str()); + ciw32[total_devices].type = st.st_rdev; + ciw32[total_devices].di.bytespersector = 2048; + strcpy(ciw32[total_devices].devname, drive.c_str()); + ciw32[total_devices].fd = fd; + total_devices++; + } + close(fd); + } + } + } + bus_open = 1; + uae_sem_init(&play_sem, 0, 1); + write_log(_T("IOCTL driver open, %d devices.\n"), total_devices); + return total_devices; +} + +static int ioctl_ismedia(int unitnum, int quick) +{ + struct dev_info_ioctl* ciw = unitisopen(unitnum); + if (!ciw) + return -1; + if (quick) { + return ciw->di.media_inserted; + } + update_device_info(unitnum); + return ismedia(ciw, unitnum); +} + +static struct device_info* info_device(int unitnum, struct device_info* di, int quick, int session) +{ + struct dev_info_ioctl* ciw = unitcheck(unitnum); + if (!ciw) + return 0; + if (!quick) + update_device_info(unitnum); + ciw->di.open = ciw->open; + memcpy(di, &ciw->di, sizeof(struct device_info)); + return di; +} + +// bool win32_ioctl_media_change(TCHAR driveletter, int insert) +// { +// for (int i = 0; i < total_devices; i++) { +// struct dev_info_ioctl* ciw = &ciw32[i]; +// if (ciw->drvletter == driveletter && ciw->di.media_inserted != insert) { +// write_log(_T("IOCTL: media change %s %d\n"), ciw->drvlettername, insert); +// ciw->di.media_inserted = insert; +// ciw->changed = true; +// int unitnum = getunitnum(ciw); +// if (unitnum >= 0) { +// update_device_info(unitnum); +// scsi_do_disk_change(unitnum, insert, NULL); +// filesys_do_disk_change(unitnum, insert != 0); +// blkdev_cd_change(unitnum, ciw->drvlettername); +// return true; +// } +// } +// } +// return false; +// } + +static int ioctl_scsiemu(int unitnum, uae_u8* cmd) +{ + uae_u8 c = cmd[0]; + if (c == 0x1b) { + int mode = cmd[4] & 3; + if (mode == 2) + eject(unitnum, true); + else if (mode == 3) + eject(unitnum, false); + return 1; + } + return -1; +} + +struct device_functions devicefunc_scsi_ioctl = { + _T("IOCTL"), + open_bus, close_bus, open_device, close_device, info_device, + 0, 0, 0, + ioctl_command_pause, ioctl_command_stop, ioctl_command_play, ioctl_command_volume, ioctl_command_qcode, + ioctl_command_toc, ioctl_command_read, ioctl_command_rawread, ioctl_command_write, + 0, ioctl_ismedia, ioctl_scsiemu +}; + +#endif diff --git a/src/osdep/cda_play.cpp b/src/osdep/cda_play.cpp index fb1796b74..4045c0c4e 100644 --- a/src/osdep/cda_play.cpp +++ b/src/osdep/cda_play.cpp @@ -341,7 +341,7 @@ static bool cdda_play2(struct cda_play* ciw, int* outpos) return restart; } -void ciw_cdda_play(void* v) +int ciw_cdda_play(void* v) { struct cda_play* ciw = (struct cda_play*)v; int outpos = -1; @@ -360,6 +360,7 @@ void ciw_cdda_play(void* v) ciw->cdda_play = 1; } ciw->cdda_play = 0; + return 0; } void ciw_cdda_stop(struct cda_play* ciw) diff --git a/src/osdep/cda_play.h b/src/osdep/cda_play.h index ac4b94350..f8d4e0730 100644 --- a/src/osdep/cda_play.h +++ b/src/osdep/cda_play.h @@ -53,6 +53,6 @@ struct cda_play cda_play_read_block read_block; }; -void ciw_cdda_play(void* ciw); +int ciw_cdda_play(void* ciw); void ciw_cdda_stop(struct cda_play* ciw); int ciw_cdda_setstate(struct cda_play* ciw, int state, int playpos); \ No newline at end of file diff --git a/src/osdep/fsdb_host.h b/src/osdep/fsdb_host.h index 85c70ce35..6cdaded7e 100644 --- a/src/osdep/fsdb_host.h +++ b/src/osdep/fsdb_host.h @@ -32,5 +32,5 @@ extern bool fs_path_exists(const std::string& s); extern std::string iso_8859_1_to_utf8(const std::string& str); extern void utf8_to_latin1_string(std::string& input, std::string& output); extern std::string prefix_with_application_directory_path(std::string currentpath); -extern std::string prefix_with_data_path(std::string filename); -extern std::string prefix_with_whdboot_path(std::string filename); +extern std::string prefix_with_data_path(const std::string& filename); +extern std::string prefix_with_whdboot_path(const std::string& filename); diff --git a/src/osdep/gui/EditCDDrive.cpp b/src/osdep/gui/EditCDDrive.cpp new file mode 100644 index 000000000..fb9d491a4 --- /dev/null +++ b/src/osdep/gui/EditCDDrive.cpp @@ -0,0 +1,525 @@ +#include +#include + +#include +#include +#include "SelectorEntry.hpp" + +#include "sysdeps.h" +#include "config.h" +#include "options.h" +#include "memory.h" +#include "autoconf.h" +#include "gui_handling.h" + +#include "amiberry_gfx.h" +#include "amiberry_input.h" +#include "rommgr.h" +#include "StringListModel.h" +#include "uae.h" + +enum +{ + DIALOG_WIDTH = 600, + DIALOG_HEIGHT = 300 +}; + +static bool dialogResult = false; +static bool dialogFinished = false; + +static gcn::Window* wndEditCDDrive; +static gcn::Button* cmdCDDriveOK; +static gcn::Button* cmdCDDriveCancel; +static gcn::Label* lblCDDrivePath; +static gcn::TextField* txtCDDrivePath; + +static gcn::Label* lblCDDriveController; +static gcn::DropDown* cboCDDriveController; +static gcn::DropDown* cboCDDriveUnit; + +static gcn::StringListModel controllerListModel; +static gcn::StringListModel unitListModel; + +class CDDriveActionListener : public gcn::ActionListener +{ +public: + void action(const gcn::ActionEvent& actionEvent) override + { + const auto source = actionEvent.getSource(); + if (source == cmdCDDriveOK) + { + if (txtCDDrivePath->getText().empty()) + { + wndEditCDDrive->setCaption("Path is empty!"); + return; + } + + dialogResult = true; + dialogFinished = true; + } + else if (source == cmdCDDriveCancel) + { + dialogResult = false; + dialogFinished = true; + } + else if (source == cboCDDriveController) + { + const auto posn = controller[cboCDDriveController->getSelected()].type; + current_cddlg.ci.controller_type = posn % HD_CONTROLLER_NEXT_UNIT; + current_cddlg.ci.controller_type_unit = posn / HD_CONTROLLER_NEXT_UNIT; + inithdcontroller(current_cddlg.ci.controller_type, current_cddlg.ci.controller_type_unit, UAEDEV_CD, current_cddlg.ci.rootdir[0] != 0); + } + else if (source == cboCDDriveUnit) + { + current_cddlg.ci.controller_unit = cboCDDriveUnit->getSelected(); + } + } +}; +static CDDriveActionListener* cdDriveActionListener; + +static void InitEditCDDrive() +{ + auto cd_drives = get_cd_drives(); + + wndEditCDDrive = new gcn::Window("CD Settings"); + wndEditCDDrive->setSize(DIALOG_WIDTH, DIALOG_HEIGHT); + wndEditCDDrive->setPosition((GUI_WIDTH - DIALOG_WIDTH) / 2, (GUI_HEIGHT - DIALOG_HEIGHT) / 2); + wndEditCDDrive->setBaseColor(gui_base_color); + wndEditCDDrive->setForegroundColor(gui_foreground_color); + wndEditCDDrive->setCaption("CD Settings"); + wndEditCDDrive->setTitleBarHeight(TITLEBAR_HEIGHT); + wndEditCDDrive->setMovable(false); + + cdDriveActionListener = new CDDriveActionListener(); + + cmdCDDriveOK = new gcn::Button("Add CD Drive"); + cmdCDDriveOK->setSize(BUTTON_WIDTH * 2, BUTTON_HEIGHT); + cmdCDDriveOK->setPosition(DIALOG_WIDTH - DISTANCE_BORDER - 4 * BUTTON_WIDTH - DISTANCE_NEXT_X, + DIALOG_HEIGHT - 2 * DISTANCE_BORDER - BUTTON_HEIGHT - 10); + cmdCDDriveOK->setBaseColor(gui_base_color); + cmdCDDriveOK->setForegroundColor(gui_foreground_color); + cmdCDDriveOK->setId("cmdCDDriveOK"); + cmdCDDriveOK->addActionListener(cdDriveActionListener); + + cmdCDDriveCancel = new gcn::Button("Cancel"); + cmdCDDriveCancel->setSize(BUTTON_WIDTH * 2, BUTTON_HEIGHT); + cmdCDDriveCancel->setPosition(DIALOG_WIDTH - DISTANCE_BORDER - 2 * BUTTON_WIDTH, + DIALOG_HEIGHT - 2 * DISTANCE_BORDER - BUTTON_HEIGHT - 10); + cmdCDDriveCancel->setBaseColor(gui_base_color); + cmdCDDriveCancel->setForegroundColor(gui_foreground_color); + cmdCDDriveCancel->setId("cmdCDDriveCancel"); + cmdCDDriveCancel->addActionListener(cdDriveActionListener); + + lblCDDrivePath = new gcn::Label("Path:"); + lblCDDrivePath->setAlignment(gcn::Graphics::Right); + txtCDDrivePath = new gcn::TextField(); + txtCDDrivePath->setSize(490, TEXTFIELD_HEIGHT); + txtCDDrivePath->setId("txtCDDrivePath"); + txtCDDrivePath->setBaseColor(gui_base_color); + txtCDDrivePath->setBackgroundColor(gui_background_color); + txtCDDrivePath->setForegroundColor(gui_foreground_color); + + lblCDDriveController = new gcn::Label("Controller:"); + lblCDDriveController->setAlignment(gcn::Graphics::Right); + cboCDDriveController = new gcn::DropDown(&controllerListModel); + cboCDDriveController->setSize(180, DROPDOWN_HEIGHT); + cboCDDriveController->setBaseColor(gui_base_color); + cboCDDriveController->setBackgroundColor(gui_background_color); + cboCDDriveController->setForegroundColor(gui_foreground_color); + cboCDDriveController->setSelectionColor(gui_selection_color); + cboCDDriveController->setId("cboCDDriveController"); + cboCDDriveController->addActionListener(cdDriveActionListener); + + cboCDDriveUnit = new gcn::DropDown(&unitListModel); + cboCDDriveUnit->setSize(60, DROPDOWN_HEIGHT); + cboCDDriveUnit->setBaseColor(gui_base_color); + cboCDDriveUnit->setBackgroundColor(gui_background_color); + cboCDDriveUnit->setForegroundColor(gui_foreground_color); + cboCDDriveUnit->setSelectionColor(gui_selection_color); + cboCDDriveUnit->setId("cboCDDriveUnit"); + cboCDDriveUnit->addActionListener(cdDriveActionListener); + + int pos_y = DISTANCE_BORDER; + + wndEditCDDrive->add(lblCDDrivePath, DISTANCE_BORDER, pos_y); + wndEditCDDrive->add(txtCDDrivePath, lblCDDrivePath->getX() + lblCDDrivePath->getWidth() + 8, pos_y); + pos_y = txtCDDrivePath->getY() + txtCDDrivePath->getHeight() + DISTANCE_NEXT_Y; + + wndEditCDDrive->add(lblCDDriveController, DISTANCE_BORDER, pos_y); + wndEditCDDrive->add(cboCDDriveController, lblCDDriveController->getX() + lblCDDriveController->getWidth() + 8, pos_y); + wndEditCDDrive->add(cboCDDriveUnit, cboCDDriveController->getX() + cboCDDriveController->getWidth() + DISTANCE_NEXT_X, pos_y); + + wndEditCDDrive->add(cmdCDDriveOK); + wndEditCDDrive->add(cmdCDDriveCancel); + + gui_top->add(wndEditCDDrive); + + wndEditCDDrive->requestModalFocus(); + focus_bug_workaround(wndEditCDDrive); + + // If we found CD Drives, auto-select the first one for now + if (!cd_drives.empty()) + { + txtCDDrivePath->setText(cd_drives.at(0)); + } +} + +static void ExitEditCDDrive() +{ + wndEditCDDrive->releaseModalFocus(); + gui_top->remove(wndEditCDDrive); + + delete cmdCDDriveOK; + delete cmdCDDriveCancel; + delete lblCDDrivePath; + delete txtCDDrivePath; + delete lblCDDriveController; + delete cboCDDriveController; + delete cboCDDriveUnit; + delete cdDriveActionListener; + delete wndEditCDDrive; +} + +static void EditCDDriveLoop() +{ + const AmigaMonitor* mon = &AMonitors[0]; + + int got_event = 0; + SDL_Event event; + SDL_Event touch_event; + didata* did = &di_joystick[0]; + while (SDL_PollEvent(&event)) + { + switch (event.type) + { + case SDL_KEYDOWN: + got_event = 1; + switch (event.key.keysym.sym) + { + case VK_ESCAPE: + dialogFinished = true; + break; + + case VK_UP: + if (handle_navigation(DIRECTION_UP)) + continue; // Don't change value when enter ComboBox -> don't send event to control + break; + + case VK_DOWN: + if (handle_navigation(DIRECTION_DOWN)) + continue; // Don't change value when enter ComboBox -> don't send event to control + break; + + case VK_LEFT: + if (handle_navigation(DIRECTION_LEFT)) + continue; // Don't change value when enter Slider -> don't send event to control + break; + + case VK_RIGHT: + if (handle_navigation(DIRECTION_RIGHT)) + continue; // Don't change value when enter Slider -> don't send event to control + break; + + case VK_Blue: + case VK_Green: + event.key.keysym.sym = SDLK_RETURN; + gui_input->pushInput(event); // Fire key down + event.type = SDL_KEYUP; // and the key up + break; + default: + break; + } + break; + + case SDL_JOYBUTTONDOWN: + case SDL_JOYHATMOTION: + if (gui_joystick) + { + got_event = 1; + const int hat = SDL_JoystickGetHat(gui_joystick, 0); + + if (SDL_JoystickGetButton(gui_joystick, did->mapping.button[SDL_CONTROLLER_BUTTON_DPAD_UP]) || (hat & SDL_HAT_UP)) // dpad + { + if (handle_navigation(DIRECTION_UP)) + continue; // Don't change value when enter Slider -> don't send event to control + PushFakeKey(SDLK_UP); + break; + } + if (SDL_JoystickGetButton(gui_joystick, did->mapping.button[SDL_CONTROLLER_BUTTON_DPAD_DOWN]) || (hat & SDL_HAT_DOWN)) // dpad + { + if (handle_navigation(DIRECTION_DOWN)) + continue; // Don't change value when enter Slider -> don't send event to control + PushFakeKey(SDLK_DOWN); + break; + } + if (SDL_JoystickGetButton(gui_joystick, did->mapping.button[SDL_CONTROLLER_BUTTON_DPAD_RIGHT]) || (hat & SDL_HAT_RIGHT)) // dpad + { + if (handle_navigation(DIRECTION_RIGHT)) + continue; // Don't change value when enter Slider -> don't send event to control + PushFakeKey(SDLK_RIGHT); + break; + } + if (SDL_JoystickGetButton(gui_joystick, did->mapping.button[SDL_CONTROLLER_BUTTON_DPAD_LEFT]) || (hat & SDL_HAT_LEFT)) // dpad + { + if (handle_navigation(DIRECTION_LEFT)) + continue; // Don't change value when enter Slider -> don't send event to control + PushFakeKey(SDLK_LEFT); + break; + } + if (SDL_JoystickGetButton(gui_joystick, did->mapping.button[SDL_CONTROLLER_BUTTON_A]) || + SDL_JoystickGetButton(gui_joystick, did->mapping.button[SDL_CONTROLLER_BUTTON_B])) + { + PushFakeKey(SDLK_RETURN); + break; + } + if (SDL_JoystickGetButton(gui_joystick, did->mapping.button[SDL_CONTROLLER_BUTTON_X]) || + SDL_JoystickGetButton(gui_joystick, did->mapping.button[SDL_CONTROLLER_BUTTON_Y]) || + SDL_JoystickGetButton(gui_joystick, did->mapping.button[SDL_CONTROLLER_BUTTON_START])) + { + dialogFinished = true; + break; + } + if ((did->mapping.is_retroarch || !did->is_controller) + && SDL_JoystickGetButton(gui_joystick, did->mapping.button[SDL_CONTROLLER_BUTTON_LEFTSHOULDER]) + || SDL_GameControllerGetButton(did->controller, + static_cast(did->mapping.button[SDL_CONTROLLER_BUTTON_LEFTSHOULDER]))) + { + for (auto z = 0; z < 10; ++z) + { + PushFakeKey(SDLK_UP); + } + } + if ((did->mapping.is_retroarch || !did->is_controller) + && SDL_JoystickGetButton(gui_joystick, did->mapping.button[SDL_CONTROLLER_BUTTON_RIGHTSHOULDER]) + || SDL_GameControllerGetButton(did->controller, + static_cast(did->mapping.button[SDL_CONTROLLER_BUTTON_RIGHTSHOULDER]))) + { + for (auto z = 0; z < 10; ++z) + { + PushFakeKey(SDLK_DOWN); + } + } + } + break; + + case SDL_JOYAXISMOTION: + if (gui_joystick) + { + got_event = 1; + if (event.jaxis.axis == SDL_CONTROLLER_AXIS_LEFTX) + { + if (event.jaxis.value > joystick_dead_zone && last_x != 1) + { + last_x = 1; + if (handle_navigation(DIRECTION_RIGHT)) + continue; // Don't change value when enter Slider -> don't send event to control + PushFakeKey(SDLK_RIGHT); + break; + } + if (event.jaxis.value < -joystick_dead_zone && last_x != -1) + { + last_x = -1; + if (handle_navigation(DIRECTION_LEFT)) + continue; // Don't change value when enter Slider -> don't send event to control + PushFakeKey(SDLK_LEFT); + break; + } + if (event.jaxis.value > -joystick_dead_zone && event.jaxis.value < joystick_dead_zone) + last_x = 0; + } + else if (event.jaxis.axis == SDL_CONTROLLER_AXIS_LEFTY) + { + if (event.jaxis.value < -joystick_dead_zone && last_y != -1) + { + last_y = -1; + if (handle_navigation(DIRECTION_UP)) + continue; // Don't change value when enter Slider -> don't send event to control + PushFakeKey(SDLK_UP); + break; + } + if (event.jaxis.value > joystick_dead_zone && last_y != 1) + { + last_y = 1; + if (handle_navigation(DIRECTION_DOWN)) + continue; // Don't change value when enter Slider -> don't send event to control + PushFakeKey(SDLK_DOWN); + break; + } + if (event.jaxis.value > -joystick_dead_zone && event.jaxis.value < joystick_dead_zone) + last_y = 0; + } + } + break; + + case SDL_FINGERDOWN: + got_event = 1; + memcpy(&touch_event, &event, sizeof event); + touch_event.type = SDL_MOUSEBUTTONDOWN; + touch_event.button.which = 0; + touch_event.button.button = SDL_BUTTON_LEFT; + touch_event.button.state = SDL_PRESSED; + + touch_event.button.x = gui_graphics->getTarget()->w * static_cast(event.tfinger.x); + touch_event.button.y = gui_graphics->getTarget()->h * static_cast(event.tfinger.y); + + gui_input->pushInput(touch_event); + break; + + case SDL_FINGERUP: + got_event = 1; + memcpy(&touch_event, &event, sizeof event); + touch_event.type = SDL_MOUSEBUTTONUP; + touch_event.button.which = 0; + touch_event.button.button = SDL_BUTTON_LEFT; + touch_event.button.state = SDL_RELEASED; + + touch_event.button.x = gui_graphics->getTarget()->w * static_cast(event.tfinger.x); + touch_event.button.y = gui_graphics->getTarget()->h * static_cast(event.tfinger.y); + + gui_input->pushInput(touch_event); + break; + + case SDL_FINGERMOTION: + got_event = 1; + memcpy(&touch_event, &event, sizeof event); + touch_event.type = SDL_MOUSEMOTION; + touch_event.motion.which = 0; + touch_event.motion.state = 0; + + touch_event.motion.x = gui_graphics->getTarget()->w * static_cast(event.tfinger.x); + touch_event.motion.y = gui_graphics->getTarget()->h * static_cast(event.tfinger.y); + + gui_input->pushInput(touch_event); + break; + + case SDL_MOUSEWHEEL: + got_event = 1; + if (event.wheel.y > 0) + { + for (auto z = 0; z < event.wheel.y; ++z) + { + PushFakeKey(SDLK_UP); + } + } + else if (event.wheel.y < 0) + { + for (auto z = 0; z > event.wheel.y; --z) + { + PushFakeKey(SDLK_DOWN); + } + } + break; + + case SDL_KEYUP: + case SDL_JOYBUTTONUP: + case SDL_MOUSEBUTTONDOWN: + case SDL_MOUSEBUTTONUP: + case SDL_MOUSEMOTION: + case SDL_RENDER_TARGETS_RESET: + case SDL_RENDER_DEVICE_RESET: + case SDL_WINDOWEVENT: + case SDL_DISPLAYEVENT: + case SDL_SYSWMEVENT: + got_event = 1; + break; + + default: + break; + } + + //------------------------------------------------- + // Send event to guisan-controls + //------------------------------------------------- + gui_input->pushInput(event); + } + + if (got_event) + { + // Now we let the Gui object perform its logic. + uae_gui->logic(); + + SDL_RenderClear(mon->gui_renderer); + + // Now we let the Gui object draw itself. + uae_gui->draw(); + // Finally we update the screen. + update_gui_screen(); + } +} + +bool EditCDDrive(const int unit_no) +{ + const AmigaMonitor* mon = &AMonitors[0]; + + mountedinfo mi{}; + uaedev_config_data* uci; + + dialogResult = false; + dialogFinished = false; + + if (current_cddlg.ci.controller_type == HD_CONTROLLER_TYPE_UAE) + current_cddlg.ci.controller_type = (is_board_enabled(&changed_prefs, ROMTYPE_A2091, 0) || + is_board_enabled(&changed_prefs, ROMTYPE_GVPS2, 0) || is_board_enabled(&changed_prefs, ROMTYPE_A4091, 0) || + (changed_prefs.cs_mbdmac & 3)) ? HD_CONTROLLER_TYPE_SCSI_AUTO : HD_CONTROLLER_TYPE_IDE_AUTO; + inithdcontroller(current_cddlg.ci.controller_type, current_cddlg.ci.controller_type_unit, UAEDEV_CD, current_cddlg.ci.rootdir[0] != 0); + + controllerListModel.clear(); + for (const auto& [type, display] : controller) { + controllerListModel.add(display); + } + + unitListModel.clear(); + for (const auto& controller_unit_item : controller_unit) { + unitListModel.add(controller_unit_item); + } + + InitEditCDDrive(); + + if (unit_no >= 0) + { + uci = &changed_prefs.mountconfig[unit_no]; + get_filesys_unitconfig(&changed_prefs, unit_no, &mi); + memcpy(¤t_cddlg.ci, uci, sizeof(uaedev_config_info)); + + txtCDDrivePath->setText(current_cddlg.ci.rootdir); + cboCDDriveController->setSelected(current_cddlg.ci.controller_type); + cboCDDriveUnit->setSelected(current_cddlg.ci.controller_unit); + } + else + { + //TODO default_cddlg ? + } + + // Prepare the screen once + uae_gui->logic(); + + SDL_RenderClear(mon->gui_renderer); + + uae_gui->draw(); + update_gui_screen(); + + while (!dialogFinished) + { + const auto start = SDL_GetPerformanceCounter(); + EditCDDriveLoop(); + cap_fps(start); + } + + if (dialogResult) + { + strncpy(current_cddlg.ci.rootdir, txtCDDrivePath->getText().c_str(), sizeof(current_cddlg.ci.rootdir) - 1); + + auto posn = controller[cboCDDriveController->getSelected()].type; + current_cddlg.ci.controller_type = posn % HD_CONTROLLER_NEXT_UNIT; + current_cddlg.ci.controller_type_unit = posn / HD_CONTROLLER_NEXT_UNIT; + inithdcontroller(current_cddlg.ci.controller_type, current_cddlg.ci.controller_type_unit, UAEDEV_CD, current_cddlg.ci.rootdir[0] != 0); + + current_cddlg.ci.controller_unit = cboCDDriveUnit->getSelected(); + + new_cddrive(unit_no); + } + + ExitEditCDDrive(); + + return dialogResult; +} \ No newline at end of file diff --git a/src/osdep/gui/EditTapeDrive.cpp b/src/osdep/gui/EditTapeDrive.cpp index f00c9ff00..238d220d1 100644 --- a/src/osdep/gui/EditTapeDrive.cpp +++ b/src/osdep/gui/EditTapeDrive.cpp @@ -46,7 +46,8 @@ class TapeDriveActionListener : public gcn::ActionListener public: void action(const gcn::ActionEvent& actionEvent) override { - if (actionEvent.getSource() == cmdTapeDriveOK) + auto source = actionEvent.getSource(); + if (source == cmdTapeDriveOK) { if (txtTapeDrivePath->getText().empty()) { @@ -56,12 +57,12 @@ class TapeDriveActionListener : public gcn::ActionListener dialogResult = true; dialogFinished = true; } - else if (actionEvent.getSource() == cmdTapeDriveCancel) + else if (source == cmdTapeDriveCancel) { dialogResult = false; dialogFinished = true; } - else if (actionEvent.getSource() == cmdTapeDriveSelectDir) + else if (source == cmdTapeDriveSelectDir) { wndEditTapeDrive->releaseModalFocus(); std::string path; @@ -82,7 +83,7 @@ class TapeDriveActionListener : public gcn::ActionListener } wndEditTapeDrive->requestModalFocus(); } - else if (actionEvent.getSource() == cmdTapeDriveSelectFile) + else if (source == cmdTapeDriveSelectFile) { wndEditTapeDrive->releaseModalFocus(); std::string path; @@ -103,14 +104,14 @@ class TapeDriveActionListener : public gcn::ActionListener } wndEditTapeDrive->requestModalFocus(); } - else if (actionEvent.getSource() == cboTapeDriveController) + else if (source == cboTapeDriveController) { auto posn = controller[cboTapeDriveController->getSelected()].type; current_tapedlg.ci.controller_type = posn % HD_CONTROLLER_NEXT_UNIT; current_tapedlg.ci.controller_type_unit = posn / HD_CONTROLLER_NEXT_UNIT; inithdcontroller(current_tapedlg.ci.controller_type, current_tapedlg.ci.controller_type_unit, UAEDEV_TAPE, current_tapedlg.ci.rootdir[0] != 0); } - else if (actionEvent.getSource() == cboTapeDriveUnit) + else if (source == cboTapeDriveUnit) { current_tapedlg.ci.controller_unit = cboTapeDriveUnit->getSelected(); } diff --git a/src/osdep/gui/PanelHD.cpp b/src/osdep/gui/PanelHD.cpp index a38767680..666d20634 100644 --- a/src/osdep/gui/PanelHD.cpp +++ b/src/osdep/gui/PanelHD.cpp @@ -16,6 +16,7 @@ #include "gui_handling.h" #include "fsdb_host.h" #include "rommgr.h" +#include "uae.h" enum { @@ -83,25 +84,19 @@ static void harddisktype(TCHAR* s, const struct uaedev_config_info* ci) } } -static int GetHDType(const int index) -{ - mountedinfo mi{}; - - auto type = get_filesys_unitconfig(&changed_prefs, index, &mi); - if (type < 0) - { - auto* uci = &changed_prefs.mountconfig[index]; - struct uaedev_config_info* ci = &uci->ci; - type = ci->type == UAEDEV_HDF || ci->type == UAEDEV_CD || ci->type == UAEDEV_TAPE ? FILESYS_HARDFILE : FILESYS_VIRTUAL; - } - return type; -} - static gcn::StringListModel cdfileList; static void RefreshCDListModel() { cdfileList.clear(); + auto cd_drives = get_cd_drives(); + if (!cd_drives.empty()) + { + for (const auto& drive : cd_drives) + { + cdfileList.add(drive); + } + } for(const auto & i : lstMRUCDList) { const std::string full_path = i; @@ -140,32 +135,44 @@ class HDEditActionListener : public gcn::ActionListener { if (actionEvent.getSource() == listCmdProps[i]) { - if (GetHDType(i) == FILESYS_VIRTUAL) + int type; + struct uaedev_config_data* uci; + struct mountedinfo mi; + + uci = &changed_prefs.mountconfig[i]; + + type = get_filesys_unitconfig(&changed_prefs, i, &mi); + if (type < 0) { - if (EditFilesysVirtual(i)) + type = uci->ci.type == UAEDEV_HDF ? FILESYS_HARDFILE : FILESYS_VIRTUAL; + } + + if (uci->ci.type == UAEDEV_CD) + { + if (EditCDDrive(i)) gui_force_rtarea_hdchange(); } - else if (GetHDType(i) == FILESYS_HARDFILE || GetHDType(i) == FILESYS_HARDFILE_RDB) + else if (uci->ci.type == UAEDEV_TAPE) { - if (EditFilesysHardfile(i)) + if (EditTapeDrive(i)) gui_force_rtarea_hdchange(); } - else if (GetHDType(i) == FILESYS_HARDDRIVE) + else if (type == FILESYS_HARDFILE || type == FILESYS_HARDFILE_RDB) { - if (EditFilesysHardDrive(i)) + if (EditFilesysHardfile(i)) gui_force_rtarea_hdchange(); } - else if (GetHDType(i) == FILESYS_CD) + else if (type == FILESYS_HARDDRIVE) { - //TODO - //if (EditCDDrive(i)) - // gui_force_rtarea_hdchange(); + if (EditFilesysHardDrive(i)) + gui_force_rtarea_hdchange(); } - else if (GetHDType(i) == FILESYS_TAPE) + else /* Filesystem */ { - if (EditTapeDrive(i)) + if (EditFilesysVirtual(i)) gui_force_rtarea_hdchange(); } + listCmdProps[i]->requestFocus(); break; } @@ -186,42 +193,38 @@ class HDAddActionListener : public gcn::ActionListener if (EditFilesysVirtual(-1)) gui_force_rtarea_hdchange(); cmdAddDirectory->requestFocus(); - RefreshPanelHD(); } else if (actionEvent.getSource() == cmdAddHardfile) { if (EditFilesysHardfile(-1)) gui_force_rtarea_hdchange(); cmdAddHardfile->requestFocus(); - RefreshPanelHD(); } else if (actionEvent.getSource() == cmdAddHardDrive) { if (EditFilesysHardDrive(-1)) gui_force_rtarea_hdchange(); cmdAddHardDrive->requestFocus(); - RefreshPanelHD(); } else if (actionEvent.getSource() == cmdAddCDDrive) { - //TODO + if (EditCDDrive(-1)) + gui_force_rtarea_hdchange(); cmdAddCDDrive->requestFocus(); - RefreshPanelHD(); } else if (actionEvent.getSource() == cmdAddTapeDrive) { if (EditTapeDrive(-1)) gui_force_rtarea_hdchange(); cmdAddTapeDrive->requestFocus(); - RefreshPanelHD(); } else if (actionEvent.getSource() == cmdCreateHardfile) { if (CreateFilesysHardfile()) gui_force_rtarea_hdchange(); cmdCreateHardfile->requestFocus(); - RefreshPanelHD(); } + RefreshPanelHD(); } }; @@ -285,6 +288,8 @@ class CDButtonActionListener : public gcn::ActionListener // Eject CD from drive //--------------------------------------- changed_prefs.cdslots[0].name[0] = 0; + changed_prefs.cdslots[0].type = SCSI_UNIT_DEFAULT; + cboCDFile->clearSelected(); AdjustDropDownControls(); } else if (actionEvent.getSource() == cmdCDSelectFile) @@ -343,21 +348,33 @@ class CDFileActionListener : public gcn::ActionListener } else { - const auto element = get_full_path_from_disk_list(cdfileList.getElementAt(idx)); - if (element != changed_prefs.cdslots[0].name) + const auto selected = cdfileList.getElementAt(idx); + // if selected starts with /dev/sr, it's a CD drive + // TODO: Check this on MacOS, it might be different there + if (selected.find("/dev/") == 0) { - strncpy(changed_prefs.cdslots[0].name, element.c_str(), MAX_DPATH); - DISK_history_add (changed_prefs.cdslots[0].name, -1, HISTORY_CD, 0); + strncpy(changed_prefs.cdslots[0].name, selected.c_str(), MAX_DPATH); changed_prefs.cdslots[0].inuse = true; - changed_prefs.cdslots[0].type = SCSI_UNIT_DEFAULT; - lstMRUCDList.erase(lstMRUCDList.begin() + idx); - lstMRUCDList.insert(lstMRUCDList.begin(), changed_prefs.cdslots[0].name); - RefreshCDListModel(); - bIgnoreListChange = true; - cboCDFile->setSelected(0); - bIgnoreListChange = false; - if (!last_loaded_config[0]) - set_last_active_config(element.c_str()); + changed_prefs.cdslots[0].type = SCSI_UNIT_IOCTL; + } + else + { + const auto element = get_full_path_from_disk_list(cdfileList.getElementAt(idx)); + if (element != changed_prefs.cdslots[0].name) + { + strncpy(changed_prefs.cdslots[0].name, element.c_str(), MAX_DPATH); + DISK_history_add(changed_prefs.cdslots[0].name, -1, HISTORY_CD, 0); + changed_prefs.cdslots[0].inuse = true; + changed_prefs.cdslots[0].type = SCSI_UNIT_DEFAULT; + lstMRUCDList.erase(lstMRUCDList.begin() + idx); + lstMRUCDList.insert(lstMRUCDList.begin(), changed_prefs.cdslots[0].name); + RefreshCDListModel(); + bIgnoreListChange = true; + cboCDFile->setSelected(0); + bIgnoreListChange = false; + if (!last_loaded_config[0]) + set_last_active_config(element.c_str()); + } } } } @@ -556,6 +573,7 @@ void InitPanelHD(const config_category& category) category.panel->add(chkCDTurbo, DISTANCE_BORDER, posY); + cboCDFile->clearSelected(); RefreshPanelHD(); } @@ -601,16 +619,21 @@ void ExitPanelHD() static void AdjustDropDownControls() { bIgnoreListChange = true; - - cboCDFile->clearSelected(); - if (changed_prefs.cdslots[0].inuse && strlen(changed_prefs.cdslots[0].name) > 0) + + if (changed_prefs.cdslots[0].inuse + && strlen(changed_prefs.cdslots[0].name) > 0 + && changed_prefs.cdslots[0].type == SCSI_UNIT_DEFAULT) { - for (auto i = 0; i < static_cast(lstMRUCDList.size()); ++i) + cboCDFile->clearSelected(); + if (changed_prefs.cdslots[0].inuse && strlen(changed_prefs.cdslots[0].name) > 0) { - if (strcmp(lstMRUCDList[i].c_str(), changed_prefs.cdslots[0].name) == 0) + for (auto i = 0; i < static_cast(lstMRUCDList.size()); ++i) { - cboCDFile->setSelected(i); - break; + if (strcmp(lstMRUCDList[i].c_str(), changed_prefs.cdslots[0].name) == 0) + { + cboCDFile->setSelected(i); + break; + } } } } diff --git a/src/osdep/gui/PanelQuickstart.cpp b/src/osdep/gui/PanelQuickstart.cpp index f7ab0d828..00a8c7ca0 100644 --- a/src/osdep/gui/PanelQuickstart.cpp +++ b/src/osdep/gui/PanelQuickstart.cpp @@ -11,6 +11,7 @@ #include "disk.h" #include "blkdev.h" #include "gui_handling.h" +#include "uae.h" static gcn::Label* lblModel; static gcn::DropDown* cboModel; @@ -314,6 +315,14 @@ static void RefreshDiskListModel() static void RefreshCDListModel() { cdfileList.clear(); + auto cd_drives = get_cd_drives(); + if (!cd_drives.empty()) + { + for (const auto& drive : cd_drives) + { + cdfileList.add(drive); + } + } for(const auto & i : lstMRUCDList) { const std::string full_path = i; @@ -344,6 +353,8 @@ class QSCDActionListener : public gcn::ActionListener // Eject CD from drive //--------------------------------------- changed_prefs.cdslots[0].name[0] = 0; + changed_prefs.cdslots[0].type = SCSI_UNIT_DEFAULT; + cboCDFile->clearSelected(); AdjustDropDownControls(); } else if (actionEvent.getSource() == cmdCDSelect) @@ -389,21 +400,32 @@ class QSCDActionListener : public gcn::ActionListener } else { - const auto element = get_full_path_from_disk_list(cdfileList.getElementAt(idx)); - if (element != changed_prefs.cdslots[0].name) + const auto selected = cdfileList.getElementAt(idx); + // if selected starts with /dev/sr, it's a CD drive + if (selected.find("/dev/") == 0) { - strncpy(changed_prefs.cdslots[0].name, element.c_str(), MAX_DPATH); - DISK_history_add(changed_prefs.cdslots[0].name, -1, HISTORY_CD, 0); + strncpy(changed_prefs.cdslots[0].name, selected.c_str(), MAX_DPATH); changed_prefs.cdslots[0].inuse = true; - changed_prefs.cdslots[0].type = SCSI_UNIT_DEFAULT; - lstMRUCDList.erase(lstMRUCDList.begin() + idx); - lstMRUCDList.insert(lstMRUCDList.begin(), changed_prefs.cdslots[0].name); - RefreshCDListModel(); - bIgnoreListChange = true; - cboCDFile->setSelected(0); - bIgnoreListChange = false; - if (!last_loaded_config[0]) - set_last_active_config(element.c_str()); + changed_prefs.cdslots[0].type = SCSI_UNIT_IOCTL; + } + else + { + const auto element = get_full_path_from_disk_list(selected); + if (element != changed_prefs.cdslots[0].name) + { + strncpy(changed_prefs.cdslots[0].name, element.c_str(), MAX_DPATH); + DISK_history_add(changed_prefs.cdslots[0].name, -1, HISTORY_CD, 0); + changed_prefs.cdslots[0].inuse = true; + changed_prefs.cdslots[0].type = SCSI_UNIT_DEFAULT; + lstMRUCDList.erase(lstMRUCDList.begin() + idx); + lstMRUCDList.insert(lstMRUCDList.begin(), changed_prefs.cdslots[0].name); + RefreshCDListModel(); + bIgnoreListChange = true; + cboCDFile->setSelected(0); + bIgnoreListChange = false; + if (!last_loaded_config[0]) + set_last_active_config(element.c_str()); + } } } } @@ -698,21 +720,10 @@ void InitPanelQuickstart(const config_category& category) amigaModelList.add(amodels[i].name); amigaConfigList.clear(); - diskfileList.clear(); - for(const auto & i : lstMRUDiskList) - { - const std::string full_path = i; - const std::string filename = full_path.substr(full_path.find_last_of("/\\") + 1); - diskfileList.add(std::string(filename).append(" { ").append(full_path).append(" }")); - } - cdfileList.clear(); - for(const auto & i : lstMRUCDList) - { - const std::string full_path = i; - const std::string filename = full_path.substr(full_path.find_last_of("/\\") + 1); - cdfileList.add(std::string(filename).append(" { ").append(full_path).append(" }")); - } + RefreshDiskListModel(); + RefreshCDListModel(); + RefreshWhdListModel(); quickstartActionListener = new QuickstartActionListener(); qs_diskActionListener = new QSDiskActionListener(); @@ -931,6 +942,7 @@ void InitPanelQuickstart(const config_category& category) cmdCDEject->setVisible(false); cmdCDSelect->setVisible(false); cboCDFile->setVisible(false); + cboCDFile->clearSelected(); bIgnoreListChange = false; @@ -1002,9 +1014,11 @@ static void AdjustDropDownControls() } } - cboCDFile->clearSelected(); - if (changed_prefs.cdslots[0].inuse && strlen(changed_prefs.cdslots[0].name) > 0) + if (changed_prefs.cdslots[0].inuse + && strlen(changed_prefs.cdslots[0].name) > 0 + && changed_prefs.cdslots[0].type == SCSI_UNIT_DEFAULT) { + cboCDFile->clearSelected(); for (auto i = 0; i < static_cast(lstMRUCDList.size()); ++i) { if (strcmp(lstMRUCDList[i].c_str(), changed_prefs.cdslots[0].name) == 0) diff --git a/src/osdep/gui/gui_handling.h b/src/osdep/gui/gui_handling.h index a3991a8c6..b27da9264 100644 --- a/src/osdep/gui/gui_handling.h +++ b/src/osdep/gui/gui_handling.h @@ -351,6 +351,7 @@ bool Create_Folder(const std::string& path); bool EditFilesysVirtual(int unit_no); bool EditFilesysHardfile(int unit_no); bool EditFilesysHardDrive(int unit_no); +bool EditCDDrive(int unit_no); bool EditTapeDrive(int unit_no); bool CreateFilesysHardfile(); void ShowHelp(const char* title, const std::vector& text); diff --git a/src/osdep/sysconfig.h b/src/osdep/sysconfig.h index 04f690c63..dc4e75551 100644 --- a/src/osdep/sysconfig.h +++ b/src/osdep/sysconfig.h @@ -115,7 +115,9 @@ /* vpar virtual parallel port */ #define WITH_VPAR 1 -/* #define WITH_SCSI_IOCTL */ +#ifndef __MACH__ +#define WITH_SCSI_IOCTL +#endif /* #define WITH_SCSI_SPTI */ // Sound boards support diff --git a/src/vm.cpp b/src/vm.cpp index 906e03437..053b9794b 100644 --- a/src/vm.cpp +++ b/src/vm.cpp @@ -369,7 +369,7 @@ void *uae_vm_reserve(uae_u32 size, int flags) void *uae_vm_reserve_fixed(void *want_addr, uae_u32 size, int flags) { void *address = NULL; - write_log("VM: Reserve 0x%-8x bytes at %p (fixed)\n", size, want_addr); + //write_log("VM: Reserve 0x%-8x bytes at %p (fixed)\n", size, want_addr); address = try_reserve((uintptr_t) want_addr, size, flags); if (address == NULL) { write_log("VM: Reserve 0x%-8x bytes at %p failed!\n", size, want_addr); @@ -379,15 +379,15 @@ void *uae_vm_reserve_fixed(void *want_addr, uae_u32 size, int flags) do_free(address, size); return NULL; } - write_log("VM: Reserve 0x%-8x bytes, got address 0x%llx\n", - size, (uae_u64) (uintptr_t) address); + // write_log("VM: Reserve 0x%-8x bytes, got address 0x%llx\n", + // size, (uae_u64) (uintptr_t) address); return address; } void *uae_vm_commit(void *address, uae_u32 size, int protect) { - write_log("VM: Commit 0x%-8x bytes at %p (%s)\n", - size, address, protect_description(protect)); + // write_log("VM: Commit 0x%-8x bytes at %p (%s)\n", + // size, address, protect_description(protect)); #ifdef _WIN32 int va_type = MEM_COMMIT ; int va_protect = protect_to_native(protect); @@ -404,7 +404,7 @@ void *uae_vm_commit(void *address, uae_u32 size, int protect) bool uae_vm_decommit(void *address, uae_u32 size) { - write_log("VM: Decommit 0x%-8x bytes at %p\n", size, address); + //write_log("VM: Decommit 0x%-8x bytes at %p\n", size, address); #ifdef _WIN32 return VirtualFree (address, size, MEM_DECOMMIT) != 0; #else