static uae_u8 *execscsicmd_out_ioctl (int unitnum, uae_u8 *cmd_data, int cmd_len) { struct scsidevdata *sdd; struct cdrom_generic_command cmd; int io_error; DEBUG_LOG ("SCSIDEV: unit = %d, execscsicmd_out_ioctl\n", unitnum); if (unitnum >= total_drives) { DEBUG_LOG ("SCSIDEV: illegal unit %d >= total_drives %d.\n", unitnum, total_drives); return 0; } sdd = &drives[unitnum]; if (cmd_len > CDROM_PACKET_SIZE) { DEBUG_LOG ("SCSIDEV: cmd_len too large (%d)\n", cmd_len); return 0; } memcpy (cmd.cmd, cmd_data, cmd_len); cmd.buffer = 0; cmd.buflen = 0; cmd.stat = 0; cmd.sense = 0; cmd.data_direction = CGC_DATA_WRITE; cmd.quiet = 0; cmd.timeout = 80*60; gui_flicker_led (LED_CD, 0, 1); io_error = ioctl (sdd->fd, CDROM_SEND_PACKET, &cmd); DEBUG_LOG ("SCSIDEV: error: %d, stat: %d\n", io_error, cmd.stat); if (io_error != 0) { DEBUG_LOG ("SCSIDEV: errno: %d, %s\n", errno, strerror (errno)); return 0; } return cmd_data; }
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; 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); }
static uae_u8 cdtvcr_battram_read (int addr) { uae_u8 v; int offset; offset = addr & CDTVCR_RAM_MASK; if (offset >= CDTVCR_RAM_SIZE) return 0; gui_flicker_led (LED_MD, 0, 1); v = cdtvcr_ram[offset]; return v; }
static int doscsi (struct dev_info_spti *di, int unitnum, SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER *swb, int *err) { DWORD status, returned; *err = 0; if (log_scsi) { write_log (L"SCSI, H=%X:%d:%d:%d:%d: ", di->handle, di->bus, di->path, di->target, di->lun); scsi_log_before (swb->spt.Cdb, swb->spt.CdbLength, swb->spt.DataIn == SCSI_IOCTL_DATA_OUT ? (uae_u8*)swb->spt.DataBuffer : NULL, swb->spt.DataTransferLength); } gui_flicker_led (LED_CD, unitnum, 1); swb->spt.ScsiStatus = 0; if (di->bus >= 0) { swb->spt.PathId = di->path; swb->spt.TargetId = di->target; swb->spt.Lun = di->lun; } status = DeviceIoControl (di->handle, IOCTL_SCSI_PASS_THROUGH_DIRECT, swb, sizeof (SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER), swb, sizeof (SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER), &returned, NULL); if (!status) { int lasterror = GetLastError(); *err = lasterror; write_log (L"SCSI ERROR, H=%X:%d:%d:%d:%d: ", di->handle, di->bus, di->path, di->target, di->lun); write_log (L"Status = %d, Error code = %d, LastError=%d\n", status, swb->spt.ScsiStatus, lasterror); scsi_log_before (swb->spt.Cdb, swb->spt.CdbLength, swb->spt.DataIn == SCSI_IOCTL_DATA_OUT ? (uae_u8*)swb->spt.DataBuffer : 0,swb->spt.DataTransferLength); } if (log_scsi) scsi_log_after (swb->spt.DataIn == SCSI_IOCTL_DATA_IN ? (uae_u8*)swb->spt.DataBuffer : NULL, swb->spt.DataTransferLength, swb->SenseBuf, swb->spt.SenseInfoLength); if (swb->spt.SenseInfoLength > 0 && (swb->SenseBuf[0] == 0 || swb->SenseBuf[0] == 1)) swb->spt.SenseInfoLength = 0; /* 0 and 1 = success, not error.. */ if (swb->spt.SenseInfoLength > 0) return 0; gui_flicker_led (LED_CD, unitnum, 1); return status; }
static int execscsicmd (int unitnum, const uae_u8 *data, int len, uae_u8 *inbuf, int inlen) { int sactual = 0; struct scsidevdata *sdd = &drives[unitnum]; SCSI *scgp = sdd->scgp; struct scg_cmd *scmd; scmd = scgp->scmd; DEBUG_LOG ("SCSIDEV: execscicmd data=%08lx len=%d, inbuf=%08lx"\ " inlen=%d\n", data, len, inbuf, inlen); uae_sem_wait (&scgp_sem); memset (scmd, 0, sizeof (*scmd)); scmd->timeout = 80 * 60; if (inbuf) { scmd->addr = (caddr_t) inbuf; scmd->size = inlen; scmd->flags = SCG_RECV_DATA; memset (inbuf, 0, inlen); } else { scmd->flags = SCG_DISRE_ENA; } scmd->cdb_len = len; memcpy (&scmd->cdb, data, len); scmd->target = sdd->target; scmd->sense_len = -1; scmd->sense_count = 0; *(uae_u8 *)&scmd->scb = 0; scg_settarget (scgp, sdd->bus, sdd->target, sdd->lun); scgp->cmdname = "???"; scgp->curcmdname = "???"; DEBUG_LOG ("SCSIDEV: sending command: 0x%2x\n", scmd->cdb.g0_cdb.cmd); gui_flicker_led (LED_CD, 0, 1); scg_cmd (scgp); uae_sem_post (&scgp_sem); DEBUG_LOG ("SCSIDEV: result: %d %d\n", scmd->error, scmd->ux_errno); return scmd->size; }
static void cdtvcr_battram_write (int addr, int v) { struct zfile *f; int offset = addr & CDTVCR_RAM_MASK; if (offset >= CDTVCR_RAM_SIZE) return; gui_flicker_led (LED_MD, 0, 2); if (cdtvcr_ram[offset] == v) return; cdtvcr_ram[offset] = v; f = zfile_fopen (currprefs.flashfile, _T("rb+"), ZFD_NORMAL); if (!f) return; zfile_fseek (f, offset, SEEK_SET); zfile_fwrite (cdtvcr_ram + offset, 1, 1, f); zfile_fclose (f); }
int32_t scsiesp_req_enqueue(SCSIRequest *req) { struct scsi_data *sd = (struct scsi_data*)req->dev->handle; if (sd->device_type == UAEDEV_CD) gui_flicker_led (LED_CD, sd->id, 1); sd->data_len = 0; scsi_start_transfer(sd); scsi_emulate_analyze(sd); #if 0 write_log (_T("%02x.%02x.%02x.%02x.%02x.%02x\n"), sd->cmd[0], sd->cmd[1], sd->cmd[2], sd->cmd[3], sd->cmd[4], sd->cmd[5]); #endif if (sd->direction <= 0) scsi_emulate_cmd(sd); if (sd->direction == 0) return 1; if (sd->direction > 0) return -sd->data_len; return sd->data_len; }
static int execscsicmd_direct (int unitnum, uaecptr acmd) { int sactual = 0; struct scsidevdata *sdd = &drives[unitnum]; SCSI *scgp = sdd->scgp; struct scg_cmd *scmd = scgp->scmd; uaecptr scsi_data = get_long (acmd + 0); uae_u32 scsi_len = get_long (acmd + 4); uaecptr scsi_cmd = get_long (acmd + 12); int scsi_cmd_len = get_word (acmd + 16); int scsi_cmd_len_orig = scsi_cmd_len; uae_u8 scsi_flags = get_byte (acmd + 20); uaecptr scsi_sense = get_long (acmd + 22); uae_u16 scsi_sense_len = get_word (acmd + 26); int io_error = 0; int parm; addrbank *bank_data = &get_mem_bank (scsi_data); addrbank *bank_cmd = &get_mem_bank (scsi_cmd); uae_u8 *scsi_datap; uae_u8 *scsi_datap_org; DEBUG_LOG ("SCSIDEV: unit=%d: execscsicmd_direct\n", unitnum); /* do transfer directly to and from Amiga memory */ if (!bank_data || !bank_data->check (scsi_data, scsi_len)) return -5; /* IOERR_BADADDRESS */ uae_sem_wait (&scgp_sem); memset (scmd, 0, sizeof (*scmd)); /* the Amiga does not tell us how long the timeout shall be, so make it * _very_ long (specified in seconds) */ scmd->timeout = 80 * 60; scsi_datap = scsi_datap_org = scsi_len ? bank_data->xlateaddr (scsi_data) : 0; scmd->size = scsi_len; scmd->flags = (scsi_flags & 1) ? SCG_RECV_DATA : SCG_DISRE_ENA; memcpy (&scmd->cdb, bank_cmd->xlateaddr (scsi_cmd), scsi_cmd_len); scmd->target = sdd->target; scmd->sense_len = (scsi_flags & 4) ? 4 : /* SCSIF_OLDAUTOSENSE */ (scsi_flags & 2) ? scsi_sense_len : /* SCSIF_AUTOSENSE */ -1; scmd->sense_count = 0; *(uae_u8 *)&scmd->scb = 0; if (sdd->isatapi) scsi_atapi_fixup_pre (scmd->cdb.cmd_cdb, &scsi_cmd_len, &scsi_datap, &scsi_len, &parm); scmd->addr = (caddr_t)scsi_datap; scmd->cdb_len = scsi_cmd_len; scg_settarget (scgp, sdd->bus, sdd->target, sdd->lun); scgp->cmdname = "???"; scgp->curcmdname = "???"; DEBUG_LOG ("SCSIDEV: sending command: 0x%2x\n", scmd->cdb.g0_cdb.cmd); scg_cmd (scgp); DEBUG_LOG ("SCSIDEV: result: %d %d %s\n", scmd->error, scmd->ux_errno,\ scgp->errstr); gui_flicker_led (LED_CD, 0, 1); put_word (acmd + 18, scmd->error == SCG_FATAL ? 0 : scsi_cmd_len); /* fake scsi_CmdActual */ put_byte (acmd + 21, *(uae_u8 *)&scmd->scb); /* scsi_Status */ if (*(uae_u8 *)&scmd->scb) { io_error = 45; /* HFERR_BadStatus */ /* copy sense? */ for (sactual = 0; scsi_sense && sactual < scsi_sense_len && sactual < scmd->sense_count; sactual++) { put_byte (scsi_sense + sactual, scmd->u_sense.cmd_sense[sactual]); } put_long (acmd + 8, 0); /* scsi_Actual */ } else { int i; for (i = 0; i < scsi_sense_len; i++) put_byte (scsi_sense + i, 0); sactual = 0; if (scmd->error != SCG_NO_ERROR || scmd->ux_errno != 0) { /* We might have been limited by the hosts DMA limits, which is usually indicated by ENOMEM */ if (scsi_len > (unsigned int)sdd->max_dma && scmd->ux_errno == ENOMEM) io_error = (uae_u8)-4; /* IOERR_BADLENGTH */ else { io_error = 20; /* io_Error, but not specified */ put_long (acmd + 8, 0); /* scsi_Actual */ } } else { scsi_len = scmd->size; if (sdd->isatapi) scsi_atapi_fixup_post (scmd->cdb.cmd_cdb, scsi_cmd_len, scsi_datap_org, scsi_datap, &scsi_len, parm); io_error = 0; put_long (acmd + 8, scsi_len); /* scsi_Actual */ } } put_word (acmd + 28, sactual); uae_sem_post (&scgp_sem); if (scsi_datap != scsi_datap_org) free (scsi_datap); return io_error; }
static int execscsicmd_direct_ioctl (int unitnum, struct amigascsi* ascsi) { struct scsidevdata *sdd; struct cdrom_generic_command cmd; struct request_sense sense; uaecptr acmd = VALUE_TO_PTR(ascsi); uaecptr scsi_data = get_long (acmd + 0); uae_u32 scsi_len = get_long (acmd + 4); uaecptr scsi_cmd = get_long (acmd + 12); int scsi_cmd_len = get_word (acmd + 16); uae_u8 scsi_flags = get_byte (acmd + 20); uae_u8 scsi_status = get_byte (acmd + 21); uaecptr scsi_sense = get_long (acmd + 22); uae_u16 scsi_sense_len = get_word (acmd + 26); int io_error; unsigned int senselen; int parm, i; addrbank *bank_data = &get_mem_bank (scsi_data); addrbank *bank_cmd = &get_mem_bank (scsi_cmd); addrbank *bank_sense = &get_mem_bank (scsi_sense); uae_u8 *scsi_datap; uae_u8 *scsi_datap_org; DEBUG_LOG ("SCSIDEV: unit = %d: execscsicmd_direct_ioctl\n", unitnum); DEBUG_LOG ("SCSIDEV: scsi_len = %d, scsi_cmd_len = %d, scsi_sense_len = %d, scsi_flags = %x\n", scsi_len, scsi_cmd_len, scsi_sense_len, scsi_flags); if (unitnum >= total_drives) { DEBUG_LOG ("SCSIDEV: illegal unit %d >= total_drives %d.\n", unitnum, total_drives); return -1; /* TODO: better error code */ } sdd = &drives[unitnum]; /* do transfer directly to and from Amiga memory */ if (!bank_data || !bank_data->check (scsi_data, scsi_len)) { DEBUG_LOG ("SCSIDEV: illegal Amiga memory buffer\n"); return -5; /* IOERR_BADADDRESS */ } if (scsi_cmd_len > CDROM_PACKET_SIZE) { DEBUG_LOG ("SCSIDEV: scsi_cmd_len too large (%d)\n", scsi_cmd_len); return -5; /* TODO: better code */ } scsi_datap = scsi_datap_org = (scsi_len ? bank_data->xlateaddr (scsi_data) : 0); memcpy (cmd.cmd, bank_cmd->xlateaddr (scsi_cmd), scsi_cmd_len); cmd.buffer = scsi_datap; cmd.buflen = scsi_len; cmd.stat = scsi_status; if (sdd->isatapi) { scsi_atapi_fixup_pre (cmd.cmd, &scsi_cmd_len, &scsi_datap, &scsi_len, &parm); } senselen = (scsi_flags & 4) ? 4 : /* SCSIF_OLDAUTOSENSE */ (scsi_flags & 2) ? scsi_sense_len : /* SCSIF_AUTOSENSE */ 0; cmd.sense = senselen > 0 ? &sense : 0; cmd.data_direction = (scsi_flags & 1) ? CGC_DATA_READ : CGC_DATA_WRITE; cmd.quiet = 0; cmd.timeout = 80*60; gui_flicker_led (LED_CD, 0, 1); io_error = ioctl (sdd->fd, CDROM_SEND_PACKET, &cmd); DEBUG_LOG ("SCSIDEV: error: %d, stat: %d\n", io_error, cmd.stat); if (cmd.stat != 0) { unsigned int n; io_error = 45; /* HFERR_BadStatus */ put_byte (acmd + 8, 0); put_byte (acmd + 18, 0 /*scsi_cmd_len */); put_byte (acmd + 21, cmd.stat); DEBUG_LOG ("SCSIDEV: bad status\n"); n = cmd.sense ? cmd.sense->add_sense_len + 7 : 0; if (senselen > n) { if (scsi_sense) memset (bank_sense->xlateaddr (scsi_sense), 0, senselen); senselen = n; } DEBUG_LOG ("SCSIDEV: senselen = %d\n", senselen); if (scsi_sense && cmd.sense && senselen > 0) { memcpy (bank_sense->xlateaddr (scsi_sense), cmd.sense, senselen); } put_byte (acmd + 28, senselen); } else { put_byte (acmd + 28, 0); if (scsi_sense && senselen > 0) { memset (bank_sense->xlateaddr (scsi_sense), 0, senselen); } if (io_error == 0) { if (sdd->isatapi) { scsi_atapi_fixup_post (cmd.cmd, scsi_cmd_len, scsi_datap_org, scsi_datap, &scsi_len, parm); } put_long (acmd + 8, scsi_len); put_word (acmd + 18, scsi_cmd_len); put_byte (acmd + 21, cmd.stat); io_error = 0; } else { DEBUG_LOG ("SCSIDEV: errno: %d, %s\n", errno, strerror (errno)); put_long (acmd + 8, 0); put_word (acmd + 18, 0); put_byte (acmd + 21, cmd.stat); io_error = 20; /* TODO: Map errors */ } } if (scsi_datap != scsi_datap_org) xfree (scsi_datap); return io_error; }
static void *cdda_play_func (void *v) { int cdda_pos; int num_sectors = CDDA_BUFFERS; int quit = 0; int bufnum; int bufon[2]; int oldplay; int idleframes; bool foundsub; struct cdunit *cdu = (struct cdunit*)v; while (cdu->cdda_play == 0) Sleep (10); oldplay = -1; bufon[0] = bufon[1] = 0; bufnum = 0; cda_audio *cda = new cda_audio (num_sectors); while (cdu->cdda_play > 0) { if (oldplay != cdu->cdda_play) { struct cdtoc *t; int sector, diff; struct _timeb tb1, tb2; idleframes = 0; foundsub = false; _ftime (&tb1); cdda_pos = cdu->cdda_start; oldplay = cdu->cdda_play; sector = cdu->cd_last_pos = cdda_pos; t = findtoc (cdu, §or); if (!t) { write_log (_T("IMAGE CDDA: illegal sector number %d\n"), cdu->cdda_start); setstate (cdu, AUDIO_STATUS_PLAY_ERROR); } else { write_log (_T("IMAGE CDDA: playing from %d to %d, track %d ('%s', offset %lld, secoffset %d)\n"), cdu->cdda_start, cdu->cdda_end, t->track, t->fname, t->offset, sector); // do this even if audio is not compressed, t->handle also could be // compressed and we want to unpack it in background too while (cdimage_unpack_active == 1) Sleep (10); cdimage_unpack_active = 0; write_comm_pipe_u32 (&unpack_pipe, cdu - &cdunits[0], 0); write_comm_pipe_u32 (&unpack_pipe, t - &cdu->toc[0], 1); while (cdimage_unpack_active == 0) Sleep (10); } idleframes = cdu->cdda_delay_frames; while (cdu->cdda_paused && cdu->cdda_play > 0) { Sleep (10); idleframes = -1; } if (cdu->cdda_scan == 0) { // find possible P-subchannel=1 and fudge starting point so that // buggy CD32/CDTV software CD+G handling does not miss any frames bool seenindex = false; for (sector = cdda_pos - 200; sector < cdda_pos; sector++) { int sec = sector; t = findtoc (cdu, &sec); if (t) { uae_u8 subbuf[SUB_CHANNEL_SIZE]; getsub_deinterleaved (subbuf, cdu, t, sector); if (seenindex) { for (int i = 2 * SUB_ENTRY_SIZE; i < SUB_CHANNEL_SIZE; i++) { if (subbuf[i]) { // non-zero R-W subchannels int diff = cdda_pos - sector + 2; write_log (_T("-> CD+G start pos fudge -> %d (%d)\n"), sector, -diff); idleframes -= diff; cdda_pos = sector; break; } } } else if (subbuf[0] == 0xff) { // P == 1? seenindex = true; } } } } cdda_pos -= idleframes; _ftime (&tb2); diff = (tb2.time * (uae_s64)1000 + tb2.millitm) - (tb1.time * (uae_s64)1000 + tb1.millitm); diff -= cdu->cdda_delay; if (idleframes >= 0 && diff < 0 && cdu->cdda_play > 0) Sleep (-diff); setstate (cdu, AUDIO_STATUS_IN_PROGRESS); } cda->wait(bufnum); bufon[bufnum] = 0; if (!cdu->cdda_play) goto end; if (idleframes <= 0 && cdda_pos >= cdu->cdda_start && !isaudiotrack (&cdu->di.toc, cdda_pos)) { setstate (cdu, AUDIO_STATUS_PLAY_ERROR); write_log (_T("IMAGE CDDA: attempted to play data track %d\n"), cdda_pos); goto end; // data track? } if ((cdda_pos < cdu->cdda_end || cdu->cdda_end == 0xffffffff) && !cdu->cdda_paused && cdu->cdda_play > 0) { struct cdtoc *t; int sector, cnt; int dofinish = 0; gui_flicker_led (LED_CD, cdu->di.unitnum - 1, LED_CD_AUDIO); memset (cda->buffers[bufnum], 0, num_sectors * 2352); for (cnt = 0; cnt < num_sectors; cnt++) { uae_u8 *dst = cda->buffers[bufnum] + cnt * 2352; uae_u8 subbuf[SUB_CHANNEL_SIZE]; sector = cdda_pos; memset (subbuf, 0, SUB_CHANNEL_SIZE); t = findtoc (cdu, §or); if (t) { if (!(t->ctrl & 4)) { if (t->enctype == ENC_CHD) { do_read (cdu, t, dst, sector, 0, t->size); for (int i = 0; i < 2352; i+=2) { uae_u8 p; p = dst[i + 0]; dst[i + 0] = dst[i + 1]; dst[i +1] = p; } } else if (t->handle) { int totalsize = t->size + t->skipsize; if ((t->enctype == AUDENC_MP3 || t->enctype == AUDENC_FLAC) && t->data) { if (t->filesize >= sector * totalsize + t->offset + t->size) memcpy (dst, t->data + sector * totalsize + t->offset, t->size); } else if (t->enctype == AUDENC_PCM) { if (sector * totalsize + t->offset + totalsize < t->filesize) { zfile_fseek (t->handle, (uae_u64)sector * totalsize + t->offset, SEEK_SET); zfile_fread (dst, t->size, 1, t->handle); } } } } getsub_deinterleaved (subbuf, cdu, t, cdda_pos); } if (idleframes > 0) { idleframes--; memset (dst, 0, 2352); memset (subbuf, 0, SUB_CHANNEL_SIZE); } if (cdda_pos < cdu->cdda_start && cdu->cdda_scan == 0) memset (dst, 0, 2352); dosub (cdu, subbuf); if (cdu->cdda_scan) { cdda_pos += cdu->cdda_scan; if (cdda_pos < 0) cdda_pos = 0; } else { cdda_pos++; } if (cdda_pos - num_sectors < cdu->cdda_end && cdda_pos >= cdu->cdda_end) dofinish = 1; } if (idleframes <= 0) cdu->cd_last_pos = cdda_pos; bufon[bufnum] = 1; cda->setvolume (currprefs.sound_volume_cd >= 0 ? currprefs.sound_volume_cd : currprefs.sound_volume, cdu->cdda_volume[0], cdu->cdda_volume[1]); if (!cda->play (bufnum)) { setstate (cdu, AUDIO_STATUS_PLAY_ERROR); goto end; } if (dofinish) { setstate (cdu, AUDIO_STATUS_PLAY_COMPLETE); cdu->cdda_play = -1; cdda_pos = cdu->cdda_end + 1; } } if (bufon[0] == 0 && bufon[1] == 0) { while (cdu->cdda_paused && cdu->cdda_play == oldplay) Sleep (10); } bufnum = 1 - bufnum; } end: cda->wait (0); cda->wait (1); while (cdimage_unpack_active == 1) Sleep (10); delete cda; cdu->cdda_play = 0; write_log (_T("IMAGE CDDA: thread killed\n")); return NULL; }
static int ioctl_command_readwrite (int unitnum, int sector, int size, int 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); cdda_stop (ciw); DWORD dtotal; int cnt = 3; uae_u8 *p = ciw->tempbuffer; int blocksize = ciw->di.bytespersector; if (!open_createfile (ciw, 0)) return 0; ciw->cd_last_pos = sector; while (cnt-- > 0) { LARGE_INTEGER offset; gui_flicker_led (LED_CD, unitnum, LED_CD_ACTIVE); seterrormode (ciw); offset.QuadPart = (uae_u64)sector * ciw->di.bytespersector; if (SetFilePointer (ciw->h, offset.LowPart, &offset.HighPart, FILE_BEGIN) == INVALID_SET_FILE_POINTER && GetLastError () != NO_ERROR) { reseterrormode (ciw); if (win32_error (ciw, unitnum, _T("SetFilePointer")) < 0) continue; return 0; } reseterrormode (ciw); break; } while (size-- > 0) { gui_flicker_led (LED_CD, unitnum, LED_CD_ACTIVE); seterrormode (ciw); if (write) { if (data) { memcpy (p, data, blocksize); data += blocksize; } if (!WriteFile (ciw->h, p, blocksize, &dtotal, 0)) { int err; reseterrormode (ciw); err = win32_error (ciw, unitnum, _T("WriteFile")); if (err < 0) continue; if (err == ERROR_WRITE_PROTECT) return -1; return 0; } } else { dtotal = 0; if (!ReadFile (ciw->h, p, blocksize, &dtotal, 0)) { reseterrormode (ciw); if (win32_error (ciw, unitnum, _T("ReadFile")) < 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: ReadFile()==0. SPTI=%d\n"), unitnum, sector, GetLastError ()); return 1; } if (data) { memcpy (data, p, blocksize); data += blocksize; } } reseterrormode (ciw); gui_flicker_led (LED_CD, unitnum, LED_CD_ACTIVE); } 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); cdda_stop (ciw); 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->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)) { reseterrormode (ciw); return ret; } ciw->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 += data - odata; sector++; } } } return ret; }
static void *cdda_play (void *v) { struct dev_info_ioctl *ciw = (struct dev_info_ioctl*)v; int cdda_pos; int num_sectors = CDDA_BUFFERS; int bufnum; int buffered; int bufon[2]; int i; int oldplay; int idleframes; int muteframes; int readblocksize = 2352 + 96; while (ciw->cdda_play == 0) Sleep (10); oldplay = -1; bufon[0] = bufon[1] = 0; bufnum = 0; buffered = 0; cda_audio *cda = new cda_audio (num_sectors); while (ciw->cdda_play > 0) { cda->wait(bufnum); if (ciw->cdda_play <= 0) goto end; bufon[bufnum] = 0; if (oldplay != ciw->cdda_play) { idleframes = 0; muteframes = 0; bool seensub = false; struct _timeb tb1, tb2; _ftime (&tb1); cdda_pos = ciw->cdda_start; ciw->cd_last_pos = cdda_pos; oldplay = ciw->cdda_play; write_log (_T("IOCTL%s CDDA: playing from %d to %d\n"), ciw->usesptiread ? _T("(SPTI)") : _T(""), ciw->cdda_start, ciw->cdda_end); ciw->subcodevalid = false; idleframes = ciw->cdda_delay_frames; while (ciw->cdda_paused && ciw->cdda_play > 0) { Sleep (10); idleframes = -1; } // force spin up if (isaudiotrack (&ciw->di.toc, cdda_pos)) read_block (ciw, -1, cda->buffers[bufnum], cdda_pos, num_sectors, readblocksize); if (!isaudiotrack (&ciw->di.toc, cdda_pos - 150)) muteframes = 75; if (ciw->cdda_scan == 0) { // find possible P-subchannel=1 and fudge starting point so that // buggy CD32/CDTV software CD+G handling does not miss any frames bool seenindex = false; for (int sector = cdda_pos - 200; sector < cdda_pos; sector++) { uae_u8 *dst = cda->buffers[bufnum]; if (sector >= 0 && isaudiotrack (&ciw->di.toc, sector) && read_block (ciw, -1, dst, sector, 1, readblocksize)) { uae_u8 subbuf[SUB_CHANNEL_SIZE]; sub_deinterleave (dst + 2352, subbuf); if (seenindex) { for (int i = 2 * SUB_ENTRY_SIZE; i < SUB_CHANNEL_SIZE; i++) { if (subbuf[i]) { // non-zero R-W subchannels? int diff = cdda_pos - sector + 2; write_log (_T("-> CD+G start pos fudge -> %d (%d)\n"), sector, -diff); idleframes -= diff; cdda_pos = sector; seensub = true; break; } } } else if (subbuf[0] == 0xff) { // P == 1? seenindex = true; } } } } cdda_pos -= idleframes; _ftime (&tb2); int diff = (tb2.time * (uae_s64)1000 + tb2.millitm) - (tb1.time * (uae_s64)1000 + tb1.millitm); diff -= ciw->cdda_delay; if (idleframes >= 0 && diff < 0 && ciw->cdda_play > 0) Sleep (-diff); if (diff > 0 && !seensub) { int ch = diff / 7 + 25; if (ch > idleframes) ch = idleframes; idleframes -= ch; cdda_pos += ch; } setstate (ciw, AUDIO_STATUS_IN_PROGRESS); } if ((cdda_pos < ciw->cdda_end || ciw->cdda_end == 0xffffffff) && !ciw->cdda_paused && ciw->cdda_play) { if (idleframes <= 0 && cdda_pos >= ciw->cdda_start && !isaudiotrack (&ciw->di.toc, cdda_pos)) { setstate (ciw, AUDIO_STATUS_PLAY_ERROR); write_log (_T("IOCTL: attempted to play data track %d\n"), cdda_pos); goto end; // data track? } gui_flicker_led (LED_CD, ciw->di.unitnum - 1, LED_CD_AUDIO); uae_sem_wait (&ciw->sub_sem); ciw->subcodevalid = false; memset (ciw->subcode, 0, sizeof ciw->subcode); memset (cda->buffers[bufnum], 0, num_sectors * readblocksize); if (cdda_pos >= 0) { if (read_block (ciw, -1, cda->buffers[bufnum], cdda_pos, num_sectors, readblocksize)) { for (i = 0; i < num_sectors; i++) { memcpy (ciw->subcode + i * SUB_CHANNEL_SIZE, cda->buffers[bufnum] + readblocksize * i + 2352, SUB_CHANNEL_SIZE); } for (i = 1; i < num_sectors; i++) { memmove (cda->buffers[bufnum] + 2352 * i, cda->buffers[bufnum] + readblocksize * i, 2352); } ciw->subcodevalid = true; } } for (i = 0; i < num_sectors; i++) { if (muteframes > 0) { memset (cda->buffers[bufnum] + 2352 * i, 0, 2352); muteframes--; } if (idleframes > 0) { idleframes--; memset (cda->buffers[bufnum] + 2352 * i, 0, 2352); memset (ciw->subcode + i * SUB_CHANNEL_SIZE, 0, SUB_CHANNEL_SIZE); } else if (cdda_pos < ciw->cdda_start && ciw->cdda_scan == 0) { memset (cda->buffers[bufnum] + 2352 * i, 0, 2352); } } if (idleframes > 0) ciw->subcodevalid = false; if (ciw->cdda_subfunc) ciw->cdda_subfunc (ciw->subcode, num_sectors); uae_sem_post (&ciw->sub_sem); if (ciw->subcodevalid) { uae_sem_wait (&ciw->sub_sem2); memcpy (ciw->subcodebuf, ciw->subcode + (num_sectors - 1) * SUB_CHANNEL_SIZE, SUB_CHANNEL_SIZE); uae_sem_post (&ciw->sub_sem2); } bufon[bufnum] = 1; cda->setvolume (currprefs.sound_volume_cd >= 0 ? currprefs.sound_volume_cd : currprefs.sound_volume, ciw->cdda_volume[0], ciw->cdda_volume[1]); if (!cda->play (bufnum)) { setstate (ciw, AUDIO_STATUS_PLAY_ERROR); goto end; // data track? } if (ciw->cdda_scan) { cdda_pos += ciw->cdda_scan * num_sectors; if (cdda_pos < 0) cdda_pos = 0; } else { if (cdda_pos < 0 && cdda_pos + num_sectors >= 0) cdda_pos = 0; else cdda_pos += num_sectors; } if (idleframes <= 0) { if (cdda_pos - num_sectors < ciw->cdda_end && cdda_pos >= ciw->cdda_end) { setstate (ciw, AUDIO_STATUS_PLAY_COMPLETE); ciw->cdda_play_finished = 1; ciw->cdda_play = -1; cdda_pos = ciw->cdda_end; } ciw->cd_last_pos = cdda_pos; } } while (ciw->cdda_paused && ciw->cdda_play == oldplay) Sleep (10); bufnum = 1 - bufnum; } end: ciw->subcodevalid = false; delete cda; ciw->cdda_play = 0; write_log (_T("IOCTL CDDA: thread killed\n")); return NULL; }