2017-05-30 03:38:38 +02: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 .
*
* This file is part of the 86 Box distribution .
*
* Implementation of the CD - ROM drive with SCSI ( - like )
* commands , for both ATAPI and SCSI usage .
*
2018-02-27 23:55:28 +01:00
* Version : @ ( # ) cdrom . c 1.0 .33 2018 / 02 / 27
2017-05-30 03:38:38 +02:00
*
* Author : Miran Grca , < mgrca8 @ gmail . com >
2017-10-08 19:14:46 -04:00
*
2018-01-24 18:38:43 +01:00
* Copyright 2016 - 2018 Miran Grca .
2017-05-30 03:38:38 +02:00
*/
2017-01-16 01:49:19 +01:00
# include <stdio.h>
# include <stdint.h>
2017-01-17 00:01:59 +01:00
# include <string.h>
2017-09-25 04:31:20 -04:00
# include <stdlib.h>
# include <stdarg.h>
# include <wchar.h>
2017-12-10 19:36:41 +01:00
# define HAVE_STDARG_H
2017-09-04 01:52:29 -04:00
# include "../86box.h"
2017-10-11 05:40:44 -04:00
# include "../config.h"
2017-10-01 16:29:15 -04:00
# include "../timer.h"
# include "../device.h"
2017-09-04 01:52:29 -04:00
# include "../piix.h"
# include "../scsi/scsi.h"
2017-09-23 21:12:26 -04:00
# include "../nvr.h"
2017-10-02 02:15:35 -04:00
# include "../disk/hdc.h"
# include "../disk/hdc_ide.h"
2017-10-10 03:07:29 -04:00
# include "../plat.h"
# include "../ui.h"
2017-01-16 01:49:19 +01:00
# include "cdrom.h"
2017-10-08 05:04:38 +02:00
# include "cdrom_image.h"
# include "cdrom_null.h"
2017-09-04 01:52:29 -04:00
2017-01-16 01:49:19 +01:00
/* Bits of 'status' */
# define ERR_STAT 0x01
# define DRQ_STAT 0x08 /* Data request */
# define DSC_STAT 0x10
# define SERVICE_STAT 0x10
# define READY_STAT 0x40
# define BUSY_STAT 0x80
/* Bits of 'error' */
# define ABRT_ERR 0x04 /* Command aborted */
# define MCR_ERR 0x08 /* Media change request */
2017-10-16 04:54:41 -04:00
cdrom_t cdrom [ CDROM_NUM ] ;
cdrom_image_t cdrom_image [ CDROM_NUM ] ;
cdrom_ioctl_t cdrom_ioctl [ CDROM_NUM ] ;
cdrom_drive_t cdrom_drives [ CDROM_NUM ] ;
2017-01-16 01:49:19 +01:00
uint8_t atapi_cdrom_drives [ 8 ] = { 0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF } ;
2017-01-18 21:51:03 +01:00
uint8_t scsi_cdrom_drives [ 16 ] [ 8 ] = { { 0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF } ,
{ 0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF } ,
{ 0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF } ,
{ 0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF } ,
{ 0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF } ,
{ 0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF } ,
{ 0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF } ,
{ 0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF } ,
{ 0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF } ,
{ 0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF } ,
{ 0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF } ,
{ 0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF } ,
{ 0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF } ,
{ 0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF } ,
{ 0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF } ,
{ 0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF } } ;
2017-01-16 01:49:19 +01:00
2017-10-13 02:44:32 -04:00
# pragma pack(push,1)
2017-05-05 01:49:42 +02:00
static struct
2017-01-16 01:49:19 +01:00
{
uint8_t opcode ;
uint8_t polled ;
uint8_t reserved2 [ 2 ] ;
uint8_t class ;
uint8_t reserved3 [ 2 ] ;
uint16_t len ;
uint8_t control ;
} * gesn_cdb ;
2017-10-13 02:44:32 -04:00
# pragma pack(pop)
2017-01-16 01:49:19 +01:00
2017-10-13 02:44:32 -04:00
# pragma pack(push,1)
2017-05-05 01:49:42 +02:00
static struct
2017-01-16 01:49:19 +01:00
{
uint16_t len ;
uint8_t notification_class ;
uint8_t supported_events ;
} * gesn_event_header ;
2017-10-13 02:44:32 -04:00
# pragma pack(pop)
2017-01-16 01:49:19 +01:00
/* Table of all SCSI commands and their flags, needed for the new disc change / not ready handler. */
uint8_t cdrom_command_flags [ 0x100 ] =
{
2017-05-05 01:49:42 +02:00
IMPLEMENTED | CHECK_READY | NONDATA ,
IMPLEMENTED | ALLOW_UA | NONDATA | SCSI_ONLY ,
0 ,
IMPLEMENTED | ALLOW_UA ,
0 , 0 , 0 , 0 ,
IMPLEMENTED | CHECK_READY ,
0 , 0 ,
IMPLEMENTED | CHECK_READY | NONDATA ,
0 , 0 , 0 , 0 , 0 , 0 ,
IMPLEMENTED | ALLOW_UA ,
IMPLEMENTED | CHECK_READY | NONDATA | SCSI_ONLY ,
0 ,
IMPLEMENTED ,
0 , 0 , 0 , 0 ,
IMPLEMENTED ,
IMPLEMENTED | CHECK_READY ,
0 , 0 ,
IMPLEMENTED | CHECK_READY ,
0 , 0 , 0 , 0 , 0 , 0 ,
IMPLEMENTED | CHECK_READY ,
0 , 0 ,
IMPLEMENTED | CHECK_READY ,
0 , 0 ,
IMPLEMENTED | CHECK_READY | NONDATA ,
0 , 0 , 0 ,
IMPLEMENTED | CHECK_READY | NONDATA | SCSI_ONLY ,
0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ,
0 , 0 ,
IMPLEMENTED | CHECK_READY ,
IMPLEMENTED | CHECK_READY , /* Read TOC - can get through UNIT_ATTENTION, per VIDE-CDD.SYS
NOTE : The ATAPI reference says otherwise , but I think this is a question of
interpreting things right - the UNIT ATTENTION condition we have here
is a tradition from not ready to ready , by definition the drive
eventually becomes ready , make the condition go away . */
IMPLEMENTED | CHECK_READY ,
IMPLEMENTED | CHECK_READY ,
IMPLEMENTED | ALLOW_UA ,
IMPLEMENTED | CHECK_READY ,
IMPLEMENTED | CHECK_READY ,
0 ,
IMPLEMENTED | ALLOW_UA ,
IMPLEMENTED | CHECK_READY ,
0 , 0 ,
IMPLEMENTED | CHECK_READY ,
0 , 0 ,
IMPLEMENTED | CHECK_READY ,
IMPLEMENTED | CHECK_READY ,
0 , 0 ,
IMPLEMENTED ,
0 , 0 , 0 , 0 ,
IMPLEMENTED ,
0 , 0 , 0 , 0 , 0 ,
0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ,
0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ,
0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ,
0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ,
0 , 0 , 0 , 0 , 0 ,
IMPLEMENTED | CHECK_READY ,
0 , 0 ,
IMPLEMENTED | CHECK_READY ,
0 , 0 , 0 , 0 ,
IMPLEMENTED | CHECK_READY ,
0 ,
IMPLEMENTED | CHECK_READY | NONDATA | SCSI_ONLY ,
0 , 0 , 0 , 0 ,
IMPLEMENTED | CHECK_READY | ATAPI_ONLY ,
0 , 0 , 0 ,
IMPLEMENTED | CHECK_READY | ATAPI_ONLY ,
IMPLEMENTED | CHECK_READY ,
IMPLEMENTED | CHECK_READY ,
IMPLEMENTED ,
IMPLEMENTED | CHECK_READY ,
IMPLEMENTED ,
IMPLEMENTED | CHECK_READY ,
IMPLEMENTED | CHECK_READY ,
0 , 0 ,
IMPLEMENTED | CHECK_READY | SCSI_ONLY ,
0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ,
IMPLEMENTED | CHECK_READY | SCSI_ONLY ,
0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ,
IMPLEMENTED | SCSI_ONLY ,
0 , 0 , 0 , 0 , 0 ,
0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ,
0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0
2017-01-16 01:49:19 +01:00
} ;
2018-01-13 22:56:13 +01:00
uint64_t cdrom_mode_sense_page_flags = ( 1LL < < GPMODE_R_W_ERROR_PAGE ) | ( 1LL < < GPMODE_CDROM_PAGE ) | ( 1LL < < GPMODE_CDROM_AUDIO_PAGE ) | ( 1LL < < GPMODE_CAPABILITIES_PAGE ) | ( 1LL < < GPMODE_ALL_PAGES ) ;
static const mode_sense_pages_t cdrom_mode_sense_pages_default =
{ {
{ 0 , 0 } ,
{ GPMODE_R_W_ERROR_PAGE , 6 , 0 , 5 , 0 , 0 , 0 , 0 } ,
{ 0 , 0 } ,
{ 0 , 0 } ,
{ 0 , 0 } ,
{ 0 , 0 } ,
{ 0 , 0 } ,
{ 0 , 0 } ,
{ 0 , 0 } ,
{ 0 , 0 } ,
{ 0 , 0 } ,
{ 0 , 0 } ,
{ 0 , 0 } ,
{ GPMODE_CDROM_PAGE , 6 , 0 , 1 , 0 , 60 , 0 , 75 } ,
{ 0x8E , 0xE , 4 , 0 , 0 , 0 , 0 , 75 , 1 , 0xFF , 2 , 0xFF , 0 , 0 , 0 , 0 } ,
{ 0 , 0 } ,
{ 0 , 0 } ,
{ 0 , 0 } ,
{ 0 , 0 } ,
{ 0 , 0 } ,
{ 0 , 0 } ,
{ 0 , 0 } ,
{ 0 , 0 } ,
{ 0 , 0 } ,
{ 0 , 0 } ,
{ 0 , 0 } ,
{ 0 , 0 } ,
{ 0 , 0 } ,
{ 0 , 0 } ,
{ 0 , 0 } ,
{ 0 , 0 } ,
{ 0 , 0 } ,
{ 0 , 0 } ,
{ 0 , 0 } ,
{ 0 , 0 } ,
{ 0 , 0 } ,
{ 0 , 0 } ,
{ 0 , 0 } ,
{ 0 , 0 } ,
{ 0 , 0 } ,
{ 0 , 0 } ,
{ 0 , 0 } ,
{ GPMODE_CAPABILITIES_PAGE , 0x14 , 0x3B , 0 , 0x71 , 0x60 , 0x29 , 0 , 0x02 , 0xC2 , 0 , 2 , 0 , 0 , 0x02 , 0xC2 , 0 , 0 , 0 , 0 , 0 , 0 }
} } ;
2018-01-17 18:43:36 +01:00
static const mode_sense_pages_t cdrom_mode_sense_pages_default_scsi =
{ {
{ 0 , 0 } ,
{ GPMODE_R_W_ERROR_PAGE , 6 , 0 , 5 , 0 , 0 , 0 , 0 } ,
{ 0 , 0 } ,
{ 0 , 0 } ,
{ 0 , 0 } ,
{ 0 , 0 } ,
{ 0 , 0 } ,
{ 0 , 0 } ,
{ 0 , 0 } ,
{ 0 , 0 } ,
{ 0 , 0 } ,
{ 0 , 0 } ,
{ 0 , 0 } ,
{ GPMODE_CDROM_PAGE , 6 , 0 , 1 , 0 , 60 , 0 , 75 } ,
{ 0x8E , 0xE , 5 , 4 , 0 , 0x80 , 0 , 75 , 1 , 0xFF , 2 , 0xFF , 0 , 0 , 0 , 0 } ,
{ 0 , 0 } ,
{ 0 , 0 } ,
{ 0 , 0 } ,
{ 0 , 0 } ,
{ 0 , 0 } ,
{ 0 , 0 } ,
{ 0 , 0 } ,
{ 0 , 0 } ,
{ 0 , 0 } ,
{ 0 , 0 } ,
{ 0 , 0 } ,
{ 0 , 0 } ,
{ 0 , 0 } ,
{ 0 , 0 } ,
{ 0 , 0 } ,
{ 0 , 0 } ,
{ 0 , 0 } ,
{ 0 , 0 } ,
{ 0 , 0 } ,
{ 0 , 0 } ,
{ 0 , 0 } ,
{ 0 , 0 } ,
{ 0 , 0 } ,
{ 0 , 0 } ,
{ 0 , 0 } ,
{ 0 , 0 } ,
{ 0 , 0 } ,
{ GPMODE_CAPABILITIES_PAGE , 0x14 , 0x3B , 0 , 0x71 , 0x60 , 0x29 , 0 , 0x02 , 0xC2 , 0 , 2 , 0 , 0 , 0x02 , 0xC2 , 0 , 0 , 0 , 0 , 0 , 0 }
} } ;
2018-01-13 22:56:13 +01:00
static const mode_sense_pages_t cdrom_mode_sense_pages_changeable =
{ {
{ 0 , 0 } ,
{ GPMODE_R_W_ERROR_PAGE , 6 , 0 , 5 , 0 , 0 , 0 , 0 } ,
{ 0 , 0 } ,
{ 0 , 0 } ,
{ 0 , 0 } ,
{ 0 , 0 } ,
{ 0 , 0 } ,
{ 0 , 0 } ,
{ 0 , 0 } ,
{ 0 , 0 } ,
{ 0 , 0 } ,
{ 0 , 0 } ,
{ 0 , 0 } ,
{ GPMODE_CDROM_PAGE , 6 , 0 , 1 , 0 , 60 , 0 , 75 } ,
2018-01-17 18:43:36 +01:00
{ 0x8E , 0xE , 5 , 4 , 0 , 0x80 , 0 , 75 , 1 , 0xFF , 2 , 0xFF , 0 , 0 , 0 , 0 } ,
2018-01-13 22:56:13 +01:00
{ 0 , 0 } ,
{ 0 , 0 } ,
{ 0 , 0 } ,
{ 0 , 0 } ,
{ 0 , 0 } ,
{ 0 , 0 } ,
{ 0 , 0 } ,
{ 0 , 0 } ,
{ 0 , 0 } ,
{ 0 , 0 } ,
{ 0 , 0 } ,
{ 0 , 0 } ,
{ 0 , 0 } ,
{ 0 , 0 } ,
{ 0 , 0 } ,
{ 0 , 0 } ,
{ 0 , 0 } ,
{ 0 , 0 } ,
{ 0 , 0 } ,
{ 0 , 0 } ,
{ 0 , 0 } ,
{ 0 , 0 } ,
{ 0 , 0 } ,
{ 0 , 0 } ,
{ 0 , 0 } ,
{ 0 , 0 } ,
{ 0 , 0 } ,
{ GPMODE_CAPABILITIES_PAGE , 0x14 , 0x3B , 0 , 0x71 , 0x60 , 0x29 , 0 , 0x02 , 0xC2 , 0 , 2 , 0 , 0 , 0x02 , 0xC2 , 0 , 0 , 0 , 0 , 0 , 0 }
} } ;
static mode_sense_pages_t cdrom_mode_sense_pages_saved [ CDROM_NUM ] ;
2017-01-16 01:49:19 +01:00
2017-10-16 06:19:18 +02:00
# ifdef ENABLE_CDROM_LOG
int cdrom_do_log = ENABLE_CDROM_LOG ;
# endif
2017-01-16 01:49:19 +01:00
2017-11-24 02:23:00 -05:00
static void
2017-12-10 15:16:24 +01:00
cdrom_log ( const char * format , . . . )
2017-01-16 01:49:19 +01:00
{
# ifdef ENABLE_CDROM_LOG
2017-12-05 23:35:35 +01:00
va_list ap ;
2017-02-07 02:19:48 +01:00
if ( cdrom_do_log )
{
2017-12-10 15:16:24 +01:00
va_start ( ap , format ) ;
pclog_ex ( format , ap ) ;
2017-01-16 01:49:19 +01:00
va_end ( ap ) ;
2017-02-07 02:19:48 +01:00
}
2017-01-16 01:49:19 +01:00
# endif
}
2017-11-24 02:23:00 -05:00
2017-01-16 01:49:19 +01:00
int find_cdrom_for_channel ( uint8_t channel )
{
uint8_t i = 0 ;
2017-10-24 04:15:05 +02:00
for ( i = 0 ; i < CDROM_NUM ; i + + ) {
2017-05-27 03:53:32 +02:00
if ( ( ( cdrom_drives [ i ] . bus_type = = CDROM_BUS_ATAPI_PIO_ONLY ) | | ( cdrom_drives [ i ] . bus_type = = CDROM_BUS_ATAPI_PIO_AND_DMA ) ) & & ( cdrom_drives [ i ] . ide_channel = = channel ) )
2017-01-16 01:49:19 +01:00
return i ;
}
return 0xff ;
}
2017-05-17 21:56:31 +02:00
void cdrom_init ( int id , int cdb_len_setting ) ;
2017-01-16 01:49:19 +01:00
void build_atapi_cdrom_map ( )
{
uint8_t i = 0 ;
memset ( atapi_cdrom_drives , 0xff , 8 ) ;
2017-10-24 04:15:05 +02:00
for ( i = 0 ; i < 8 ; i + + ) {
2017-01-16 01:49:19 +01:00
atapi_cdrom_drives [ i ] = find_cdrom_for_channel ( i ) ;
if ( atapi_cdrom_drives [ i ] ! = 0xff )
2017-05-17 21:56:31 +02:00
cdrom_init ( atapi_cdrom_drives [ i ] , 12 ) ;
2017-01-16 01:49:19 +01:00
}
}
2017-01-18 21:51:03 +01:00
int find_cdrom_for_scsi_id ( uint8_t scsi_id , uint8_t scsi_lun )
2017-01-16 01:49:19 +01:00
{
uint8_t i = 0 ;
2017-10-24 04:15:05 +02:00
for ( i = 0 ; i < CDROM_NUM ; i + + ) {
2017-05-27 03:53:32 +02:00
if ( ( cdrom_drives [ i ] . bus_type = = CDROM_BUS_SCSI ) & & ( cdrom_drives [ i ] . scsi_device_id = = scsi_id ) & & ( cdrom_drives [ i ] . scsi_device_lun = = scsi_lun ) )
2017-01-16 01:49:19 +01:00
return i ;
}
return 0xff ;
}
void build_scsi_cdrom_map ( )
{
uint8_t i = 0 ;
2017-01-18 21:51:03 +01:00
uint8_t j = 0 ;
2017-01-16 01:49:19 +01:00
2017-01-18 21:51:03 +01:00
for ( i = 0 ; i < 16 ; i + + )
memset ( scsi_cdrom_drives [ i ] , 0xff , 8 ) ;
2017-01-16 01:49:19 +01:00
2017-10-24 04:15:05 +02:00
for ( i = 0 ; i < 16 ; i + + ) {
for ( j = 0 ; j < 8 ; j + + ) {
2017-01-18 21:51:03 +01:00
scsi_cdrom_drives [ i ] [ j ] = find_cdrom_for_scsi_id ( i , j ) ;
if ( scsi_cdrom_drives [ i ] [ j ] ! = 0xff )
2017-05-17 21:56:31 +02:00
cdrom_init ( scsi_cdrom_drives [ i ] [ j ] , 12 ) ;
2017-01-16 01:49:19 +01:00
}
}
}
2017-10-26 20:37:39 +02:00
void cdrom_set_callback ( uint8_t id )
{
if ( cdrom_drives [ id ] . bus_type ! = CDROM_BUS_SCSI )
ide_set_callback ( cdrom_drives [ id ] . ide_channel , cdrom [ id ] . callback ) ;
}
2017-01-16 01:49:19 +01:00
void cdrom_set_cdb_len ( int id , int cdb_len )
{
cdrom [ id ] . cdb_len = cdb_len ;
}
void cdrom_reset_cdb_len ( int id )
{
cdrom [ id ] . cdb_len = cdrom [ id ] . cdb_len_setting ? 16 : 12 ;
}
void cdrom_set_signature ( int id )
{
2017-02-13 20:21:57 +01:00
if ( id > = CDROM_NUM )
return ;
2017-01-16 01:49:19 +01:00
cdrom [ id ] . phase = 1 ;
cdrom [ id ] . request_length = 0xEB14 ;
}
2017-05-17 21:56:31 +02:00
void cdrom_init ( int id , int cdb_len_setting )
2017-01-16 01:49:19 +01:00
{
if ( id > = CDROM_NUM )
return ;
memset ( & ( cdrom [ id ] ) , 0 , sizeof ( cdrom_t ) ) ;
cdrom [ id ] . requested_blocks = 1 ;
if ( cdb_len_setting < = 1 )
cdrom [ id ] . cdb_len_setting = cdb_len_setting ;
cdrom_reset_cdb_len ( id ) ;
cdrom [ id ] . cd_status = CD_STATUS_EMPTY ;
cdrom [ id ] . sense [ 0 ] = 0xf0 ;
cdrom [ id ] . sense [ 7 ] = 10 ;
2017-05-17 21:56:31 +02:00
cdrom_drives [ id ] . bus_mode = 0 ;
2017-10-22 03:16:52 +02:00
if ( cdrom_drives [ id ] . bus_type > = CDROM_BUS_ATAPI_PIO_AND_DMA )
2017-05-17 21:56:31 +02:00
cdrom_drives [ id ] . bus_mode | = 2 ;
2017-05-27 03:53:32 +02:00
if ( cdrom_drives [ id ] . bus_type < CDROM_BUS_SCSI )
2017-05-17 21:56:31 +02:00
cdrom_drives [ id ] . bus_mode | = 1 ;
2017-01-17 19:41:42 +01:00
cdrom_log ( " CD-ROM %i: Bus type %i, bus mode %i \n " , id , cdrom_drives [ id ] . bus_type , cdrom_drives [ id ] . bus_mode ) ;
2017-05-27 03:53:32 +02:00
if ( cdrom_drives [ id ] . bus_type < CDROM_BUS_SCSI )
2017-01-16 01:49:19 +01:00
cdrom_set_signature ( id ) ;
2017-10-24 04:15:05 +02:00
cdrom_drives [ id ] . max_blocks_at_once = 85 ;
2017-01-16 01:49:19 +01:00
cdrom [ id ] . status = READY_STAT | DSC_STAT ;
cdrom [ id ] . pos = 0 ;
cdrom [ id ] . packet_status = 0xff ;
cdrom_sense_key = cdrom_asc = cdrom_ascq = cdrom [ id ] . unit_attention = 0 ;
cdrom [ id ] . cdb_len_setting = 0 ;
cdrom [ id ] . cdb_len = 12 ;
}
int cdrom_supports_pio ( int id )
{
return ( cdrom_drives [ id ] . bus_mode & 1 ) ;
}
int cdrom_supports_dma ( int id )
{
return ( cdrom_drives [ id ] . bus_mode & 2 ) ;
}
/* Returns: 0 for none, 1 for PIO, 2 for DMA. */
int cdrom_current_mode ( int id )
{
if ( ! cdrom_supports_pio ( id ) & & ! cdrom_supports_dma ( id ) )
return 0 ;
2017-10-24 04:15:05 +02:00
if ( cdrom_supports_pio ( id ) & & ! cdrom_supports_dma ( id ) ) {
2017-10-22 03:16:52 +02:00
cdrom_log ( " CD-ROM %i: Drive does not support DMA, setting to PIO \n " , id ) ;
2017-01-16 01:49:19 +01:00
return 1 ;
}
if ( ! cdrom_supports_pio ( id ) & & cdrom_supports_dma ( id ) )
return 2 ;
2017-10-24 04:15:05 +02:00
if ( cdrom_supports_pio ( id ) & & cdrom_supports_dma ( id ) ) {
2017-10-22 03:16:52 +02:00
cdrom_log ( " CD-ROM %i: Drive supports both, setting to %s \n " , id , ( cdrom [ id ] . features & 1 ) ? " DMA " : " PIO " , id ) ;
2017-01-16 01:49:19 +01:00
return ( cdrom [ id ] . features & 1 ) ? 2 : 1 ;
}
2017-05-05 01:49:42 +02:00
return 0 ;
2017-01-16 01:49:19 +01:00
}
/* Translates ATAPI status (ERR_STAT flag) to SCSI status. */
int cdrom_CDROM_PHASE_to_scsi ( uint8_t id )
{
if ( cdrom [ id ] . status & ERR_STAT )
return SCSI_STATUS_CHECK_CONDITION ;
else
return SCSI_STATUS_OK ;
}
/* Translates ATAPI phase (DRQ, I/O, C/D) to SCSI phase (MSG, C/D, I/O). */
int cdrom_atapi_phase_to_scsi ( uint8_t id )
{
2017-10-24 04:15:05 +02:00
if ( cdrom [ id ] . status & 8 ) {
switch ( cdrom [ id ] . phase & 3 ) {
2017-01-16 01:49:19 +01:00
case 0 :
return 0 ;
case 1 :
return 2 ;
case 2 :
return 1 ;
case 3 :
return 7 ;
}
2017-10-24 04:15:05 +02:00
} else {
2017-01-16 01:49:19 +01:00
if ( ( cdrom [ id ] . phase & 3 ) = = 3 )
return 3 ;
else
return 4 ;
}
2017-05-05 01:49:42 +02:00
return 0 ;
2017-01-16 01:49:19 +01:00
}
int cdrom_lba_to_msf_accurate ( int lba )
{
int temp_pos ;
int m , s , f ;
temp_pos = lba + 150 ;
f = temp_pos % 75 ;
temp_pos - = f ;
temp_pos / = 75 ;
s = temp_pos % 60 ;
temp_pos - = s ;
temp_pos / = 60 ;
m = temp_pos ;
return ( ( m < < 16 ) | ( s < < 8 ) | f ) ;
}
uint32_t cdrom_mode_sense_get_channel ( uint8_t id , int channel )
{
2018-01-13 22:56:13 +01:00
return cdrom_mode_sense_pages_saved [ id ] . pages [ GPMODE_CDROM_AUDIO_PAGE ] [ channel ? 10 : 8 ] ;
2017-01-16 01:49:19 +01:00
}
uint32_t cdrom_mode_sense_get_volume ( uint8_t id , int channel )
{
2018-01-13 22:56:13 +01:00
return cdrom_mode_sense_pages_saved [ id ] . pages [ GPMODE_CDROM_AUDIO_PAGE ] [ channel ? 11 : 9 ] ;
2017-01-16 01:49:19 +01:00
}
void cdrom_mode_sense_load ( uint8_t id )
{
FILE * f ;
2018-01-13 22:56:13 +01:00
wchar_t file_name [ 512 ] ;
int i ;
memset ( & cdrom_mode_sense_pages_saved [ id ] , 0 , sizeof ( mode_sense_pages_t ) ) ;
for ( i = 0 ; i < 0x3f ; i + + ) {
2018-01-17 18:43:36 +01:00
if ( cdrom_mode_sense_pages_default . pages [ i ] [ 1 ] ! = 0 ) {
if ( cdrom_drives [ id ] . bus_type = = CDROM_BUS_SCSI )
memcpy ( cdrom_mode_sense_pages_saved [ id ] . pages [ i ] , cdrom_mode_sense_pages_default_scsi . pages [ i ] , cdrom_mode_sense_pages_default_scsi . pages [ i ] [ 1 ] + 2 ) ;
else
memcpy ( cdrom_mode_sense_pages_saved [ id ] . pages [ i ] , cdrom_mode_sense_pages_default . pages [ i ] , cdrom_mode_sense_pages_default . pages [ i ] [ 1 ] + 2 ) ;
}
2018-01-13 22:56:13 +01:00
}
memset ( file_name , 0 , 512 * sizeof ( wchar_t ) ) ;
2018-01-17 18:43:36 +01:00
if ( cdrom_drives [ id ] . bus_type = = CDROM_BUS_SCSI )
swprintf ( file_name , 512 , L " scsi_cdrom_%02i_mode_sense_bin " , id ) ;
else
swprintf ( file_name , 512 , L " cdrom_%02i_mode_sense_bin " , id ) ;
2018-01-13 22:56:13 +01:00
f = plat_fopen ( nvr_path ( file_name ) , L " rb " ) ;
if ( f ) {
fread ( cdrom_mode_sense_pages_saved [ id ] . pages [ GPMODE_CDROM_AUDIO_PAGE ] , 1 , 0x10 , f ) ;
fclose ( f ) ;
2017-01-16 01:49:19 +01:00
}
}
void cdrom_mode_sense_save ( uint8_t id )
{
FILE * f ;
2018-01-13 22:56:13 +01:00
wchar_t file_name [ 512 ] ;
memset ( file_name , 0 , 512 * sizeof ( wchar_t ) ) ;
2018-01-17 18:43:36 +01:00
if ( cdrom_drives [ id ] . bus_type = = CDROM_BUS_SCSI )
swprintf ( file_name , 512 , L " scsi_cdrom_%02i_mode_sense_bin " , id ) ;
else
swprintf ( file_name , 512 , L " cdrom_%02i_mode_sense_bin " , id ) ;
2018-01-13 22:56:13 +01:00
f = plat_fopen ( nvr_path ( file_name ) , L " wb " ) ;
if ( f ) {
fwrite ( cdrom_mode_sense_pages_saved [ id ] . pages [ GPMODE_CDROM_AUDIO_PAGE ] , 1 , 0x10 , f ) ;
fclose ( f ) ;
2017-01-16 01:49:19 +01:00
}
}
static void cdrom_command_complete ( uint8_t id ) ;
2017-01-27 23:03:20 +01:00
uint8_t cdrom_read_capacity_cdb [ 12 ] = { 0x25 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 } ;
2017-05-05 01:49:42 +02:00
static int cdrom_pass_through ( uint8_t id , uint32_t * len , uint8_t * cdb , uint8_t * buffer ) ;
2017-01-27 23:03:20 +01:00
2017-05-05 01:49:42 +02:00
int cdrom_read_capacity ( uint8_t id , uint8_t * cdb , uint8_t * buffer , uint32_t * len )
2017-01-27 23:03:20 +01:00
{
int ret = 0 ;
int size = 0 ;
2017-10-24 04:15:05 +02:00
if ( cdrom_drives [ id ] . handler - > pass_through ) {
2017-01-27 23:03:20 +01:00
ret = cdrom_pass_through ( id , len , cdb , buffer ) ;
if ( ! ret )
return 0 ;
if ( * len = = 65534 )
* len = 8 ;
2017-10-24 04:15:05 +02:00
} else {
2017-01-27 23:03:20 +01:00
size = cdrom_drives [ id ] . handler - > size ( id ) - 1 ; /* IMPORTANT: What's returned is the last LBA block. */
memset ( buffer , 0 , 8 ) ;
buffer [ 0 ] = ( size > > 24 ) & 0xff ;
buffer [ 1 ] = ( size > > 16 ) & 0xff ;
buffer [ 2 ] = ( size > > 8 ) & 0xff ;
buffer [ 3 ] = size & 0xff ;
buffer [ 6 ] = 8 ; /* 2048 = 0x0800 */
* len = 8 ;
}
return 1 ;
}
2017-01-16 01:49:19 +01:00
/*SCSI Mode Sense 6/10*/
uint8_t cdrom_mode_sense_read ( uint8_t id , uint8_t page_control , uint8_t page , uint8_t pos )
{
2017-10-24 04:15:05 +02:00
switch ( page_control ) {
2017-01-16 01:49:19 +01:00
case 0 :
case 3 :
2018-01-13 22:56:13 +01:00
return cdrom_mode_sense_pages_saved [ id ] . pages [ page ] [ pos ] ;
2017-01-16 01:49:19 +01:00
break ;
case 1 :
2018-01-13 22:56:13 +01:00
return cdrom_mode_sense_pages_changeable . pages [ page ] [ pos ] ;
2017-01-16 01:49:19 +01:00
break ;
case 2 :
2018-01-17 18:43:36 +01:00
if ( cdrom_drives [ id ] . bus_type = = CDROM_BUS_SCSI )
return cdrom_mode_sense_pages_default_scsi . pages [ page ] [ pos ] ;
else
return cdrom_mode_sense_pages_default . pages [ page ] [ pos ] ;
2017-01-16 01:49:19 +01:00
break ;
}
2017-05-05 01:49:42 +02:00
return 0 ;
2017-01-16 01:49:19 +01:00
}
2017-01-27 23:03:20 +01:00
uint32_t cdrom_mode_sense ( uint8_t id , uint8_t * buf , uint32_t pos , uint8_t type , uint8_t block_descriptor_len )
2017-01-16 01:49:19 +01:00
{
uint8_t page_control = ( type > > 6 ) & 3 ;
int i = 0 ;
int j = 0 ;
uint8_t msplen ;
type & = 0x3f ;
2017-10-24 04:15:05 +02:00
if ( block_descriptor_len ) {
2017-01-27 23:03:20 +01:00
buf [ pos + + ] = 1 ; /* Density code. */
buf [ pos + + ] = 0 ; /* Number of blocks (0 = all). */
buf [ pos + + ] = 0 ;
buf [ pos + + ] = 0 ;
buf [ pos + + ] = 0 ; /* Reserved. */
buf [ pos + + ] = 0 ; /* Block length (0x800 = 2048 bytes). */
buf [ pos + + ] = 8 ;
buf [ pos + + ] = 0 ;
}
2017-10-24 04:15:05 +02:00
for ( i = 0 ; i < 0x40 ; i + + ) {
if ( ( type = = GPMODE_ALL_PAGES ) | | ( type = = i ) ) {
2018-01-13 22:56:13 +01:00
if ( cdrom_mode_sense_page_flags & ( 1LL < < cdrom [ id ] . current_page_code ) ) {
2017-01-16 01:49:19 +01:00
buf [ pos + + ] = cdrom_mode_sense_read ( id , page_control , i , 0 ) ;
msplen = cdrom_mode_sense_read ( id , page_control , i , 1 ) ;
buf [ pos + + ] = msplen ;
cdrom_log ( " CD-ROM %i: MODE SENSE: Page [%02X] length %i \n " , id , i , msplen ) ;
for ( j = 0 ; j < msplen ; j + + )
buf [ pos + + ] = cdrom_mode_sense_read ( id , page_control , i , 2 + j ) ;
}
}
}
return pos ;
}
void cdrom_update_request_length ( uint8_t id , int len , int block_len )
{
2017-10-22 03:16:52 +02:00
uint32_t bt ;
2018-02-27 23:55:28 +01:00
cdrom [ id ] . max_transfer_len = cdrom [ id ] . request_length ;
2017-10-22 03:16:52 +02:00
2017-01-16 01:49:19 +01:00
/* For media access commands, make sure the requested DRQ length matches the block length. */
2017-10-24 04:15:05 +02:00
switch ( cdrom [ id ] . current_cdb [ 0 ] ) {
2017-01-16 01:49:19 +01:00
case 0x08 :
case 0x28 :
case 0xa8 :
case 0xb9 :
case 0xbe :
2018-02-27 23:55:28 +01:00
if ( cdrom [ id ] . max_transfer_len < block_len )
cdrom [ id ] . max_transfer_len = block_len ;
2017-10-22 03:16:52 +02:00
bt = ( cdrom [ id ] . requested_blocks * block_len ) ;
if ( len > bt )
len = bt ;
2017-01-16 01:49:19 +01:00
default :
cdrom [ id ] . packet_len = len ;
break ;
}
/* If the DRQ length is odd, and the total remaining length is bigger, make sure it's even. */
2018-02-27 23:55:28 +01:00
if ( ( cdrom [ id ] . max_transfer_len & 1 ) & & ( cdrom [ id ] . max_transfer_len < len ) )
cdrom [ id ] . max_transfer_len & = 0xfffe ;
2017-01-16 01:49:19 +01:00
/* If the DRQ length is smaller or equal in size to the total remaining length, set it to that. */
2018-02-27 23:55:28 +01:00
if ( ! cdrom [ id ] . max_transfer_len )
cdrom [ id ] . max_transfer_len = 65534 ;
if ( len < = cdrom [ id ] . max_transfer_len )
cdrom [ id ] . max_transfer_len = len ;
2017-01-16 01:49:19 +01:00
return ;
}
static void cdrom_command_common ( uint8_t id )
{
cdrom [ id ] . status = BUSY_STAT ;
cdrom [ id ] . phase = 1 ;
cdrom [ id ] . pos = 0 ;
2017-10-26 20:37:39 +02:00
if ( cdrom [ id ] . packet_status = = CDROM_PHASE_COMPLETE ) {
2017-10-09 01:48:36 +02:00
cdrom [ id ] . callback = 20LL * CDROM_TIME ;
2017-10-26 20:37:39 +02:00
cdrom_set_callback ( id ) ;
2018-01-13 22:56:13 +01:00
} else if ( cdrom [ id ] . packet_status = = CDROM_PHASE_DATA_IN ) {
2017-10-24 04:15:05 +02:00
if ( cdrom [ id ] . current_cdb [ 0 ] = = 0x42 ) {
2018-02-15 23:14:44 +01:00
cdrom_log ( " CD-ROM %i: READ SUBCHANNEL \n " , id ) ;
2017-10-09 01:48:36 +02:00
cdrom [ id ] . callback = 1000LL * CDROM_TIME ;
2017-10-26 20:37:39 +02:00
cdrom_set_callback ( id ) ;
} else {
2017-10-09 01:48:36 +02:00
cdrom [ id ] . callback = 60LL * CDROM_TIME ;
2017-10-26 20:37:39 +02:00
cdrom_set_callback ( id ) ;
}
} else {
2017-10-09 01:48:36 +02:00
cdrom [ id ] . callback = 60LL * CDROM_TIME ;
2017-10-26 20:37:39 +02:00
cdrom_set_callback ( id ) ;
}
2017-01-16 01:49:19 +01:00
}
static void cdrom_command_complete ( uint8_t id )
{
cdrom [ id ] . packet_status = CDROM_PHASE_COMPLETE ;
cdrom_command_common ( id ) ;
}
static void cdrom_command_read ( uint8_t id )
{
cdrom [ id ] . packet_status = CDROM_PHASE_DATA_IN ;
cdrom_command_common ( id ) ;
cdrom [ id ] . total_read = 0 ;
}
static void cdrom_command_read_dma ( uint8_t id )
{
cdrom [ id ] . packet_status = CDROM_PHASE_DATA_IN_DMA ;
cdrom_command_common ( id ) ;
cdrom [ id ] . total_read = 0 ;
}
static void cdrom_command_write ( uint8_t id )
{
cdrom [ id ] . packet_status = CDROM_PHASE_DATA_OUT ;
cdrom_command_common ( id ) ;
}
static void cdrom_command_write_dma ( uint8_t id )
{
cdrom [ id ] . packet_status = CDROM_PHASE_DATA_OUT_DMA ;
cdrom_command_common ( id ) ;
}
2017-10-22 03:16:52 +02:00
/* id = Current CD-ROM device ID;
len = Total transfer length ;
block_len = Length of a single block ( why does it matter ? ! ) ;
alloc_len = Allocated transfer length ;
direction = Transfer direction ( 0 = read from host , 1 = write to host ) . */
2017-01-16 01:49:19 +01:00
static void cdrom_data_command_finish ( uint8_t id , int len , int block_len , int alloc_len , int direction )
{
cdrom_log ( " CD-ROM %i: Finishing command (%02X): %i, %i, %i, %i, %i \n " , id , cdrom [ id ] . current_cdb [ 0 ] , len , block_len , alloc_len , direction , cdrom [ id ] . request_length ) ;
cdrom [ id ] . pos = 0 ;
2017-10-24 04:15:05 +02:00
if ( alloc_len > = 0 ) {
if ( alloc_len < len ) {
2017-01-16 01:49:19 +01:00
len = alloc_len ;
}
}
2018-02-27 23:55:28 +01:00
if ( ( len = = 0 ) | | ( cdrom_current_mode ( id ) = = 0 ) ) {
2017-10-24 04:15:05 +02:00
if ( cdrom_drives [ id ] . bus_type ! = CDROM_BUS_SCSI ) {
cdrom [ id ] . packet_len = 0 ;
2017-02-08 18:42:20 +01:00
}
2017-01-16 01:49:19 +01:00
cdrom_command_complete ( id ) ;
}
2017-10-24 04:15:05 +02:00
else {
if ( cdrom_current_mode ( id ) = = 2 ) {
if ( cdrom_drives [ id ] . bus_type ! = CDROM_BUS_SCSI ) {
cdrom [ id ] . packet_len = alloc_len ;
}
2017-01-16 01:49:19 +01:00
if ( direction = = 0 )
cdrom_command_read_dma ( id ) ;
else
cdrom_command_write_dma ( id ) ;
}
2017-10-24 04:15:05 +02:00
else {
2017-01-16 01:49:19 +01:00
cdrom_update_request_length ( id , len , block_len ) ;
if ( direction = = 0 )
cdrom_command_read ( id ) ;
else
cdrom_command_write ( id ) ;
}
}
cdrom_log ( " CD-ROM %i: Status: %i, cylinder %i, packet length: %i, position: %i, phase: %i \n " , id , cdrom [ id ] . packet_status , cdrom [ id ] . request_length , cdrom [ id ] . packet_len , cdrom [ id ] . pos , cdrom [ id ] . phase ) ;
}
2017-01-21 06:21:46 +01:00
static void cdrom_sense_clear ( int id , int command )
2017-01-16 01:49:19 +01:00
{
2017-01-21 06:21:46 +01:00
cdrom [ id ] . previous_command = command ;
cdrom_sense_key = cdrom_asc = cdrom_ascq = 0 ;
2017-01-16 01:49:19 +01:00
}
2018-01-06 22:47:41 +01:00
static void cdrom_set_phase ( uint8_t id , uint8_t phase )
{
uint8_t scsi_id = cdrom_drives [ id ] . scsi_device_id ;
uint8_t scsi_lun = cdrom_drives [ id ] . scsi_device_lun ;
if ( cdrom_drives [ id ] . bus_type ! = CDROM_BUS_SCSI )
return ;
SCSIDevices [ scsi_id ] [ scsi_lun ] . Phase = phase ;
}
2017-01-16 01:49:19 +01:00
static void cdrom_cmd_error ( uint8_t id )
{
2018-01-06 22:47:41 +01:00
cdrom_set_phase ( id , SCSI_PHASE_STATUS ) ;
2017-01-16 01:49:19 +01:00
cdrom [ id ] . error = ( ( cdrom_sense_key & 0xf ) < < 4 ) | ABRT_ERR ;
if ( cdrom [ id ] . unit_attention )
cdrom [ id ] . error | = MCR_ERR ;
cdrom [ id ] . status = READY_STAT | ERR_STAT ;
cdrom [ id ] . phase = 3 ;
2018-01-13 22:56:13 +01:00
cdrom [ id ] . pos = 0 ;
2017-01-16 01:49:19 +01:00
cdrom [ id ] . packet_status = 0x80 ;
2017-10-09 01:48:36 +02:00
cdrom [ id ] . callback = 50LL * CDROM_TIME ;
2017-10-26 20:37:39 +02:00
cdrom_set_callback ( id ) ;
2017-01-21 01:19:49 +01:00
cdrom_log ( " CD-ROM %i: ERROR: %02X/%02X/%02X \n " , id , cdrom_sense_key , cdrom_asc , cdrom_ascq ) ;
2017-01-16 01:49:19 +01:00
}
static void cdrom_unit_attention ( uint8_t id )
{
2018-01-06 22:47:41 +01:00
cdrom_set_phase ( id , SCSI_PHASE_STATUS ) ;
2017-01-16 01:49:19 +01:00
cdrom [ id ] . error = ( SENSE_UNIT_ATTENTION < < 4 ) | ABRT_ERR ;
if ( cdrom [ id ] . unit_attention )
cdrom [ id ] . error | = MCR_ERR ;
cdrom [ id ] . status = READY_STAT | ERR_STAT ;
cdrom [ id ] . phase = 3 ;
2018-01-13 22:56:13 +01:00
cdrom [ id ] . pos = 0 ;
2017-01-16 01:49:19 +01:00
cdrom [ id ] . packet_status = 0x80 ;
2017-10-09 01:48:36 +02:00
cdrom [ id ] . callback = 50LL * CDROM_TIME ;
2017-10-26 20:37:39 +02:00
cdrom_set_callback ( id ) ;
2017-01-21 01:17:49 +01:00
cdrom_log ( " CD-ROM %i: UNIT ATTENTION \n " , id ) ;
2017-01-16 01:49:19 +01:00
}
2017-10-26 20:37:39 +02:00
static void cdrom_bus_master_error ( uint8_t id )
{
cdrom_sense_key = cdrom_asc = cdrom_ascq = 0 ;
cdrom_cmd_error ( id ) ;
}
2017-01-16 01:49:19 +01:00
static void cdrom_not_ready ( uint8_t id )
{
cdrom_sense_key = SENSE_NOT_READY ;
cdrom_asc = ASC_MEDIUM_NOT_PRESENT ;
cdrom_ascq = 0 ;
cdrom_cmd_error ( id ) ;
}
2017-01-21 01:17:49 +01:00
static void cdrom_invalid_lun ( uint8_t id )
2017-01-18 21:51:03 +01:00
{
cdrom_sense_key = SENSE_ILLEGAL_REQUEST ;
2017-01-21 01:17:49 +01:00
cdrom_asc = ASC_INV_LUN ;
2017-01-18 21:51:03 +01:00
cdrom_ascq = 0 ;
cdrom_cmd_error ( id ) ;
}
2017-01-16 01:49:19 +01:00
static void cdrom_illegal_opcode ( uint8_t id )
{
cdrom_sense_key = SENSE_ILLEGAL_REQUEST ;
cdrom_asc = ASC_ILLEGAL_OPCODE ;
cdrom_ascq = 0 ;
cdrom_cmd_error ( id ) ;
}
static void cdrom_lba_out_of_range ( uint8_t id )
{
cdrom_sense_key = SENSE_ILLEGAL_REQUEST ;
cdrom_asc = ASC_LBA_OUT_OF_RANGE ;
cdrom_ascq = 0 ;
cdrom_cmd_error ( id ) ;
}
static void cdrom_invalid_field ( uint8_t id )
{
cdrom_sense_key = SENSE_ILLEGAL_REQUEST ;
cdrom_asc = ASC_INV_FIELD_IN_CMD_PACKET ;
cdrom_ascq = 0 ;
cdrom_cmd_error ( id ) ;
cdrom [ id ] . status = 0x53 ;
}
static void cdrom_invalid_field_pl ( uint8_t id )
{
cdrom_sense_key = SENSE_ILLEGAL_REQUEST ;
cdrom_asc = ASC_INV_FIELD_IN_PARAMETER_LIST ;
cdrom_ascq = 0 ;
cdrom_cmd_error ( id ) ;
cdrom [ id ] . status = 0x53 ;
}
static void cdrom_illegal_mode ( uint8_t id )
{
cdrom_sense_key = SENSE_ILLEGAL_REQUEST ;
cdrom_asc = ASC_ILLEGAL_MODE_FOR_THIS_TRACK ;
cdrom_ascq = 0 ;
cdrom_cmd_error ( id ) ;
}
static void cdrom_incompatible_format ( uint8_t id )
{
cdrom_sense_key = SENSE_ILLEGAL_REQUEST ;
cdrom_asc = ASC_INCOMPATIBLE_FORMAT ;
2017-12-10 15:16:24 +01:00
cdrom_ascq = 2 ;
2017-01-16 01:49:19 +01:00
cdrom_cmd_error ( id ) ;
}
static void cdrom_data_phase_error ( uint8_t id )
{
cdrom_sense_key = SENSE_ILLEGAL_REQUEST ;
cdrom_asc = ASC_DATA_PHASE_ERROR ;
cdrom_ascq = 0 ;
cdrom_cmd_error ( id ) ;
}
2017-05-05 01:49:42 +02:00
static int cdrom_pass_through ( uint8_t id , uint32_t * len , uint8_t * cdb , uint8_t * buffer )
2017-01-16 01:49:19 +01:00
{
int ret = 0 ;
2017-05-05 01:49:42 +02:00
uint8_t temp_cdb [ 16 ] ;
memset ( temp_cdb , 0 , 16 ) ;
2017-10-24 04:15:05 +02:00
if ( cdb [ 0 ] = = 8 ) {
2017-05-05 01:49:42 +02:00
temp_cdb [ 0 ] = 0x28 ;
temp_cdb [ 8 ] = cdb [ 4 ] ;
temp_cdb [ 3 ] = cdb [ 1 ] ;
temp_cdb [ 4 ] = cdb [ 2 ] ;
temp_cdb [ 5 ] = cdb [ 3 ] ;
2017-10-24 04:15:05 +02:00
} else
2017-05-05 01:49:42 +02:00
memcpy ( temp_cdb , cdb , 16 ) ;
2017-01-16 01:49:19 +01:00
2017-05-05 01:49:42 +02:00
ret = cdrom_drives [ id ] . handler - > pass_through ( id , temp_cdb , buffer , len ) ;
2017-01-27 23:03:20 +01:00
cdrom_log ( " CD-ROM %i: Data from pass through: %02X %02X %02X %02X %02X %02X %02X %02X \n " , id , buffer [ 0 ] , buffer [ 1 ] , buffer [ 2 ] , buffer [ 3 ] , buffer [ 4 ] , buffer [ 5 ] , buffer [ 6 ] , buffer [ 7 ] ) ;
2017-01-16 01:49:19 +01:00
cdrom_log ( " CD-ROM %i: Returned value: %i \n " , id , ret ) ;
2017-10-24 04:15:05 +02:00
if ( ! ret ) {
2017-01-16 01:49:19 +01:00
/* Command failed with OS error code, return illegal opcode. */
cdrom_log ( " CD-ROM %i: Command failed with OS error code, return illegal opcode. \n " , id ) ;
cdrom_illegal_opcode ( id ) ;
return 0 ;
2017-10-24 04:15:05 +02:00
} else {
if ( ( cdrom_sense_key ! = 0 ) | | ( cdrom_asc ! = 0 ) | | ( cdrom_ascq ! = 0 ) ) {
2017-01-16 01:49:19 +01:00
/* Command failed with sense, error with that sense. */
2017-01-18 21:51:03 +01:00
cdrom_log ( " CD-ROM %i: Command failed with sense, error with that sense (%02X/%02X/%02X). \n " , id , cdrom_sense_key , cdrom_asc , cdrom_ascq ) ;
2017-01-16 01:49:19 +01:00
cdrom_cmd_error ( id ) ;
return 0 ;
2017-10-24 04:15:05 +02:00
} else {
2017-01-16 01:49:19 +01:00
/* Command was performed successfully. */
cdrom_log ( " CD-ROM %i: Command was performed successfully. \n " , id ) ;
return 1 ;
}
}
}
2017-05-05 01:49:42 +02:00
void cdrom_update_cdb ( uint8_t * cdb , int lba_pos , int number_of_blocks )
2017-01-16 01:49:19 +01:00
{
int temp = 0 ;
2017-10-24 04:15:05 +02:00
switch ( cdb [ 0 ] ) {
2017-01-16 01:49:19 +01:00
case GPCMD_READ_6 :
2017-01-18 21:51:03 +01:00
cdb [ 1 ] = ( lba_pos > > 16 ) & 0xff ;
cdb [ 2 ] = ( lba_pos > > 8 ) & 0xff ;
cdb [ 3 ] = lba_pos & 0xff ;
2017-01-16 01:49:19 +01:00
break ;
case GPCMD_READ_10 :
2017-01-18 21:51:03 +01:00
cdb [ 2 ] = ( lba_pos > > 24 ) & 0xff ;
cdb [ 3 ] = ( lba_pos > > 16 ) & 0xff ;
cdb [ 4 ] = ( lba_pos > > 8 ) & 0xff ;
cdb [ 5 ] = lba_pos & 0xff ;
cdb [ 7 ] = ( number_of_blocks > > 8 ) & 0xff ;
cdb [ 8 ] = number_of_blocks & 0xff ;
2017-01-16 01:49:19 +01:00
break ;
case GPCMD_READ_12 :
2017-01-18 21:51:03 +01:00
cdb [ 2 ] = ( lba_pos > > 24 ) & 0xff ;
cdb [ 3 ] = ( lba_pos > > 16 ) & 0xff ;
cdb [ 4 ] = ( lba_pos > > 8 ) & 0xff ;
cdb [ 5 ] = lba_pos & 0xff ;
cdb [ 6 ] = ( number_of_blocks > > 24 ) & 0xff ;
cdb [ 7 ] = ( number_of_blocks > > 16 ) & 0xff ;
cdb [ 8 ] = ( number_of_blocks > > 8 ) & 0xff ;
cdb [ 9 ] = number_of_blocks & 0xff ;
2017-01-16 01:49:19 +01:00
break ;
2017-10-24 04:15:05 +02:00
2017-01-16 01:49:19 +01:00
case GPCMD_READ_CD_MSF :
2017-01-18 21:51:03 +01:00
temp = cdrom_lba_to_msf_accurate ( lba_pos ) ;
cdb [ 3 ] = ( temp > > 16 ) & 0xff ;
cdb [ 4 ] = ( temp > > 8 ) & 0xff ;
cdb [ 5 ] = temp & 0xff ;
temp = cdrom_lba_to_msf_accurate ( lba_pos + number_of_blocks - 1 ) ;
cdb [ 6 ] = ( temp > > 16 ) & 0xff ;
cdb [ 7 ] = ( temp > > 8 ) & 0xff ;
cdb [ 8 ] = temp & 0xff ;
2017-01-16 01:49:19 +01:00
break ;
case GPCMD_READ_CD :
2017-01-18 21:51:03 +01:00
cdb [ 2 ] = ( lba_pos > > 24 ) & 0xff ;
cdb [ 3 ] = ( lba_pos > > 16 ) & 0xff ;
cdb [ 4 ] = ( lba_pos > > 8 ) & 0xff ;
cdb [ 5 ] = lba_pos & 0xff ;
cdb [ 6 ] = ( number_of_blocks > > 16 ) & 0xff ;
cdb [ 7 ] = ( number_of_blocks > > 8 ) & 0xff ;
cdb [ 8 ] = number_of_blocks & 0xff ;
2017-01-16 01:49:19 +01:00
break ;
}
}
2017-10-16 06:19:18 +02:00
# define cdbufferb cdrom[id].buffer
2017-05-05 01:49:42 +02:00
int cdrom_read_data ( uint8_t id , int msf , int type , int flags , uint32_t * len )
2017-01-16 01:49:19 +01:00
{
int ret = 0 ;
int cdsize = 0 ;
int i = 0 ;
2017-01-17 00:01:59 +01:00
int temp_len = 0 ;
2017-01-16 01:49:19 +01:00
2017-01-20 23:53:19 +01:00
int last_valid_data_pos = 0 ;
2017-10-24 04:15:05 +02:00
if ( cdrom_drives [ id ] . handler - > pass_through ) {
2017-01-16 01:49:19 +01:00
cdsize = cdrom_drives [ id ] . handler - > size ( id ) ;
2017-01-27 23:03:20 +01:00
ret = cdrom_pass_through ( id , len , cdrom [ id ] . current_cdb , cdbufferb + cdrom [ id ] . data_pos ) ;
2017-01-16 01:49:19 +01:00
cdrom [ id ] . data_pos + = * len ;
if ( ! ret )
return 0 ;
2017-10-24 04:15:05 +02:00
if ( cdrom [ id ] . sector_pos > ( cdsize - 1 ) ) {
2017-05-05 01:49:42 +02:00
/* cdrom_log("CD-ROM %i: Trying to read beyond the end of disc\n", id); */
2017-01-16 01:49:19 +01:00
cdrom_lba_out_of_range ( id ) ;
return 0 ;
}
cdrom [ id ] . old_len = * len ;
2017-10-24 04:15:05 +02:00
} else {
if ( cdrom [ id ] . sector_pos > ( cdrom_drives [ id ] . handler - > size ( id ) - 1 ) ) {
2017-05-05 01:49:42 +02:00
/* cdrom_log("CD-ROM %i: Trying to read beyond the end of disc\n", id); */
2017-01-16 01:49:19 +01:00
cdrom_lba_out_of_range ( id ) ;
return 0 ;
}
cdrom [ id ] . old_len = 0 ;
2017-01-17 00:01:59 +01:00
* len = 0 ;
2017-01-16 01:49:19 +01:00
2017-10-24 04:15:05 +02:00
for ( i = 0 ; i < cdrom [ id ] . requested_blocks ; i + + ) {
2017-01-20 23:53:19 +01:00
ret = cdrom_drives [ id ] . handler - > readsector_raw ( id , cdbufferb + cdrom [ id ] . data_pos , cdrom [ id ] . sector_pos + i , msf , type , flags , & temp_len ) ;
last_valid_data_pos = cdrom [ id ] . data_pos ;
2017-01-17 00:01:59 +01:00
cdrom [ id ] . data_pos + = temp_len ;
cdrom [ id ] . old_len + = temp_len ;
2017-01-16 01:49:19 +01:00
2017-01-17 00:01:59 +01:00
* len + = temp_len ;
2017-01-16 01:49:19 +01:00
2017-10-24 04:15:05 +02:00
if ( ! ret ) {
2017-01-16 01:49:19 +01:00
cdrom_illegal_mode ( id ) ;
return 0 ;
}
}
2017-01-20 23:53:19 +01:00
cdrom_log ( " CD-ROM %i: Data from raw sector read: %02X %02X %02X %02X %02X %02X %02X %02X \n " , id , cdbufferb [ last_valid_data_pos + 0 ] , cdbufferb [ last_valid_data_pos + 1 ] , cdbufferb [ last_valid_data_pos + 2 ] , cdbufferb [ last_valid_data_pos + 3 ] , cdbufferb [ last_valid_data_pos + 4 ] , cdbufferb [ last_valid_data_pos + 5 ] , cdbufferb [ last_valid_data_pos + 6 ] , cdbufferb [ last_valid_data_pos + 7 ] ) ;
2017-01-16 01:49:19 +01:00
}
return 1 ;
}
2017-05-05 01:49:42 +02:00
int cdrom_read_blocks ( uint8_t id , uint32_t * len , int first_batch )
2017-01-16 01:49:19 +01:00
{
int ret = 0 ;
int msf = 0 ;
int type = 0 ;
int flags = 0 ;
if ( cdrom [ id ] . current_cdb [ 0 ] = = 0xb9 )
msf = 1 ;
2017-10-24 04:15:05 +02:00
if ( ( cdrom [ id ] . current_cdb [ 0 ] = = 0xb9 ) | | ( cdrom [ id ] . current_cdb [ 0 ] = = 0xbe ) ) {
2017-01-16 01:49:19 +01:00
type = ( cdrom [ id ] . current_cdb [ 1 ] > > 2 ) & 7 ;
2018-01-13 22:56:13 +01:00
flags = cdrom [ id ] . current_cdb [ 9 ] | ( ( ( uint32_t ) cdrom [ id ] . current_cdb [ 10 ] ) < < 8 ) ;
2017-10-24 04:15:05 +02:00
} else {
2017-06-14 05:17:13 +02:00
type = 8 ;
2017-01-16 01:49:19 +01:00
flags = 0x10 ;
}
cdrom [ id ] . data_pos = 0 ;
2017-10-24 04:15:05 +02:00
if ( ! cdrom [ id ] . sector_len ) {
2017-01-16 01:49:19 +01:00
cdrom_command_complete ( id ) ;
2017-01-17 19:41:42 +01:00
return - 1 ;
2017-01-16 01:49:19 +01:00
}
cdrom_log ( " Reading %i blocks starting from %i... \n " , cdrom [ id ] . requested_blocks , cdrom [ id ] . sector_pos ) ;
2017-01-18 21:51:03 +01:00
cdrom_update_cdb ( cdrom [ id ] . current_cdb , cdrom [ id ] . sector_pos , cdrom [ id ] . requested_blocks ) ;
2017-01-16 01:49:19 +01:00
ret = cdrom_read_data ( id , msf , type , flags , len ) ;
cdrom_log ( " Read %i bytes of blocks... \n " , * len ) ;
2017-10-24 04:15:05 +02:00
if ( ! ret | | ( ( cdrom [ id ] . old_len ! = * len ) & & ! first_batch ) ) {
2017-01-16 01:49:19 +01:00
if ( ( cdrom [ id ] . old_len ! = * len ) & & ! first_batch )
cdrom_illegal_mode ( id ) ;
return 0 ;
}
cdrom [ id ] . sector_pos + = cdrom [ id ] . requested_blocks ;
cdrom [ id ] . sector_len - = cdrom [ id ] . requested_blocks ;
return 1 ;
}
/*SCSI Get Configuration*/
/*SCSI Read DVD Structure*/
static int cdrom_read_dvd_structure ( uint8_t id , int format , const uint8_t * packet , uint8_t * buf )
{
int layer = packet [ 6 ] ;
uint64_t total_sectors ;
2017-10-24 04:15:05 +02:00
switch ( format ) {
2017-01-16 01:49:19 +01:00
case 0x00 : /* Physical format information */
total_sectors = ( uint64_t ) cdrom_drives [ id ] . handler - > size ( id ) ;
2017-10-24 04:15:05 +02:00
if ( layer ! = 0 ) {
2017-01-16 01:49:19 +01:00
cdrom_invalid_field ( id ) ;
return 0 ;
}
total_sectors > > = 2 ;
2017-10-24 04:15:05 +02:00
if ( total_sectors = = 0 ) {
2017-05-05 01:49:42 +02:00
/* return -ASC_MEDIUM_NOT_PRESENT; */
2017-01-16 01:49:19 +01:00
cdrom_not_ready ( id ) ;
return 0 ;
}
buf [ 4 ] = 1 ; /* DVD-ROM, part version 1 */
buf [ 5 ] = 0xf ; /* 120mm disc, minimum rate unspecified */
buf [ 6 ] = 1 ; /* one layer, read-only (per MMC-2 spec) */
buf [ 7 ] = 0 ; /* default densities */
/* FIXME: 0x30000 per spec? */
buf [ 8 ] = buf [ 9 ] = buf [ 10 ] = buf [ 11 ] = 0 ; /* start sector */
buf [ 12 ] = ( total_sectors > > 24 ) & 0xff ; /* end sector */
buf [ 13 ] = ( total_sectors > > 16 ) & 0xff ;
buf [ 14 ] = ( total_sectors > > 8 ) & 0xff ;
buf [ 15 ] = total_sectors & 0xff ;
buf [ 16 ] = ( total_sectors > > 24 ) & 0xff ; /* l0 end sector */
buf [ 17 ] = ( total_sectors > > 16 ) & 0xff ;
buf [ 18 ] = ( total_sectors > > 8 ) & 0xff ;
buf [ 19 ] = total_sectors & 0xff ;
/* Size of buffer, not including 2 byte size field */
buf [ 0 ] = ( ( 2048 + 2 ) > > 8 ) & 0xff ;
buf [ 1 ] = ( 2048 + 2 ) & 0xff ;
/* 2k data + 4 byte header */
return ( 2048 + 4 ) ;
case 0x01 : /* DVD copyright information */
buf [ 4 ] = 0 ; /* no copyright data */
buf [ 5 ] = 0 ; /* no region restrictions */
/* Size of buffer, not including 2 byte size field */
buf [ 0 ] = ( ( 4 + 2 ) > > 8 ) & 0xff ;
buf [ 1 ] = ( 4 + 2 ) & 0xff ;
/* 4 byte header + 4 byte data */
return ( 4 + 4 ) ;
case 0x03 : /* BCA information - invalid field for no BCA info */
cdrom_invalid_field ( id ) ;
return 0 ;
case 0x04 : /* DVD disc manufacturing information */
/* Size of buffer, not including 2 byte size field */
buf [ 0 ] = ( ( 2048 + 2 ) > > 8 ) & 0xff ;
buf [ 1 ] = ( 2048 + 2 ) & 0xff ;
/* 2k data + 4 byte header */
return ( 2048 + 4 ) ;
case 0xff :
/*
* This lists all the command capabilities above . Add new ones
* in order and update the length and buffer return values .
*/
buf [ 4 ] = 0x00 ; /* Physical format */
buf [ 5 ] = 0x40 ; /* Not writable, is readable */
buf [ 6 ] = ( ( 2048 + 4 ) > > 8 ) & 0xff ;
buf [ 7 ] = ( 2048 + 4 ) & 0xff ;
buf [ 8 ] = 0x01 ; /* Copyright info */
buf [ 9 ] = 0x40 ; /* Not writable, is readable */
buf [ 10 ] = ( ( 4 + 4 ) > > 8 ) & 0xff ;
buf [ 11 ] = ( 4 + 4 ) & 0xff ;
buf [ 12 ] = 0x03 ; /* BCA info */
buf [ 13 ] = 0x40 ; /* Not writable, is readable */
buf [ 14 ] = ( ( 188 + 4 ) > > 8 ) & 0xff ;
buf [ 15 ] = ( 188 + 4 ) & 0xff ;
buf [ 16 ] = 0x04 ; /* Manufacturing info */
buf [ 17 ] = 0x40 ; /* Not writable, is readable */
buf [ 18 ] = ( ( 2048 + 4 ) > > 8 ) & 0xff ;
buf [ 19 ] = ( 2048 + 4 ) & 0xff ;
/* Size of buffer, not including 2 byte size field */
buf [ 6 ] = ( ( 16 + 2 ) > > 8 ) & 0xff ;
buf [ 7 ] = ( 16 + 2 ) & 0xff ;
/* data written + 4 byte header */
return ( 16 + 4 ) ;
default : /* TODO: formats beyond DVD-ROM requires */
cdrom_invalid_field ( id ) ;
return 0 ;
}
}
void cdrom_insert ( uint8_t id )
{
cdrom [ id ] . unit_attention = 1 ;
}
/*SCSI Sense Initialization*/
void cdrom_sense_code_ok ( uint8_t id )
{
cdrom_sense_key = SENSE_NONE ;
cdrom_asc = 0 ;
cdrom_ascq = 0 ;
}
int cdrom_pre_execution_check ( uint8_t id , uint8_t * cdb )
{
int ready = 0 ;
2017-10-24 04:15:05 +02:00
if ( cdrom_drives [ id ] . bus_type = = CDROM_BUS_SCSI ) {
if ( ( ( cdrom [ id ] . request_length > > 5 ) & 7 ) ! = cdrom_drives [ id ] . scsi_device_lun ) {
2017-01-18 21:51:03 +01:00
cdrom_log ( " CD-ROM %i: Attempting to execute a unknown command targeted at SCSI LUN %i \n " , id , ( ( cdrom [ id ] . request_length > > 5 ) & 7 ) ) ;
2017-01-21 01:17:49 +01:00
cdrom_invalid_lun ( id ) ;
2017-01-18 21:51:03 +01:00
return 0 ;
}
}
2017-10-24 04:15:05 +02:00
if ( ! ( cdrom_command_flags [ cdb [ 0 ] ] & IMPLEMENTED ) ) {
2017-05-27 03:53:32 +02:00
cdrom_log ( " CD-ROM %i: Attempting to execute unknown command %02X over %s \n " , id , cdb [ 0 ] , ( cdrom_drives [ id ] . bus_type = = CDROM_BUS_SCSI ) ? " SCSI " : ( ( cdrom_drives [ id ] . bus_type = = CDROM_BUS_ATAPI_PIO_AND_DMA ) ? " ATAPI PIO/DMA " : " ATAPI PIO " ) ) ;
2017-05-17 21:56:31 +02:00
2017-01-16 01:49:19 +01:00
cdrom_illegal_opcode ( id ) ;
return 0 ;
}
2017-10-24 04:15:05 +02:00
if ( ( cdrom_drives [ id ] . bus_type < CDROM_BUS_SCSI ) & & ( cdrom_command_flags [ cdb [ 0 ] ] & SCSI_ONLY ) ) {
2017-01-16 01:49:19 +01:00
cdrom_log ( " CD-ROM %i: Attempting to execute SCSI-only command %02X over ATAPI \n " , id , cdb [ 0 ] ) ;
cdrom_illegal_opcode ( id ) ;
return 0 ;
}
2017-10-24 04:15:05 +02:00
if ( ( cdrom_drives [ id ] . bus_type = = CDROM_BUS_SCSI ) & & ( cdrom_command_flags [ cdb [ 0 ] ] & ATAPI_ONLY ) ) {
2017-01-16 01:49:19 +01:00
cdrom_log ( " CD-ROM %i: Attempting to execute ATAPI-only command %02X over SCSI \n " , id , cdb [ 0 ] ) ;
cdrom_illegal_opcode ( id ) ;
return 0 ;
}
2017-10-24 04:15:05 +02:00
if ( ( cdrom_drives [ id ] . handler - > status ( id ) = = CD_STATUS_PLAYING ) | | ( cdrom_drives [ id ] . handler - > status ( id ) = = CD_STATUS_PAUSED ) ) {
2017-06-01 01:47:54 +02:00
ready = 1 ;
goto skip_ready_check ;
}
2017-01-16 01:49:19 +01:00
if ( cdrom_drives [ id ] . handler - > medium_changed ( id ) )
cdrom_insert ( id ) ;
ready = cdrom_drives [ id ] . handler - > ready ( id ) ;
2017-06-01 01:47:54 +02:00
skip_ready_check :
2017-10-24 04:15:05 +02:00
/* If the drive is not ready, there is no reason to keep the
UNIT ATTENTION condition present , as we only use it to mark
disc changes . */
2017-01-16 01:49:19 +01:00
if ( ! ready & & cdrom [ id ] . unit_attention )
cdrom [ id ] . unit_attention = 0 ;
2017-01-21 06:21:46 +01:00
2017-01-16 01:49:19 +01:00
/* If the UNIT ATTENTION condition is set and the command does not allow
execution under it , error out and report the condition . */
2017-10-24 04:15:05 +02:00
if ( cdrom [ id ] . unit_attention = = 1 ) {
2017-01-21 06:21:46 +01:00
/* Only increment the unit attention phase if the command can not pass through it. */
2017-10-24 04:15:05 +02:00
if ( ! ( cdrom_command_flags [ cdb [ 0 ] ] & ALLOW_UA ) ) {
2017-05-05 01:49:42 +02:00
/* cdrom_log("CD-ROM %i: Unit attention now 2\n", id); */
2017-01-21 06:21:46 +01:00
cdrom [ id ] . unit_attention = 2 ;
2017-01-16 01:49:19 +01:00
cdrom_log ( " CD-ROM %i: UNIT ATTENTION: Command %02X not allowed to pass through \n " , id , cdb [ 0 ] ) ;
cdrom_unit_attention ( id ) ;
return 0 ;
}
}
2017-10-24 04:15:05 +02:00
else if ( cdrom [ id ] . unit_attention = = 2 ) {
if ( cdb [ 0 ] ! = GPCMD_REQUEST_SENSE ) {
2017-05-05 01:49:42 +02:00
/* cdrom_log("CD-ROM %i: Unit attention now 0\n", id); */
2017-01-16 01:49:19 +01:00
cdrom [ id ] . unit_attention = 0 ;
}
}
/* Unless the command is REQUEST SENSE, clear the sense. This will *NOT*
the UNIT ATTENTION condition if it ' s set . */
if ( cdb [ 0 ] ! = GPCMD_REQUEST_SENSE )
2017-01-21 06:21:46 +01:00
cdrom_sense_clear ( id , cdb [ 0 ] ) ;
2017-01-16 01:49:19 +01:00
/* Next it's time for NOT READY. */
2017-10-11 01:17:41 +02:00
if ( ! ready )
cdrom [ id ] . media_status = MEC_MEDIA_REMOVAL ;
else
cdrom [ id ] . media_status = ( cdrom [ id ] . unit_attention ) ? MEC_NEW_MEDIA : MEC_NO_CHANGE ;
2017-10-24 04:15:05 +02:00
if ( ( cdrom_command_flags [ cdb [ 0 ] ] & CHECK_READY ) & & ! ready ) {
2017-01-16 01:49:19 +01:00
cdrom_log ( " CD-ROM %i: Not ready (%02X) \n " , id , cdb [ 0 ] ) ;
cdrom_not_ready ( id ) ;
return 0 ;
}
2017-05-17 21:56:31 +02:00
cdrom_log ( " CD-ROM %i: Continuing with command %02X \n " , id , cdb [ 0 ] ) ;
2017-01-16 01:49:19 +01:00
return 1 ;
}
void cdrom_clear_callback ( uint8_t channel )
{
uint8_t id = atapi_cdrom_drives [ channel ] ;
2017-10-26 20:37:39 +02:00
if ( id < CDROM_NUM )
2017-01-16 01:49:19 +01:00
{
2017-10-09 01:48:36 +02:00
cdrom [ id ] . callback = 0LL ;
2017-10-26 20:37:39 +02:00
cdrom_set_callback ( id ) ;
2017-01-16 01:49:19 +01:00
}
}
static void cdrom_seek ( uint8_t id , uint32_t pos )
{
2017-05-05 01:49:42 +02:00
/* cdrom_log("CD-ROM %i: Seek %08X\n", id, pos); */
2017-01-16 01:49:19 +01:00
cdrom [ id ] . seek_pos = pos ;
if ( cdrom_drives [ id ] . handler - > stop )
cdrom_drives [ id ] . handler - > stop ( id ) ;
}
static void cdrom_rezero ( uint8_t id )
{
if ( cdrom_drives [ id ] . handler - > stop )
cdrom_drives [ id ] . handler - > stop ( id ) ;
cdrom [ id ] . sector_pos = cdrom [ id ] . sector_len = 0 ;
cdrom_seek ( id , 0 ) ;
}
void cdrom_reset ( uint8_t id )
{
cdrom_rezero ( id ) ;
cdrom [ id ] . status = 0 ;
2017-10-09 01:48:36 +02:00
cdrom [ id ] . callback = 0LL ;
2017-10-26 20:37:39 +02:00
cdrom_set_callback ( id ) ;
2017-01-16 01:49:19 +01:00
cdrom [ id ] . packet_status = 0xff ;
cdrom [ id ] . unit_attention = 0 ;
}
2017-01-21 02:02:35 +01:00
int cdrom_playing_completed ( uint8_t id )
2017-01-21 01:58:48 +01:00
{
cdrom [ id ] . prev_status = cdrom [ id ] . cd_status ;
cdrom [ id ] . cd_status = cdrom_drives [ id ] . handler - > status ( id ) ;
if ( ( ( cdrom [ id ] . prev_status = = CD_STATUS_PLAYING ) | | ( cdrom [ id ] . prev_status = = CD_STATUS_PAUSED ) ) & & ( ( cdrom [ id ] . cd_status ! = CD_STATUS_PLAYING ) & & ( cdrom [ id ] . cd_status ! = CD_STATUS_PAUSED ) ) )
return 1 ;
else
return 0 ;
}
2017-01-21 01:48:55 +01:00
void cdrom_request_sense ( uint8_t id , uint8_t * buffer , uint8_t alloc_length )
{
/*Will return 18 bytes of 0*/
2017-10-24 04:15:05 +02:00
if ( alloc_length ! = 0 ) {
2017-01-21 01:48:55 +01:00
memset ( buffer , 0 , alloc_length ) ;
memcpy ( buffer , cdrom [ id ] . sense , alloc_length ) ;
}
buffer [ 0 ] = 0x70 ;
2017-10-24 04:15:05 +02:00
if ( ( cdrom_sense_key > 0 ) & & ( ( cdrom [ id ] . cd_status < CD_STATUS_PLAYING ) | | ( cdrom [ id ] . cd_status = = CD_STATUS_STOPPED ) ) & & cdrom_playing_completed ( id ) ) {
2017-01-21 01:48:55 +01:00
buffer [ 2 ] = SENSE_ILLEGAL_REQUEST ;
buffer [ 12 ] = ASC_AUDIO_PLAY_OPERATION ;
buffer [ 13 ] = ASCQ_AUDIO_PLAY_OPERATION_COMPLETED ;
}
2017-10-24 04:15:05 +02:00
else if ( ( cdrom_sense_key = = 0 ) & & ( cdrom [ id ] . cd_status > = CD_STATUS_PLAYING ) & & ( cdrom [ id ] . cd_status ! = CD_STATUS_STOPPED ) ) {
2017-01-21 01:48:55 +01:00
buffer [ 2 ] = SENSE_ILLEGAL_REQUEST ;
buffer [ 12 ] = ASC_AUDIO_PLAY_OPERATION ;
buffer [ 13 ] = ( cdrom [ id ] . cd_status = = CD_STATUS_PLAYING ) ? ASCQ_AUDIO_PLAY_OPERATION_IN_PROGRESS : ASCQ_AUDIO_PLAY_OPERATION_PAUSED ;
}
2017-10-24 04:15:05 +02:00
else {
if ( cdrom [ id ] . unit_attention & & ( cdrom_sense_key = = 0 ) ) {
2017-01-21 01:48:55 +01:00
buffer [ 2 ] = SENSE_UNIT_ATTENTION ;
buffer [ 12 ] = ASC_MEDIUM_MAY_HAVE_CHANGED ;
buffer [ 13 ] = 0 ;
}
}
2017-10-08 05:04:38 +02:00
cdrom_log ( " CD-ROM %i: Reporting sense: %02X %02X %02X \n " , id , buffer [ 2 ] , buffer [ 12 ] , buffer [ 13 ] ) ;
2017-01-21 01:48:55 +01:00
2017-10-24 04:15:05 +02:00
if ( buffer [ 2 ] = = SENSE_UNIT_ATTENTION ) {
2017-01-21 01:48:55 +01:00
/* If the last remaining sense is unit attention, clear
that condition . */
cdrom [ id ] . unit_attention = 0 ;
}
/* Clear the sense stuff as per the spec. */
2017-01-21 06:21:46 +01:00
cdrom_sense_clear ( id , GPCMD_REQUEST_SENSE ) ;
2017-01-21 01:48:55 +01:00
}
void cdrom_request_sense_for_scsi ( uint8_t id , uint8_t * buffer , uint8_t alloc_length )
{
int ready = 0 ;
if ( cdrom_drives [ id ] . handler - > medium_changed ( id ) )
cdrom_insert ( id ) ;
ready = cdrom_drives [ id ] . handler - > ready ( id ) ;
2017-10-24 04:15:05 +02:00
if ( ! ready & & cdrom [ id ] . unit_attention ) {
2017-01-21 01:48:55 +01:00
/* If the drive is not ready, there is no reason to keep the
UNIT ATTENTION condition present , as we only use it to mark
disc changes . */
cdrom [ id ] . unit_attention = 0 ;
}
2017-01-21 06:21:46 +01:00
2017-01-21 03:03:46 +01:00
/* Do *NOT* advance the unit attention phase. */
2017-01-21 01:48:55 +01:00
cdrom_request_sense ( id , buffer , alloc_length ) ;
}
2017-10-16 06:19:18 +02:00
void cdrom_set_buf_len ( uint8_t id , int32_t * BufLen , uint32_t * src_len )
{
2017-10-24 04:15:05 +02:00
if ( cdrom_drives [ id ] . bus_type = = CDROM_BUS_SCSI ) {
2017-10-16 06:19:18 +02:00
if ( * BufLen = = - 1 )
* BufLen = * src_len ;
2017-10-24 04:15:05 +02:00
else {
2017-10-16 06:19:18 +02:00
* BufLen = MIN ( * src_len , * BufLen ) ;
* src_len = * BufLen ;
}
cdrom_log ( " CD-ROM %i: Actual transfer length: %i \n " , id , * BufLen ) ;
}
}
void cdrom_buf_alloc ( uint8_t id , uint32_t len )
{
cdrom_log ( " CD-ROM %i: Allocated buffer length: %i \n " , id , len ) ;
cdbufferb = ( uint8_t * ) malloc ( len ) ;
}
void cdrom_buf_free ( uint8_t id )
{
if ( cdbufferb ) {
cdrom_log ( " CD-ROM %i: Freeing buffer... \n " , id ) ;
free ( cdbufferb ) ;
cdbufferb = NULL ;
}
}
2017-01-16 01:49:19 +01:00
void cdrom_command ( uint8_t id , uint8_t * cdb )
{
2017-05-05 01:49:42 +02:00
uint32_t len ;
2017-01-16 01:49:19 +01:00
int msf ;
int pos = 0 ;
2017-10-16 06:19:18 +02:00
uint32_t max_len ;
2017-12-10 15:16:24 +01:00
uint32_t feature ;
2017-10-16 06:19:18 +02:00
uint32_t used_len ;
2017-01-16 01:49:19 +01:00
unsigned idx = 0 ;
unsigned size_idx ;
unsigned preamble_len ;
int toc_format ;
2017-05-05 01:49:42 +02:00
uint32_t alloc_length ;
2017-01-27 23:03:20 +01:00
int block_desc = 0 ;
2017-05-05 01:49:42 +02:00
int format = 0 ;
2017-01-16 01:49:19 +01:00
int ret ;
int real_pos ;
int track = 0 ;
2017-05-27 03:53:32 +02:00
char device_identify [ 9 ] = { ' 8 ' , ' 6 ' , ' B ' , ' _ ' , ' C ' , ' D ' , ' 0 ' , ' 0 ' , 0 } ;
char device_identify_ex [ 15 ] = { ' 8 ' , ' 6 ' , ' B ' , ' _ ' , ' C ' , ' D ' , ' 0 ' , ' 0 ' , ' ' , ' v ' , ' 1 ' , ' . ' , ' 0 ' , ' 0 ' , 0 } ;
2017-10-14 07:03:19 +02:00
int32_t blen = 0 ;
int32_t * BufLen ;
2017-12-10 15:16:24 +01:00
uint8_t * b ;
uint32_t profiles [ 2 ] = { MMC_PROFILE_CD_ROM , MMC_PROFILE_DVD_ROM } ;
uint32_t i = 0 ;
2017-01-16 01:49:19 +01:00
2017-10-24 04:15:05 +02:00
if ( cdrom_drives [ id ] . bus_type = = CDROM_BUS_SCSI ) {
2017-10-14 07:03:19 +02:00
BufLen = & SCSIDevices [ cdrom_drives [ id ] . scsi_device_id ] [ cdrom_drives [ id ] . scsi_device_lun ] . BufferLength ;
2017-01-16 01:49:19 +01:00
cdrom [ id ] . status & = ~ ERR_STAT ;
2017-10-24 04:15:05 +02:00
} else {
2017-10-14 07:03:19 +02:00
BufLen = & blen ;
2017-01-17 00:01:59 +01:00
cdrom [ id ] . error = 0 ;
}
2017-01-16 01:49:19 +01:00
cdrom [ id ] . packet_len = 0 ;
cdrom [ id ] . request_pos = 0 ;
2017-05-27 03:53:32 +02:00
device_identify [ 7 ] = id + 0x30 ;
2017-01-16 01:49:19 +01:00
2017-05-27 03:53:32 +02:00
device_identify_ex [ 7 ] = id + 0x30 ;
2017-06-04 02:11:19 -04:00
device_identify_ex [ 10 ] = EMU_VERSION [ 0 ] ;
device_identify_ex [ 12 ] = EMU_VERSION [ 2 ] ;
device_identify_ex [ 13 ] = EMU_VERSION [ 3 ] ;
2017-01-16 01:49:19 +01:00
cdrom [ id ] . data_pos = 0 ;
memcpy ( cdrom [ id ] . current_cdb , cdb , cdrom [ id ] . cdb_len ) ;
2017-05-05 01:49:42 +02:00
cdrom [ id ] . cd_status = cdrom_drives [ id ] . handler - > status ( id ) ;
2017-10-24 04:15:05 +02:00
if ( cdb [ 0 ] ! = 0 ) {
2017-11-05 01:57:04 -05:00
cdrom_log ( " CD-ROM %i: Command 0x%02X, Sense Key %02X, Asc %02X, Ascq %02X, Unit attention: %i \n " , id , cdb [ 0 ] , cdrom_sense_key , cdrom_asc , cdrom_ascq , cdrom [ id ] . unit_attention ) ;
2017-01-27 23:03:20 +01:00
cdrom_log ( " CD-ROM %i: Request length: %04X \n " , id , cdrom [ id ] . request_length ) ;
2018-02-15 23:14:44 +01:00
cdrom_log ( " CD-ROM %i: CDB: %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X \n " , id ,
cdb [ 0 ] , cdb [ 1 ] , cdb [ 2 ] , cdb [ 3 ] , cdb [ 4 ] , cdb [ 5 ] , cdb [ 6 ] , cdb [ 7 ] ,
cdb [ 8 ] , cdb [ 9 ] , cdb [ 10 ] , cdb [ 11 ] ) ;
2017-01-27 23:03:20 +01:00
}
2017-01-16 01:49:19 +01:00
msf = cdb [ 1 ] & 2 ;
cdrom [ id ] . sector_len = 0 ;
2018-01-06 22:47:41 +01:00
cdrom_set_phase ( id , SCSI_PHASE_STATUS ) ;
2017-10-09 02:35:12 +02:00
2017-01-16 01:49:19 +01:00
/* This handles the Not Ready/Unit Attention check if it has to be handled at this point. */
2017-01-20 23:53:19 +01:00
if ( cdrom_pre_execution_check ( id , cdb ) = = 0 )
return ;
2017-01-16 01:49:19 +01:00
2017-10-24 04:15:05 +02:00
switch ( cdb [ 0 ] ) {
2017-01-16 01:49:19 +01:00
case GPCMD_TEST_UNIT_READY :
2018-01-06 22:47:41 +01:00
cdrom_set_phase ( id , SCSI_PHASE_STATUS ) ;
2017-01-16 01:49:19 +01:00
cdrom_command_complete ( id ) ;
break ;
case GPCMD_REZERO_UNIT :
if ( cdrom_drives [ id ] . handler - > stop )
cdrom_drives [ id ] . handler - > stop ( id ) ;
cdrom [ id ] . sector_pos = cdrom [ id ] . sector_len = 0 ;
cdrom_seek ( id , 0 ) ;
2018-01-06 22:47:41 +01:00
cdrom_set_phase ( id , SCSI_PHASE_STATUS ) ;
2017-01-16 01:49:19 +01:00
break ;
2017-01-21 01:48:55 +01:00
case GPCMD_REQUEST_SENSE :
2017-01-21 03:03:46 +01:00
/* If there's a unit attention condition and there's a buffered not ready, a standalone REQUEST SENSE
should forget about the not ready , and report unit attention straight away . */
2018-01-06 22:47:41 +01:00
cdrom_set_phase ( id , SCSI_PHASE_DATA_IN ) ;
2017-10-16 06:19:18 +02:00
max_len = cdb [ 4 ] ;
cdrom_buf_alloc ( id , 256 ) ;
cdrom_set_buf_len ( id , BufLen , & max_len ) ;
cdrom_request_sense ( id , cdbufferb , max_len ) ;
2017-01-21 01:48:55 +01:00
cdrom_data_command_finish ( id , 18 , 18 , cdb [ 4 ] , 0 ) ;
2017-01-16 01:49:19 +01:00
break ;
case GPCMD_SET_SPEED :
case GPCMD_SET_SPEED_ALT :
2018-01-06 22:47:41 +01:00
cdrom_set_phase ( id , SCSI_PHASE_STATUS ) ;
2017-01-16 01:49:19 +01:00
cdrom_command_complete ( id ) ;
break ;
case GPCMD_MECHANISM_STATUS :
2018-01-06 22:47:41 +01:00
cdrom_set_phase ( id , SCSI_PHASE_DATA_IN ) ;
2017-07-20 08:24:07 +02:00
len = ( cdb [ 7 ] < < 16 ) | ( cdb [ 8 ] < < 8 ) | cdb [ 9 ] ;
2017-01-16 01:49:19 +01:00
2017-10-16 06:19:18 +02:00
cdrom_buf_alloc ( id , 8 ) ;
cdrom_set_buf_len ( id , BufLen , & len ) ;
2017-10-08 05:04:38 +02:00
2017-01-16 01:49:19 +01:00
memset ( cdbufferb , 0 , 8 ) ;
cdbufferb [ 5 ] = 1 ;
cdrom_data_command_finish ( id , 8 , 8 , len , 0 ) ;
break ;
case GPCMD_READ_TOC_PMA_ATIP :
cdrom [ id ] . toctimes + + ;
2018-01-06 22:47:41 +01:00
cdrom_set_phase ( id , SCSI_PHASE_DATA_IN ) ;
2017-10-08 05:04:38 +02:00
2017-02-07 02:19:48 +01:00
max_len = cdb [ 7 ] ;
max_len < < = 8 ;
max_len | = cdb [ 8 ] ;
2017-10-16 06:19:18 +02:00
cdrom_buf_alloc ( id , 65536 ) ;
2017-10-24 04:15:05 +02:00
if ( cdrom_drives [ id ] . handler - > pass_through ) {
2017-01-27 23:03:20 +01:00
ret = cdrom_pass_through ( id , & len , cdrom [ id ] . current_cdb , cdbufferb ) ;
2017-10-24 04:15:05 +02:00
if ( ! ret ) {
2017-06-01 02:33:02 +02:00
cdrom_sense_key = cdrom_asc = cdrom_ascq = 0 ;
goto cdrom_readtoc_fallback ;
2017-01-16 01:49:19 +01:00
}
2017-02-07 02:19:48 +01:00
alloc_length = cdbufferb [ 0 ] ;
alloc_length < < = 8 ;
alloc_length | = cdbufferb [ 1 ] ;
alloc_length + = 2 ;
2017-10-16 06:19:18 +02:00
len = MIN ( alloc_length , len ) ;
cdrom_set_buf_len ( id , BufLen , & len ) ;
2017-10-24 04:15:05 +02:00
} else {
2017-06-01 02:33:02 +02:00
cdrom_readtoc_fallback :
2017-01-16 01:49:19 +01:00
toc_format = cdb [ 2 ] & 0xf ;
if ( toc_format = = 0 )
toc_format = ( cdb [ 9 ] > > 6 ) & 3 ;
2017-10-24 04:15:05 +02:00
switch ( toc_format ) {
2017-01-16 01:49:19 +01:00
case 0 : /*Normal*/
2017-05-13 02:58:36 +02:00
len = cdrom_drives [ id ] . handler - > readtoc ( id , cdbufferb , cdb [ 6 ] , msf , max_len , 0 ) ;
2017-01-16 01:49:19 +01:00
break ;
case 1 : /*Multi session*/
2017-05-13 02:58:36 +02:00
len = cdrom_drives [ id ] . handler - > readtoc_session ( id , cdbufferb , msf , max_len ) ;
2017-01-16 01:49:19 +01:00
cdbufferb [ 0 ] = 0 ; cdbufferb [ 1 ] = 0xA ;
break ;
case 2 : /*Raw*/
2017-06-01 02:33:02 +02:00
len = cdrom_drives [ id ] . handler - > readtoc_raw ( id , cdbufferb , max_len ) ;
2017-01-16 01:49:19 +01:00
break ;
default :
cdrom_invalid_field ( id ) ;
2018-01-06 22:47:41 +01:00
cdrom_buf_free ( id ) ;
2017-01-16 01:49:19 +01:00
return ;
}
}
2017-10-24 04:15:05 +02:00
if ( len > max_len ) {
2017-05-13 02:58:36 +02:00
len = max_len ;
cdbufferb [ 0 ] = ( ( len - 2 ) > > 8 ) & 0xff ;
cdbufferb [ 1 ] = ( len - 2 ) & 0xff ;
}
2017-10-16 06:19:18 +02:00
cdrom_set_buf_len ( id , BufLen , & len ) ;
2017-10-08 05:04:38 +02:00
2018-02-15 23:14:44 +01:00
if ( len > = 8 ) {
cdrom_log ( " CD-ROM %i: TOC: %02X %02X %02X %02X %02X %02X %02X %02X \n " , id ,
cdbufferb [ 0 ] , cdbufferb [ 1 ] , cdbufferb [ 2 ] , cdbufferb [ 3 ] ,
cdbufferb [ 4 ] , cdbufferb [ 5 ] , cdbufferb [ 6 ] , cdbufferb [ 7 ] ) ;
}
if ( len > = 16 ) {
cdrom_log ( " %02X %02X %02X %02X %02X %02X %02X %02X \n " ,
cdbufferb [ 8 ] , cdbufferb [ 9 ] , cdbufferb [ 10 ] , cdbufferb [ 11 ] ,
cdbufferb [ 12 ] , cdbufferb [ 13 ] , cdbufferb [ 14 ] , cdbufferb [ 15 ] ) ;
}
if ( len > = 24 ) {
cdrom_log ( " %02X %02X %02X %02X %02X %02X %02X %02X \n " ,
cdbufferb [ 16 ] , cdbufferb [ 17 ] , cdbufferb [ 18 ] , cdbufferb [ 19 ] ,
cdbufferb [ 20 ] , cdbufferb [ 21 ] , cdbufferb [ 22 ] , cdbufferb [ 23 ] ) ;
}
if ( len > = 32 ) {
cdrom_log ( " %02X %02X %02X %02X %02X %02X %02X %02X \n " ,
cdbufferb [ 24 ] , cdbufferb [ 25 ] , cdbufferb [ 26 ] , cdbufferb [ 27 ] ,
cdbufferb [ 28 ] , cdbufferb [ 29 ] , cdbufferb [ 30 ] , cdbufferb [ 31 ] ) ;
}
if ( len > = 36 ) {
cdrom_log ( " %02X %02X %02X %02X \n " ,
cdbufferb [ 32 ] , cdbufferb [ 33 ] , cdbufferb [ 34 ] , cdbufferb [ 35 ] ) ;
}
2017-01-16 01:49:19 +01:00
cdrom_data_command_finish ( id , len , len , len , 0 ) ;
2017-05-05 01:49:42 +02:00
/* cdrom_log("CD-ROM %i: READ_TOC_PMA_ATIP format %02X, length %i (%i)\n", id, toc_format, ide->cylinder, cdbufferb[1]); */
2017-01-16 01:49:19 +01:00
return ;
case GPCMD_READ_CD_OLD :
cdrom [ id ] . current_cdb [ 0 ] = 0xbe ; /* IMPORTANT: Convert the command to new read CD for pass through purposes. */
case GPCMD_READ_6 :
case GPCMD_READ_10 :
case GPCMD_READ_12 :
case GPCMD_READ_CD :
case GPCMD_READ_CD_MSF :
2018-01-06 22:47:41 +01:00
cdrom_set_phase ( id , SCSI_PHASE_DATA_IN ) ;
2017-10-16 06:19:18 +02:00
alloc_length = 2048 ;
2017-10-24 04:15:05 +02:00
switch ( cdb [ 0 ] ) {
2017-01-16 01:49:19 +01:00
case GPCMD_READ_6 :
cdrom [ id ] . sector_len = cdb [ 4 ] ;
cdrom [ id ] . sector_pos = ( ( ( ( uint32_t ) cdb [ 1 ] ) & 0x1f ) < < 16 ) | ( ( ( uint32_t ) cdb [ 2 ] ) < < 8 ) | ( ( uint32_t ) cdb [ 3 ] ) ;
msf = 0 ;
break ;
case GPCMD_READ_10 :
cdrom [ id ] . sector_len = ( cdb [ 7 ] < < 8 ) | cdb [ 8 ] ;
cdrom [ id ] . sector_pos = ( cdb [ 2 ] < < 24 ) | ( cdb [ 3 ] < < 16 ) | ( cdb [ 4 ] < < 8 ) | cdb [ 5 ] ;
cdrom_log ( " CD-ROM %i: Length: %i, LBA: %i \n " , id , cdrom [ id ] . sector_len , cdrom [ id ] . sector_pos ) ;
msf = 0 ;
break ;
case GPCMD_READ_12 :
cdrom [ id ] . sector_len = ( ( ( uint32_t ) cdb [ 6 ] ) < < 24 ) | ( ( ( uint32_t ) cdb [ 7 ] ) < < 16 ) | ( ( ( uint32_t ) cdb [ 8 ] ) < < 8 ) | ( ( uint32_t ) cdb [ 9 ] ) ;
cdrom [ id ] . sector_pos = ( ( ( uint32_t ) cdb [ 2 ] ) < < 24 ) | ( ( ( uint32_t ) cdb [ 3 ] ) < < 16 ) | ( ( ( uint32_t ) cdb [ 4 ] ) < < 8 ) | ( ( uint32_t ) cdb [ 5 ] ) ;
2018-01-24 18:38:43 +01:00
cdrom_log ( " CD-ROM %i: Length: %i, LBA: %i \n " , id , cdrom [ id ] . sector_len , cdrom [ id ] . sector_pos ) ;
2017-01-16 01:49:19 +01:00
msf = 0 ;
break ;
case GPCMD_READ_CD_MSF :
2017-05-05 01:49:42 +02:00
/* cdrom_log("CD-ROM %i: Read CD MSF: Start MSF %02X%02X%02X End MSF %02X%02X%02X Flags %02X\n", id, cdb[3], cdb[4], cdb[5], cdb[6], cdb[7], cdb[8], cdb[9]); */
2017-10-16 06:19:18 +02:00
alloc_length = 2856 ;
2017-01-16 01:49:19 +01:00
cdrom [ id ] . sector_len = MSFtoLBA ( cdb [ 6 ] , cdb [ 7 ] , cdb [ 8 ] ) ;
cdrom [ id ] . sector_pos = MSFtoLBA ( cdb [ 3 ] , cdb [ 4 ] , cdb [ 5 ] ) ;
cdrom [ id ] . sector_len - = cdrom [ id ] . sector_pos ;
cdrom [ id ] . sector_len + + ;
msf = 1 ;
break ;
case GPCMD_READ_CD_OLD :
case GPCMD_READ_CD :
2017-05-05 01:49:42 +02:00
/* cdrom_log("CD-ROM %i: Read CD: Start LBA %02X%02X%02X%02X Length %02X%02X%02X Flags %02X\n", id, cdb[2], cdb[3], cdb[4], cdb[5], cdb[6], cdb[7], cdb[8], cdb[9]); */
2017-10-16 06:19:18 +02:00
alloc_length = 2856 ;
2017-01-16 01:49:19 +01:00
cdrom [ id ] . sector_len = ( cdb [ 6 ] < < 16 ) | ( cdb [ 7 ] < < 8 ) | cdb [ 8 ] ;
cdrom [ id ] . sector_pos = ( cdb [ 2 ] < < 24 ) | ( cdb [ 3 ] < < 16 ) | ( cdb [ 4 ] < < 8 ) | cdb [ 5 ] ;
msf = 0 ;
break ;
}
2017-10-24 04:15:05 +02:00
if ( ! cdrom [ id ] . sector_len ) {
2018-01-06 22:47:41 +01:00
cdrom_set_phase ( id , SCSI_PHASE_STATUS ) ;
2017-05-05 01:49:42 +02:00
/* cdrom_log("CD-ROM %i: All done - callback set\n", id); */
2017-01-16 01:49:19 +01:00
cdrom [ id ] . packet_status = CDROM_PHASE_COMPLETE ;
2017-10-09 01:48:36 +02:00
cdrom [ id ] . callback = 20LL * CDROM_TIME ;
2017-10-26 20:37:39 +02:00
cdrom_set_callback ( id ) ;
2017-01-16 01:49:19 +01:00
break ;
}
max_len = cdrom [ id ] . sector_len ;
2017-10-22 03:16:52 +02:00
cdrom [ id ] . requested_blocks = max_len ; /* If we're reading all blocks in one go for DMA, why not also for PIO, it should NOT
matter anyway , this step should be identical and only the way the read dat is
transferred to the host should be different . */
2017-01-16 01:49:19 +01:00
2017-10-16 06:19:18 +02:00
cdrom [ id ] . packet_len = max_len * alloc_length ;
cdrom_buf_alloc ( id , cdrom [ id ] . packet_len ) ;
2017-01-16 01:49:19 +01:00
ret = cdrom_read_blocks ( id , & alloc_length , 1 ) ;
2018-01-06 22:47:41 +01:00
if ( ret < = 0 ) {
cdrom_buf_free ( id ) ;
2017-01-16 01:49:19 +01:00
return ;
2018-01-06 22:47:41 +01:00
}
2017-01-16 01:49:19 +01:00
2017-10-22 03:16:52 +02:00
cdrom [ id ] . requested_blocks = max_len ;
cdrom [ id ] . packet_len = alloc_length ;
2017-10-16 06:41:26 +02:00
2017-10-16 06:19:18 +02:00
cdrom_set_buf_len ( id , BufLen , & cdrom [ id ] . packet_len ) ;
2017-10-08 05:04:38 +02:00
2017-10-22 03:16:52 +02:00
cdrom_data_command_finish ( id , alloc_length , alloc_length / cdrom [ id ] . requested_blocks , alloc_length , 0 ) ;
2017-01-16 01:49:19 +01:00
cdrom [ id ] . all_blocks_total = cdrom [ id ] . block_total ;
if ( cdrom [ id ] . packet_status ! = CDROM_PHASE_COMPLETE )
2017-10-10 03:07:29 -04:00
ui_sb_update_icon ( SB_CDROM | id , 1 ) ;
2017-05-05 01:49:42 +02:00
else
2017-10-10 03:07:29 -04:00
ui_sb_update_icon ( SB_CDROM | id , 0 ) ;
2017-01-16 01:49:19 +01:00
return ;
case GPCMD_READ_HEADER :
2018-01-06 22:47:41 +01:00
cdrom_set_phase ( id , SCSI_PHASE_DATA_IN ) ;
2017-10-16 06:19:18 +02:00
2017-10-23 01:36:00 +02:00
alloc_length = ( ( cdb [ 7 ] < < 8 ) | cdb [ 8 ] ) ;
cdrom_buf_alloc ( id , 8 ) ;
2017-10-16 06:19:18 +02:00
2017-10-24 04:15:05 +02:00
if ( cdrom_drives [ id ] . handler - > pass_through ) {
2017-01-27 23:03:20 +01:00
ret = cdrom_pass_through ( id , & len , cdrom [ id ] . current_cdb , cdbufferb ) ;
2018-01-06 22:47:41 +01:00
if ( ! ret ) {
cdrom_buf_free ( id ) ;
2017-01-16 01:49:19 +01:00
return ;
2018-01-06 22:47:41 +01:00
}
2017-10-24 04:15:05 +02:00
} else {
2017-10-23 01:36:00 +02:00
cdrom [ id ] . sector_len = 1 ;
2017-01-16 01:49:19 +01:00
cdrom [ id ] . sector_pos = ( cdb [ 2 ] < < 24 ) | ( cdb [ 3 ] < < 16 ) | ( cdb [ 4 ] < < 8 ) | cdb [ 5 ] ;
if ( msf )
real_pos = cdrom_lba_to_msf_accurate ( cdrom [ id ] . sector_pos ) ;
else
real_pos = cdrom [ id ] . sector_pos ;
cdbufferb [ 0 ] = 1 ; /*2048 bytes user data*/
cdbufferb [ 1 ] = cdbufferb [ 2 ] = cdbufferb [ 3 ] = 0 ;
cdbufferb [ 4 ] = ( real_pos > > 24 ) ;
cdbufferb [ 5 ] = ( ( real_pos > > 16 ) & 0xff ) ;
cdbufferb [ 6 ] = ( ( real_pos > > 8 ) & 0xff ) ;
cdbufferb [ 7 ] = real_pos & 0xff ;
len = 8 ;
}
2017-10-16 06:19:18 +02:00
len = MIN ( len , alloc_length ) ;
cdrom_set_buf_len ( id , BufLen , & len ) ;
2017-10-08 05:04:38 +02:00
2017-01-16 01:49:19 +01:00
cdrom_data_command_finish ( id , len , len , len , 0 ) ;
return ;
2017-10-16 06:19:18 +02:00
2017-01-16 01:49:19 +01:00
case GPCMD_MODE_SENSE_6 :
case GPCMD_MODE_SENSE_10 :
2018-01-06 22:47:41 +01:00
cdrom_set_phase ( id , SCSI_PHASE_DATA_IN ) ;
2017-10-08 05:04:38 +02:00
2017-05-27 03:53:32 +02:00
if ( cdrom_drives [ id ] . bus_type = = CDROM_BUS_SCSI )
2017-01-27 23:03:20 +01:00
block_desc = ( ( cdb [ 1 ] > > 3 ) & 1 ) ? 0 : 1 ;
else
block_desc = 0 ;
2017-10-24 04:15:05 +02:00
if ( cdb [ 0 ] = = GPCMD_MODE_SENSE_6 ) {
2017-01-16 01:49:19 +01:00
len = cdb [ 4 ] ;
2017-10-16 06:19:18 +02:00
cdrom_buf_alloc ( id , 256 ) ;
2017-10-24 04:15:05 +02:00
} else {
2017-01-16 01:49:19 +01:00
len = ( cdb [ 8 ] | ( cdb [ 7 ] < < 8 ) ) ;
2017-10-16 06:19:18 +02:00
cdrom_buf_alloc ( id , 65536 ) ;
2017-01-16 01:49:19 +01:00
}
2017-05-17 21:56:31 +02:00
cdrom [ id ] . current_page_code = cdb [ 2 ] & 0x3F ;
2018-01-13 22:56:13 +01:00
if ( ! ( cdrom_mode_sense_page_flags & ( 1LL < < cdrom [ id ] . current_page_code ) ) ) {
2017-01-16 01:49:19 +01:00
cdrom_invalid_field ( id ) ;
2018-01-06 22:47:41 +01:00
cdrom_buf_free ( id ) ;
2017-01-16 01:49:19 +01:00
return ;
}
memset ( cdbufferb , 0 , len ) ;
alloc_length = len ;
2017-10-24 04:15:05 +02:00
if ( cdb [ 0 ] = = GPCMD_MODE_SENSE_6 ) {
2017-01-27 23:03:20 +01:00
len = cdrom_mode_sense ( id , cdbufferb , 4 , cdb [ 2 ] , block_desc ) ;
2017-10-24 04:15:05 +02:00
len = MIN ( len , alloc_length ) ;
2017-01-27 23:03:20 +01:00
cdbufferb [ 0 ] = len - 1 ;
cdbufferb [ 1 ] = cdrom_drives [ id ] . handler - > media_type_id ( id ) ;
if ( block_desc )
cdbufferb [ 3 ] = 8 ;
2017-10-24 04:15:05 +02:00
} else {
2017-01-27 23:03:20 +01:00
len = cdrom_mode_sense ( id , cdbufferb , 8 , cdb [ 2 ] , block_desc ) ;
2017-10-24 04:15:05 +02:00
len = MIN ( len , alloc_length ) ;
2017-01-16 01:49:19 +01:00
cdbufferb [ 0 ] = ( len - 2 ) > > 8 ;
cdbufferb [ 1 ] = ( len - 2 ) & 255 ;
2017-01-27 23:03:20 +01:00
cdbufferb [ 2 ] = cdrom_drives [ id ] . handler - > media_type_id ( id ) ;
2017-10-24 04:15:05 +02:00
if ( block_desc ) {
2017-01-27 23:03:20 +01:00
cdbufferb [ 6 ] = 0 ;
cdbufferb [ 7 ] = 8 ;
2017-01-16 01:49:19 +01:00
}
}
2017-10-16 06:19:18 +02:00
cdrom_set_buf_len ( id , BufLen , & len ) ;
2017-01-27 23:03:20 +01:00
2017-01-16 01:49:19 +01:00
cdrom_log ( " CD-ROM %i: Reading mode page: %02X... \n " , id , cdb [ 2 ] ) ;
cdrom_data_command_finish ( id , len , len , alloc_length , 0 ) ;
return ;
case GPCMD_MODE_SELECT_6 :
case GPCMD_MODE_SELECT_10 :
2018-01-06 22:47:41 +01:00
cdrom_set_phase ( id , SCSI_PHASE_DATA_OUT ) ;
2017-10-08 05:04:38 +02:00
2017-10-24 04:15:05 +02:00
if ( cdb [ 0 ] = = GPCMD_MODE_SELECT_6 ) {
2017-01-16 01:49:19 +01:00
len = cdb [ 4 ] ;
2017-10-16 06:19:18 +02:00
cdrom_buf_alloc ( id , 256 ) ;
2017-10-24 04:15:05 +02:00
} else {
2017-01-16 01:49:19 +01:00
len = ( cdb [ 7 ] < < 8 ) | cdb [ 8 ] ;
2017-10-16 06:19:18 +02:00
cdrom_buf_alloc ( id , 65536 ) ;
2017-01-16 01:49:19 +01:00
}
2017-10-16 06:19:18 +02:00
cdrom_set_buf_len ( id , BufLen , & len ) ;
2018-01-13 22:56:13 +01:00
cdrom [ id ] . total_length = len ;
cdrom [ id ] . do_page_save = cdb [ 1 ] & 1 ;
cdrom [ id ] . current_page_pos = 0 ;
2017-10-16 06:19:18 +02:00
2017-01-16 01:49:19 +01:00
cdrom_data_command_finish ( id , len , len , len , 1 ) ;
return ;
case GPCMD_GET_CONFIGURATION :
2018-01-06 22:47:41 +01:00
cdrom_set_phase ( id , SCSI_PHASE_DATA_IN ) ;
2017-12-10 15:16:24 +01:00
2017-01-16 01:49:19 +01:00
/* XXX: could result in alignment problems in some architectures */
2017-12-10 15:16:24 +01:00
feature = ( cdb [ 2 ] < < 8 ) | cdb [ 3 ] ;
2017-10-16 06:19:18 +02:00
max_len = ( cdb [ 7 ] < < 8 ) | cdb [ 8 ] ;
2017-01-16 01:49:19 +01:00
/* only feature 0 is supported */
2017-12-10 15:16:24 +01:00
if ( ( cdb [ 2 ] ! = 0 ) | | ( cdb [ 3 ] > 2 ) ) {
2017-01-16 01:49:19 +01:00
cdrom_invalid_field ( id ) ;
2018-01-06 22:47:41 +01:00
cdrom_buf_free ( id ) ;
2017-01-16 01:49:19 +01:00
return ;
}
2017-10-16 06:19:18 +02:00
cdrom_buf_alloc ( id , 65536 ) ;
memset ( cdbufferb , 0 , max_len ) ;
2017-12-10 15:16:24 +01:00
alloc_length = 0 ;
b = cdbufferb ;
2017-01-16 01:49:19 +01:00
/*
* the number of sectors from the media tells us which profile
* to use as current . 0 means there is no media
*/
2017-12-10 15:16:24 +01:00
if ( cdrom_drives [ id ] . handler - > ready ( id ) ) {
len = cdrom_drives [ id ] . handler - > size ( id ) ;
if ( len > CD_MAX_SECTORS ) {
b [ 6 ] = ( MMC_PROFILE_DVD_ROM > > 8 ) & 0xff ;
b [ 7 ] = MMC_PROFILE_DVD_ROM & 0xff ;
ret = 1 ;
2018-02-25 09:18:32 +01:00
} else {
2017-12-10 15:16:24 +01:00
b [ 6 ] = ( MMC_PROFILE_CD_ROM > > 8 ) & 0xff ;
b [ 7 ] = MMC_PROFILE_CD_ROM & 0xff ;
ret = 0 ;
}
2018-02-25 09:18:32 +01:00
} else
2017-12-10 15:16:24 +01:00
ret = 2 ;
alloc_length = 8 ;
b + = 8 ;
if ( ( feature = = 0 ) | | ( ( cdb [ 1 ] & 3 ) < 2 ) ) {
b [ 2 ] = ( 0 < < 2 ) | 0x02 | 0x01 ; /* persistent and current */
b [ 3 ] = 8 ;
alloc_length + = 4 ;
b + = 4 ;
for ( i = 0 ; i < 2 ; i + + ) {
b [ 0 ] = ( profiles [ i ] > > 8 ) & 0xff ;
b [ 1 ] = profiles [ i ] & 0xff ;
if ( ret = = i )
b [ 2 ] | = 1 ;
alloc_length + = 4 ;
b + = 4 ;
}
}
if ( ( feature = = 1 ) | | ( ( cdb [ 1 ] & 3 ) < 2 ) ) {
b [ 1 ] = 1 ;
b [ 2 ] = ( 2 < < 2 ) | 0x02 | 0x01 ; /* persistent and current */
b [ 3 ] = 8 ;
if ( cdrom_drives [ id ] . bus_type = = CDROM_BUS_SCSI )
b [ 7 ] = 1 ;
else
b [ 7 ] = 2 ;
b [ 8 ] = 1 ;
alloc_length + = 12 ;
b + = 12 ;
}
if ( ( feature = = 2 ) | | ( ( cdb [ 1 ] & 3 ) < 2 ) ) {
b [ 1 ] = 2 ;
b [ 2 ] = ( 1 < < 2 ) | 0x02 | 0x01 ; /* persistent and current */
b [ 3 ] = 4 ;
b [ 4 ] = 2 ;
alloc_length + = 8 ;
b + = 8 ;
2017-01-16 01:49:19 +01:00
}
2017-12-10 15:16:24 +01:00
2017-01-16 01:49:19 +01:00
cdbufferb [ 0 ] = ( ( alloc_length - 4 ) > > 24 ) & 0xff ;
cdbufferb [ 1 ] = ( ( alloc_length - 4 ) > > 16 ) & 0xff ;
cdbufferb [ 2 ] = ( ( alloc_length - 4 ) > > 8 ) & 0xff ;
2017-12-10 15:16:24 +01:00
cdbufferb [ 3 ] = ( alloc_length - 4 ) & 0xff ;
2017-01-16 01:49:19 +01:00
2017-10-16 06:19:18 +02:00
alloc_length = MIN ( alloc_length , max_len ) ;
2017-10-08 05:04:38 +02:00
2017-10-16 06:19:18 +02:00
cdrom_set_buf_len ( id , BufLen , & alloc_length ) ;
cdrom_data_command_finish ( id , alloc_length , alloc_length , alloc_length , 0 ) ;
2017-01-16 01:49:19 +01:00
break ;
case GPCMD_GET_EVENT_STATUS_NOTIFICATION :
2018-01-06 22:47:41 +01:00
cdrom_set_phase ( id , SCSI_PHASE_DATA_IN ) ;
2017-10-16 06:19:18 +02:00
cdrom_buf_alloc ( id , 8 + sizeof ( gesn_event_header ) ) ;
2017-10-08 05:04:38 +02:00
2017-01-16 01:49:19 +01:00
gesn_cdb = ( void * ) cdb ;
gesn_event_header = ( void * ) cdbufferb ;
/* It is fine by the MMC spec to not support async mode operations. */
2017-10-24 04:15:05 +02:00
if ( ! ( gesn_cdb - > polled & 0x01 ) ) {
2017-01-16 01:49:19 +01:00
/* asynchronous mode */
/* Only polling is supported, asynchronous mode is not. */
cdrom_invalid_field ( id ) ;
2018-01-06 22:47:41 +01:00
cdrom_buf_free ( id ) ;
2017-01-16 01:49:19 +01:00
return ;
}
/* polling mode operation */
/*
* These are the supported events .
*
* We currently only support requests of the ' media ' type .
* Notification class requests and supported event classes are bitmasks ,
* but they are built from the same values as the " notification class "
* field .
*/
gesn_event_header - > supported_events = 1 < < GESN_MEDIA ;
/*
* We use | = below to set the class field ; other bits in this byte
* are reserved now but this is useful to do if we have to use the
* reserved fields later .
*/
gesn_event_header - > notification_class = 0 ;
/*
* Responses to requests are to be based on request priority . The
* notification_class_request_type enum above specifies the
* priority : upper elements are higher prio than lower ones .
*/
2017-10-24 04:15:05 +02:00
if ( gesn_cdb - > class & ( 1 < < GESN_MEDIA ) ) {
2017-01-16 01:49:19 +01:00
gesn_event_header - > notification_class | = GESN_MEDIA ;
2017-10-11 01:17:41 +02:00
cdbufferb [ 4 ] = cdrom [ id ] . media_status ; /* Bits 7-4 = Reserved, Bits 4-1 = Media Status */
cdbufferb [ 5 ] = 1 ; /* Power Status (1 = Active) */
cdbufferb [ 6 ] = 0 ;
cdbufferb [ 7 ] = 0 ;
used_len = 8 ;
2017-10-24 04:15:05 +02:00
} else {
2017-01-16 01:49:19 +01:00
gesn_event_header - > notification_class = 0x80 ; /* No event available */
used_len = sizeof ( * gesn_event_header ) ;
}
gesn_event_header - > len = used_len - sizeof ( * gesn_event_header ) ;
2017-10-11 01:17:41 +02:00
memcpy ( cdbufferb , gesn_event_header , 4 ) ;
2017-10-16 06:19:18 +02:00
cdrom_set_buf_len ( id , BufLen , & used_len ) ;
2017-10-08 05:04:38 +02:00
2017-01-16 01:49:19 +01:00
cdrom_data_command_finish ( id , used_len , used_len , used_len , 0 ) ;
break ;
case GPCMD_READ_DISC_INFORMATION :
2018-01-06 22:47:41 +01:00
cdrom_set_phase ( id , SCSI_PHASE_DATA_IN ) ;
2017-10-08 05:04:38 +02:00
2017-01-24 01:03:23 +01:00
max_len = cdb [ 7 ] ;
max_len < < = 8 ;
max_len | = cdb [ 8 ] ;
2017-10-16 06:19:18 +02:00
cdrom_buf_alloc ( id , 65536 ) ;
2017-10-24 04:15:05 +02:00
if ( cdrom_drives [ id ] . handler - > pass_through ) {
2017-01-27 23:03:20 +01:00
ret = cdrom_pass_through ( id , & len , cdrom [ id ] . current_cdb , cdbufferb ) ;
2018-01-06 22:47:41 +01:00
if ( ! ret ) {
cdrom_buf_free ( id ) ;
2017-01-16 01:49:19 +01:00
return ;
2018-01-06 22:47:41 +01:00
}
2017-02-07 02:19:48 +01:00
alloc_length = cdbufferb [ 0 ] ;
alloc_length < < = 8 ;
alloc_length | = cdbufferb [ 1 ] ;
alloc_length + = 2 ;
2017-11-20 05:53:08 +01:00
len = alloc_length ;
2017-10-24 04:15:05 +02:00
} else {
2017-01-16 01:49:19 +01:00
memset ( cdbufferb , 0 , 34 ) ;
memset ( cdbufferb , 1 , 9 ) ;
cdbufferb [ 0 ] = 0 ;
cdbufferb [ 1 ] = 32 ;
cdbufferb [ 2 ] = 0xe ; /* last session complete, disc finalized */
cdbufferb [ 7 ] = 0x20 ; /* unrestricted use */
cdbufferb [ 8 ] = 0x00 ; /* CD-ROM */
len = 34 ;
}
2017-11-20 05:53:08 +01:00
len = MIN ( len , max_len ) ;
2017-10-16 06:19:18 +02:00
cdrom_set_buf_len ( id , BufLen , & len ) ;
2017-10-08 05:04:38 +02:00
2017-10-16 06:19:18 +02:00
cdrom_data_command_finish ( id , len , len , len , 0 ) ;
2017-01-16 01:49:19 +01:00
break ;
case GPCMD_READ_TRACK_INFORMATION :
2018-01-06 22:47:41 +01:00
cdrom_set_phase ( id , SCSI_PHASE_DATA_IN ) ;
2017-10-08 05:04:38 +02:00
2017-01-16 01:49:19 +01:00
max_len = cdb [ 7 ] ;
max_len < < = 8 ;
max_len | = cdb [ 8 ] ;
2017-10-16 06:19:18 +02:00
cdrom_buf_alloc ( id , 65536 ) ;
2017-01-16 01:49:19 +01:00
track = ( ( uint32_t ) cdb [ 2 ] ) < < 24 ;
track | = ( ( uint32_t ) cdb [ 3 ] ) < < 16 ;
track | = ( ( uint32_t ) cdb [ 4 ] ) < < 8 ;
track | = ( uint32_t ) cdb [ 5 ] ;
2017-10-24 04:15:05 +02:00
if ( cdrom_drives [ id ] . handler - > pass_through ) {
2017-01-27 23:03:20 +01:00
ret = cdrom_pass_through ( id , & len , cdrom [ id ] . current_cdb , cdbufferb ) ;
2018-01-06 22:47:41 +01:00
if ( ! ret ) {
cdrom_buf_free ( id ) ;
2017-01-16 01:49:19 +01:00
return ;
2018-01-06 22:47:41 +01:00
}
2017-02-07 02:19:48 +01:00
alloc_length = cdbufferb [ 0 ] ;
alloc_length < < = 8 ;
alloc_length | = cdbufferb [ 1 ] ;
alloc_length + = 2 ;
2017-10-24 04:15:05 +02:00
len = MIN ( len , alloc_length ) ;
} else {
if ( ( ( cdb [ 1 ] & 0x03 ) ! = 1 ) | | ( track ! = 1 ) ) {
2017-01-16 01:49:19 +01:00
cdrom_invalid_field ( id ) ;
2018-01-06 22:47:41 +01:00
cdrom_buf_free ( id ) ;
2017-01-16 01:49:19 +01:00
return ;
}
len = 36 ;
memset ( cdbufferb , 0 , 36 ) ;
2017-01-24 20:25:58 +01:00
cdbufferb [ 0 ] = 0 ;
2017-01-16 01:49:19 +01:00
cdbufferb [ 1 ] = 34 ;
cdbufferb [ 2 ] = 1 ; /* track number (LSB) */
cdbufferb [ 3 ] = 1 ; /* session number (LSB) */
cdbufferb [ 5 ] = ( 0 < < 5 ) | ( 0 < < 4 ) | ( 4 < < 0 ) ; /* not damaged, primary copy, data track */
cdbufferb [ 6 ] = ( 0 < < 7 ) | ( 0 < < 6 ) | ( 0 < < 5 ) | ( 0 < < 6 ) | ( 1 < < 0 ) ; /* not reserved track, not blank, not packet writing, not fixed packet, data mode 1 */
cdbufferb [ 7 ] = ( 0 < < 1 ) | ( 0 < < 0 ) ; /* last recorded address not valid, next recordable address not valid */
cdbufferb [ 24 ] = ( cdrom_drives [ id ] . handler - > size ( id ) > > 24 ) & 0xff ; /* track size */
cdbufferb [ 25 ] = ( cdrom_drives [ id ] . handler - > size ( id ) > > 16 ) & 0xff ; /* track size */
cdbufferb [ 26 ] = ( cdrom_drives [ id ] . handler - > size ( id ) > > 8 ) & 0xff ; /* track size */
cdbufferb [ 27 ] = cdrom_drives [ id ] . handler - > size ( id ) & 0xff ; /* track size */
2017-10-24 04:15:05 +02:00
if ( len > max_len ) {
2017-01-16 01:49:19 +01:00
len = max_len ;
cdbufferb [ 0 ] = ( ( max_len - 2 ) > > 8 ) & 0xff ;
cdbufferb [ 1 ] = ( max_len - 2 ) & 0xff ;
}
}
2017-10-16 06:19:18 +02:00
cdrom_set_buf_len ( id , BufLen , & len ) ;
2017-10-08 05:04:38 +02:00
2017-01-24 01:03:23 +01:00
cdrom_data_command_finish ( id , len , len , max_len , 0 ) ;
2017-01-16 01:49:19 +01:00
break ;
case GPCMD_PLAY_AUDIO_10 :
case GPCMD_PLAY_AUDIO_12 :
case GPCMD_PLAY_AUDIO_MSF :
case GPCMD_PLAY_AUDIO_TRACK_INDEX :
2018-01-06 22:47:41 +01:00
cdrom_set_phase ( id , SCSI_PHASE_STATUS ) ;
2017-10-08 05:04:38 +02:00
2017-10-24 04:15:05 +02:00
switch ( cdb [ 0 ] ) {
2017-01-16 01:49:19 +01:00
case GPCMD_PLAY_AUDIO_10 :
msf = 0 ;
pos = ( cdb [ 2 ] < < 24 ) | ( cdb [ 3 ] < < 16 ) | ( cdb [ 4 ] < < 8 ) | cdb [ 5 ] ;
len = ( cdb [ 7 ] < < 8 ) | cdb [ 8 ] ;
break ;
case GPCMD_PLAY_AUDIO_12 :
msf = 0 ;
pos = ( cdb [ 2 ] < < 24 ) | ( cdb [ 3 ] < < 16 ) | ( cdb [ 4 ] < < 8 ) | cdb [ 5 ] ;
len = ( cdb [ 6 ] < < 24 ) | ( cdb [ 7 ] < < 16 ) | ( cdb [ 8 ] < < 8 ) | cdb [ 9 ] ;
break ;
case GPCMD_PLAY_AUDIO_MSF :
/* This is apparently deprecated in the ATAPI spec, and apparently
has been since 1995 ( ! ) . Hence I ' m having to guess most of it . */
msf = 1 ;
pos = ( cdb [ 3 ] < < 16 ) | ( cdb [ 4 ] < < 8 ) | cdb [ 5 ] ;
len = ( cdb [ 6 ] < < 16 ) | ( cdb [ 7 ] < < 8 ) | cdb [ 8 ] ;
break ;
case GPCMD_PLAY_AUDIO_TRACK_INDEX :
msf = 2 ;
pos = ( cdb [ 4 ] < < 8 ) | cdb [ 5 ] ;
len = ( cdb [ 7 ] < < 8 ) | cdb [ 8 ] ;
break ;
}
2018-02-15 23:14:44 +01:00
if ( ! cdrom_drives [ id ] . handler - > is_track_audio )
break ;
if ( ( cdrom_drives [ id ] . host_drive < 1 ) | | ( cdrom [ id ] . cd_status < = CD_STATUS_DATA_ONLY ) | | ! cdrom_drives [ id ] . handler - > is_track_audio ( id , pos , msf ) ) {
2017-01-16 01:49:19 +01:00
cdrom_illegal_mode ( id ) ;
break ;
}
if ( cdrom_drives [ id ] . handler - > playaudio )
cdrom_drives [ id ] . handler - > playaudio ( id , pos , len , msf ) ;
2017-10-24 04:15:05 +02:00
else {
2017-01-16 01:49:19 +01:00
cdrom_illegal_mode ( id ) ;
break ;
}
cdrom_command_complete ( id ) ;
break ;
case GPCMD_READ_SUBCHANNEL :
2018-01-06 22:47:41 +01:00
cdrom_set_phase ( id , SCSI_PHASE_DATA_IN ) ;
2017-10-08 05:04:38 +02:00
2017-01-25 06:58:40 +01:00
max_len = cdb [ 7 ] ;
max_len < < = 8 ;
max_len | = cdb [ 8 ] ;
2017-01-27 23:03:20 +01:00
msf = ( cdb [ 1 ] > > 1 ) & 1 ;
2017-01-25 06:58:40 +01:00
2017-10-16 06:19:18 +02:00
cdrom_buf_alloc ( id , 65536 ) ;
2017-05-19 00:25:16 +02:00
cdrom_log ( " CD-ROM %i: Getting page %i (%s) \n " , id , cdb [ 3 ] , msf ? " MSF " : " LBA " ) ;
2017-10-24 04:15:05 +02:00
if ( ( cdrom_drives [ id ] . handler - > pass_through ) & & ( cdb [ 3 ] ! = 1 ) ) {
2017-01-27 23:03:20 +01:00
ret = cdrom_pass_through ( id , & len , cdrom [ id ] . current_cdb , cdbufferb ) ;
2018-01-06 22:47:41 +01:00
if ( ! ret ) {
cdrom_buf_free ( id ) ;
2017-01-16 01:49:19 +01:00
return ;
2018-01-06 22:47:41 +01:00
}
2017-10-24 04:15:05 +02:00
switch ( cdrom [ id ] . cd_status ) {
2017-01-16 01:49:19 +01:00
case CD_STATUS_PLAYING :
cdbufferb [ 1 ] = 0x11 ;
break ;
case CD_STATUS_PAUSED :
cdbufferb [ 1 ] = 0x12 ;
break ;
2017-01-27 23:03:20 +01:00
case CD_STATUS_DATA_ONLY :
cdbufferb [ 1 ] = 0x15 ;
break ;
2017-01-16 01:49:19 +01:00
default :
2017-01-27 23:03:20 +01:00
cdbufferb [ 1 ] = 0x13 ;
2017-01-16 01:49:19 +01:00
break ;
}
2017-10-24 04:15:05 +02:00
switch ( cdb [ 3 ] ) {
2017-02-07 02:19:48 +01:00
case 0 :
alloc_length = 4 ;
break ;
case 1 :
alloc_length = 16 ;
break ;
default :
alloc_length = 24 ;
break ;
}
2017-05-11 06:34:25 +02:00
if ( ! ( cdb [ 2 ] & 0x40 ) | | ( cdb [ 3 ] = = 0 ) )
len = 4 ;
else
2017-02-07 02:19:48 +01:00
len = alloc_length ;
2017-10-24 04:15:05 +02:00
} else {
if ( cdb [ 3 ] > 3 ) {
2017-05-05 01:49:42 +02:00
/* cdrom_log("CD-ROM %i: Read subchannel check condition %02X\n", id, cdb[3]); */
2017-01-16 01:49:19 +01:00
cdrom_invalid_field ( id ) ;
2018-01-06 22:47:41 +01:00
cdrom_buf_free ( id ) ;
2017-01-16 01:49:19 +01:00
return ;
}
2017-10-24 04:15:05 +02:00
switch ( cdb [ 3 ] ) {
2017-01-16 01:49:19 +01:00
case 0 :
alloc_length = 4 ;
break ;
case 1 :
alloc_length = 16 ;
break ;
default :
alloc_length = 24 ;
break ;
}
2017-05-05 01:49:42 +02:00
memset ( cdbufferb , 0 , 24 ) ;
2017-01-16 01:49:19 +01:00
pos = 0 ;
cdbufferb [ pos + + ] = 0 ;
cdbufferb [ pos + + ] = 0 ; /*Audio status*/
cdbufferb [ pos + + ] = 0 ; cdbufferb [ pos + + ] = 0 ; /*Subchannel length*/
cdbufferb [ pos + + ] = cdb [ 3 ] & 3 ; /*Format code*/
2017-10-24 04:15:05 +02:00
if ( cdb [ 3 ] = = 1 ) {
2017-01-16 01:49:19 +01:00
cdbufferb [ 1 ] = cdrom_drives [ id ] . handler - > getcurrentsubchannel ( id , & cdbufferb [ 5 ] , msf ) ;
2017-10-24 04:15:05 +02:00
switch ( cdrom [ id ] . cd_status ) {
2017-01-27 23:03:20 +01:00
case CD_STATUS_PLAYING :
cdbufferb [ 1 ] = 0x11 ;
break ;
case CD_STATUS_PAUSED :
cdbufferb [ 1 ] = 0x12 ;
break ;
case CD_STATUS_DATA_ONLY :
cdbufferb [ 1 ] = 0x15 ;
break ;
default :
cdbufferb [ 1 ] = 0x13 ;
break ;
2017-01-16 01:49:19 +01:00
}
}
2017-01-25 06:58:40 +01:00
if ( ! ( cdb [ 2 ] & 0x40 ) | | ( cdb [ 3 ] = = 0 ) )
2017-01-16 01:49:19 +01:00
len = 4 ;
else
len = alloc_length ;
}
2018-01-25 20:17:56 +01:00
len = MIN ( len , max_len ) ;
2017-10-16 06:19:18 +02:00
cdrom_set_buf_len ( id , BufLen , & len ) ;
2017-10-08 05:04:38 +02:00
2017-10-16 06:19:18 +02:00
cdrom_data_command_finish ( id , len , len , len , 0 ) ;
2017-01-16 01:49:19 +01:00
break ;
case GPCMD_READ_DVD_STRUCTURE :
2018-01-06 22:47:41 +01:00
cdrom_set_phase ( id , SCSI_PHASE_DATA_IN ) ;
2017-10-16 06:19:18 +02:00
2017-12-10 15:16:24 +01:00
alloc_length = ( ( ( uint32_t ) cdb [ 8 ] ) < < 8 ) | ( ( uint32_t ) cdb [ 9 ] ) ;
2017-10-16 06:19:18 +02:00
cdrom_buf_alloc ( id , alloc_length ) ;
2017-10-24 04:15:05 +02:00
if ( cdrom_drives [ id ] . handler - > pass_through ) {
2017-01-27 23:03:20 +01:00
ret = cdrom_pass_through ( id , & len , cdrom [ id ] . current_cdb , cdbufferb ) ;
2017-12-10 15:16:24 +01:00
if ( ! ret ) {
2018-01-06 22:47:41 +01:00
cdrom_buf_free ( id ) ;
2017-01-16 01:49:19 +01:00
return ;
2017-12-10 15:16:24 +01:00
} else {
2017-10-24 04:15:05 +02:00
if ( cdrom_drives [ id ] . bus_type = = CDROM_BUS_SCSI ) {
2017-10-16 06:19:18 +02:00
if ( * BufLen = = - 1 )
* BufLen = len ;
2017-10-24 04:15:05 +02:00
else {
2017-10-16 06:19:18 +02:00
* BufLen = MIN ( len , * BufLen ) ;
len = * BufLen ;
}
2017-10-08 05:04:38 +02:00
}
}
2017-10-24 04:15:05 +02:00
} else {
2017-12-10 15:16:24 +01:00
len = cdrom_drives [ id ] . handler - > size ( id ) ;
2017-01-16 01:49:19 +01:00
2017-12-10 15:16:24 +01:00
if ( cdb [ 7 ] < 0xc0 ) {
2017-10-24 04:15:05 +02:00
if ( len < = CD_MAX_SECTORS ) {
2017-01-16 01:49:19 +01:00
cdrom_incompatible_format ( id ) ;
2018-01-06 22:47:41 +01:00
cdrom_buf_free ( id ) ;
2017-01-16 01:49:19 +01:00
return ;
}
}
2017-10-16 06:19:18 +02:00
memset ( cdbufferb , 0 , alloc_length ) ;
2017-01-16 01:49:19 +01:00
2018-01-13 22:56:13 +01:00
if ( ( ( cdb [ 7 ] > = 0x00 ) & & ( cdb [ 7 ] < = 0x7f ) ) | | ( cdb [ 7 ] = = 0xff ) ) {
if ( cdb [ 1 ] = = 0 ) {
ret = cdrom_read_dvd_structure ( id , format , cdb , cdbufferb ) ;
if ( ret ) {
cdrom_set_buf_len ( id , BufLen , & alloc_length ) ;
cdrom_data_command_finish ( id , alloc_length , alloc_length , len , 0 ) ;
} else
cdrom_buf_free ( id ) ;
2017-01-16 01:49:19 +01:00
return ;
2018-01-13 22:56:13 +01:00
}
} else {
cdrom_invalid_field ( id ) ;
cdrom_buf_free ( id ) ;
return ;
2017-01-16 01:49:19 +01:00
}
}
break ;
case GPCMD_START_STOP_UNIT :
2018-01-06 22:47:41 +01:00
cdrom_set_phase ( id , SCSI_PHASE_STATUS ) ;
2017-10-08 05:04:38 +02:00
2017-10-24 04:15:05 +02:00
switch ( cdb [ 4 ] & 3 ) {
2017-01-16 01:49:19 +01:00
case 0 : /* Stop the disc. */
if ( cdrom_drives [ id ] . handler - > stop )
cdrom_drives [ id ] . handler - > stop ( id ) ;
break ;
case 1 : /* Start the disc and read the TOC. */
cdrom_drives [ id ] . handler - > medium_changed ( id ) ; /* This causes a TOC reload. */
break ;
case 2 : /* Eject the disc if possible. */
if ( cdrom_drives [ id ] . handler - > stop )
cdrom_drives [ id ] . handler - > stop ( id ) ;
2017-05-27 03:53:32 +02:00
cdrom_eject ( id ) ;
2017-01-16 01:49:19 +01:00
break ;
case 3 : /* Load the disc (close tray). */
2017-05-27 03:53:32 +02:00
cdrom_reload ( id ) ;
2017-01-16 01:49:19 +01:00
break ;
}
cdrom_command_complete ( id ) ;
break ;
case GPCMD_INQUIRY :
2018-01-06 22:47:41 +01:00
cdrom_set_phase ( id , SCSI_PHASE_DATA_IN ) ;
2017-10-08 05:04:38 +02:00
2017-03-05 19:42:56 +01:00
max_len = cdb [ 3 ] ;
max_len < < = 8 ;
max_len | = cdb [ 4 ] ;
2017-10-16 06:19:18 +02:00
cdrom_buf_alloc ( id , 65536 ) ;
2017-10-24 04:15:05 +02:00
if ( cdb [ 1 ] & 1 ) {
2017-01-16 01:49:19 +01:00
preamble_len = 4 ;
size_idx = 3 ;
cdbufferb [ idx + + ] = 05 ;
cdbufferb [ idx + + ] = cdb [ 2 ] ;
cdbufferb [ idx + + ] = 0 ;
idx + + ;
2017-10-24 04:15:05 +02:00
switch ( cdb [ 2 ] ) {
2017-01-16 01:49:19 +01:00
case 0x00 :
cdbufferb [ idx + + ] = 0x00 ;
cdbufferb [ idx + + ] = 0x83 ;
break ;
case 0x83 :
2017-10-24 04:15:05 +02:00
if ( idx + 24 > max_len ) {
2017-01-16 01:49:19 +01:00
cdrom_data_phase_error ( id ) ;
2018-01-06 22:47:41 +01:00
cdrom_buf_free ( id ) ;
2017-01-16 01:49:19 +01:00
return ;
}
cdbufferb [ idx + + ] = 0x02 ;
cdbufferb [ idx + + ] = 0x00 ;
cdbufferb [ idx + + ] = 0x00 ;
cdbufferb [ idx + + ] = 20 ;
ide_padstr8 ( cdbufferb + idx , 20 , " 53R141 " ) ; /* Serial */
idx + = 20 ;
if ( idx + 72 > cdb [ 4 ] )
goto atapi_out ;
cdbufferb [ idx + + ] = 0x02 ;
cdbufferb [ idx + + ] = 0x01 ;
cdbufferb [ idx + + ] = 0x00 ;
cdbufferb [ idx + + ] = 68 ;
2017-06-04 02:11:19 -04:00
ide_padstr8 ( cdbufferb + idx , 8 , EMU_NAME ) ; /* Vendor */
2017-01-16 01:49:19 +01:00
idx + = 8 ;
ide_padstr8 ( cdbufferb + idx , 40 , device_identify_ex ) ; /* Product */
idx + = 40 ;
ide_padstr8 ( cdbufferb + idx , 20 , " 53R141 " ) ; /* Product */
idx + = 20 ;
break ;
default :
cdrom_log ( " INQUIRY: Invalid page: %02X \n " , cdb [ 2 ] ) ;
cdrom_invalid_field ( id ) ;
2018-01-06 22:47:41 +01:00
cdrom_buf_free ( id ) ;
2017-01-16 01:49:19 +01:00
return ;
}
2017-10-24 04:15:05 +02:00
} else {
2017-01-16 01:49:19 +01:00
preamble_len = 5 ;
size_idx = 4 ;
memset ( cdbufferb , 0 , 8 ) ;
cdbufferb [ 0 ] = 5 ; /*CD-ROM*/
cdbufferb [ 1 ] = 0x80 ; /*Removable*/
2017-05-27 03:53:32 +02:00
cdbufferb [ 2 ] = ( cdrom_drives [ id ] . bus_type = = CDROM_BUS_SCSI ) ? 0x02 : 0x00 ; /*SCSI-2 compliant*/
2017-12-10 15:16:24 +01:00
cdbufferb [ 3 ] = ( cdrom_drives [ id ] . bus_type = = CDROM_BUS_SCSI ) ? 0x12 : 0x21 ;
2017-01-16 01:49:19 +01:00
cdbufferb [ 4 ] = 31 ;
2017-12-10 15:16:24 +01:00
if ( cdrom_drives [ id ] . bus_type = = CDROM_BUS_SCSI ) {
cdbufferb [ 6 ] = 1 ; /* 16-bit transfers supported */
cdbufferb [ 7 ] = 0x20 ; /* Wide bus supported */
}
2017-01-16 01:49:19 +01:00
2017-06-04 02:11:19 -04:00
ide_padstr8 ( cdbufferb + 8 , 8 , EMU_NAME ) ; /* Vendor */
2017-01-16 01:49:19 +01:00
ide_padstr8 ( cdbufferb + 16 , 16 , device_identify ) ; /* Product */
2017-06-04 02:11:19 -04:00
ide_padstr8 ( cdbufferb + 32 , 4 , EMU_VERSION ) ; /* Revision */
2017-01-16 01:49:19 +01:00
idx = 36 ;
2017-12-10 15:16:24 +01:00
if ( max_len = = 96 ) {
cdbufferb [ 4 ] = 91 ;
idx = 96 ;
}
2017-01-16 01:49:19 +01:00
}
atapi_out :
cdbufferb [ size_idx ] = idx - preamble_len ;
len = idx ;
2017-12-10 15:16:24 +01:00
len = MIN ( len , max_len ) ;
2017-10-16 06:19:18 +02:00
cdrom_set_buf_len ( id , BufLen , & len ) ;
2017-10-08 05:04:38 +02:00
2017-03-05 19:42:56 +01:00
cdrom_data_command_finish ( id , len , len , max_len , 0 ) ;
2017-01-16 01:49:19 +01:00
break ;
case GPCMD_PREVENT_REMOVAL :
2018-01-06 22:47:41 +01:00
cdrom_set_phase ( id , SCSI_PHASE_STATUS ) ;
2017-01-16 01:49:19 +01:00
cdrom_command_complete ( id ) ;
break ;
2017-01-24 01:03:23 +01:00
case GPCMD_PAUSE_RESUME_ALT :
2017-01-16 01:49:19 +01:00
case GPCMD_PAUSE_RESUME :
2018-01-06 22:47:41 +01:00
cdrom_set_phase ( id , SCSI_PHASE_STATUS ) ;
2017-10-08 05:04:38 +02:00
2017-10-24 04:15:05 +02:00
if ( cdb [ 8 ] & 1 ) {
2017-01-16 01:49:19 +01:00
if ( cdrom_drives [ id ] . handler - > resume )
cdrom_drives [ id ] . handler - > resume ( id ) ;
2017-10-24 04:15:05 +02:00
else {
2017-01-16 01:49:19 +01:00
cdrom_illegal_mode ( id ) ;
break ;
}
2017-10-24 04:15:05 +02:00
} else {
2017-01-16 01:49:19 +01:00
if ( cdrom_drives [ id ] . handler - > pause )
cdrom_drives [ id ] . handler - > pause ( id ) ;
2017-10-24 04:15:05 +02:00
else {
2017-01-16 01:49:19 +01:00
cdrom_illegal_mode ( id ) ;
break ;
}
}
cdrom_command_complete ( id ) ;
break ;
case GPCMD_SEEK_6 :
case GPCMD_SEEK_10 :
2018-01-06 22:47:41 +01:00
cdrom_set_phase ( id , SCSI_PHASE_STATUS ) ;
2017-10-08 05:04:38 +02:00
2017-10-24 04:15:05 +02:00
switch ( cdb [ 0 ] ) {
2017-01-16 01:49:19 +01:00
case GPCMD_SEEK_6 :
pos = ( cdb [ 2 ] < < 8 ) | cdb [ 3 ] ;
break ;
case GPCMD_SEEK_10 :
pos = ( cdb [ 2 ] < < 24 ) | ( cdb [ 3 ] < < 16 ) | ( cdb [ 4 ] < < 8 ) | cdb [ 5 ] ;
break ;
}
cdrom_seek ( id , pos ) ;
cdrom_command_complete ( id ) ;
break ;
case GPCMD_READ_CDROM_CAPACITY :
2018-01-06 22:47:41 +01:00
cdrom_set_phase ( id , SCSI_PHASE_DATA_IN ) ;
2017-10-16 06:19:18 +02:00
cdrom_buf_alloc ( id , 8 ) ;
2018-01-06 22:47:41 +01:00
if ( cdrom_read_capacity ( id , cdrom [ id ] . current_cdb , cdbufferb , & len ) = = 0 ) {
cdrom_buf_free ( id ) ;
2017-01-27 23:03:20 +01:00
return ;
2018-01-06 22:47:41 +01:00
}
2017-01-16 01:49:19 +01:00
2017-10-16 06:19:18 +02:00
cdrom_set_buf_len ( id , BufLen , & len ) ;
2017-10-08 05:04:38 +02:00
2017-01-16 01:49:19 +01:00
cdrom_data_command_finish ( id , len , len , len , 0 ) ;
break ;
case GPCMD_STOP_PLAY_SCAN :
2018-01-06 22:47:41 +01:00
cdrom_set_phase ( id , SCSI_PHASE_STATUS ) ;
2017-10-08 05:04:38 +02:00
2017-01-16 01:49:19 +01:00
if ( cdrom_drives [ id ] . handler - > stop )
cdrom_drives [ id ] . handler - > stop ( id ) ;
2017-10-24 04:15:05 +02:00
else {
2017-01-16 01:49:19 +01:00
cdrom_illegal_mode ( id ) ;
break ;
}
cdrom_command_complete ( id ) ;
break ;
default :
cdrom_illegal_opcode ( id ) ;
break ;
}
2017-05-05 01:49:42 +02:00
/* cdrom_log("CD-ROM %i: Phase: %02X, request length: %i\n", cdrom[id].phase, cdrom[id].request_length); */
2018-01-06 22:47:41 +01:00
if ( cdrom_atapi_phase_to_scsi ( id ) = = SCSI_PHASE_STATUS )
cdrom_buf_free ( id ) ;
2017-01-16 01:49:19 +01:00
}
2018-01-13 22:56:13 +01:00
/* The command second phase function, needed for Mode Select. */
uint8_t cdrom_phase_data_out ( uint8_t id )
{
uint16_t block_desc_len ;
uint16_t pos ;
uint8_t error = 0 ;
uint8_t page , page_len ;
uint16_t i = 0 ;
uint8_t hdr_len , val , old_val , ch ;
2018-01-24 18:38:43 +01:00
FILE * f ;
2018-01-13 22:56:13 +01:00
switch ( cdrom [ id ] . current_cdb [ 0 ] ) {
case GPCMD_MODE_SELECT_6 :
case GPCMD_MODE_SELECT_10 :
2018-01-24 18:38:43 +01:00
f = nvr_fopen ( L " modeselect.bin " , L " wb " ) ;
fwrite ( cdbufferb , 1 , cdrom [ id ] . total_length , f ) ;
fclose ( f ) ;
2018-01-13 22:56:13 +01:00
if ( cdrom [ id ] . current_cdb [ 0 ] = = GPCMD_MODE_SELECT_10 )
hdr_len = 8 ;
else
hdr_len = 4 ;
if ( cdrom_drives [ id ] . bus_type = = CDROM_BUS_SCSI ) {
2018-01-24 18:38:43 +01:00
if ( cdrom [ id ] . current_cdb [ 0 ] = = GPCMD_MODE_SELECT_6 ) {
block_desc_len = cdbufferb [ 2 ] ;
block_desc_len < < = 8 ;
block_desc_len | = cdbufferb [ 3 ] ;
} else {
block_desc_len = cdbufferb [ 6 ] ;
block_desc_len < < = 8 ;
block_desc_len | = cdbufferb [ 7 ] ;
}
2018-01-13 22:56:13 +01:00
} else
block_desc_len = 0 ;
pos = hdr_len + block_desc_len ;
while ( 1 ) {
page = cdbufferb [ pos ] & 0x3F ;
page_len = cdbufferb [ pos + 1 ] ;
pos + = 2 ;
2018-01-24 18:38:43 +01:00
if ( ! ( cdrom_mode_sense_page_flags & ( 1LL < < ( ( uint64_t ) page ) ) ) ) {
cdrom_log ( " Unimplemented page %02X \n " , page ) ;
2018-01-13 22:56:13 +01:00
error | = 1 ;
2018-01-24 18:38:43 +01:00
} else {
2018-01-13 22:56:13 +01:00
for ( i = 0 ; i < page_len ; i + + ) {
ch = cdrom_mode_sense_pages_changeable . pages [ page ] [ i + 2 ] ;
val = cdbufferb [ pos + i ] ;
old_val = cdrom_mode_sense_pages_saved [ id ] . pages [ page ] [ i + 2 ] ;
if ( val ! = old_val ) {
if ( ch )
cdrom_mode_sense_pages_saved [ id ] . pages [ page ] [ i + 2 ] = val ;
2018-01-24 18:38:43 +01:00
else {
cdrom_log ( " Unchangeable value on position %02X on page %02X \n " , i + 2 , page ) ;
2018-01-13 22:56:13 +01:00
error | = 1 ;
2018-01-24 18:38:43 +01:00
}
2018-01-13 22:56:13 +01:00
}
}
}
pos + = page_len ;
2018-01-17 18:43:36 +01:00
if ( cdrom_drives [ id ] . bus_type = = CDROM_BUS_SCSI )
val = cdrom_mode_sense_pages_default_scsi . pages [ page ] [ 0 ] & 0x80 ;
else
val = cdrom_mode_sense_pages_default . pages [ page ] [ 0 ] & 0x80 ;
2018-01-13 22:56:13 +01:00
if ( cdrom [ id ] . do_page_save & & val )
cdrom_mode_sense_save ( id ) ;
if ( pos > = cdrom [ id ] . total_length )
break ;
}
if ( error ) {
cdrom_invalid_field_pl ( id ) ;
return 0 ;
}
break ;
}
return 1 ;
}
/* This is the general ATAPI PIO request function. */
void cdrom_pio_request ( uint8_t id , uint8_t out )
2017-01-16 01:49:19 +01:00
{
int old_pos = 0 ;
2018-01-13 22:56:13 +01:00
int ret = 0 ;
2017-01-16 01:49:19 +01:00
2017-10-24 04:15:05 +02:00
if ( cdrom_drives [ id ] . bus_type < CDROM_BUS_SCSI ) {
2017-01-16 01:49:19 +01:00
cdrom_log ( " CD-ROM %i: Lowering IDE IRQ \n " , id ) ;
ide_irq_lower ( & ( ide_drives [ cdrom_drives [ id ] . ide_channel ] ) ) ;
}
cdrom [ id ] . status = BUSY_STAT ;
2018-01-13 22:56:13 +01:00
if ( cdrom [ id ] . pos > = cdrom [ id ] . packet_len ) {
cdrom_log ( " CD-ROM %i: %i bytes %s, command done \n " , id , cdrom [ id ] . pos , out ? " written " : " read " ) ;
2017-01-16 01:49:19 +01:00
cdrom [ id ] . pos = cdrom [ id ] . request_pos = 0 ;
2018-01-13 22:56:13 +01:00
if ( out ) {
ret = cdrom_phase_data_out ( id ) ;
/* If ret = 0 (phase 1 error), then we do not do anything else other than
free the buffer , as the phase and callback have already been set by the
error function . */
if ( ret )
cdrom_command_complete ( id ) ;
} else
cdrom_command_complete ( id ) ;
2018-01-06 22:47:41 +01:00
cdrom_buf_free ( id ) ;
2017-10-24 04:15:05 +02:00
} else {
2018-01-13 22:56:13 +01:00
cdrom_log ( " CD-ROM %i: %i bytes %s, %i bytes are still left \n " , id , cdrom [ id ] . pos , out ? " written " : " read " , cdrom [ id ] . packet_len - cdrom [ id ] . pos ) ;
2017-01-16 01:49:19 +01:00
/* Make sure to keep pos, and reset request_pos to 0. */
/* Also make sure to not reset total_read. */
2018-02-15 23:14:44 +01:00
/* If less than (packet length) bytes are remaining, update packet length
accordingly . */
2018-02-27 23:55:28 +01:00
if ( ( cdrom [ id ] . packet_len - cdrom [ id ] . pos ) < ( cdrom [ id ] . max_transfer_len ) )
cdrom [ id ] . max_transfer_len = cdrom [ id ] . packet_len - cdrom [ id ] . pos ;
cdrom_log ( " CD-ROM %i: Packet length %i, request length %i \n " , id , cdrom [ id ] . packet_len , cdrom [ id ] . max_transfer_len ) ;
2018-02-15 23:14:44 +01:00
2017-01-16 01:49:19 +01:00
old_pos = cdrom [ id ] . pos ;
2018-01-13 22:56:13 +01:00
cdrom [ id ] . packet_status = out ? CDROM_PHASE_DATA_OUT : CDROM_PHASE_DATA_IN ;
2017-01-16 01:49:19 +01:00
cdrom_command_common ( id ) ;
cdrom [ id ] . pos = old_pos ;
2018-02-15 23:14:44 +01:00
2017-01-16 01:49:19 +01:00
cdrom [ id ] . request_pos = 0 ;
}
}
2017-01-20 23:53:19 +01:00
void cdrom_phase_callback ( uint8_t id ) ;
2017-01-16 01:49:19 +01:00
int cdrom_read_from_ide_dma ( uint8_t channel )
{
uint8_t id = atapi_cdrom_drives [ channel ] ;
if ( id > CDROM_NUM )
return 0 ;
2017-10-24 04:15:05 +02:00
if ( ide_bus_master_write ) {
if ( ide_bus_master_write ( channel > > 1 , cdbufferb , cdrom [ id ] . packet_len ) ) {
2017-10-26 20:37:39 +02:00
cdrom_bus_master_error ( id ) ;
2017-01-16 01:49:19 +01:00
cdrom_phase_callback ( id ) ;
return 0 ;
2017-10-24 04:15:05 +02:00
} else
2017-01-16 01:49:19 +01:00
return 1 ;
2017-10-24 04:15:05 +02:00
} else {
2017-10-26 20:37:39 +02:00
cdrom_bus_master_error ( id ) ;
2017-10-24 04:15:05 +02:00
cdrom_phase_callback ( id ) ;
return 0 ;
2017-01-16 01:49:19 +01:00
}
2017-05-05 01:49:42 +02:00
return 0 ;
2017-01-16 01:49:19 +01:00
}
2017-01-18 21:51:03 +01:00
int cdrom_read_from_scsi_dma ( uint8_t scsi_id , uint8_t scsi_lun )
2017-01-16 01:49:19 +01:00
{
2017-01-18 21:51:03 +01:00
uint8_t id = scsi_cdrom_drives [ scsi_id ] [ scsi_lun ] ;
2017-10-14 07:03:19 +02:00
int32_t * BufLen = & SCSIDevices [ scsi_id ] [ scsi_lun ] . BufferLength ;
2017-01-16 01:49:19 +01:00
if ( id > CDROM_NUM )
return 0 ;
2017-10-14 07:03:19 +02:00
cdrom_log ( " Reading from SCSI DMA: SCSI ID %02X, init length %i \n " , scsi_id , * BufLen ) ;
memcpy ( cdbufferb , SCSIDevices [ scsi_id ] [ scsi_lun ] . CmdBuffer , * BufLen ) ;
2017-01-16 01:49:19 +01:00
return 1 ;
}
int cdrom_read_from_dma ( uint8_t id )
{
2017-10-14 07:03:19 +02:00
int32_t * BufLen = & SCSIDevices [ cdrom_drives [ id ] . scsi_device_id ] [ cdrom_drives [ id ] . scsi_device_lun ] . BufferLength ;
2017-01-16 01:49:19 +01:00
int ret = 0 ;
2017-05-27 03:53:32 +02:00
if ( cdrom_drives [ id ] . bus_type = = CDROM_BUS_SCSI )
2017-01-18 21:51:03 +01:00
ret = cdrom_read_from_scsi_dma ( cdrom_drives [ id ] . scsi_device_id , cdrom_drives [ id ] . scsi_device_lun ) ;
2017-01-16 01:49:19 +01:00
else
ret = cdrom_read_from_ide_dma ( cdrom_drives [ id ] . ide_channel ) ;
if ( ! ret )
return 0 ;
2018-02-27 23:55:28 +01:00
if ( cdrom_drives [ id ] . bus_type = = CDROM_BUS_SCSI )
cdrom_log ( " CD-ROM %i: SCSI Input data length: %i \n " , id , * BufLen ) ;
else
cdrom_log ( " CD-ROM %i: ATAPI Input data length: %i \n " , id , cdrom [ id ] . packet_len ) ;
2017-02-04 06:53:46 +01:00
2018-01-13 22:56:13 +01:00
ret = cdrom_phase_data_out ( id ) ;
if ( ! ret ) {
cdrom_phase_callback ( id ) ;
return 0 ;
} else
return 1 ;
2017-05-05 01:49:42 +02:00
return 0 ;
2017-01-16 01:49:19 +01:00
}
int cdrom_write_to_ide_dma ( uint8_t channel )
{
uint8_t id = atapi_cdrom_drives [ channel ] ;
2017-10-26 20:37:39 +02:00
if ( id > CDROM_NUM ) {
cdrom_log ( " CD-ROM %i: Drive not found \n " , id ) ;
2017-01-16 01:49:19 +01:00
return 0 ;
2017-10-26 20:37:39 +02:00
}
2017-02-09 01:41:32 +01:00
2017-10-24 04:15:05 +02:00
if ( ide_bus_master_read ) {
2017-10-26 20:37:39 +02:00
if ( ide_bus_master_read ( channel > > 1 , cdbufferb , cdrom [ id ] . packet_len ) ) {
cdrom_log ( " CD-ROM %i: ATAPI DMA error \n " , id ) ;
cdrom_bus_master_error ( id ) ;
2017-01-16 01:49:19 +01:00
cdrom_phase_callback ( id ) ;
return 0 ;
}
2017-10-26 20:37:39 +02:00
else {
cdrom_log ( " CD-ROM %i: ATAPI DMA success \n " , id ) ;
2017-01-16 01:49:19 +01:00
return 1 ;
2017-10-26 20:37:39 +02:00
}
2017-10-24 04:15:05 +02:00
} else {
2017-10-26 20:37:39 +02:00
cdrom_log ( " CD-ROM %i: No bus master \n " , id ) ;
cdrom_bus_master_error ( id ) ;
2017-10-24 04:15:05 +02:00
cdrom_phase_callback ( id ) ;
return 0 ;
2017-01-16 01:49:19 +01:00
}
2017-05-05 01:49:42 +02:00
return 0 ;
2017-01-16 01:49:19 +01:00
}
2017-01-18 21:51:03 +01:00
int cdrom_write_to_scsi_dma ( uint8_t scsi_id , uint8_t scsi_lun )
2017-01-16 01:49:19 +01:00
{
2017-01-18 21:51:03 +01:00
uint8_t id = scsi_cdrom_drives [ scsi_id ] [ scsi_lun ] ;
2017-10-14 07:03:19 +02:00
int32_t * BufLen = & SCSIDevices [ scsi_id ] [ scsi_lun ] . BufferLength ;
2017-01-16 01:49:19 +01:00
if ( id > CDROM_NUM )
return 0 ;
2017-10-14 07:03:19 +02:00
cdrom_log ( " Writing to SCSI DMA: SCSI ID %02X, init length %i \n " , scsi_id , * BufLen ) ;
memcpy ( SCSIDevices [ scsi_id ] [ scsi_lun ] . CmdBuffer , cdbufferb , * BufLen ) ;
2017-01-16 01:49:19 +01:00
cdrom_log ( " CD-ROM %i: Data from CD buffer: %02X %02X %02X %02X %02X %02X %02X %02X \n " , id , cdbufferb [ 0 ] , cdbufferb [ 1 ] , cdbufferb [ 2 ] , cdbufferb [ 3 ] , cdbufferb [ 4 ] , cdbufferb [ 5 ] , cdbufferb [ 6 ] , cdbufferb [ 7 ] ) ;
2017-01-18 21:51:03 +01:00
cdrom_log ( " CD-ROM %i: Data from SCSI DMA : %02X %02X %02X %02X %02X %02X %02X %02X \n " , id , SCSIDevices [ scsi_id ] [ scsi_lun ] . CmdBuffer [ 0 ] , SCSIDevices [ scsi_id ] [ scsi_lun ] . CmdBuffer [ 1 ] , SCSIDevices [ scsi_id ] [ scsi_lun ] . CmdBuffer [ 2 ] , SCSIDevices [ scsi_id ] [ scsi_lun ] . CmdBuffer [ 3 ] , SCSIDevices [ scsi_id ] [ scsi_lun ] . CmdBuffer [ 4 ] , SCSIDevices [ scsi_id ] [ scsi_lun ] . CmdBuffer [ 5 ] , SCSIDevices [ scsi_id ] [ scsi_lun ] . CmdBuffer [ 6 ] , SCSIDevices [ scsi_id ] [ scsi_lun ] . CmdBuffer [ 7 ] ) ;
2017-01-16 01:49:19 +01:00
return 1 ;
}
int cdrom_write_to_dma ( uint8_t id )
{
int ret = 0 ;
2017-10-24 04:15:05 +02:00
if ( cdrom_drives [ id ] . bus_type = = CDROM_BUS_SCSI ) {
2017-10-14 07:03:19 +02:00
cdrom_log ( " Write to SCSI DMA: (%02X:%02X) \n " , cdrom_drives [ id ] . scsi_device_id , cdrom_drives [ id ] . scsi_device_lun ) ;
2017-01-18 21:51:03 +01:00
ret = cdrom_write_to_scsi_dma ( cdrom_drives [ id ] . scsi_device_id , cdrom_drives [ id ] . scsi_device_lun ) ;
2017-10-24 04:15:05 +02:00
} else
2017-01-16 01:49:19 +01:00
ret = cdrom_write_to_ide_dma ( cdrom_drives [ id ] . ide_channel ) ;
if ( ! ret )
return 0 ;
return 1 ;
}
2017-01-20 23:53:19 +01:00
void cdrom_irq_raise ( uint8_t id )
{
2017-05-27 03:53:32 +02:00
if ( cdrom_drives [ id ] . bus_type < CDROM_BUS_SCSI )
2017-01-20 23:53:19 +01:00
ide_irq_raise ( & ( ide_drives [ cdrom_drives [ id ] . ide_channel ] ) ) ;
}
2017-01-16 01:49:19 +01:00
/* If the result is 1, issue an IRQ, otherwise not. */
2017-01-20 23:53:19 +01:00
void cdrom_phase_callback ( uint8_t id )
2017-01-16 01:49:19 +01:00
{
2017-10-24 04:15:05 +02:00
switch ( cdrom [ id ] . packet_status ) {
2017-01-16 01:49:19 +01:00
case CDROM_PHASE_IDLE :
2017-01-20 23:53:19 +01:00
cdrom_log ( " CD-ROM %i: CDROM_PHASE_IDLE \n " , id ) ;
2017-01-16 01:49:19 +01:00
cdrom [ id ] . pos = 0 ;
cdrom [ id ] . phase = 1 ;
cdrom [ id ] . status = READY_STAT | DRQ_STAT | ( cdrom [ id ] . status & ERR_STAT ) ;
2017-01-20 23:53:19 +01:00
return ;
2017-01-16 01:49:19 +01:00
case CDROM_PHASE_COMMAND :
2017-01-20 23:53:19 +01:00
cdrom_log ( " CD-ROM %i: CDROM_PHASE_COMMAND \n " , id ) ;
2017-01-16 01:49:19 +01:00
cdrom [ id ] . status = BUSY_STAT | ( cdrom [ id ] . status & ERR_STAT ) ;
2017-10-16 17:33:01 +02:00
memcpy ( cdrom [ id ] . atapi_cdb , cdbufferb , cdrom [ id ] . cdb_len ) ;
2017-01-16 01:49:19 +01:00
cdrom_command ( id , cdrom [ id ] . atapi_cdb ) ;
2017-01-20 23:53:19 +01:00
return ;
2017-01-16 01:49:19 +01:00
case CDROM_PHASE_COMPLETE :
2017-01-20 23:53:19 +01:00
cdrom_log ( " CD-ROM %i: CDROM_PHASE_COMPLETE \n " , id ) ;
2017-01-16 01:49:19 +01:00
cdrom [ id ] . status = READY_STAT ;
cdrom [ id ] . phase = 3 ;
2017-01-17 19:41:42 +01:00
cdrom [ id ] . packet_status = 0xFF ;
2017-10-10 03:07:29 -04:00
ui_sb_update_icon ( SB_CDROM | id , 0 ) ;
2017-01-20 23:53:19 +01:00
cdrom_irq_raise ( id ) ;
return ;
2017-01-16 01:49:19 +01:00
case CDROM_PHASE_DATA_OUT :
2017-01-20 23:53:19 +01:00
cdrom_log ( " CD-ROM %i: CDROM_PHASE_DATA_OUT \n " , id ) ;
2017-01-16 01:49:19 +01:00
cdrom [ id ] . status = READY_STAT | DRQ_STAT | ( cdrom [ id ] . status & ERR_STAT ) ;
cdrom [ id ] . phase = 0 ;
2017-01-20 23:53:19 +01:00
cdrom_irq_raise ( id ) ;
return ;
2017-01-16 01:49:19 +01:00
case CDROM_PHASE_DATA_OUT_DMA :
2017-01-20 23:53:19 +01:00
cdrom_log ( " CD-ROM %i: CDROM_PHASE_DATA_OUT_DMA \n " , id ) ;
2017-01-16 01:49:19 +01:00
cdrom_read_from_dma ( id ) ;
2018-01-06 22:47:41 +01:00
cdrom_buf_free ( id ) ;
2017-01-16 01:49:19 +01:00
cdrom [ id ] . packet_status = CDROM_PHASE_COMPLETE ;
cdrom [ id ] . status = READY_STAT ;
cdrom [ id ] . phase = 3 ;
2017-10-10 03:07:29 -04:00
ui_sb_update_icon ( SB_CDROM | id , 0 ) ;
2017-01-20 23:53:19 +01:00
cdrom_irq_raise ( id ) ;
return ;
2017-01-16 01:49:19 +01:00
case CDROM_PHASE_DATA_IN :
2017-01-20 23:53:19 +01:00
cdrom_log ( " CD-ROM %i: CDROM_PHASE_DATA_IN \n " , id ) ;
2017-01-16 01:49:19 +01:00
cdrom [ id ] . status = READY_STAT | DRQ_STAT | ( cdrom [ id ] . status & ERR_STAT ) ;
cdrom [ id ] . phase = 2 ;
2017-01-20 23:53:19 +01:00
cdrom_irq_raise ( id ) ;
return ;
2017-01-16 01:49:19 +01:00
case CDROM_PHASE_DATA_IN_DMA :
2017-01-20 23:53:19 +01:00
cdrom_log ( " CD-ROM %i: CDROM_PHASE_DATA_IN_DMA \n " , id ) ;
2017-01-16 01:49:19 +01:00
cdrom_write_to_dma ( id ) ;
2018-01-06 22:47:41 +01:00
cdrom_buf_free ( id ) ;
2017-01-16 01:49:19 +01:00
cdrom [ id ] . packet_status = CDROM_PHASE_COMPLETE ;
cdrom [ id ] . status = READY_STAT ;
cdrom [ id ] . phase = 3 ;
2017-10-10 03:07:29 -04:00
ui_sb_update_icon ( SB_CDROM | id , 0 ) ;
2017-01-20 23:53:19 +01:00
cdrom_irq_raise ( id ) ;
return ;
2017-01-16 01:49:19 +01:00
case CDROM_PHASE_ERROR :
2017-01-20 23:53:19 +01:00
cdrom_log ( " CD-ROM %i: CDROM_PHASE_ERROR \n " , id ) ;
2017-01-16 01:49:19 +01:00
cdrom [ id ] . status = READY_STAT | ERR_STAT ;
cdrom [ id ] . phase = 3 ;
2017-01-20 23:53:19 +01:00
cdrom_irq_raise ( id ) ;
2017-10-16 06:19:18 +02:00
ui_sb_update_icon ( SB_CDROM | id , 0 ) ;
2017-01-20 23:53:19 +01:00
return ;
2017-01-16 01:49:19 +01:00
}
}
2017-01-17 00:01:59 +01:00
/* Reimplement as 8-bit due to reimplementation of IDE data read and write. */
2017-01-18 21:51:03 +01:00
uint32_t cdrom_read ( uint8_t channel , int length )
2017-01-16 01:49:19 +01:00
{
2017-01-18 21:51:03 +01:00
uint16_t * cdbufferw ;
uint32_t * cdbufferl ;
2017-01-17 00:01:59 +01:00
2017-01-16 01:49:19 +01:00
uint8_t id = atapi_cdrom_drives [ channel ] ;
2017-01-18 21:51:03 +01:00
uint32_t temp = 0 ;
2017-01-16 01:49:19 +01:00
if ( id > CDROM_NUM )
return 0 ;
2017-10-16 06:19:18 +02:00
cdbufferw = ( uint16_t * ) cdbufferb ;
cdbufferl = ( uint32_t * ) cdbufferb ;
2017-01-16 01:49:19 +01:00
2017-10-16 17:33:01 +02:00
if ( ! cdbufferb )
return 0 ;
2017-10-22 03:16:52 +02:00
/* Make sure we return a 0 and don't attempt to read from the buffer if we're transferring bytes beyond it,
which can happen when issuing media access commands with an allocated length below minimum request length
( which is 1 sector = 2048 bytes ) . */
2017-10-24 04:15:05 +02:00
switch ( length ) {
2017-01-18 21:51:03 +01:00
case 1 :
2017-10-22 03:16:52 +02:00
temp = ( cdrom [ id ] . pos < cdrom [ id ] . packet_len ) ? cdbufferb [ cdrom [ id ] . pos ] : 0 ;
2017-01-18 21:51:03 +01:00
cdrom [ id ] . pos + + ;
cdrom [ id ] . request_pos + + ;
break ;
case 2 :
2017-10-22 03:16:52 +02:00
temp = ( cdrom [ id ] . pos < cdrom [ id ] . packet_len ) ? cdbufferw [ cdrom [ id ] . pos > > 1 ] : 0 ;
2017-01-18 21:51:03 +01:00
cdrom [ id ] . pos + = 2 ;
cdrom [ id ] . request_pos + = 2 ;
break ;
case 4 :
2017-10-22 03:16:52 +02:00
temp = ( cdrom [ id ] . pos < cdrom [ id ] . packet_len ) ? cdbufferl [ cdrom [ id ] . pos > > 2 ] : 0 ;
2017-01-18 21:51:03 +01:00
cdrom [ id ] . pos + = 4 ;
cdrom [ id ] . request_pos + = 4 ;
break ;
default :
return 0 ;
}
2017-01-16 01:49:19 +01:00
2017-10-24 04:15:05 +02:00
if ( cdrom [ id ] . packet_status = = CDROM_PHASE_DATA_IN ) {
2018-02-27 23:55:28 +01:00
if ( ( cdrom [ id ] . request_pos > = cdrom [ id ] . max_transfer_len ) | | ( cdrom [ id ] . pos > = cdrom [ id ] . packet_len ) ) {
2017-10-22 03:16:52 +02:00
/* Time for a DRQ. */
2017-10-26 20:37:39 +02:00
// cdrom_log("CD-ROM %i: Issuing read callback\n", id);
2018-01-13 22:56:13 +01:00
cdrom_pio_request ( id , 0 ) ;
2017-01-16 01:49:19 +01:00
}
2017-10-26 20:37:39 +02:00
// cdrom_log("CD-ROM %i: Returning: %02X (buffer position: %i, request position: %i)\n", id, temp, cdrom[id].pos, cdrom[id].request_pos);
2017-01-16 01:49:19 +01:00
return temp ;
2017-10-24 04:15:05 +02:00
} else {
2017-10-26 20:37:39 +02:00
// cdrom_log("CD-ROM %i: Returning zero (buffer position: %i, request position: %i)\n", id, cdrom[id].pos, cdrom[id].request_pos);
2017-01-16 01:49:19 +01:00
return 0 ;
}
}
2017-01-17 00:01:59 +01:00
/* Reimplement as 8-bit due to reimplementation of IDE data read and write. */
2017-01-18 21:51:03 +01:00
void cdrom_write ( uint8_t channel , uint32_t val , int length )
2017-01-16 01:49:19 +01:00
{
2017-01-18 21:51:03 +01:00
uint16_t * cdbufferw ;
uint32_t * cdbufferl ;
2017-01-17 00:01:59 +01:00
2017-01-16 01:49:19 +01:00
uint8_t id = atapi_cdrom_drives [ channel ] ;
if ( id > CDROM_NUM )
2017-01-17 00:04:49 +01:00
return ;
2017-01-16 01:49:19 +01:00
2017-10-16 17:33:01 +02:00
if ( cdrom [ id ] . packet_status = = CDROM_PHASE_IDLE ) {
if ( ! cdbufferb )
cdrom_buf_alloc ( id , cdrom [ id ] . cdb_len ) ;
}
2017-10-16 06:19:18 +02:00
cdbufferw = ( uint16_t * ) cdbufferb ;
cdbufferl = ( uint32_t * ) cdbufferb ;
2017-01-17 00:01:59 +01:00
2018-01-13 22:56:13 +01:00
if ( ! cdbufferb )
return ;
2017-01-27 23:03:20 +01:00
2017-10-24 04:15:05 +02:00
switch ( length ) {
2017-01-18 21:51:03 +01:00
case 1 :
cdbufferb [ cdrom [ id ] . pos ] = val & 0xff ;
cdrom [ id ] . pos + + ;
2018-01-13 22:56:13 +01:00
cdrom [ id ] . request_pos + + ;
2017-01-18 21:51:03 +01:00
break ;
case 2 :
2017-01-20 23:53:19 +01:00
cdbufferw [ cdrom [ id ] . pos > > 1 ] = val & 0xffff ;
2017-01-18 21:51:03 +01:00
cdrom [ id ] . pos + = 2 ;
2018-01-13 22:56:13 +01:00
cdrom [ id ] . request_pos + = 2 ;
2017-01-18 21:51:03 +01:00
break ;
case 4 :
cdbufferl [ cdrom [ id ] . pos > > 2 ] = val ;
cdrom [ id ] . pos + = 4 ;
2018-01-13 22:56:13 +01:00
cdrom [ id ] . request_pos + = 4 ;
2017-01-18 21:51:03 +01:00
break ;
default :
return ;
}
2017-01-16 01:49:19 +01:00
2017-10-24 04:15:05 +02:00
if ( cdrom [ id ] . packet_status = = CDROM_PHASE_DATA_OUT ) {
2018-02-27 23:55:28 +01:00
if ( ( cdrom [ id ] . request_pos > = cdrom [ id ] . max_transfer_len ) | | ( cdrom [ id ] . pos > = cdrom [ id ] . packet_len ) ) {
2018-01-13 22:56:13 +01:00
/* Time for a DRQ. */
cdrom_pio_request ( id , 1 ) ;
2017-01-18 21:51:03 +01:00
}
2017-01-17 00:01:59 +01:00
return ;
2017-10-24 04:15:05 +02:00
} else if ( cdrom [ id ] . packet_status = = CDROM_PHASE_IDLE ) {
if ( cdrom [ id ] . pos > = cdrom [ id ] . cdb_len ) {
2017-01-16 01:49:19 +01:00
cdrom [ id ] . pos = 0 ;
cdrom [ id ] . status = BUSY_STAT ;
cdrom [ id ] . packet_status = CDROM_PHASE_COMMAND ;
timer_process ( ) ;
cdrom_phase_callback ( id ) ;
timer_update_outstanding ( ) ;
}
2017-01-17 00:04:49 +01:00
return ;
2017-01-16 01:49:19 +01:00
}
}
2017-10-08 05:04:38 +02:00
void cdrom_hard_reset ( void )
{
int i = 0 ;
for ( i = 0 ; i < CDROM_NUM ; i + + ) {
2017-10-24 04:15:05 +02:00
if ( cdrom_drives [ i ] . host_drive = = 200 )
2017-10-08 05:04:38 +02:00
image_reset ( i ) ;
else if ( ( cdrom_drives [ i ] . host_drive > = ' A ' ) & & ( cdrom_drives [ i ] . host_drive < = ' Z ' ) )
ioctl_reset ( i ) ;
2018-01-13 22:56:13 +01:00
cdrom_mode_sense_load ( i ) ;
2017-10-08 05:04:38 +02:00
}
}
2017-10-13 02:44:32 -04:00
/* Peform a master init on the entire module. */
void
cdrom_global_init ( void )
2017-10-08 05:04:38 +02:00
{
2017-10-13 02:44:32 -04:00
int c ;
/* Clear the global data. */
memset ( cdrom , 0x00 , sizeof ( cdrom ) ) ;
memset ( cdrom_drives , 0x00 , sizeof ( cdrom_drives ) ) ;
2017-10-08 05:04:38 +02:00
2017-10-13 02:44:32 -04:00
/* Initialize the host devices, if any. */
2017-10-08 05:04:38 +02:00
cdrom_init_host_drives ( ) ;
2017-10-13 02:44:32 -04:00
/* Set all drives to NULL mode. */
for ( c = 0 ; c < CDROM_NUM ; c + + )
cdrom_null_open ( c , cdrom_drives [ c ] . host_drive ) ;
}
void
cdrom_global_reset ( void )
{
int c ;
2017-10-08 05:04:38 +02:00
for ( c = 0 ; c < CDROM_NUM ; c + + ) {
2017-10-24 04:15:05 +02:00
if ( cdrom_drives [ c ] . bus_type )
2017-10-08 05:04:38 +02:00
SCSIReset ( cdrom_drives [ c ] . scsi_device_id , cdrom_drives [ c ] . scsi_device_lun ) ;
2018-01-24 18:38:43 +01:00
cdrom_log ( " CDROM global_reset drive=%d host=%02x \n " , c , cdrom_drives [ c ] . host_drive ) ;
2017-10-24 04:15:05 +02:00
if ( cdrom_drives [ c ] . host_drive = = 200 )
2017-10-08 05:04:38 +02:00
image_open ( c , cdrom_image [ c ] . image_path ) ;
2017-10-24 04:15:05 +02:00
else if ( ( cdrom_drives [ c ] . host_drive > = ' A ' ) & & ( cdrom_drives [ c ] . host_drive < = ' Z ' ) )
2017-10-08 05:04:38 +02:00
ioctl_open ( c , cdrom_drives [ c ] . host_drive ) ;
2017-10-24 04:15:05 +02:00
else
2017-10-08 05:04:38 +02:00
cdrom_null_open ( c , cdrom_drives [ c ] . host_drive ) ;
}
}
2017-10-11 05:40:44 -04:00
void
cdrom_close ( uint8_t id )
{
switch ( cdrom_drives [ id ] . host_drive ) {
case 0 :
null_close ( id ) ;
break ;
case 200 :
image_close ( id ) ;
break ;
default :
ioctl_close ( id ) ;
break ;
}
}