/* * UAE - The Un*x Amiga Emulator * * Hardfile emulation * * Copyright 1995 Bernd Schmidt * 2002 Toni Wilen (scsi emulation, 64-bit support) */ #include "sysconfig.h" #include "sysdeps.h" #include "threaddep/thread.h" #include "options.h" #include "memory.h" #include "custom.h" #include "newcpu.h" #include "disk.h" #include "autoconf.h" #include "traps.h" #include "filesys.h" #include "execlib.h" #include "native2amiga.h" #include "gui.h" #include "uae.h" #include "sleep.h" #define CMD_INVALID 0 #define CMD_RESET 1 #define CMD_READ 2 #define CMD_WRITE 3 #define CMD_UPDATE 4 #define CMD_CLEAR 5 #define CMD_STOP 6 #define CMD_START 7 #define CMD_FLUSH 8 #define CMD_MOTOR 9 #define CMD_SEEK 10 #define CMD_FORMAT 11 #define CMD_REMOVE 12 #define CMD_CHANGENUM 13 #define CMD_CHANGESTATE 14 #define CMD_PROTSTATUS 15 #define CMD_GETDRIVETYPE 18 #define CMD_GETNUMTRACKS 19 #define CMD_ADDCHANGEINT 20 #define CMD_REMCHANGEINT 21 #define CMD_GETGEOMETRY 22 #define HD_SCSICMD 28 /* Trackdisk64 support */ #define TD_READ64 24 #define TD_WRITE64 25 #define TD_SEEK64 26 #define TD_FORMAT64 27 /* New Style Devices (NSD) support */ #define DRIVE_NEWSTYLE 0x4E535459L /* 'NSTY' */ #define NSCMD_DEVICEQUERY 0x4000 #define NSCMD_TD_READ64 0xc000 #define NSCMD_TD_WRITE64 0xc001 #define NSCMD_TD_SEEK64 0xc002 #define NSCMD_TD_FORMAT64 0xc003 #undef DEBUGME //#define DEBUGME #ifdef DEBUGME #define hf_log write_log #define hf_log2 write_log #define scsi_log write_log #else # ifdef __GCC__ # define hf_log(x...) do { ; } while (0) # define hf_log2(x...) do { ; } while (0) # define scsi_log(x...) do { ; } while (0) # else /* C99 vararg macros */ # define hf_log(x,...) do { ; } while (0) # define hf_log2(x,...) do { ; } while (0) # define scsi_log(x,...) do { ; } while (0) # endif #endif #define MAX_ASYNC_REQUESTS 50 #define ASYNC_REQUEST_NONE 0 #define ASYNC_REQUEST_TEMP 1 #define ASYNC_REQUEST_CHANGEINT 10 struct hardfileprivdata { volatile uaecptr d_request[MAX_ASYNC_REQUESTS]; volatile int d_request_type[MAX_ASYNC_REQUESTS]; volatile uae_u32 d_request_data[MAX_ASYNC_REQUESTS]; smp_comm_pipe requests; uae_thread_id tid; int thread_running; uae_sem_t sync_sem; int opencount; }; static uae_sem_t change_sem; static struct hardfileprivdata hardfpd[MAX_FILESYSTEM_UNITS]; static uae_u32 nscmd_cmd; static void wl (uae_u8 *p, int v) { p[0] = v >> 24; p[1] = v >> 16; p[2] = v >> 8; p[3] = v; } static int rl (uae_u8 *p) { return (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | (p[3]); } static uae_u64 cmd_read (struct hardfiledata *hfd, uaecptr dataptr, uae_u64 offset, uae_u64 len) { addrbank *bank_data = &get_mem_bank (dataptr); gui_hd_led (1); hf_log2 ("cmd_read: %p %04.4x-%08.8x %08.8x\n", dataptr, (uae_u32)(offset >> 32), (uae_u32)offset, (uae_u32)len); if (!bank_data || !bank_data->check (dataptr, len)) return 0; return hdf_read (hfd, bank_data->xlateaddr (dataptr), offset, len); } static uae_u64 cmd_write (struct hardfiledata *hfd, uaecptr dataptr, uae_u64 offset, uae_u64 len) { addrbank *bank_data = &get_mem_bank (dataptr); gui_hd_led (1); hf_log2 ("cmd_write: %p %04.4x-%08.8x %08.8x\n", dataptr, (uae_u32)(offset >> 32), (uae_u32)offset, (uae_u32)len); if (!bank_data || !bank_data->check (dataptr, len)) return 0; return hdf_write (hfd, bank_data->xlateaddr (dataptr), offset, len); } static int handle_scsi (uaecptr request, struct hardfiledata *hfd) { uae_u32 acmd = get_long (request + 40); uaecptr scsi_data = get_long (acmd + 0); uae_u32 scsi_len = get_long (acmd + 4); uaecptr scsi_cmd = get_long (acmd + 12); uae_u16 scsi_cmd_len = get_word (acmd + 16); uae_u8 scsi_flags = get_byte (acmd + 20); uaecptr scsi_sense = get_long (acmd + 22); uae_u16 scsi_sense_len = get_word (acmd + 26); uae_u8 cmd = get_byte (scsi_cmd); uae_u8 cmdbuf[256]; int status, ret = 0, lr, ls; uae_u32 i; uae_u8 r[256], s[256]; uae_u64 len, offset; scsi_sense_len = (scsi_flags & 4) ? 4 : /* SCSIF_OLDAUTOSENSE */ (scsi_flags & 2) ? scsi_sense_len : /* SCSIF_AUTOSENSE */ 32; status = 0; memset (r, 0, sizeof (r)); lr = 0; ls = 0; scsi_log ("hdf scsiemu: cmd=%02.2X,%d flags=%02.2X sense=%p,%d data=%p,%d\n", cmd, scsi_cmd_len, scsi_flags, scsi_sense, scsi_sense_len, scsi_data, scsi_len); for (i = 0; i < scsi_cmd_len; i++) { cmdbuf[i] = get_byte (scsi_cmd + i); scsi_log ("%02.2X%c", get_byte (scsi_cmd + i), i < scsi_cmd_len - 1 ? '.' : ' '); } scsi_log ("\n"); switch (cmd) { case 0x00: /* TEST UNIT READY */ break; case 0x08: /* READ (6) */ offset = ((cmdbuf[1] & 31) << 16) | (cmdbuf[2] << 8) | cmdbuf[3]; offset *= hfd->blocksize; len = cmdbuf[4]; if (!len) len = 256; len *= hfd->blocksize; scsi_len = (uae_u32)cmd_read (hfd, scsi_data, offset, len); break; case 0x0a: /* WRITE (6) */ offset = ((cmdbuf[1] & 31) << 16) | (cmdbuf[2] << 8) | cmdbuf[3]; offset *= hfd->blocksize; len = cmdbuf[4]; if (!len) len = 256; len *= hfd->blocksize; scsi_len = (uae_u32)cmd_write (hfd, scsi_data, offset, len); break; case 0x12: /* INQUIRY */ len = cmdbuf[4]; r[2] = 2; /* supports SCSI-2 */ r[3] = 2; /* response data format */ r[4] = 32; /* additional length */ r[7] = 0x20; /* 16 bit bus */ i = 0; /* vendor id */ while (i < 8 && hfd->vendor_id[i]) { r[8 + i] = hfd->vendor_id[i]; i++; } while (i < 8) { r[8 + i] = 32; i++; } i = 0; /* product id */ while (i < 16 && hfd->product_id[i]) { r[16 + i] = hfd->product_id[i]; i++; } while (i < 16) { r[16 + i] = 32; i++; } i = 0; /* product revision */ while (i < 4 && hfd->product_rev[i]) { r[32 + i] = hfd->product_rev[i]; i++; } while (i < 4) { r[32 + i] = 32; i++; } scsi_len = lr = len < 36 ? (uae_u32)len : 36; break; case 0x25: /* READ_CAPACITY */ wl (r, (uae_u32)(hfd->size / hfd->blocksize - 1)); wl (r + 4, hfd->blocksize); scsi_len = lr = 8; break; case 0x28: /* READ (10) */ offset = rl (cmdbuf + 2); offset *= hfd->blocksize; len = rl (cmdbuf + 7 - 2) & 0xffff; len *= hfd->blocksize; scsi_len = (uae_u32)cmd_read (hfd, scsi_data, offset, len); break; case 0x2a: /* WRITE (10) */ offset = rl (cmdbuf + 2); offset *= hfd->blocksize; len = rl (cmdbuf + 7 - 2) & 0xffff; len *= hfd->blocksize; scsi_len = (uae_u32)cmd_write (hfd, scsi_data, offset, len); break; case 0xa8: /* READ (12) */ offset = rl (cmdbuf + 2); offset *= hfd->blocksize; len = rl (cmdbuf + 6); len *= hfd->blocksize; scsi_len = (uae_u32)cmd_read (hfd, scsi_data, offset, len); break; case 0xaa: /* WRITE (12) */ offset = rl (cmdbuf + 2); offset *= hfd->blocksize; len = rl (cmdbuf + 6); len *= hfd->blocksize; scsi_len = (uae_u32)cmd_write (hfd, scsi_data, offset, len); break; case 0x37: /* READ DEFECT DATA */ write_log ("UAEHF: READ DEFECT DATA\n"); status = 2; /* CHECK CONDITION */ s[0] = 0x70; s[2] = 0; /* NO SENSE */ s[12] = 0x1c; /* DEFECT LIST NOT FOUND */ ls = 12; break; default: lr = -1; write_log ("UAEHF: unsupported scsi command 0x%02.2X\n", cmd); status = 2; /* CHECK CONDITION */ s[0] = 0x70; s[2] = 5; /* ILLEGAL REQUEST */ s[12] = 0x24; /* ILLEGAL FIELD IN CDB */ ls = 12; break; } put_word (acmd + 18, status != 0 ? 0 : scsi_cmd_len); /* fake scsi_CmdActual */ put_byte (acmd + 21, status); /* scsi_Status */ if (lr > 0) { scsi_log ("RD:"); i = 0; while ((int)i < lr && i < scsi_len) { if (i < 24) scsi_log ("%02.2X%c", r[i], i < scsi_len - 1 ? '.' : ' '); put_byte (scsi_data + i, r[i]); i++; } scsi_log ("\n"); } i = 0; if (ls > 0 && scsi_sense) { while ((int)i < ls && i < scsi_sense_len) { put_byte (scsi_sense + i, s[i]); i++; } } while (i < scsi_sense_len && scsi_sense) { put_byte (scsi_sense + i, 0); i++; } if (lr < 0) { put_long (acmd + 8, 0); /* scsi_Actual */ ret = 20; } else { put_long (acmd + 8, scsi_len); /* scsi_Actual */ } return ret; } static int add_async_request (struct hardfileprivdata *hfpd, uaecptr request, int type, uae_u32 data) { int i; i = 0; while (i < MAX_ASYNC_REQUESTS) { if (hfpd->d_request[i] == request) { hfpd->d_request_type[i] = type; hfpd->d_request_data[i] = data; hf_log ("old async request %p (%d) added\n", request, type); return 0; } i++; } i = 0; while (i < MAX_ASYNC_REQUESTS) { if (hfpd->d_request[i] == 0) { hfpd->d_request[i] = request; hfpd->d_request_type[i] = type; hfpd->d_request_data[i] = data; hf_log ("async request %p (%d) added (total=%d)\n", request, type, i); return 0; } i++; } hf_log ("async request overflow %p!\n", request); return -1; } static int release_async_request (struct hardfileprivdata *hfpd, uaecptr request) { int i = 0; while (i < MAX_ASYNC_REQUESTS) { if (hfpd->d_request[i] == request) { int type = hfpd->d_request_type[i]; hfpd->d_request[i] = 0; hfpd->d_request_data[i] = 0; hfpd->d_request_type[i] = 0; hf_log ("async request %p removed\n", request); return type; } i++; } hf_log ("tried to remove non-existing request %p\n", request); return -1; } static void abort_async (struct hardfileprivdata *hfpd, uaecptr request, int errcode, int type) { int i; hf_log ("aborting async request %p\n", request); i = 0; while (i < MAX_ASYNC_REQUESTS) { if (hfpd->d_request[i] == request && hfpd->d_request_type[i] == ASYNC_REQUEST_TEMP) { /* ASYNC_REQUEST_TEMP = request is processing */ uae_msleep (1); i = 0; continue; } i++; } i = release_async_request (hfpd, request); if (i >= 0) hf_log ("asyncronous request=%08.8X aborted, error=%d\n", request, errcode); } static void *hardfile_thread (void *devs); static int start_thread (int unit) { struct hardfileprivdata *hfpd = &hardfpd[unit]; if (hfpd->thread_running) return 1; memset (hfpd, 0, sizeof (struct hardfileprivdata)); init_comm_pipe (&hfpd->requests, 100, 1); uae_sem_init (&hfpd->sync_sem, 0, 0); uae_start_thread (hardfile_thread, hfpd, &hfpd->tid); uae_sem_wait (&hfpd->sync_sem); return hfpd->thread_running; } static int mangleunit (int unit) { if (unit <= 99) return unit; if (unit == 100) return 8; if (unit == 110) return 9; return -1; } static uae_u32 REGPARAM2 hardfile_open (TrapContext *context) { uaecptr tmp1 = m68k_areg (&context->regs, 1); /* IOReq */ int unit = mangleunit (m68k_dreg (&context->regs, 0)); struct hardfileprivdata *hfpd = &hardfpd[unit]; int err = -1; /* Check unit number */ if (unit >= 0 && get_hardfile_data (unit) && start_thread (unit)) { hfpd->opencount++; put_word (m68k_areg(&context->regs, 6) + 32, get_word (m68k_areg(&context->regs, 6) + 32) + 1); put_long (tmp1 + 24, unit); /* io_Unit */ put_byte (tmp1 + 31, 0); /* io_Error */ put_byte (tmp1 + 8, 7); /* ln_type = NT_REPLYMSG */ hf_log ("hardfile_open, unit %d (%d), OK\n", unit, m68k_dreg (&context->regs, 0)); return 0; } if (is_hardfile(NULL, unit) == FILESYS_VIRTUAL) err = -6; hf_log ("hardfile_open, unit %d (%d), ERR=%d\n", unit, m68k_dreg (&context->regs, 0), err); put_long (tmp1 + 20, (uae_u32)err); put_byte (tmp1 + 31, (uae_u8)err); return (uae_u32)err; } static uae_u32 REGPARAM2 hardfile_close (TrapContext *context) { uaecptr request = m68k_areg (&context->regs, 1); /* IOReq */ int unit = mangleunit (get_long (request + 24)); struct hardfileprivdata *hfpd = &hardfpd[unit]; if (!hfpd->opencount) return 0; hfpd->opencount--; if (hfpd->opencount == 0) write_comm_pipe_u32 (&hfpd->requests, 0, 1); put_word (m68k_areg (&context->regs, 6) + 32, get_word (m68k_areg (&context->regs, 6) + 32) - 1); return 0; } static uae_u32 REGPARAM2 hardfile_expunge (TrapContext *context) { return 0; /* Simply ignore this one... */ } static void getchs2 (struct hardfiledata *hfd, int *cyl, int *cylsec, int *head, int *tracksec) { unsigned int total = (unsigned int)(hfd->size / 1024); int heads; int sectors = 63; /* do we have RDB values? */ if (hfd->cylinders) { *cyl = hfd->cylinders; *tracksec = hfd->sectors; *head = hfd->heads; *cylsec = hfd->sectors * hfd->heads; return; } /* what about HDF settings? */ if (hfd->surfaces && hfd->secspertrack) { *head = hfd->surfaces; *tracksec = hfd->secspertrack; *cylsec = (*head) * (*tracksec); *cyl = (unsigned int)(hfd->size / hfd->blocksize) / ((*tracksec) * (*head)); return; } /* no, lets guess something.. */ if (total <= 504 * 1024) heads = 16; else if (total <= 1008 * 1024) heads = 32; else if (total <= 2016 * 1024) heads = 64; else if (total <= 4032 * 1024) heads = 128; else heads = 255; *cyl = (unsigned int)(hfd->size / hfd->blocksize) / (sectors * heads); *cylsec = sectors * heads; *tracksec = sectors; *head = heads; } static void getchs (struct hardfiledata *hfd, int *cyl, int *cylsec, int *head, int *tracksec) { getchs2 (hfd, cyl, cylsec, head, tracksec); hf_log ("CHS: %08.8X-%08.8X %d %d %d %d %d\n", (uae_u32)(hfd->size >> 32),(uae_u32)hfd->size, *cyl, *cylsec, *head, *tracksec); } static void outofbounds (int cmd, uae_u64 offset, uae_u64 len, uae_u64 max) { write_log ("UAEHF: cmd %d: out of bounds, %08.8X-%08.8X + %08.8X-%08.8X > %08.8X-%08.8X\n", cmd, (uae_u32)(offset >> 32),(uae_u32)offset,(uae_u32)(len >> 32),(uae_u32)len, (uae_u32)(max >> 32),(uae_u32)max); } static void unaligned (int cmd, uae_u64 offset, uae_u64 len, int blocksize) { write_log ("UAEHF: cmd %d: unaligned access, %08.8X-%08.8X, %08.8X-%08.8X, %08.8X\n", cmd, (uae_u32)(offset >> 32),(uae_u32)offset,(uae_u32)(len >> 32),(uae_u32)len, blocksize); } static uae_u32 hardfile_do_io (struct hardfiledata *hfd, struct hardfileprivdata *hfpd, uaecptr request) { uae_u32 dataptr, offset, actual = 0, cmd; uae_u64 offset64; int unit = get_long (request + 24); uae_u32 error = 0, len; int async = 0; int bmask = hfd->blocksize - 1; cmd = get_word (request + 28); /* io_Command */ dataptr = get_long (request + 40); switch (cmd) { case CMD_READ: offset = get_long (request + 44); len = get_long (request + 36); /* io_Length */ if ((offset & bmask) || (len & bmask)) { unaligned (cmd, offset, len, hfd->blocksize); goto bad_command; } if (len + offset > hfd->size) { outofbounds (cmd, offset, len, hfd->size); goto bad_command; } actual = (uae_u32)cmd_read (hfd, dataptr, offset, len); break; case TD_READ64: case NSCMD_TD_READ64: offset64 = get_long (request + 44) | ((uae_u64)get_long (request + 32) << 32); len = get_long (request + 36); /* io_Length */ if ((offset64 & bmask) || (len & bmask)) { unaligned (cmd, offset64, len, hfd->blocksize); goto bad_command; } if (len + offset64 > hfd->size) { outofbounds (cmd, offset64, len, hfd->size); goto bad_command; } actual = (uae_u32)cmd_read (hfd, dataptr, offset64, len); break; case CMD_WRITE: case CMD_FORMAT: /* Format */ if (hfd->readonly) { error = 28; /* write protect */ } else { offset = get_long (request + 44); len = get_long (request + 36); /* io_Length */ if ((offset & bmask) || (len & bmask)) { unaligned (cmd, offset, len, hfd->blocksize); goto bad_command; } if (len + offset > hfd->size) { outofbounds (cmd, offset, len, hfd->size); goto bad_command; } actual = (uae_u32)cmd_write (hfd, dataptr, offset, len); } break; case TD_WRITE64: case TD_FORMAT64: case NSCMD_TD_WRITE64: case NSCMD_TD_FORMAT64: if (hfd->readonly) { error = 28; /* write protect */ } else { offset64 = get_long (request + 44) | ((uae_u64)get_long (request + 32) << 32); len = get_long (request + 36); /* io_Length */ if ((offset64 & bmask) || (len & bmask)) { unaligned (cmd, offset64, len, hfd->blocksize); goto bad_command; } if (len + offset64 > hfd->size) { outofbounds (cmd, offset64, len, hfd->size); goto bad_command; } put_long (request + 32, (uae_u32)cmd_write (hfd, dataptr, offset64, len)); } break; bad_command: error = -5; /* IOERR_BADADDRESS */ break; case NSCMD_DEVICEQUERY: put_long (dataptr + 4, 16); /* size */ put_word (dataptr + 8, 5); /* NSDEVTYPE_TRACKDISK */ put_word (dataptr + 10, 0); put_long (dataptr + 12, nscmd_cmd); actual = 16; break; case CMD_GETDRIVETYPE: actual = DRIVE_NEWSTYLE; break; case CMD_GETNUMTRACKS: { int cyl, cylsec, head, tracksec; getchs (hfd, &cyl, &cylsec, &head, &tracksec); actual = cyl * head; break; } case CMD_GETGEOMETRY: { int cyl, cylsec, head, tracksec; getchs (hfd, &cyl, &cylsec, &head, &tracksec); put_long (dataptr + 0, hfd->blocksize); put_long (dataptr + 4, (uae_u32)(hfd->size / hfd->blocksize)); put_long (dataptr + 8, cyl); put_long (dataptr + 12, cylsec); put_long (dataptr + 16, head); put_long (dataptr + 20, tracksec); put_long (dataptr + 24, 0); /* bufmemtype */ put_byte (dataptr + 28, 0); /* type = DG_DIRECT_ACCESS */ put_byte (dataptr + 29, 0); /* flags */ } break; case CMD_PROTSTATUS: if (hfd->readonly) actual = -1; else actual = 0; break; case CMD_CHANGESTATE: actual = 0; break; /* Some commands that just do nothing and return zero */ case CMD_UPDATE: case CMD_CLEAR: case CMD_MOTOR: case CMD_SEEK: case CMD_CHANGENUM: case TD_SEEK64: case NSCMD_TD_SEEK64: break; case CMD_REMOVE: break; case CMD_ADDCHANGEINT: error = add_async_request (hfpd, request, ASYNC_REQUEST_CHANGEINT, get_long (request + 40)); if (!error) async = 1; break; case CMD_REMCHANGEINT: release_async_request (hfpd, request); break; case HD_SCSICMD: /* SCSI */ if (hfd->nrcyls == 0) { error = handle_scsi (request, hfd); } else { /* we don't want users trashing their "partition" hardfiles with hdtoolbox */ error = -3; /* IOERR_NOCMD */ write_log ("UAEHF: HD_SCSICMD tried on regular HDF, unit %d", unit); } break; default: /* Command not understood. */ error = -3; /* IOERR_NOCMD */ break; } put_long (request + 32, actual); put_byte (request + 31, error); hf_log2 ("hf: unit=%d, request=%p, cmd=%d offset=%u len=%d, actual=%d error%=%d\n", unit, request, get_word(request + 28), get_long (request + 44), get_long (request + 36), actual, error); return async; } static uae_u32 REGPARAM2 hardfile_abortio (TrapContext *context) { uae_u32 request = m68k_areg (&context->regs, 1); int unit = mangleunit (get_long (request + 24)); struct hardfiledata *hfd = get_hardfile_data (unit); struct hardfileprivdata *hfpd = &hardfpd[unit]; hf_log2 ("uaehf.device abortio "); if (!hfd) { put_byte (request + 31, 32); hf_log2 ("error\n"); return get_byte (request + 31); } put_byte (request + 31, -2); hf_log2 ("unit=%d, request=%08.8X\n", unit, request); abort_async (hfpd, request, -2, 0); return 0; } static int hardfile_can_quick (uae_u32 command) { switch (command) { case CMD_RESET: case CMD_STOP: case CMD_START: case CMD_CHANGESTATE: case CMD_PROTSTATUS: case CMD_MOTOR: case CMD_GETDRIVETYPE: case CMD_GETNUMTRACKS: case CMD_GETGEOMETRY: case NSCMD_DEVICEQUERY: return 1; } return 0; } static int hardfile_canquick (struct hardfiledata *hfd, uaecptr request) { uae_u32 command = get_word (request + 28); return hardfile_can_quick (command); } static uae_u32 REGPARAM2 hardfile_beginio (TrapContext *context) { uae_u32 request = m68k_areg (&context->regs, 1); uae_u8 flags = get_byte (request + 30); int cmd = get_word (request + 28); int unit = mangleunit (get_long (request + 24)); struct hardfiledata *hfd = get_hardfile_data (unit); struct hardfileprivdata *hfpd = &hardfpd[unit]; put_byte (request + 8, NT_MESSAGE); if (!hfd) { put_byte (request + 31, 32); return get_byte (request + 31); } put_byte (request + 31, 0); if ((flags & 1) && hardfile_canquick (hfd, request)) { hf_log ("hf quickio unit=%d request=%p cmd=%d\n", unit, request, cmd); if (hardfile_do_io (hfd, hfpd, request)) hf_log2 ("uaehf.device cmd %d bug with IO_QUICK\n", cmd); return get_byte (request + 31); } else { hf_log2 ("hf asyncio unit=%d request=%p cmd=%d\n", unit, request, cmd); add_async_request (hfpd, request, ASYNC_REQUEST_TEMP, 0); put_byte (request + 30, get_byte (request + 30) & ~1); write_comm_pipe_u32 (&hfpd->requests, request, 1); return 0; } } static void *hardfile_thread (void *devs) { struct hardfileprivdata *hfpd = devs; uae_set_thread_priority (2); hfpd->thread_running = 1; uae_sem_post (&hfpd->sync_sem); for (;;) { uaecptr request = (uaecptr)read_comm_pipe_u32_blocking (&hfpd->requests); uae_sem_wait (&change_sem); if (!request) { hfpd->thread_running = 0; uae_sem_post (&hfpd->sync_sem); uae_sem_post (&change_sem); return 0; } else if (hardfile_do_io (get_hardfile_data (hfpd - &hardfpd[0]), hfpd, request) == 0) { put_byte (request + 30, get_byte (request + 30) & ~1); release_async_request (hfpd, request); uae_ReplyMsg (request); } else { hf_log2 ("async request %08.8X\n", request); } uae_sem_post (&change_sem); } } void hardfile_reset (void) { int i, j; struct hardfileprivdata *hfpd; for (i = 0; i < MAX_FILESYSTEM_UNITS; i++) { hfpd = &hardfpd[i]; if (hfpd->opencount > 0) { for (j = 0; j < MAX_ASYNC_REQUESTS; j++) { uaecptr request; if ((request = hfpd->d_request[i])) abort_async (hfpd, request, 0, 0); } } memset (hfpd, 0, sizeof (struct hardfileprivdata)); } } void hardfile_install (void) { uae_u32 functable, datatable; uae_u32 initcode, openfunc, closefunc, expungefunc; uae_u32 beginiofunc, abortiofunc; uae_sem_init (&change_sem, 0, 1); ROM_hardfile_resname = ds ("uaehf.device"); ROM_hardfile_resid = ds ("UAE hardfile.device 0.2"); nscmd_cmd = here (); dw (NSCMD_DEVICEQUERY); dw (CMD_RESET); dw (CMD_READ); dw (CMD_WRITE); dw (CMD_UPDATE); dw (CMD_CLEAR); dw (CMD_START); dw (CMD_STOP); dw (CMD_FLUSH); dw (CMD_MOTOR); dw (CMD_SEEK); dw (CMD_FORMAT); dw (CMD_REMOVE); dw (CMD_CHANGENUM); dw (CMD_CHANGESTATE); dw (CMD_PROTSTATUS); dw (CMD_GETDRIVETYPE); dw (CMD_GETGEOMETRY); dw (CMD_ADDCHANGEINT); dw (CMD_REMCHANGEINT); dw (HD_SCSICMD); dw (NSCMD_TD_READ64); dw (NSCMD_TD_WRITE64); dw (NSCMD_TD_SEEK64); dw (NSCMD_TD_FORMAT64); dw (0); /* initcode */ #if 0 initcode = here (); calltrap (deftrap (hardfile_init)); dw (RTS); #else initcode = filesys_initcode; #endif /* Open */ openfunc = here (); calltrap (deftrap (hardfile_open)); dw (RTS); /* Close */ closefunc = here (); calltrap (deftrap (hardfile_close)); dw (RTS); /* Expunge */ expungefunc = here (); calltrap (deftrap (hardfile_expunge)); dw (RTS); /* BeginIO */ beginiofunc = here (); calltrap (deftrap (hardfile_beginio)); dw (RTS); /* AbortIO */ abortiofunc = here (); calltrap (deftrap (hardfile_abortio)); dw (RTS); /* FuncTable */ functable = here (); dl (openfunc); /* Open */ dl (closefunc); /* Close */ dl (expungefunc); /* Expunge */ dl (EXPANSION_nullfunc); /* Null */ dl (beginiofunc); /* BeginIO */ dl (abortiofunc); /* AbortIO */ dl (0xFFFFFFFFul); /* end of table */ /* DataTable */ datatable = here (); dw (0xE000); /* INITBYTE */ dw (0x0008); /* LN_TYPE */ dw (0x0300); /* NT_DEVICE */ dw (0xC000); /* INITLONG */ dw (0x000A); /* LN_NAME */ dl (ROM_hardfile_resname); dw (0xE000); /* INITBYTE */ dw (0x000E); /* LIB_FLAGS */ dw (0x0600); /* LIBF_SUMUSED | LIBF_CHANGED */ dw (0xD000); /* INITWORD */ dw (0x0014); /* LIB_VERSION */ dw (0x0004); /* 0.4 */ dw (0xD000); dw (0x0016); /* LIB_REVISION */ dw (0x0000); dw (0xC000); dw (0x0018); /* LIB_IDSTRING */ dl (ROM_hardfile_resid); dw (0x0000); /* end of table */ ROM_hardfile_init = here (); dl (0x00000100); /* ??? */ dl (functable); dl (datatable); dl (initcode); }