2022-11-05 20:15:00 -04:00
/*
2023-01-08 15:25:28 -05:00
* 86 Box A hypervisor and IBM PC system emulator that specializes in
* running old operating systems and software designed for IBM
* PC systems and compatibles from 1981 through fairly recent
* system designs based on the PCI bus .
2022-11-05 20:15:00 -04:00
*
2023-01-08 15:25:28 -05:00
* This file is part of the 86 Box distribution .
2022-11-05 20:15:00 -04:00
*
2023-01-08 15:25:28 -05:00
* Mitsumi CD - ROM emulation for the ISA bus .
2022-11-05 20:15:00 -04:00
*
*
*
2023-01-08 15:25:28 -05:00
* Authors : Miran Grca , < mgrca8 @ gmail . com >
2022-11-05 20:15:00 -04:00
*
2023-01-08 15:25:28 -05:00
* Copyright 2022 Miran Grca .
2022-11-05 20:15:00 -04:00
*/
# include <inttypes.h>
# include <stdarg.h>
# include <stdint.h>
# include <stdio.h>
# include <string.h>
# include <stdlib.h>
# include <wchar.h>
# define HAVE_STDARG_H
# include <86box/86box.h>
# include <86box/device.h>
# include <86box/io.h>
# include <86box/pic.h>
# include <86box/dma.h>
# include <86box/cdrom.h>
2023-01-08 14:32:58 +01:00
# include <86box/cdrom_interface.h>
2022-11-05 20:15:00 -04:00
# include <86box/cdrom_mitsumi.h>
# include <86box/plat.h>
# include <86box/sound.h>
# define RAW_SECTOR_SIZE 2352
# define COOKED_SECTOR_SIZE 2048
enum {
STAT_CMD_CHECK = 0x01 ,
STAT_PLAY_CDDA = 0x02 ,
STAT_ERROR = 0x04 ,
STAT_DISK_CDDA = 0x08 ,
STAT_SPIN = 0x10 ,
STAT_CHANGE = 0x20 ,
STAT_READY = 0x40 ,
STAT_OPEN = 0x80
} ;
enum {
CMD_GET_INFO = 0x10 ,
CMD_GET_Q = 0x20 ,
CMD_GET_STAT = 0x40 ,
CMD_SET_MODE = 0x50 ,
CMD_SOFT_RESET = 0x60 ,
CMD_STOPCDDA = 0x70 ,
CMD_CONFIG = 0x90 ,
CMD_SET_VOL = 0xae ,
CMD_READ1X = 0xc0 ,
CMD_READ2X = 0xc1 ,
CMD_GET_VER = 0xdc ,
CMD_STOP = 0xf0 ,
CMD_EJECT = 0xf6 ,
CMD_LOCK = 0xfe
} ;
enum {
MODE_MUTE = 0x01 ,
MODE_GET_TOC = 0x04 ,
MODE_STOP = 0x08 ,
MODE_ECC = 0x20 ,
MODE_DATA = 0x40
} ;
enum {
DRV_MODE_STOP ,
DRV_MODE_READ ,
DRV_MODE_CDDA
} ;
enum {
FLAG_NODATA = 2 ,
FLAG_NOSTAT = 4 ,
FLAG_UNK = 8 , //??
FLAG_OPEN = 16
} ;
enum {
IRQ_DATAREADY = 1 ,
IRQ_DATACOMP = 2 ,
IRQ_ERROR = 4
} ;
typedef struct {
int dma , irq ;
int change ;
int data ;
uint8_t stat ;
uint8_t buf [ RAW_SECTOR_SIZE ] ;
int buf_count ;
int buf_idx ;
uint8_t cmdbuf [ 16 ] ;
int cmdbuf_count ;
int cmdrd_count ;
int cmdbuf_idx ;
uint8_t mode ;
uint8_t cmd ;
uint8_t conf ;
uint8_t enable_irq ;
uint8_t enable_dma ;
uint16_t dmalen ;
uint32_t readmsf ;
uint32_t readcount ;
int locked ;
int drvmode ;
int cur_toc_track ;
int pos ;
2023-01-08 14:32:58 +01:00
int newstat ;
2022-11-05 20:15:00 -04:00
} mcd_t ;
/* The addresses sent from the guest are absolute, ie. a LBA of 0 corresponds to a MSF of 00:00:00. Otherwise, the counter displayed by the guest is wrong:
there is a seeming 2 seconds in which audio plays but counter does not move , while a data track before audio jumps to 2 seconds before the actual start
of the audio while audio still plays . With an absolute conversion , the counter is fine . */
2023-06-26 22:31:03 -04:00
# ifdef MSFtoLBA
2022-11-05 20:15:00 -04:00
# undef MSFtoLBA
2023-06-26 22:31:03 -04:00
# endif
2022-11-05 20:15:00 -04:00
# define MSFtoLBA(m, s, f) ((((m * 60) + s) * 75) + f)
# define CD_BCD(x) (((x) % 10) | (((x) / 10) << 4))
# define CD_DCB(x) ((((x) &0xf0) >> 4) * 10 + ((x) &0x0f))
# ifdef ENABLE_MITSUMI_CDROM_LOG
int mitsumi_cdrom_do_log = ENABLE_MITSUMI_CDROM_LOG ;
void
mitsumi_cdrom_log ( const char * fmt , . . . )
{
va_list ap ;
if ( mitsumi_cdrom_do_log ) {
va_start ( ap , fmt ) ;
pclog_ex ( fmt , ap ) ;
va_end ( ap ) ;
}
}
# else
# define mitsumi_cdrom_log(fmt, ...)
# endif
static void
mitsumi_cdrom_reset ( mcd_t * dev )
{
2023-01-08 14:32:58 +01:00
cdrom_t cdrom ;
2023-02-06 01:49:21 -05:00
cdrom . host_drive = 0 ;
2022-11-05 20:15:00 -04:00
2023-01-08 14:32:58 +01:00
dev - > stat = cdrom . host_drive ? ( STAT_READY | STAT_CHANGE ) : 0 ;
2022-11-05 20:15:00 -04:00
dev - > cmdrd_count = 0 ;
dev - > cmdbuf_count = 0 ;
dev - > buf_count = 0 ;
dev - > cur_toc_track = 0 ;
dev - > enable_dma = 0 ;
dev - > enable_irq = 0 ;
dev - > conf = 0 ;
dev - > dmalen = COOKED_SECTOR_SIZE ;
dev - > locked = 0 ;
dev - > change = 1 ;
2023-01-08 14:32:58 +01:00
dev - > newstat = 1 ;
2022-11-05 20:15:00 -04:00
dev - > data = 0 ;
}
static int
mitsumi_cdrom_read_sector ( mcd_t * dev , int first )
{
2023-01-08 14:32:58 +01:00
cdrom_t cdrom ;
2022-11-05 20:15:00 -04:00
uint8_t status ;
int ret ;
if ( dev - > drvmode = = DRV_MODE_CDDA ) {
2023-01-08 14:32:58 +01:00
status = cdrom_mitsumi_audio_play ( & cdrom , dev - > readmsf , dev - > readcount ) ;
2022-11-05 20:15:00 -04:00
if ( status = = 1 )
return status ;
else
dev - > drvmode = DRV_MODE_READ ;
}
if ( ( dev - > enable_irq & IRQ_DATACOMP ) & & ! first ) {
picint ( 1 < < dev - > irq ) ;
}
if ( ! dev - > readcount ) {
dev - > data = 0 ;
return 0 ;
}
2023-01-08 14:32:58 +01:00
cdrom_stop ( & cdrom ) ;
ret = cdrom_readsector_raw ( & cdrom , dev - > buf , cdrom . seek_pos , 0 , 2 , 0x10 , ( int * ) & dev - > readcount , 0 ) ;
2022-11-05 20:15:00 -04:00
if ( ! ret )
return 0 ;
if ( dev - > mode & 0x40 ) {
dev - > buf [ 12 ] = CD_BCD ( ( dev - > readmsf > > 16 ) & 0xff ) ;
dev - > buf [ 13 ] = CD_BCD ( ( dev - > readmsf > > 8 ) & 0xff ) ;
}
2023-01-08 14:32:58 +01:00
dev - > readmsf = cdrom_lba_to_msf_accurate ( cdrom . seek_pos + 1 ) ;
2022-11-05 20:15:00 -04:00
dev - > buf_count = dev - > dmalen + 1 ;
dev - > buf_idx = 0 ;
dev - > data = 1 ;
if ( dev - > enable_dma ) {
while ( dev - > pos < dev - > readcount ) {
dma_channel_write ( dev - > dma , dev - > buf [ dev - > pos ] ) ;
dev - > pos + + ;
}
dev - > pos = 0 ;
}
dev - > readcount - - ;
if ( ( dev - > enable_irq & IRQ_DATAREADY ) & & first )
picint ( 1 < < dev - > irq ) ;
return 1 ;
}
static uint8_t
mitsumi_cdrom_in ( uint16_t port , void * priv )
{
mcd_t * dev = ( mcd_t * ) priv ;
uint8_t ret ;
2023-01-08 14:32:58 +01:00
pclog ( " Mitsumi CD-ROM IN=%03x \n " , port ) ;
2022-11-05 20:15:00 -04:00
switch ( port & 1 ) {
case 0 :
if ( dev - > cmdbuf_count ) {
dev - > cmdbuf_count - - ;
return dev - > cmdbuf [ dev - > cmdbuf_idx + + ] ;
} else if ( dev - > buf_count ) {
ret = ( dev - > buf_idx < RAW_SECTOR_SIZE ) ? dev - > buf [ dev - > buf_idx ] : 0 ;
dev - > buf_idx + + ;
dev - > buf_count - - ;
if ( ! dev - > buf_count )
mitsumi_cdrom_read_sector ( dev , 0 ) ;
2023-01-08 14:32:58 +01:00
pclog ( " Read port 0: ret = %02x \n " , ret ) ;
2022-11-05 20:15:00 -04:00
return ret ;
}
2023-01-08 14:32:58 +01:00
pclog ( " Read port 0: stat = %02x \n " , dev - > stat ) ;
2022-11-05 20:15:00 -04:00
return dev - > stat ;
case 1 :
ret = 0 ;
picintc ( 1 < < dev - > irq ) ;
if ( ! dev - > buf_count | | ! dev - > data | | dev - > enable_dma )
ret | = FLAG_NODATA ;
2023-01-08 14:32:58 +01:00
if ( ! dev - > cmdbuf_count | | ! dev - > newstat )
2022-11-05 20:15:00 -04:00
ret | = FLAG_NOSTAT ;
2023-01-08 14:32:58 +01:00
pclog ( " Read port 1: ret = %02x \n " , ret | FLAG_UNK ) ;
2022-11-05 20:15:00 -04:00
return ret | FLAG_UNK ;
2023-06-26 12:47:04 -04:00
default :
break ;
2022-11-05 20:15:00 -04:00
}
2023-06-26 12:47:04 -04:00
return 0xff ;
2022-11-05 20:15:00 -04:00
}
static void
mitsumi_cdrom_out ( uint16_t port , uint8_t val , void * priv )
{
mcd_t * dev = ( mcd_t * ) priv ;
2023-01-08 14:32:58 +01:00
cdrom_t cdrom ;
2022-11-05 20:15:00 -04:00
2023-01-08 14:32:58 +01:00
pclog ( " Mitsumi CD-ROM OUT=%03x, val=%02x \n " , port , val ) ;
2022-11-05 20:15:00 -04:00
switch ( port & 1 ) {
case 0 :
if ( dev - > cmdrd_count ) {
dev - > cmdrd_count - - ;
switch ( dev - > cmd ) {
case CMD_SET_MODE :
dev - > mode = val ;
dev - > cmdbuf [ 1 ] = 0 ;
dev - > cmdbuf_count = 2 ;
break ;
case CMD_LOCK :
dev - > locked = val & 1 ;
dev - > cmdbuf [ 1 ] = 0 ;
dev - > cmdbuf [ 2 ] = 0 ;
dev - > cmdbuf_count = 3 ;
break ;
case CMD_CONFIG :
switch ( dev - > cmdrd_count ) {
case 0 :
switch ( dev - > conf ) {
case 0x01 :
dev - > dmalen | = val ;
break ;
case 0x02 :
dev - > enable_dma = val ;
break ;
case 0x10 :
dev - > enable_irq = val ;
break ;
2023-06-26 12:47:04 -04:00
default :
break ;
2022-11-05 20:15:00 -04:00
}
dev - > cmdbuf [ 1 ] = 0 ;
dev - > cmdbuf_count = 2 ;
dev - > conf = 0 ;
break ;
case 1 :
if ( dev - > conf = = 1 ) {
dev - > dmalen = val < < 8 ;
break ;
}
dev - > conf = val ;
if ( dev - > conf = = 1 )
dev - > cmdrd_count + + ;
break ;
2023-06-26 12:47:04 -04:00
default :
break ;
2022-11-05 20:15:00 -04:00
}
break ;
case CMD_READ1X :
case CMD_READ2X :
switch ( dev - > cmdrd_count ) {
case 0 :
dev - > readcount | = val ;
mitsumi_cdrom_read_sector ( dev , 1 ) ;
dev - > cmdbuf_count = 1 ;
dev - > cmdbuf [ 0 ] = STAT_SPIN | STAT_READY ;
break ;
case 1 :
dev - > readcount | = ( val < < 8 ) ;
break ;
case 2 :
dev - > readcount = ( val < < 16 ) ;
break ;
case 5 :
dev - > readmsf = 0 ;
2023-08-09 19:44:56 -04:00
fallthrough ;
2022-11-05 20:15:00 -04:00
case 4 :
case 3 :
dev - > readmsf | = CD_DCB ( val ) < < ( ( dev - > cmdrd_count - 3 ) < < 3 ) ;
break ;
2023-06-26 12:47:04 -04:00
default :
break ;
2022-11-05 20:15:00 -04:00
}
break ;
2023-06-26 12:47:04 -04:00
default :
break ;
2022-11-05 20:15:00 -04:00
}
if ( ! dev - > cmdrd_count )
2023-01-08 14:32:58 +01:00
dev - > stat = cdrom . host_drive ? ( STAT_READY | ( dev - > change ? STAT_CHANGE : 0 ) ) : 0 ;
2022-11-05 20:15:00 -04:00
return ;
}
dev - > cmd = val ;
dev - > cmdbuf_idx = 0 ;
dev - > cmdrd_count = 0 ;
dev - > cmdbuf_count = 1 ;
2023-01-08 14:32:58 +01:00
dev - > cmdbuf [ 0 ] = cdrom . host_drive ? ( STAT_READY | ( dev - > change ? STAT_CHANGE : 0 ) ) : 0 ;
2022-11-05 20:15:00 -04:00
dev - > data = 0 ;
switch ( val ) {
case CMD_GET_INFO :
2023-01-08 14:32:58 +01:00
if ( cdrom . host_drive ) {
cdrom_get_track_buffer ( & cdrom , & ( dev - > cmdbuf [ 1 ] ) ) ;
2022-11-05 20:15:00 -04:00
dev - > cmdbuf_count = 10 ;
dev - > readcount = 0 ;
} else {
dev - > cmdbuf_count = 1 ;
dev - > cmdbuf [ 0 ] = STAT_CMD_CHECK ;
}
break ;
case CMD_GET_Q :
2023-01-08 14:32:58 +01:00
if ( cdrom . host_drive ) {
cdrom_get_q ( & cdrom , & ( dev - > cmdbuf [ 1 ] ) , & dev - > cur_toc_track , dev - > mode & MODE_GET_TOC ) ;
2022-11-05 20:15:00 -04:00
dev - > cmdbuf_count = 11 ;
dev - > readcount = 0 ;
} else {
dev - > cmdbuf_count = 1 ;
dev - > cmdbuf [ 0 ] = STAT_CMD_CHECK ;
}
break ;
case CMD_GET_STAT :
dev - > change = 0 ;
break ;
case CMD_SET_MODE :
dev - > cmdrd_count = 1 ;
break ;
case CMD_STOPCDDA :
case CMD_STOP :
2023-01-08 14:32:58 +01:00
cdrom_stop ( & cdrom ) ;
2022-11-05 20:15:00 -04:00
dev - > drvmode = DRV_MODE_STOP ;
dev - > cur_toc_track = 0 ;
break ;
case CMD_CONFIG :
dev - > cmdrd_count = 2 ;
break ;
case CMD_READ1X :
case CMD_READ2X :
2023-01-08 14:32:58 +01:00
if ( cdrom . host_drive ) {
2022-11-05 20:15:00 -04:00
dev - > readcount = 0 ;
dev - > drvmode = ( val = = CMD_READ1X ) ? DRV_MODE_CDDA : DRV_MODE_READ ;
dev - > cmdrd_count = 6 ;
} else {
dev - > cmdbuf_count = 1 ;
dev - > cmdbuf [ 0 ] = STAT_CMD_CHECK ;
}
break ;
case CMD_GET_VER :
dev - > cmdbuf [ 1 ] = 1 ;
dev - > cmdbuf [ 2 ] = ' D ' ;
dev - > cmdbuf [ 3 ] = 0 ;
dev - > cmdbuf_count = 4 ;
break ;
case CMD_EJECT :
2023-01-08 14:32:58 +01:00
cdrom_stop ( & cdrom ) ;
2022-11-05 20:15:00 -04:00
cdrom_eject ( 0 ) ;
dev - > readcount = 0 ;
break ;
case CMD_LOCK :
dev - > cmdrd_count = 1 ;
break ;
2023-01-08 14:32:58 +01:00
case CMD_SOFT_RESET :
pclog ( " Soft Reset \n " ) ;
mitsumi_cdrom_reset ( dev ) ;
break ;
2022-11-05 20:15:00 -04:00
default :
dev - > cmdbuf [ 0 ] = dev - > stat | STAT_CMD_CHECK ;
break ;
}
break ;
case 1 :
mitsumi_cdrom_reset ( dev ) ;
break ;
2023-06-26 12:47:04 -04:00
default :
break ;
2022-11-05 20:15:00 -04:00
}
}
static void *
2023-06-26 12:47:04 -04:00
mitsumi_cdrom_init ( UNUSED ( const device_t * info ) )
2022-11-05 20:15:00 -04:00
{
mcd_t * dev ;
dev = malloc ( sizeof ( mcd_t ) ) ;
memset ( dev , 0x00 , sizeof ( mcd_t ) ) ;
dev - > irq = 5 ;
dev - > dma = 5 ;
io_sethandler ( 0x310 , 2 ,
mitsumi_cdrom_in , NULL , NULL , mitsumi_cdrom_out , NULL , NULL , dev ) ;
mitsumi_cdrom_reset ( dev ) ;
return dev ;
}
static void
mitsumi_cdrom_close ( void * priv )
{
mcd_t * dev = ( mcd_t * ) priv ;
if ( dev ) {
free ( dev ) ;
dev = NULL ;
}
}
const device_t mitsumi_cdrom_device = {
2023-01-08 14:32:58 +01:00
. name = " Mitsumi CD-ROM interface " ,
. internal_name = " mcd " ,
. flags = DEVICE_ISA | DEVICE_AT ,
. local = 1 ,
. init = mitsumi_cdrom_init ,
. close = mitsumi_cdrom_close ,
. reset = NULL ,
{ . available = NULL } ,
. speed_changed = NULL ,
. force_redraw = NULL ,
. config = NULL
2022-11-05 20:15:00 -04:00
} ;