2016-11-12 15:06:38 +01:00
|
|
|
/* Copyright holders: Sarah Walker, Tenshi, SA1988
|
2016-08-14 22:07:17 -04:00
|
|
|
see COPYING for more details
|
|
|
|
|
*/
|
2016-06-26 00:34:39 +02:00
|
|
|
#define CDROM_ISO 200
|
|
|
|
|
#define IDE_TIME (5 * 100 * (1 << TIMER_SHIFT))
|
|
|
|
|
|
|
|
|
|
#define _LARGEFILE_SOURCE
|
|
|
|
|
#define _LARGEFILE64_SOURCE
|
|
|
|
|
#define _GNU_SOURCE
|
|
|
|
|
#include <errno.h>
|
2016-09-29 21:54:34 +02:00
|
|
|
#include <ctype.h>
|
2016-06-26 00:34:39 +02:00
|
|
|
#include <stdio.h>
|
|
|
|
|
#include <stdint.h>
|
|
|
|
|
#include <string.h>
|
|
|
|
|
|
|
|
|
|
#include <sys/types.h>
|
|
|
|
|
|
2016-12-29 20:40:24 +01:00
|
|
|
#include "86box.h"
|
|
|
|
|
#include "ibm.h"
|
|
|
|
|
#include "io.h"
|
|
|
|
|
#include "pic.h"
|
|
|
|
|
#include "timer.h"
|
2016-11-12 15:06:38 +01:00
|
|
|
#include "cdrom.h"
|
|
|
|
|
#include "scsi.h"
|
2016-06-26 00:34:39 +02:00
|
|
|
#include "ide.h"
|
|
|
|
|
|
|
|
|
|
/* Bits of 'atastat' */
|
|
|
|
|
#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 */
|
|
|
|
|
|
|
|
|
|
/* ATA Commands */
|
2016-08-10 01:14:22 +02:00
|
|
|
#define WIN_NOP 0x00
|
2016-06-26 00:34:39 +02:00
|
|
|
#define WIN_SRST 0x08 /* ATAPI Device Reset */
|
|
|
|
|
#define WIN_RECAL 0x10
|
|
|
|
|
#define WIN_RESTORE WIN_RECAL
|
|
|
|
|
#define WIN_READ 0x20 /* 28-Bit Read */
|
|
|
|
|
#define WIN_READ_NORETRY 0x21 /* 28-Bit Read - no retry*/
|
|
|
|
|
#define WIN_WRITE 0x30 /* 28-Bit Write */
|
|
|
|
|
#define WIN_WRITE_NORETRY 0x31 /* 28-Bit Write */
|
|
|
|
|
#define WIN_VERIFY 0x40 /* 28-Bit Verify */
|
|
|
|
|
#define WIN_VERIFY_ONCE 0x41 /* Added by OBattler - deprected older ATA command, according to the specification I found, it is identical to 0x40 */
|
|
|
|
|
#define WIN_FORMAT 0x50
|
|
|
|
|
#define WIN_SEEK 0x70
|
|
|
|
|
#define WIN_DRIVE_DIAGNOSTICS 0x90 /* Execute Drive Diagnostics */
|
|
|
|
|
#define WIN_SPECIFY 0x91 /* Initialize Drive Parameters */
|
|
|
|
|
#define WIN_PACKETCMD 0xA0 /* Send a packet command. */
|
|
|
|
|
#define WIN_PIDENTIFY 0xA1 /* Identify ATAPI device */
|
|
|
|
|
#define WIN_READ_MULTIPLE 0xC4
|
|
|
|
|
#define WIN_WRITE_MULTIPLE 0xC5
|
|
|
|
|
#define WIN_SET_MULTIPLE_MODE 0xC6
|
|
|
|
|
#define WIN_READ_DMA 0xC8
|
|
|
|
|
#define WIN_WRITE_DMA 0xCA
|
2016-08-10 00:46:56 +02:00
|
|
|
#define WIN_STANDBYNOW1 0xE0
|
2016-06-26 00:34:39 +02:00
|
|
|
#define WIN_SETIDLE1 0xE3
|
2016-08-10 00:46:56 +02:00
|
|
|
#define WIN_CHECKPOWERMODE1 0xE5
|
2016-06-26 00:34:39 +02:00
|
|
|
#define WIN_IDENTIFY 0xEC /* Ask drive to identify itself */
|
2016-08-10 00:46:56 +02:00
|
|
|
#define WIN_SET_FEATURES 0xEF
|
|
|
|
|
#define WIN_READ_NATIVE_MAX 0xF8
|
2016-06-26 00:34:39 +02:00
|
|
|
|
|
|
|
|
/** Evaluate to non-zero if the currently selected drive is an ATAPI device */
|
|
|
|
|
#define IDE_DRIVE_IS_CDROM(ide) (ide->type == IDE_CDROM)
|
|
|
|
|
|
|
|
|
|
#define ATAPI_STATUS_IDLE 0
|
|
|
|
|
#define ATAPI_STATUS_COMMAND 1
|
|
|
|
|
#define ATAPI_STATUS_COMPLETE 2
|
|
|
|
|
#define ATAPI_STATUS_DATA 3
|
|
|
|
|
#define ATAPI_STATUS_PACKET_REQ 4
|
|
|
|
|
#define ATAPI_STATUS_PACKET_RECEIVED 5
|
|
|
|
|
#define ATAPI_STATUS_READCD 6
|
|
|
|
|
#define ATAPI_STATUS_REQ_SENSE 7
|
|
|
|
|
#define ATAPI_STATUS_ERROR 0x80
|
|
|
|
|
#define ATAPI_STATUS_ERROR_2 0x81
|
|
|
|
|
|
|
|
|
|
enum
|
|
|
|
|
{
|
|
|
|
|
IDE_NONE = 0,
|
|
|
|
|
IDE_HDD,
|
|
|
|
|
IDE_CDROM
|
|
|
|
|
};
|
|
|
|
|
|
2016-12-29 20:40:24 +01:00
|
|
|
static struct
|
|
|
|
|
{
|
|
|
|
|
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;
|
|
|
|
|
|
|
|
|
|
static struct
|
|
|
|
|
{
|
|
|
|
|
uint16_t len;
|
|
|
|
|
uint8_t notification_class;
|
|
|
|
|
uint8_t supported_events;
|
|
|
|
|
} *gesn_event_header;
|
|
|
|
|
|
|
|
|
|
static unsigned int used_len;
|
|
|
|
|
|
2016-09-25 21:39:21 +02:00
|
|
|
uint64_t hdt[128][3] = { { 306, 4, 17 }, { 615, 2, 17 }, { 306, 4, 26 }, { 1024, 2, 17 }, { 697, 3, 17 }, { 306, 8, 17 }, { 614, 4, 17 }, { 615, 4, 17 }, /* 000-007 */
|
|
|
|
|
{ 670, 4, 17 }, { 697, 4, 17 }, { 987, 3, 17 }, { 820, 4, 17 }, { 670, 5, 17 }, { 697, 5, 17 }, { 733, 5, 17 }, { 615, 6, 17 }, /* 008-015 */
|
|
|
|
|
{ 462, 8, 17 }, { 306, 8, 26 }, { 615, 4, 26 }, { 1024, 4, 17 }, { 855, 5, 17 }, { 925, 5, 17 }, { 932, 5, 17 }, { 1024, 2, 40 }, /* 016-023 */
|
|
|
|
|
{ 809, 6, 17 }, { 976, 5, 17 }, { 977, 5, 17 }, { 698, 7, 17 }, { 699, 7, 17 }, { 981, 5, 17 }, { 615, 8, 17 }, { 989, 5, 17 }, /* 024-031 */
|
|
|
|
|
{ 820, 4, 26 }, { 1024, 5, 17 }, { 733, 7, 17 }, { 754, 7, 17 }, { 733, 5, 26 }, { 940, 6, 17 }, { 615, 6, 26 }, { 462, 8, 26 }, /* 032-039 */
|
|
|
|
|
{ 830, 7, 17 }, { 855, 7, 17 }, { 751, 8, 17 }, { 1024, 4, 26 }, { 918, 7, 17 }, { 925, 7, 17 }, { 855, 5, 26 }, { 977, 7, 17 }, /* 040-047 */
|
|
|
|
|
{ 987, 7, 17 }, { 1024, 7, 17 }, { 823, 4, 38 }, { 925, 8, 17 }, { 809, 6, 26 }, { 976, 5, 26 }, { 977, 5, 26 }, { 698, 7, 26 }, /* 048-055 */
|
|
|
|
|
{ 699, 7, 26 }, { 940, 8, 17 }, { 615, 8, 26 }, { 1024, 5, 26 }, { 733, 7, 26 }, { 1024, 8, 17 }, { 823, 10, 17 }, { 754, 11, 17 }, /* 056-063 */
|
|
|
|
|
{ 830, 10, 17 }, { 925, 9, 17 }, { 1224, 7, 17 }, { 940, 6, 26 }, { 855, 7, 26 }, { 751, 8, 26 }, { 1024, 9, 17 }, { 965, 10, 17 }, /* 064-071 */
|
|
|
|
|
{ 969, 5, 34 }, { 980, 10, 17 }, { 960, 5, 35 }, { 918, 11, 17 }, { 1024, 10, 17 }, { 977, 7, 26 }, { 1024, 7, 26 }, { 1024, 11, 17 }, /* 072-079 */
|
|
|
|
|
{ 940, 8, 26 }, { 776, 8, 33 }, { 755, 16, 17 }, { 1024, 12, 17 }, { 1024, 8, 26 }, { 823, 10, 26 }, { 830, 10, 26 }, { 925, 9, 26 }, /* 080-087 */
|
|
|
|
|
{ 960, 9, 26 }, { 1024, 13, 17 }, { 1224, 11, 17 }, { 900, 15, 17 }, { 969, 7, 34 }, { 917, 15, 17 }, { 918, 15, 17 }, { 1524, 4, 39 }, /* 088-095 */
|
|
|
|
|
{ 1024, 9, 26 }, { 1024, 14, 17 }, { 965, 10, 26 }, { 980, 10, 26 }, { 1020, 15, 17 }, { 1023, 15, 17 }, { 1024, 15, 17 }, { 1024, 16, 17 }, /* 096-103 */
|
|
|
|
|
{ 1224, 15, 17 }, { 755, 16, 26 }, { 903, 8, 46 }, { 984, 10, 34 }, { 900, 15, 26 }, { 917, 15, 26 }, { 1023, 15, 26 }, { 684, 16, 38 }, /* 104-111 */
|
|
|
|
|
{ 1930, 4, 62 }, { 967, 16, 31 }, { 1013, 10, 63 }, { 1218, 15, 36 }, { 654, 16, 63 }, { 659, 16, 63 }, { 702, 16, 63 }, { 1002, 13, 63 }, /* 112-119 */
|
|
|
|
|
{ 854, 16, 63 }, { 987, 16, 63 }, { 995, 16, 63 }, { 1024, 16, 63 }, { 1036, 16, 63 }, { 1120, 16, 59 }, { 1054, 16, 63 }, { 0, 0, 0 } }; /* 119-127 */
|
|
|
|
|
|
2016-06-26 00:34:39 +02:00
|
|
|
typedef struct IDE
|
|
|
|
|
{
|
|
|
|
|
int type;
|
|
|
|
|
int board;
|
|
|
|
|
uint8_t atastat;
|
|
|
|
|
uint8_t error;
|
2016-08-10 06:15:52 +02:00
|
|
|
int secount,sector,cylinder,head,drive,cylprecomp;
|
2016-06-26 00:34:39 +02:00
|
|
|
uint8_t command;
|
|
|
|
|
uint8_t fdisk;
|
|
|
|
|
int pos;
|
|
|
|
|
int packlen;
|
|
|
|
|
int spt,hpc;
|
|
|
|
|
int tracks;
|
|
|
|
|
int packetstatus;
|
|
|
|
|
uint8_t asc;
|
|
|
|
|
int reset;
|
|
|
|
|
FILE *hdfile;
|
|
|
|
|
uint16_t buffer[65536];
|
|
|
|
|
int irqstat;
|
|
|
|
|
int service;
|
|
|
|
|
int lba;
|
|
|
|
|
uint32_t lba_addr;
|
|
|
|
|
int skip512;
|
|
|
|
|
int blocksize, blockcount;
|
2016-08-10 00:46:56 +02:00
|
|
|
uint16_t dma_identify_data[3];
|
2016-09-25 21:39:21 +02:00
|
|
|
int hdi,base;
|
|
|
|
|
int hdc_num;
|
2016-06-26 00:34:39 +02:00
|
|
|
} IDE;
|
|
|
|
|
|
2016-12-28 23:34:00 +01:00
|
|
|
IDE ide_drives[IDE_NUM];
|
2016-06-26 00:34:39 +02:00
|
|
|
|
|
|
|
|
IDE *ext_ide;
|
|
|
|
|
|
2016-12-28 23:34:00 +01:00
|
|
|
char ide_fn[IDE_NUM][512];
|
2016-06-26 00:34:39 +02:00
|
|
|
|
|
|
|
|
int (*ide_bus_master_read_sector)(int channel, uint8_t *data);
|
|
|
|
|
int (*ide_bus_master_write_sector)(int channel, uint8_t *data);
|
|
|
|
|
void (*ide_bus_master_set_irq)(int channel);
|
|
|
|
|
|
|
|
|
|
static void callnonreadcd(IDE *ide);
|
|
|
|
|
static void callreadcd(IDE *ide);
|
|
|
|
|
static void atapicommand(int ide_board);
|
|
|
|
|
|
2016-12-28 23:34:00 +01:00
|
|
|
int idecallback[4] = {0, 0, 0, 0};
|
2016-06-26 00:34:39 +02:00
|
|
|
|
2016-12-28 23:34:00 +01:00
|
|
|
int cur_ide[4];
|
2016-06-26 00:34:39 +02:00
|
|
|
|
2016-11-12 15:06:38 +01:00
|
|
|
int atapi_command = 0;
|
|
|
|
|
|
|
|
|
|
int atapi_cdrom_channel = 2;
|
|
|
|
|
|
2016-06-26 00:34:39 +02:00
|
|
|
uint8_t getstat(IDE *ide) { return ide->atastat; }
|
|
|
|
|
|
2016-09-29 21:54:34 +02:00
|
|
|
int image_is_hdi(const char *s)
|
2016-09-25 21:39:21 +02:00
|
|
|
{
|
2016-09-29 21:54:34 +02:00
|
|
|
int i, len;
|
2016-09-25 21:39:21 +02:00
|
|
|
char ext[5] = { 0, 0, 0, 0, 0 };
|
|
|
|
|
len = strlen(s);
|
2016-09-29 21:54:34 +02:00
|
|
|
if ((len < 4) || (s[0] == '.'))
|
|
|
|
|
{
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
memcpy(ext, s + len - 4, 4);
|
|
|
|
|
for (i = 0; i < 4; i++)
|
|
|
|
|
{
|
|
|
|
|
ext[i] = toupper(ext[i]);
|
|
|
|
|
}
|
2016-09-25 21:39:21 +02:00
|
|
|
if (strcmp(ext, ".HDI") == 0)
|
|
|
|
|
{
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2016-12-29 20:40:24 +01:00
|
|
|
int ide_enable[4] = { 1, 1, 0, 0 };
|
|
|
|
|
int ide_irq[4] = { 14, 15, 10, 11 };
|
2016-12-28 23:34:00 +01:00
|
|
|
|
2016-06-26 00:34:39 +02:00
|
|
|
static inline void ide_irq_raise(IDE *ide)
|
|
|
|
|
{
|
2016-12-29 20:40:24 +01:00
|
|
|
if ((ide->board > 3) || ide->irqstat)
|
|
|
|
|
{
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// pclog("Raising IRQ %i (board %i)\n", ide_irq[ide->board], ide->board);
|
|
|
|
|
|
|
|
|
|
if (!(ide->fdisk&2))
|
|
|
|
|
{
|
|
|
|
|
picint(1 << ide_irq[ide->board]);
|
|
|
|
|
// if (ide->board && !ide->irqstat) pclog("IDE_IRQ_RAISE\n");
|
|
|
|
|
|
|
|
|
|
if (ide->board < 2)
|
|
|
|
|
{
|
|
|
|
|
if (ide_bus_master_set_irq)
|
|
|
|
|
{
|
|
|
|
|
ide_bus_master_set_irq(ide->board);
|
|
|
|
|
}
|
|
|
|
|
}
|
2016-06-26 00:34:39 +02:00
|
|
|
}
|
2016-12-29 20:40:24 +01:00
|
|
|
|
2016-06-26 00:34:39 +02:00
|
|
|
ide->irqstat=1;
|
2016-12-29 20:40:24 +01:00
|
|
|
ide->service=1;
|
2016-06-26 00:34:39 +02:00
|
|
|
// pclog("raising interrupt %i\n", 14 + ide->board);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static inline void ide_irq_lower(IDE *ide)
|
|
|
|
|
{
|
2016-12-29 20:40:24 +01:00
|
|
|
if ((ide->board > 3) || !(ide->irqstat))
|
|
|
|
|
{
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// pclog("Lowering IRQ %i (board %i)\n", ide_irq[ide->board], ide->board);
|
|
|
|
|
|
|
|
|
|
picintc(1 << ide_irq[ide->board]);
|
2016-06-26 00:34:39 +02:00
|
|
|
ide->irqstat=0;
|
2016-12-23 03:16:24 +01:00
|
|
|
// ide->service=0;
|
2016-06-26 00:34:39 +02:00
|
|
|
}
|
|
|
|
|
|
2016-12-29 20:40:24 +01:00
|
|
|
void ide_irq_update(IDE *ide)
|
2016-06-26 00:34:39 +02:00
|
|
|
{
|
2016-12-29 20:40:24 +01:00
|
|
|
int pending = 0;
|
|
|
|
|
int mask = 0;
|
|
|
|
|
|
|
|
|
|
if (ide->board > 3)
|
|
|
|
|
{
|
|
|
|
|
return;
|
|
|
|
|
}
|
2016-06-26 00:34:39 +02:00
|
|
|
|
2016-12-29 20:40:24 +01:00
|
|
|
mask = ide_irq[ide->board];
|
|
|
|
|
mask &= 7;
|
2016-12-23 03:16:24 +01:00
|
|
|
|
2016-12-29 20:40:24 +01:00
|
|
|
// pclog("Updating IRQ %i (%i) (board %i)\n", ide_irq[ide->board], mask, ide->board);
|
|
|
|
|
|
|
|
|
|
pending = (pic2.pend | pic2.ins);
|
|
|
|
|
pending &= (1 << mask);
|
|
|
|
|
|
|
|
|
|
if (ide->irqstat && !pending && !(ide->fdisk & 2))
|
|
|
|
|
{
|
|
|
|
|
picint(1 << ide_irq[ide->board]);
|
|
|
|
|
}
|
|
|
|
|
else if (pending)
|
|
|
|
|
{
|
|
|
|
|
picintc(1 << ide_irq[ide->board]);
|
|
|
|
|
}
|
2016-06-26 00:34:39 +02:00
|
|
|
}
|
|
|
|
|
/**
|
|
|
|
|
* Copy a string into a buffer, padding with spaces, and placing characters as
|
|
|
|
|
* if they were packed into 16-bit values, stored little-endian.
|
|
|
|
|
*
|
|
|
|
|
* @param str Destination buffer
|
|
|
|
|
* @param src Source string
|
|
|
|
|
* @param len Length of destination buffer to fill in. Strings shorter than
|
|
|
|
|
* this length will be padded with spaces.
|
|
|
|
|
*/
|
|
|
|
|
static void
|
|
|
|
|
ide_padstr(char *str, const char *src, int len)
|
|
|
|
|
{
|
|
|
|
|
int i, v;
|
|
|
|
|
|
2016-12-29 20:40:24 +01:00
|
|
|
for (i = 0; i < len; i++)
|
|
|
|
|
{
|
|
|
|
|
if (*src != '\0')
|
|
|
|
|
{
|
2016-06-26 00:34:39 +02:00
|
|
|
v = *src++;
|
2016-12-29 20:40:24 +01:00
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2016-06-26 00:34:39 +02:00
|
|
|
v = ' ';
|
|
|
|
|
}
|
|
|
|
|
str[i ^ 1] = v;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Copy a string into a buffer, padding with spaces. Does not add string
|
|
|
|
|
* terminator.
|
|
|
|
|
*
|
|
|
|
|
* @param buf Destination buffer
|
|
|
|
|
* @param buf_size Size of destination buffer to fill in. Strings shorter than
|
|
|
|
|
* this length will be padded with spaces.
|
|
|
|
|
* @param src Source string
|
|
|
|
|
*/
|
|
|
|
|
static void
|
|
|
|
|
ide_padstr8(uint8_t *buf, int buf_size, const char *src)
|
|
|
|
|
{
|
|
|
|
|
int i;
|
|
|
|
|
|
2016-12-29 20:40:24 +01:00
|
|
|
for (i = 0; i < buf_size; i++)
|
|
|
|
|
{
|
|
|
|
|
if (*src != '\0')
|
|
|
|
|
{
|
2016-06-26 00:34:39 +02:00
|
|
|
buf[i] = *src++;
|
2016-12-29 20:40:24 +01:00
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2016-06-26 00:34:39 +02:00
|
|
|
buf[i] = ' ';
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Fill in ide->buffer with the output of the "IDENTIFY DEVICE" command
|
|
|
|
|
*/
|
|
|
|
|
static void ide_identify(IDE *ide)
|
|
|
|
|
{
|
2016-12-23 03:16:24 +01:00
|
|
|
int c, h, s;
|
|
|
|
|
|
2016-06-26 00:34:39 +02:00
|
|
|
memset(ide->buffer, 0, 512);
|
|
|
|
|
|
|
|
|
|
//ide->buffer[1] = 101; /* Cylinders */
|
2016-12-23 03:16:24 +01:00
|
|
|
|
|
|
|
|
c = hdc[cur_ide[ide->board]].tracks; /* Cylinders */
|
|
|
|
|
h = hdc[cur_ide[ide->board]].hpc; /* Heads */
|
|
|
|
|
s = hdc[cur_ide[ide->board]].spt; /* Sectors */
|
2016-06-26 00:34:39 +02:00
|
|
|
|
|
|
|
|
ide->buffer[1] = hdc[cur_ide[ide->board]].tracks; /* Cylinders */
|
|
|
|
|
ide->buffer[3] = hdc[cur_ide[ide->board]].hpc; /* Heads */
|
|
|
|
|
ide->buffer[6] = hdc[cur_ide[ide->board]].spt; /* Sectors */
|
|
|
|
|
ide_padstr((char *) (ide->buffer + 10), "", 20); /* Serial Number */
|
2016-11-12 15:06:38 +01:00
|
|
|
ide_padstr((char *) (ide->buffer + 23), emulator_version, 8); /* Firmware */
|
2016-08-15 03:26:37 +02:00
|
|
|
ide_padstr((char *) (ide->buffer + 27), "86BoxHD", 40); /* Model */
|
2016-11-12 15:06:38 +01:00
|
|
|
ide->buffer[20] = 3; /*Buffer type*/
|
|
|
|
|
ide->buffer[21] = 512; /*Buffer size*/
|
|
|
|
|
ide->buffer[47] = 16; /*Max sectors on multiple transfer command*/
|
|
|
|
|
ide->buffer[48] = 1; /*Dword transfers supported*/
|
2016-12-29 20:40:24 +01:00
|
|
|
if (ide->board < 2)
|
|
|
|
|
{
|
|
|
|
|
ide->buffer[49] = (1 << 8); /* LBA and DMA supported */
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
ide->buffer[49] = 0;
|
|
|
|
|
}
|
2016-12-23 03:16:24 +01:00
|
|
|
if ((c > 1024) || (h > 16) || (s > 63))
|
|
|
|
|
{
|
|
|
|
|
ide->buffer[49] |= (1 << 9);
|
|
|
|
|
}
|
2016-06-26 00:34:39 +02:00
|
|
|
ide->buffer[50] = 0x4000; /* Capabilities */
|
|
|
|
|
ide->buffer[51] = 2 << 8; /*PIO timing mode*/
|
|
|
|
|
ide->buffer[52] = 2 << 8; /*DMA timing mode*/
|
|
|
|
|
ide->buffer[59] = ide->blocksize ? (ide->blocksize | 0x100) : 0;
|
|
|
|
|
ide->buffer[60] = (hdc[cur_ide[ide->board]].tracks * hdc[cur_ide[ide->board]].hpc * hdc[cur_ide[ide->board]].spt) & 0xFFFF; /* Total addressable sectors (LBA) */
|
|
|
|
|
ide->buffer[61] = (hdc[cur_ide[ide->board]].tracks * hdc[cur_ide[ide->board]].hpc * hdc[cur_ide[ide->board]].spt) >> 16;
|
2016-08-10 00:46:56 +02:00
|
|
|
// ide->buffer[63] = 7; /*Multiword DMA*/
|
2016-12-29 20:40:24 +01:00
|
|
|
if (ide->board < 2)
|
|
|
|
|
{
|
|
|
|
|
ide->buffer[62] = ide->dma_identify_data[0];
|
|
|
|
|
ide->buffer[63] = ide->dma_identify_data[1];
|
|
|
|
|
ide->buffer[80] = 0xe; /*ATA-1 to ATA-3 supported*/
|
|
|
|
|
ide->buffer[88] = ide->dma_identify_data[2];
|
|
|
|
|
}
|
2016-06-26 00:34:39 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Fill in ide->buffer with the output of the "IDENTIFY PACKET DEVICE" command
|
|
|
|
|
*/
|
|
|
|
|
static void ide_atapi_identify(IDE *ide)
|
|
|
|
|
{
|
|
|
|
|
memset(ide->buffer, 0, 512);
|
|
|
|
|
|
|
|
|
|
ide->buffer[0] = 0x8000 | (5<<8) | 0x80 | (2<<5); /* ATAPI device, CD-ROM drive, removable media, accelerated DRQ */
|
|
|
|
|
ide_padstr((char *) (ide->buffer + 10), "", 20); /* Serial Number */
|
2016-11-12 15:06:38 +01:00
|
|
|
ide_padstr((char *) (ide->buffer + 23), emulator_version, 8); /* Firmware */
|
2016-08-15 03:26:37 +02:00
|
|
|
ide_padstr((char *) (ide->buffer + 27), "86BoxCD", 40); /* Model */
|
2016-11-17 20:41:27 +01:00
|
|
|
ide->buffer[49] = 0x200; /* LBA supported */
|
|
|
|
|
ide->buffer[51] = 2 << 8; /*PIO timing mode*/
|
2016-06-26 00:34:39 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Return the sector offset for the current register values
|
|
|
|
|
*/
|
|
|
|
|
static off64_t ide_get_sector(IDE *ide)
|
|
|
|
|
{
|
|
|
|
|
if (ide->lba)
|
|
|
|
|
{
|
|
|
|
|
return (off64_t)ide->lba_addr + ide->skip512;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
int heads = ide->hpc;
|
|
|
|
|
int sectors = ide->spt;
|
|
|
|
|
|
|
|
|
|
return ((((off64_t) ide->cylinder * heads) + ide->head) *
|
|
|
|
|
sectors) + (ide->sector - 1) + ide->skip512;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Move to the next sector using CHS addressing
|
|
|
|
|
*/
|
|
|
|
|
static void ide_next_sector(IDE *ide)
|
|
|
|
|
{
|
|
|
|
|
if (ide->lba)
|
|
|
|
|
{
|
|
|
|
|
ide->lba_addr++;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
ide->sector++;
|
2016-12-29 20:40:24 +01:00
|
|
|
if (ide->sector == (ide->spt + 1))
|
|
|
|
|
{
|
2016-06-26 00:34:39 +02:00
|
|
|
ide->sector = 1;
|
|
|
|
|
ide->head++;
|
2016-12-29 20:40:24 +01:00
|
|
|
if (ide->head == ide->hpc)
|
|
|
|
|
{
|
2016-06-26 00:34:39 +02:00
|
|
|
ide->head = 0;
|
|
|
|
|
ide->cylinder++;
|
2016-12-29 20:40:24 +01:00
|
|
|
}
|
|
|
|
|
}
|
2016-06-26 00:34:39 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void loadhd(IDE *ide, int d, const char *fn)
|
|
|
|
|
{
|
2016-09-25 21:39:21 +02:00
|
|
|
uint32_t sector_size = 512;
|
|
|
|
|
uint32_t zero = 0;
|
|
|
|
|
uint32_t full_size = 0;
|
|
|
|
|
int c;
|
|
|
|
|
ide->base = 0;
|
|
|
|
|
ide->hdi = 0;
|
2016-12-29 20:40:24 +01:00
|
|
|
if (ide->hdfile == NULL)
|
|
|
|
|
{
|
2016-06-26 00:34:39 +02:00
|
|
|
/* Try to open existing hard disk image */
|
2016-09-29 21:54:34 +02:00
|
|
|
if (fn[0] == '.')
|
|
|
|
|
{
|
|
|
|
|
ide->type = IDE_NONE;
|
|
|
|
|
return;
|
|
|
|
|
}
|
2016-06-26 00:34:39 +02:00
|
|
|
ide->hdfile = fopen64(fn, "rb+");
|
2016-12-29 20:40:24 +01:00
|
|
|
if (ide->hdfile == NULL)
|
|
|
|
|
{
|
2016-06-26 00:34:39 +02:00
|
|
|
/* Failed to open existing hard disk image */
|
2016-12-29 20:40:24 +01:00
|
|
|
if (errno == ENOENT)
|
|
|
|
|
{
|
2016-06-26 00:34:39 +02:00
|
|
|
/* Failed because it does not exist,
|
|
|
|
|
so try to create new file */
|
|
|
|
|
ide->hdfile = fopen64(fn, "wb+");
|
2016-12-29 20:40:24 +01:00
|
|
|
if (ide->hdfile == NULL)
|
|
|
|
|
{
|
|
|
|
|
ide->type = IDE_NONE;
|
2016-06-26 00:34:39 +02:00
|
|
|
return;
|
|
|
|
|
}
|
2016-09-25 21:39:21 +02:00
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
if (image_is_hdi(fn))
|
|
|
|
|
{
|
|
|
|
|
full_size = hdc[d].spt * hdc[d].hpc * hdc[d].tracks * 512;
|
|
|
|
|
ide->base = 0x1000;
|
|
|
|
|
ide->hdi = 1;
|
|
|
|
|
fwrite(&zero, 1, 4, ide->hdfile);
|
|
|
|
|
fwrite(&zero, 1, 4, ide->hdfile);
|
|
|
|
|
fwrite(&(ide->base), 1, 4, ide->hdfile);
|
|
|
|
|
fwrite(&full_size, 1, 4, ide->hdfile);
|
|
|
|
|
fwrite(§or_size, 1, 4, ide->hdfile);
|
|
|
|
|
fwrite(&(hdc[d].spt), 1, 4, ide->hdfile);
|
|
|
|
|
fwrite(&(hdc[d].hpc), 1, 4, ide->hdfile);
|
|
|
|
|
fwrite(&(hdc[d].tracks), 1, 4, ide->hdfile);
|
|
|
|
|
for (c = 0; c < 0x3f8; c++)
|
|
|
|
|
{
|
|
|
|
|
fwrite(&zero, 1, 4, ide->hdfile);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
ide->hdc_num = d;
|
|
|
|
|
}
|
2016-12-29 20:40:24 +01:00
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2016-06-26 00:34:39 +02:00
|
|
|
/* Failed for another reason */
|
2016-12-29 20:40:24 +01:00
|
|
|
ide->type = IDE_NONE;
|
2016-06-26 00:34:39 +02:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
2016-09-29 21:54:34 +02:00
|
|
|
else
|
2016-09-25 21:39:21 +02:00
|
|
|
{
|
2016-09-29 21:54:34 +02:00
|
|
|
if (image_is_hdi(fn))
|
2016-09-25 21:39:21 +02:00
|
|
|
{
|
2016-09-29 21:54:34 +02:00
|
|
|
fseek(ide->hdfile, 0x8, SEEK_SET);
|
|
|
|
|
fread(&(ide->base), 1, 4, ide->hdfile);
|
|
|
|
|
fseek(ide->hdfile, 0x10, SEEK_SET);
|
|
|
|
|
fread(§or_size, 1, 4, ide->hdfile);
|
|
|
|
|
if (sector_size != 512)
|
|
|
|
|
{
|
|
|
|
|
/* Sector size is not 512 */
|
|
|
|
|
fclose(ide->hdfile);
|
|
|
|
|
ide->type = IDE_NONE;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
fread(&(hdc[d].spt), 1, 4, ide->hdfile);
|
|
|
|
|
fread(&(hdc[d].hpc), 1, 4, ide->hdfile);
|
|
|
|
|
fread(&(hdc[d].tracks), 1, 4, ide->hdfile);
|
|
|
|
|
ide->hdi = 1;
|
2016-09-25 21:39:21 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2016-09-29 21:54:34 +02:00
|
|
|
ide->spt = hdc[d].spt;
|
|
|
|
|
ide->hpc = hdc[d].hpc;
|
|
|
|
|
ide->tracks = hdc[d].tracks;
|
|
|
|
|
ide->type = IDE_HDD;
|
|
|
|
|
ide->hdc_num = d;
|
2016-06-26 00:34:39 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void ide_set_signature(IDE *ide)
|
|
|
|
|
{
|
|
|
|
|
ide->secount=1;
|
|
|
|
|
ide->sector=1;
|
|
|
|
|
ide->head=0;
|
|
|
|
|
ide->cylinder=(IDE_DRIVE_IS_CDROM(ide) ? 0xEB14 : ((ide->type == IDE_HDD) ? 0 : 0xFFFF));
|
2016-12-29 20:40:24 +01:00
|
|
|
if (ide->type == IDE_HDD)
|
|
|
|
|
{
|
|
|
|
|
ide->drive = 0;
|
|
|
|
|
}
|
2016-06-26 00:34:39 +02:00
|
|
|
}
|
|
|
|
|
|
2016-08-10 00:46:56 +02:00
|
|
|
int ide_set_features(IDE *ide)
|
|
|
|
|
{
|
|
|
|
|
uint8_t val = ide->secount & 7;
|
|
|
|
|
|
|
|
|
|
if (ide->type == IDE_NONE) return 0;
|
|
|
|
|
|
|
|
|
|
switch(ide->cylprecomp)
|
|
|
|
|
{
|
|
|
|
|
case 0x02:
|
|
|
|
|
case 0x82:
|
|
|
|
|
return 0;
|
|
|
|
|
case 0xcc:
|
|
|
|
|
case 0x66:
|
|
|
|
|
case 0xaa:
|
|
|
|
|
case 0x55:
|
|
|
|
|
case 0x05:
|
|
|
|
|
case 0x85:
|
|
|
|
|
case 0x69:
|
|
|
|
|
case 0x67:
|
|
|
|
|
case 0x96:
|
|
|
|
|
case 0x9a:
|
|
|
|
|
case 0x42:
|
|
|
|
|
case 0xc2:
|
|
|
|
|
return 1;
|
|
|
|
|
case 0x03:
|
2016-11-17 20:41:27 +01:00
|
|
|
if (ide->type == IDE_CDROM)
|
|
|
|
|
{
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
2016-08-10 00:46:56 +02:00
|
|
|
switch(ide->secount >> 3)
|
|
|
|
|
{
|
|
|
|
|
case 0:
|
|
|
|
|
case 1:
|
2016-08-10 01:04:08 +02:00
|
|
|
ide->dma_identify_data[0] = ide->dma_identify_data[1] = 7;
|
|
|
|
|
ide->dma_identify_data[2] = 0x3f;
|
2016-08-10 00:46:56 +02:00
|
|
|
break;
|
|
|
|
|
case 2:
|
2016-12-29 20:40:24 +01:00
|
|
|
if ((ide->type == IDE_CDROM) || (ide->board >= 2))
|
|
|
|
|
{
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
2016-08-10 01:04:08 +02:00
|
|
|
ide->dma_identify_data[0] = 7 | (1 << (val + 8));
|
|
|
|
|
ide->dma_identify_data[1] = 7;
|
|
|
|
|
ide->dma_identify_data[2] = 0x3f;
|
2016-08-10 00:46:56 +02:00
|
|
|
break;
|
|
|
|
|
case 4:
|
2016-12-29 20:40:24 +01:00
|
|
|
if ((ide->type == IDE_CDROM) || (ide->board >= 2))
|
|
|
|
|
{
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
2016-08-10 01:04:08 +02:00
|
|
|
ide->dma_identify_data[0] = 7;
|
|
|
|
|
ide->dma_identify_data[1] = 7 | (1 << (val + 8));
|
|
|
|
|
ide->dma_identify_data[2] = 0x3f;
|
2016-08-10 00:46:56 +02:00
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void ide_set_sector(IDE *ide, int64_t sector_num)
|
|
|
|
|
{
|
|
|
|
|
unsigned int cyl, r;
|
2016-08-10 06:15:52 +02:00
|
|
|
if (ide->lba)
|
2016-08-10 00:46:56 +02:00
|
|
|
{
|
2016-08-10 01:04:08 +02:00
|
|
|
ide->head = (sector_num >> 24);
|
2016-08-10 00:54:09 +02:00
|
|
|
ide->cylinder = (sector_num >> 8);
|
2016-08-10 00:46:56 +02:00
|
|
|
ide->sector = (sector_num);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
cyl = sector_num / (hdc[cur_ide[ide->board]].hpc * hdc[cur_ide[ide->board]].spt);
|
|
|
|
|
r = sector_num % (hdc[cur_ide[ide->board]].hpc * hdc[cur_ide[ide->board]].spt);
|
2016-08-10 00:54:09 +02:00
|
|
|
ide->cylinder = cyl;
|
2016-08-10 01:04:08 +02:00
|
|
|
ide->head = ((r / hdc[cur_ide[ide->board]].spt) & 0x0f);
|
2016-08-10 00:46:56 +02:00
|
|
|
ide->sector = (r % hdc[cur_ide[ide->board]].spt) + 1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2016-06-26 00:34:39 +02:00
|
|
|
void resetide(void)
|
|
|
|
|
{
|
2016-12-29 20:40:24 +01:00
|
|
|
int d;
|
|
|
|
|
|
|
|
|
|
/* Close hard disk image files (if previously open) */
|
|
|
|
|
for (d = 0; d < IDE_NUM; d++)
|
|
|
|
|
{
|
|
|
|
|
ide_drives[d].type = IDE_NONE;
|
|
|
|
|
if (ide_drives[d].hdfile != NULL)
|
|
|
|
|
{
|
|
|
|
|
fclose(ide_drives[d].hdfile);
|
|
|
|
|
ide_drives[d].hdfile = NULL;
|
|
|
|
|
}
|
|
|
|
|
ide_drives[d].atastat = READY_STAT | DSC_STAT;
|
|
|
|
|
ide_drives[d].service = 0;
|
|
|
|
|
ide_drives[d].board = d >> 1;
|
|
|
|
|
}
|
2016-06-26 00:34:39 +02:00
|
|
|
|
|
|
|
|
page_flags[GPMODE_CDROM_AUDIO_PAGE] &= 0xFD; /* Clear changed flag for CDROM AUDIO mode page. */
|
|
|
|
|
memset(mode_pages_in[GPMODE_CDROM_AUDIO_PAGE], 0, 256); /* Clear the page itself. */
|
|
|
|
|
|
2016-11-12 15:06:38 +01:00
|
|
|
idecallback[0]=idecallback[1]=0;
|
2016-12-28 23:34:00 +01:00
|
|
|
idecallback[2]=idecallback[3]=0;
|
2016-11-12 15:06:38 +01:00
|
|
|
|
2016-12-29 20:40:24 +01:00
|
|
|
for (d = 0; d < IDE_NUM; d++)
|
2016-06-26 00:34:39 +02:00
|
|
|
{
|
|
|
|
|
ide_drives[d].packetstatus = 0xFF;
|
|
|
|
|
|
2016-11-13 05:39:21 +01:00
|
|
|
if ((atapi_cdrom_channel == d) && cdrom_enabled && !scsi_cdrom_enabled)
|
2016-06-26 00:34:39 +02:00
|
|
|
{
|
2016-11-13 05:39:21 +01:00
|
|
|
ide_drives[d].type = IDE_CDROM;
|
2016-06-26 00:34:39 +02:00
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
loadhd(&ide_drives[d], d, ide_fn[d]);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ide_set_signature(&ide_drives[d]);
|
2016-08-10 01:04:08 +02:00
|
|
|
|
2016-09-15 14:32:26 +02:00
|
|
|
if (ide_drives[d].type != IDE_NONE)
|
2016-08-10 01:04:08 +02:00
|
|
|
{
|
2016-08-10 01:19:12 +02:00
|
|
|
ide_drives[d].dma_identify_data[0] = 7;
|
2016-08-10 01:21:03 +02:00
|
|
|
ide_drives[d].dma_identify_data[1] = 7 | (1 << 15);
|
2016-08-10 01:19:12 +02:00
|
|
|
ide_drives[d].dma_identify_data[2] = 0x3f;
|
2016-08-10 01:04:08 +02:00
|
|
|
}
|
2016-08-10 01:14:22 +02:00
|
|
|
|
2016-12-23 03:16:24 +01:00
|
|
|
ide_drives[d].error = 1;
|
|
|
|
|
}
|
2016-06-26 00:34:39 +02:00
|
|
|
|
2016-12-29 20:40:24 +01:00
|
|
|
for (d = 0; d < 4; d++)
|
|
|
|
|
{
|
|
|
|
|
cur_ide[d] = d << 1;
|
|
|
|
|
}
|
2016-06-26 00:34:39 +02:00
|
|
|
|
2016-12-29 20:40:24 +01:00
|
|
|
page_flags[GPMODE_CDROM_AUDIO_PAGE] &= ~PAGE_CHANGED;
|
2016-11-17 20:41:27 +01:00
|
|
|
|
2016-12-29 20:40:24 +01:00
|
|
|
SCSISense.UnitAttention = 0;
|
2016-06-26 00:34:39 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int idetimes=0;
|
|
|
|
|
void writeidew(int ide_board, uint16_t val)
|
|
|
|
|
{
|
2016-12-29 20:40:24 +01:00
|
|
|
IDE *ide = &ide_drives[cur_ide[ide_board]];
|
2017-01-04 20:37:31 +01:00
|
|
|
|
|
|
|
|
#if 0
|
|
|
|
|
if (ide->type == IDE_CDROM)
|
|
|
|
|
{
|
|
|
|
|
pclog("CD-ROM write data: %04X\n", val);
|
|
|
|
|
}
|
|
|
|
|
#endif
|
2016-06-26 00:34:39 +02:00
|
|
|
|
2016-12-29 20:40:24 +01:00
|
|
|
/* Some software issue excess writes after the 12 bytes required by the command, this will have all of them ignored. */
|
2016-06-26 00:34:39 +02:00
|
|
|
if (ide->packetstatus && (ide->packetstatus != ATAPI_STATUS_PACKET_REQ))
|
2016-12-29 20:40:24 +01:00
|
|
|
{
|
|
|
|
|
return;
|
|
|
|
|
}
|
2016-11-12 15:06:38 +01:00
|
|
|
|
2016-12-29 20:40:24 +01:00
|
|
|
// pclog("Write IDEw %04X\n",val);
|
|
|
|
|
ide->buffer[ide->pos >> 1] = val;
|
|
|
|
|
ide->pos+=2;
|
2016-06-26 00:34:39 +02:00
|
|
|
|
2016-12-29 20:40:24 +01:00
|
|
|
if (ide->packetstatus == ATAPI_STATUS_PACKET_REQ)
|
|
|
|
|
{
|
|
|
|
|
if ((ide->pos>=prefix_len+4) && (page_flags[page_current] & PAGE_CHANGEABLE))
|
|
|
|
|
{
|
|
|
|
|
mode_pages_in[page_current][ide->pos - prefix_len - 4] = ((uint8_t *) ide->buffer)[ide->pos - 2];
|
|
|
|
|
mode_pages_in[page_current][ide->pos - prefix_len - 3] = ((uint8_t *) ide->buffer)[ide->pos - 1];
|
|
|
|
|
}
|
|
|
|
|
if (ide->pos>=(ide->packlen+2))
|
|
|
|
|
{
|
|
|
|
|
ide->packetstatus = ATAPI_STATUS_PACKET_RECEIVED;
|
|
|
|
|
timer_process();
|
|
|
|
|
idecallback[ide_board]=6*IDE_TIME;
|
|
|
|
|
timer_update_outstanding();
|
|
|
|
|
// pclog("Packet over!\n");
|
|
|
|
|
ide_irq_lower(ide);
|
|
|
|
|
}
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
else if (ide->packetstatus == ATAPI_STATUS_PACKET_RECEIVED)
|
|
|
|
|
{
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
else if (ide->command == WIN_PACKETCMD && ide->pos>=0xC)
|
|
|
|
|
{
|
|
|
|
|
ide->pos=0;
|
|
|
|
|
ide->atastat = BUSY_STAT;
|
|
|
|
|
ide->packetstatus = ATAPI_STATUS_COMMAND;
|
2016-06-26 00:34:39 +02:00
|
|
|
timer_process();
|
2016-12-29 20:40:24 +01:00
|
|
|
callbackide(ide_board);
|
|
|
|
|
timer_update_outstanding();
|
|
|
|
|
}
|
|
|
|
|
else if (ide->pos>=512)
|
|
|
|
|
{
|
|
|
|
|
ide->pos=0;
|
|
|
|
|
ide->atastat = BUSY_STAT;
|
|
|
|
|
timer_process();
|
|
|
|
|
if (ide->command == WIN_WRITE_MULTIPLE)
|
|
|
|
|
{
|
|
|
|
|
callbackide(ide_board);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
idecallback[ide_board]=6*IDE_TIME;
|
|
|
|
|
}
|
|
|
|
|
timer_update_outstanding();
|
|
|
|
|
}
|
2016-06-26 00:34:39 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void writeidel(int ide_board, uint32_t val)
|
|
|
|
|
{
|
2016-12-29 20:40:24 +01:00
|
|
|
// pclog("WriteIDEl %08X\n", val);
|
|
|
|
|
writeidew(ide_board, val);
|
|
|
|
|
writeidew(ide_board, val >> 16);
|
2016-06-26 00:34:39 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void writeide(int ide_board, uint16_t addr, uint8_t val)
|
|
|
|
|
{
|
2016-12-29 20:40:24 +01:00
|
|
|
IDE *ide = &ide_drives[cur_ide[ide_board]];
|
|
|
|
|
IDE *ide_other = &ide_drives[cur_ide[ide_board] ^ 1];
|
|
|
|
|
|
|
|
|
|
// pclog("WriteIDE %04X %02X from %04X(%08X):%08X %i\n", addr, val, CS, cs, cpu_state.pc, ins);
|
|
|
|
|
addr|=0x90;
|
|
|
|
|
addr&=0xFFF7;
|
|
|
|
|
|
|
|
|
|
if (ide->type == IDE_NONE && (addr == 0x1f0 || addr == 0x1f7)) return;
|
2016-06-26 00:34:39 +02:00
|
|
|
|
2016-12-29 20:40:24 +01:00
|
|
|
switch (addr)
|
|
|
|
|
{
|
2016-06-26 00:34:39 +02:00
|
|
|
case 0x1F0: /* Data */
|
2016-12-29 20:40:24 +01:00
|
|
|
writeidew(ide_board, val | (val << 8));
|
|
|
|
|
return;
|
2016-06-26 00:34:39 +02:00
|
|
|
|
|
|
|
|
case 0x1F1: /* Features */
|
2016-12-29 20:40:24 +01:00
|
|
|
ide->cylprecomp = val;
|
|
|
|
|
ide_other->cylprecomp = val;
|
|
|
|
|
return;
|
2016-06-26 00:34:39 +02:00
|
|
|
|
|
|
|
|
case 0x1F2: /* Sector count */
|
2016-12-29 20:40:24 +01:00
|
|
|
ide->secount = val;
|
|
|
|
|
ide_other->secount = val;
|
|
|
|
|
return;
|
2016-06-26 00:34:39 +02:00
|
|
|
|
|
|
|
|
case 0x1F3: /* Sector */
|
2016-12-29 20:40:24 +01:00
|
|
|
ide->sector = val;
|
|
|
|
|
ide->lba_addr = (ide->lba_addr & 0xFFFFF00) | val;
|
|
|
|
|
ide_other->sector = val;
|
|
|
|
|
ide_other->lba_addr = (ide_other->lba_addr & 0xFFFFF00) | val;
|
|
|
|
|
return;
|
2016-06-26 00:34:39 +02:00
|
|
|
|
|
|
|
|
case 0x1F4: /* Cylinder low */
|
2016-12-29 20:40:24 +01:00
|
|
|
ide->cylinder = (ide->cylinder & 0xFF00) | val;
|
|
|
|
|
ide->lba_addr = (ide->lba_addr & 0xFFF00FF) | (val << 8);
|
|
|
|
|
ide_other->cylinder = (ide_other->cylinder&0xFF00) | val;
|
|
|
|
|
ide_other->lba_addr = (ide_other->lba_addr&0xFFF00FF) | (val << 8);
|
|
|
|
|
return;
|
2016-06-26 00:34:39 +02:00
|
|
|
|
|
|
|
|
case 0x1F5: /* Cylinder high */
|
2016-12-29 20:40:24 +01:00
|
|
|
ide->cylinder = (ide->cylinder & 0xFF) | (val << 8);
|
|
|
|
|
ide->lba_addr = (ide->lba_addr & 0xF00FFFF) | (val << 16);
|
|
|
|
|
ide_other->cylinder = (ide_other->cylinder & 0xFF) | (val << 8);
|
|
|
|
|
ide_other->lba_addr = (ide_other->lba_addr & 0xF00FFFF) | (val << 16);
|
|
|
|
|
return;
|
2016-06-26 00:34:39 +02:00
|
|
|
|
|
|
|
|
case 0x1F6: /* Drive/Head */
|
2016-12-29 20:40:24 +01:00
|
|
|
if (cur_ide[ide_board] != ((val>>4)&1)+(ide_board<<1))
|
|
|
|
|
{
|
|
|
|
|
cur_ide[ide_board]=((val>>4)&1)+(ide_board<<1);
|
|
|
|
|
|
|
|
|
|
if (ide->reset || ide_other->reset)
|
|
|
|
|
{
|
|
|
|
|
ide->atastat = ide_other->atastat = READY_STAT | DSC_STAT;
|
|
|
|
|
ide->error = ide_other->error = 1;
|
|
|
|
|
ide->secount = ide_other->secount = 1;
|
|
|
|
|
ide->sector = ide_other->sector = 1;
|
|
|
|
|
ide->head = ide_other->head = 0;
|
|
|
|
|
ide->cylinder = ide_other->cylinder = 0;
|
|
|
|
|
ide->reset = ide_other->reset = 0;
|
|
|
|
|
|
|
|
|
|
if (IDE_DRIVE_IS_CDROM(ide))
|
|
|
|
|
{
|
|
|
|
|
ide->cylinder=0xEB14;
|
|
|
|
|
}
|
|
|
|
|
if (IDE_DRIVE_IS_CDROM(ide_other))
|
|
|
|
|
{
|
|
|
|
|
ide_other->cylinder=0xEB14;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
idecallback[ide_board] = 0;
|
|
|
|
|
timer_update_outstanding();
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ide = &ide_drives[cur_ide[ide_board]];
|
|
|
|
|
}
|
2016-06-26 00:34:39 +02:00
|
|
|
|
2016-12-29 20:40:24 +01:00
|
|
|
ide->head = val & 0xF;
|
|
|
|
|
ide->lba = val & 0x40;
|
|
|
|
|
ide_other->head = val & 0xF;
|
|
|
|
|
ide_other->lba = val & 0x40;
|
2016-06-26 00:34:39 +02:00
|
|
|
|
2016-12-29 20:40:24 +01:00
|
|
|
ide->lba_addr = (ide->lba_addr & 0x0FFFFFF) | ((val & 0xF) << 24);
|
|
|
|
|
ide_other->lba_addr = (ide_other->lba_addr & 0x0FFFFFF)|((val & 0xF) << 24);
|
2016-08-10 06:15:52 +02:00
|
|
|
|
2016-12-29 20:40:24 +01:00
|
|
|
ide_irq_update(ide);
|
|
|
|
|
return;
|
2016-06-26 00:34:39 +02:00
|
|
|
|
|
|
|
|
case 0x1F7: /* Command register */
|
2016-12-29 20:40:24 +01:00
|
|
|
if (ide->type == IDE_NONE)
|
|
|
|
|
{
|
|
|
|
|
ide->error=1;
|
|
|
|
|
return;
|
|
|
|
|
}
|
2017-01-04 20:37:31 +01:00
|
|
|
#if 0
|
|
|
|
|
if (ide->type == IDE_CDROM)
|
|
|
|
|
{
|
|
|
|
|
pclog("Write CD-ROM ATA command: %02X\n", val);
|
|
|
|
|
}
|
|
|
|
|
#endif
|
2016-12-29 20:40:24 +01:00
|
|
|
ide_irq_lower(ide);
|
|
|
|
|
ide->command=val;
|
2016-06-26 00:34:39 +02:00
|
|
|
|
2016-12-29 20:40:24 +01:00
|
|
|
// pclog("New IDE command - %02X %i %i\n",ide->command,cur_ide[ide_board],ide_board);
|
|
|
|
|
ide->error=0;
|
|
|
|
|
switch (val)
|
|
|
|
|
{
|
2016-06-26 00:34:39 +02:00
|
|
|
case WIN_SRST: /* ATAPI Device Reset */
|
2016-12-29 20:40:24 +01:00
|
|
|
if (IDE_DRIVE_IS_CDROM(ide))
|
|
|
|
|
{
|
|
|
|
|
ide->atastat = BUSY_STAT;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
ide->atastat = READY_STAT;
|
|
|
|
|
}
|
2016-06-26 00:34:39 +02:00
|
|
|
timer_process();
|
|
|
|
|
idecallback[ide_board]=100*IDE_TIME;
|
|
|
|
|
timer_update_outstanding();
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
case WIN_RESTORE:
|
|
|
|
|
case WIN_SEEK:
|
|
|
|
|
ide->atastat = READY_STAT;
|
|
|
|
|
timer_process();
|
|
|
|
|
idecallback[ide_board]=100*IDE_TIME;
|
|
|
|
|
timer_update_outstanding();
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
case WIN_READ_MULTIPLE:
|
2016-12-29 20:40:24 +01:00
|
|
|
/* Fatal removed in accordance with the official ATAPI reference:
|
|
|
|
|
If the Read Multiple command is attempted before the Set Multiple Mode
|
|
|
|
|
command has been executed or when Read Multiple commands are
|
|
|
|
|
disabled, the Read Multiple operation is rejected with an Aborted Com-
|
|
|
|
|
mand error. */
|
|
|
|
|
ide->blockcount = 0;
|
2016-06-26 00:34:39 +02:00
|
|
|
|
|
|
|
|
case WIN_READ:
|
|
|
|
|
case WIN_READ_NORETRY:
|
|
|
|
|
case WIN_READ_DMA:
|
2016-12-29 20:40:24 +01:00
|
|
|
ide->atastat = BUSY_STAT;
|
|
|
|
|
timer_process();
|
|
|
|
|
idecallback[ide_board]=200*IDE_TIME;
|
|
|
|
|
timer_update_outstanding();
|
|
|
|
|
return;
|
2016-06-26 00:34:39 +02:00
|
|
|
|
|
|
|
|
case WIN_WRITE_MULTIPLE:
|
2016-12-29 20:40:24 +01:00
|
|
|
if (!ide->blocksize && (ide->type != IDE_CDROM))
|
|
|
|
|
{
|
|
|
|
|
fatal("Write_MULTIPLE - blocksize = 0\n");
|
|
|
|
|
}
|
|
|
|
|
ide->blockcount = 0;
|
2016-06-26 00:34:39 +02:00
|
|
|
|
|
|
|
|
case WIN_WRITE:
|
|
|
|
|
case WIN_WRITE_NORETRY:
|
2016-12-29 20:40:24 +01:00
|
|
|
ide->atastat = DRQ_STAT | DSC_STAT | READY_STAT;
|
|
|
|
|
ide->pos=0;
|
|
|
|
|
return;
|
2016-06-26 00:34:39 +02:00
|
|
|
|
|
|
|
|
case WIN_WRITE_DMA:
|
2016-12-29 20:40:24 +01:00
|
|
|
ide->atastat = BUSY_STAT;
|
|
|
|
|
timer_process();
|
|
|
|
|
idecallback[ide_board]=200*IDE_TIME;
|
|
|
|
|
timer_update_outstanding();
|
|
|
|
|
return;
|
2016-06-26 00:34:39 +02:00
|
|
|
|
|
|
|
|
case WIN_VERIFY:
|
|
|
|
|
case WIN_VERIFY_ONCE:
|
2016-12-29 20:40:24 +01:00
|
|
|
ide->atastat = BUSY_STAT;
|
|
|
|
|
timer_process();
|
|
|
|
|
idecallback[ide_board]=200*IDE_TIME;
|
|
|
|
|
timer_update_outstanding();
|
|
|
|
|
return;
|
2016-06-26 00:34:39 +02:00
|
|
|
|
|
|
|
|
case WIN_FORMAT:
|
2016-12-29 20:40:24 +01:00
|
|
|
ide->atastat = DRQ_STAT;
|
|
|
|
|
ide->pos=0;
|
|
|
|
|
return;
|
2016-06-26 00:34:39 +02:00
|
|
|
|
|
|
|
|
case WIN_SPECIFY: /* Initialize Drive Parameters */
|
2016-12-29 20:40:24 +01:00
|
|
|
ide->atastat = BUSY_STAT;
|
|
|
|
|
timer_process();
|
|
|
|
|
idecallback[ide_board]=30*IDE_TIME;
|
|
|
|
|
timer_update_outstanding();
|
|
|
|
|
return;
|
2016-06-26 00:34:39 +02:00
|
|
|
|
|
|
|
|
case WIN_DRIVE_DIAGNOSTICS: /* Execute Drive Diagnostics */
|
|
|
|
|
case WIN_PIDENTIFY: /* Identify Packet Device */
|
|
|
|
|
case WIN_SET_MULTIPLE_MODE: /*Set Multiple Mode*/
|
2016-08-10 01:14:22 +02:00
|
|
|
case WIN_NOP:
|
2016-08-10 00:46:56 +02:00
|
|
|
case WIN_STANDBYNOW1:
|
2016-06-26 00:34:39 +02:00
|
|
|
case WIN_SETIDLE1: /* Idle */
|
2016-08-10 00:46:56 +02:00
|
|
|
case WIN_CHECKPOWERMODE1:
|
2016-12-29 20:40:24 +01:00
|
|
|
ide->atastat = BUSY_STAT;
|
|
|
|
|
timer_process();
|
|
|
|
|
idecallback[ide_board]=30*IDE_TIME;
|
|
|
|
|
timer_update_outstanding();
|
|
|
|
|
return;
|
2016-06-26 00:34:39 +02:00
|
|
|
|
|
|
|
|
case WIN_IDENTIFY: /* Identify Device */
|
2016-08-10 00:46:56 +02:00
|
|
|
case WIN_SET_FEATURES:
|
2016-08-10 01:36:17 +02:00
|
|
|
case WIN_READ_NATIVE_MAX:
|
2016-12-29 20:40:24 +01:00
|
|
|
ide->atastat = BUSY_STAT;
|
|
|
|
|
timer_process();
|
|
|
|
|
idecallback[ide_board]=200*IDE_TIME;
|
|
|
|
|
timer_update_outstanding();
|
|
|
|
|
return;
|
2016-06-26 00:34:39 +02:00
|
|
|
|
|
|
|
|
case WIN_PACKETCMD: /* ATAPI Packet */
|
2017-01-04 20:37:31 +01:00
|
|
|
#if 0
|
2016-12-29 20:40:24 +01:00
|
|
|
ide->packetstatus = ATAPI_STATUS_IDLE;
|
|
|
|
|
ide->atastat = BUSY_STAT;
|
|
|
|
|
timer_process();
|
2017-01-04 20:37:31 +01:00
|
|
|
// idecallback[ide_board]=1;//30*IDE_TIME;
|
|
|
|
|
idecallback[ide_board]=30*IDE_TIME;
|
2016-12-29 20:40:24 +01:00
|
|
|
timer_update_outstanding();
|
|
|
|
|
ide->pos=0;
|
2017-01-04 20:37:31 +01:00
|
|
|
#endif
|
|
|
|
|
/* Skip the command callbackwait, and process immediately. */
|
|
|
|
|
ide->packetstatus = ATAPI_STATUS_IDLE;
|
|
|
|
|
readcdmode=0;
|
|
|
|
|
ide->pos=0;
|
|
|
|
|
ide->secount = 1;
|
|
|
|
|
ide->atastat = READY_STAT | DRQ_STAT |(ide->atastat&ERR_STAT);
|
2016-12-29 20:40:24 +01:00
|
|
|
return;
|
2016-06-26 00:34:39 +02:00
|
|
|
|
|
|
|
|
case 0xF0:
|
2016-12-29 20:40:24 +01:00
|
|
|
default:
|
2016-06-26 00:34:39 +02:00
|
|
|
ide->atastat = READY_STAT | ERR_STAT | DSC_STAT;
|
|
|
|
|
ide->error = ABRT_ERR;
|
2016-12-29 20:40:24 +01:00
|
|
|
ide_irq_raise(ide);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
return;
|
2016-06-26 00:34:39 +02:00
|
|
|
|
|
|
|
|
case 0x3F6: /* Device control */
|
2016-12-29 20:40:24 +01:00
|
|
|
if ((ide->fdisk & 4) && !(val&4) && (ide->type != IDE_NONE || ide_other->type != IDE_NONE))
|
|
|
|
|
{
|
|
|
|
|
timer_process();
|
|
|
|
|
idecallback[ide_board]=500*IDE_TIME;
|
|
|
|
|
timer_update_outstanding();
|
|
|
|
|
|
|
|
|
|
if (ide->type != IDE_NONE)
|
|
|
|
|
{
|
|
|
|
|
ide->reset = 1;
|
|
|
|
|
}
|
|
|
|
|
if (ide_other->type != IDE_NONE)
|
|
|
|
|
{
|
|
|
|
|
ide->reset = 1;
|
|
|
|
|
}
|
|
|
|
|
ide->atastat = ide_other->atastat = BUSY_STAT;
|
|
|
|
|
// pclog("IDE Reset %i\n", ide_board);
|
|
|
|
|
}
|
|
|
|
|
ide->fdisk = ide_other->fdisk = val;
|
|
|
|
|
ide_irq_update(ide);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
// fatal("Bad IDE write %04X %02X\n", addr, val);
|
2016-06-26 00:34:39 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
uint8_t readide(int ide_board, uint16_t addr)
|
|
|
|
|
{
|
2016-12-29 20:40:24 +01:00
|
|
|
IDE *ide = &ide_drives[cur_ide[ide_board]];
|
|
|
|
|
uint8_t temp;
|
|
|
|
|
uint16_t tempw;
|
2016-06-26 00:34:39 +02:00
|
|
|
|
2016-12-29 20:40:24 +01:00
|
|
|
addr|=0x90;
|
|
|
|
|
addr&=0xFFF7;
|
2016-11-12 15:06:38 +01:00
|
|
|
|
2016-12-29 20:40:24 +01:00
|
|
|
if (ide->type == IDE_NONE && (addr == 0x1f0 || addr == 0x1f7))
|
|
|
|
|
{
|
|
|
|
|
if (addr == 0x1f7)
|
2016-12-23 03:16:24 +01:00
|
|
|
{
|
2016-12-29 20:40:24 +01:00
|
|
|
/* This is apparently required for an empty ID channel. */
|
|
|
|
|
return 0x20;
|
2016-12-23 03:16:24 +01:00
|
|
|
}
|
2016-12-29 20:40:24 +01:00
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
switch (addr)
|
|
|
|
|
{
|
|
|
|
|
case 0x1F0: /* Data */
|
|
|
|
|
tempw = readidew(ide_board);
|
|
|
|
|
temp = tempw & 0xff;
|
|
|
|
|
break;
|
2016-06-26 00:34:39 +02:00
|
|
|
|
2016-12-29 20:40:24 +01:00
|
|
|
case 0x1F1: /* Error */
|
|
|
|
|
if (ide->type == IDE_NONE)
|
|
|
|
|
{
|
|
|
|
|
temp = 1;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
temp = ide->error;
|
|
|
|
|
}
|
|
|
|
|
break;
|
2016-06-26 00:34:39 +02:00
|
|
|
|
2016-12-29 20:40:24 +01:00
|
|
|
case 0x1F2: /* Sector count */
|
|
|
|
|
if (ide->type == IDE_NONE)
|
|
|
|
|
{
|
|
|
|
|
temp = 1;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
temp = (uint8_t)ide->secount;
|
|
|
|
|
}
|
|
|
|
|
break;
|
2016-06-26 00:34:39 +02:00
|
|
|
|
2016-12-29 20:40:24 +01:00
|
|
|
case 0x1F3: /* Sector */
|
|
|
|
|
if (ide->type == IDE_NONE)
|
|
|
|
|
{
|
|
|
|
|
temp = 1;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
temp = (uint8_t)ide->sector;
|
|
|
|
|
}
|
|
|
|
|
break;
|
2016-06-26 00:34:39 +02:00
|
|
|
|
2016-12-29 20:40:24 +01:00
|
|
|
case 0x1F4: /* Cylinder low */
|
|
|
|
|
if (ide->type == IDE_NONE)
|
|
|
|
|
{
|
|
|
|
|
temp = 0xFF;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
temp = (uint8_t)(ide->cylinder&0xFF);
|
|
|
|
|
}
|
|
|
|
|
break;
|
2016-06-26 00:34:39 +02:00
|
|
|
|
2016-12-29 20:40:24 +01:00
|
|
|
case 0x1F5: /* Cylinder high */
|
|
|
|
|
if (ide->type == IDE_NONE)
|
|
|
|
|
{
|
|
|
|
|
temp = 0xFF;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
temp = (uint8_t)(ide->cylinder>>8);
|
|
|
|
|
}
|
|
|
|
|
break;
|
2016-06-26 00:34:39 +02:00
|
|
|
|
2016-12-29 20:40:24 +01:00
|
|
|
case 0x1F6: /* Drive/Head */
|
|
|
|
|
if (ide->type == IDE_NONE)
|
|
|
|
|
{
|
|
|
|
|
temp = (uint8_t)(((cur_ide[ide_board] & 1) ? 0x10 : 0) | 0xa0);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
temp = (uint8_t)(ide->head | ((cur_ide[ide_board] & 1) ? 0x10 : 0) | (ide->lba ? 0x40 : 0) | 0xa0);
|
|
|
|
|
}
|
|
|
|
|
break;
|
2016-06-26 00:34:39 +02:00
|
|
|
|
2016-12-29 20:40:24 +01:00
|
|
|
case 0x1F7: /* Status */
|
|
|
|
|
ide_irq_lower(ide);
|
|
|
|
|
if (ide->type == IDE_CDROM)
|
|
|
|
|
{
|
|
|
|
|
temp = (ide->atastat & ~DSC_STAT) | (ide->service ? SERVICE_STAT : 0);
|
2017-01-04 20:37:31 +01:00
|
|
|
// pclog("Read CD-ROM status: %02X\n", temp);
|
2016-12-29 20:40:24 +01:00
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
temp = ide->atastat;
|
|
|
|
|
}
|
|
|
|
|
break;
|
2016-06-26 00:34:39 +02:00
|
|
|
|
2016-12-29 20:40:24 +01:00
|
|
|
case 0x3F6: /* Alternate Status */
|
|
|
|
|
if (ide->type == IDE_NONE)
|
|
|
|
|
{
|
|
|
|
|
temp = DSC_STAT;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
if (ide->type == IDE_CDROM)
|
|
|
|
|
{
|
|
|
|
|
temp = (ide->atastat & ~DSC_STAT) | (ide->service ? SERVICE_STAT : 0);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
temp = ide->atastat;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
// /* if (ide_board) */ pclog("Read IDEb %04X %02X %02X %02X %i %04X:%04X %i\n", addr, temp, ide->atastat,(ide->atastat & ~DSC_STAT) | (ide->service ? SERVICE_STAT : 0),cur_ide[ide_board],CS,cpu_state.pc,ide_board);
|
|
|
|
|
return temp;
|
|
|
|
|
// fatal("Bad IDE read %04X\n", addr);
|
2016-06-26 00:34:39 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
uint16_t readidew(int ide_board)
|
|
|
|
|
{
|
2016-12-29 20:40:24 +01:00
|
|
|
IDE *ide = &ide_drives[cur_ide[ide_board]];
|
|
|
|
|
uint16_t temp;
|
2016-06-26 00:34:39 +02:00
|
|
|
|
2016-12-29 20:40:24 +01:00
|
|
|
temp = ide->buffer[ide->pos >> 1];
|
2016-11-12 15:06:38 +01:00
|
|
|
|
2016-12-29 20:40:24 +01:00
|
|
|
ide->pos+=2;
|
2016-06-26 00:34:39 +02:00
|
|
|
if ((ide->command == WIN_PACKETCMD) && ((ide->packetstatus == ATAPI_STATUS_REQ_SENSE) || (ide->packetstatus==8)))
|
|
|
|
|
{
|
|
|
|
|
callnonreadcd(ide);
|
|
|
|
|
return temp;
|
|
|
|
|
}
|
2016-12-29 20:40:24 +01:00
|
|
|
if ((ide->pos>=512 && ide->command != WIN_PACKETCMD) || (ide->command == WIN_PACKETCMD && ide->pos>=ide->packlen))
|
|
|
|
|
{
|
|
|
|
|
ide->pos=0;
|
|
|
|
|
if (ide->command == WIN_PACKETCMD)// && ide.packetstatus==6)
|
|
|
|
|
{
|
|
|
|
|
callreadcd(ide);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
ide->atastat = READY_STAT | DSC_STAT;
|
|
|
|
|
ide->packetstatus = ATAPI_STATUS_IDLE;
|
|
|
|
|
if (ide->command == WIN_READ || ide->command == WIN_READ_NORETRY || ide->command == WIN_READ_MULTIPLE)
|
|
|
|
|
{
|
|
|
|
|
ide->secount = (ide->secount - 1) & 0xff;
|
|
|
|
|
if (ide->secount)
|
|
|
|
|
{
|
|
|
|
|
ide_next_sector(ide);
|
|
|
|
|
ide->atastat = BUSY_STAT;
|
|
|
|
|
timer_process();
|
|
|
|
|
if (ide->command == WIN_READ_MULTIPLE)
|
|
|
|
|
{
|
|
|
|
|
callbackide(ide_board);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
idecallback[ide_board]=6*IDE_TIME;
|
|
|
|
|
}
|
|
|
|
|
timer_update_outstanding();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// pclog("Read IDEw %04X\n",temp);
|
|
|
|
|
return temp;
|
2016-06-26 00:34:39 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
uint32_t readidel(int ide_board)
|
|
|
|
|
{
|
2016-12-29 20:40:24 +01:00
|
|
|
uint16_t temp;
|
|
|
|
|
// pclog("Read IDEl %i\n", ide_board);
|
|
|
|
|
temp = readidew(ide_board);
|
|
|
|
|
return temp | (readidew(ide_board) << 16);
|
2016-06-26 00:34:39 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int times30=0;
|
|
|
|
|
void callbackide(int ide_board)
|
|
|
|
|
{
|
2016-12-29 20:40:24 +01:00
|
|
|
IDE *ide = &ide_drives[cur_ide[ide_board]];
|
|
|
|
|
IDE *ide_other = &ide_drives[cur_ide[ide_board] ^ 1];
|
|
|
|
|
off64_t addr;
|
|
|
|
|
uint64_t faddr;
|
|
|
|
|
int c;
|
|
|
|
|
ext_ide = ide;
|
|
|
|
|
int64_t snum;
|
|
|
|
|
|
|
|
|
|
if (ide->command==0x30) times30++;
|
|
|
|
|
// /*if (ide_board) */pclog("CALLBACK %02X %i %i %i\n",ide->command,times30,ide->reset,cur_ide[ide_board]);
|
|
|
|
|
|
|
|
|
|
if (ide->reset)
|
|
|
|
|
{
|
|
|
|
|
ide->atastat = ide_other->atastat = READY_STAT | DSC_STAT;
|
|
|
|
|
ide->error = ide_other->error = 1;
|
|
|
|
|
ide->secount = ide_other->secount = 1;
|
|
|
|
|
ide->sector = ide_other->sector = 1;
|
|
|
|
|
ide->head = ide_other->head = 0;
|
|
|
|
|
ide->cylinder = ide_other->cylinder = 0;
|
|
|
|
|
ide->reset = ide_other->reset = 0;
|
|
|
|
|
|
2016-06-26 00:34:39 +02:00
|
|
|
if (IDE_DRIVE_IS_CDROM(ide))
|
2016-12-29 20:40:24 +01:00
|
|
|
{
|
|
|
|
|
ide->cylinder=0xEB14;
|
|
|
|
|
cdrom->stop();
|
|
|
|
|
}
|
|
|
|
|
if (ide->type == IDE_NONE)
|
|
|
|
|
{
|
|
|
|
|
ide->cylinder=0xFFFF;
|
|
|
|
|
cdrom->stop();
|
|
|
|
|
}
|
|
|
|
|
if (IDE_DRIVE_IS_CDROM(ide_other))
|
|
|
|
|
{
|
|
|
|
|
ide_other->cylinder=0xEB14;
|
|
|
|
|
cdrom->stop();
|
|
|
|
|
}
|
|
|
|
|
if (ide_other->type == IDE_NONE)
|
|
|
|
|
{
|
|
|
|
|
ide_other->cylinder=0xFFFF;
|
|
|
|
|
cdrom->stop();
|
|
|
|
|
}
|
|
|
|
|
// pclog("Reset callback\n");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
switch (ide->command)
|
|
|
|
|
{
|
|
|
|
|
/* Initialize the Task File Registers as follows: Status = 00h, Error = 01h, Sector Count = 01h, Sector Number = 01h,
|
|
|
|
|
Cylinder Low = 14h, Cylinder High =EBh and Drive/Head = 00h. */
|
|
|
|
|
case WIN_SRST: /*ATAPI Device Reset */
|
|
|
|
|
ide->atastat = READY_STAT | DSC_STAT;
|
|
|
|
|
ide->error=1; /*Device passed*/
|
|
|
|
|
ide->secount = ide->sector = 1;
|
|
|
|
|
ide_set_signature(ide);
|
|
|
|
|
|
|
|
|
|
if (IDE_DRIVE_IS_CDROM(ide))
|
|
|
|
|
{
|
|
|
|
|
ide->atastat = 0;
|
|
|
|
|
}
|
|
|
|
|
ide_irq_raise(ide);
|
|
|
|
|
if (IDE_DRIVE_IS_CDROM(ide))
|
|
|
|
|
{
|
|
|
|
|
ide->service = 0;
|
|
|
|
|
}
|
|
|
|
|
return;
|
2016-06-26 00:34:39 +02:00
|
|
|
|
|
|
|
|
case WIN_RESTORE:
|
|
|
|
|
case WIN_SEEK:
|
2016-12-29 20:40:24 +01:00
|
|
|
if (IDE_DRIVE_IS_CDROM(ide))
|
|
|
|
|
{
|
|
|
|
|
goto abort_cmd;
|
|
|
|
|
}
|
2016-08-10 01:14:22 +02:00
|
|
|
case WIN_NOP:
|
2016-08-10 00:46:56 +02:00
|
|
|
case WIN_STANDBYNOW1:
|
|
|
|
|
case WIN_SETIDLE1:
|
2016-12-29 20:40:24 +01:00
|
|
|
ide->atastat = READY_STAT | DSC_STAT;
|
|
|
|
|
ide_irq_raise(ide);
|
|
|
|
|
return;
|
2016-06-26 00:34:39 +02:00
|
|
|
|
2016-08-10 00:46:56 +02:00
|
|
|
case WIN_CHECKPOWERMODE1:
|
2016-12-29 20:40:24 +01:00
|
|
|
if (IDE_DRIVE_IS_CDROM(ide))
|
|
|
|
|
{
|
|
|
|
|
goto abort_cmd;
|
|
|
|
|
}
|
|
|
|
|
ide->secount = 0xFF;
|
|
|
|
|
ide->atastat = READY_STAT | DSC_STAT;
|
|
|
|
|
ide_irq_raise(ide);
|
|
|
|
|
return;
|
2016-08-10 00:46:56 +02:00
|
|
|
|
2016-06-26 00:34:39 +02:00
|
|
|
case WIN_READ:
|
|
|
|
|
case WIN_READ_NORETRY:
|
2016-12-29 20:40:24 +01:00
|
|
|
if (IDE_DRIVE_IS_CDROM(ide))
|
|
|
|
|
{
|
|
|
|
|
ide_set_signature(ide);
|
|
|
|
|
goto abort_cmd;
|
|
|
|
|
}
|
|
|
|
|
addr = ide_get_sector(ide) * 512;
|
|
|
|
|
|
|
|
|
|
fseeko64(ide->hdfile, ide->base + addr, SEEK_SET);
|
|
|
|
|
fread(ide->buffer, 512, 1, ide->hdfile);
|
|
|
|
|
ide->pos=0;
|
|
|
|
|
ide->atastat = DRQ_STAT | READY_STAT | DSC_STAT;
|
|
|
|
|
|
|
|
|
|
ide_irq_raise(ide);
|
|
|
|
|
|
|
|
|
|
readflash=1;
|
|
|
|
|
return;
|
2016-06-26 00:34:39 +02:00
|
|
|
|
|
|
|
|
case WIN_READ_DMA:
|
2016-12-29 20:40:24 +01:00
|
|
|
if (IDE_DRIVE_IS_CDROM(ide) || (ide->board >= 2))
|
|
|
|
|
{
|
|
|
|
|
goto abort_cmd;
|
|
|
|
|
}
|
|
|
|
|
addr = ide_get_sector(ide) * 512;
|
|
|
|
|
fseeko64(ide->hdfile, addr, SEEK_SET);
|
|
|
|
|
fread(ide->buffer, 512, 1, ide->hdfile);
|
|
|
|
|
ide->pos=0;
|
2016-06-26 00:34:39 +02:00
|
|
|
|
2016-12-29 20:40:24 +01:00
|
|
|
if (ide_bus_master_read_sector)
|
|
|
|
|
{
|
|
|
|
|
if (ide_bus_master_read_sector(ide_board, (uint8_t *)ide->buffer))
|
|
|
|
|
{
|
|
|
|
|
idecallback[ide_board]=6*IDE_TIME; /*DMA not performed, try again later*/
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
/*DMA successful*/
|
|
|
|
|
ide->atastat = DRQ_STAT | READY_STAT | DSC_STAT;
|
|
|
|
|
|
|
|
|
|
ide->secount = (ide->secount - 1) & 0xff;
|
|
|
|
|
if (ide->secount)
|
|
|
|
|
{
|
|
|
|
|
ide_next_sector(ide);
|
|
|
|
|
ide->atastat = BUSY_STAT;
|
|
|
|
|
idecallback[ide_board]=6*IDE_TIME;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
ide_irq_raise(ide);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
readflash=1;
|
|
|
|
|
return;
|
2016-06-26 00:34:39 +02:00
|
|
|
|
|
|
|
|
case WIN_READ_MULTIPLE:
|
2016-12-29 20:40:24 +01:00
|
|
|
/* According to the official ATA reference:
|
|
|
|
|
|
|
|
|
|
If the Read Multiple command is attempted before the Set Multiple Mode
|
|
|
|
|
command has been executed or when Read Multiple commands are
|
|
|
|
|
disabled, the Read Multiple operation is rejected with an Aborted Com-
|
|
|
|
|
mand error. */
|
|
|
|
|
if (IDE_DRIVE_IS_CDROM(ide) || !ide->blocksize)
|
|
|
|
|
{
|
|
|
|
|
goto abort_cmd;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
addr = ide_get_sector(ide) * 512;
|
|
|
|
|
fseeko64(ide->hdfile, ide->base + addr, SEEK_SET);
|
|
|
|
|
fread(ide->buffer, 512, 1, ide->hdfile);
|
|
|
|
|
ide->pos=0;
|
|
|
|
|
ide->atastat = DRQ_STAT | READY_STAT | DSC_STAT;
|
|
|
|
|
if (!ide->blockcount)
|
|
|
|
|
{
|
|
|
|
|
// pclog("Read multiple int\n");
|
|
|
|
|
ide_irq_raise(ide);
|
|
|
|
|
}
|
|
|
|
|
ide->blockcount++;
|
|
|
|
|
if (ide->blockcount >= ide->blocksize)
|
|
|
|
|
{
|
|
|
|
|
ide->blockcount = 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
readflash=1;
|
|
|
|
|
return;
|
2016-06-26 00:34:39 +02:00
|
|
|
|
|
|
|
|
case WIN_WRITE:
|
|
|
|
|
case WIN_WRITE_NORETRY:
|
2016-12-29 20:40:24 +01:00
|
|
|
if (IDE_DRIVE_IS_CDROM(ide))
|
|
|
|
|
{
|
|
|
|
|
goto abort_cmd;
|
|
|
|
|
}
|
|
|
|
|
addr = ide_get_sector(ide) * 512;
|
|
|
|
|
fseeko64(ide->hdfile, ide->base + addr, SEEK_SET);
|
|
|
|
|
fwrite(ide->buffer, 512, 1, ide->hdfile);
|
|
|
|
|
ide_irq_raise(ide);
|
|
|
|
|
ide->secount = (ide->secount - 1) & 0xff;
|
|
|
|
|
if (ide->secount)
|
|
|
|
|
{
|
|
|
|
|
ide->atastat = DRQ_STAT | READY_STAT | DSC_STAT;
|
|
|
|
|
ide->pos=0;
|
|
|
|
|
ide_next_sector(ide);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
ide->atastat = READY_STAT | DSC_STAT;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
readflash=1;
|
|
|
|
|
return;
|
2016-06-26 00:34:39 +02:00
|
|
|
|
|
|
|
|
case WIN_WRITE_DMA:
|
2016-12-29 20:40:24 +01:00
|
|
|
if (IDE_DRIVE_IS_CDROM(ide) || (ide_board >= 2))
|
|
|
|
|
{
|
|
|
|
|
goto abort_cmd;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (ide_bus_master_write_sector)
|
|
|
|
|
{
|
|
|
|
|
if (ide_bus_master_write_sector(ide_board, (uint8_t *)ide->buffer))
|
|
|
|
|
{
|
|
|
|
|
idecallback[ide_board]=6*IDE_TIME; /*DMA not performed, try again later*/
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
/*DMA successful*/
|
|
|
|
|
addr = ide_get_sector(ide) * 512;
|
|
|
|
|
fseeko64(ide->hdfile, ide->base + addr, SEEK_SET);
|
|
|
|
|
fwrite(ide->buffer, 512, 1, ide->hdfile);
|
|
|
|
|
|
|
|
|
|
ide->atastat = DRQ_STAT | READY_STAT | DSC_STAT;
|
|
|
|
|
|
|
|
|
|
ide->secount = (ide->secount - 1) & 0xff;
|
|
|
|
|
if (ide->secount)
|
|
|
|
|
{
|
|
|
|
|
ide_next_sector(ide);
|
|
|
|
|
ide->atastat = BUSY_STAT;
|
|
|
|
|
idecallback[ide_board]=6*IDE_TIME;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
ide_irq_raise(ide);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
readflash=1;
|
|
|
|
|
return;
|
2016-06-26 00:34:39 +02:00
|
|
|
|
|
|
|
|
case WIN_WRITE_MULTIPLE:
|
2016-12-29 20:40:24 +01:00
|
|
|
if (IDE_DRIVE_IS_CDROM(ide))
|
|
|
|
|
{
|
|
|
|
|
goto abort_cmd;
|
|
|
|
|
}
|
|
|
|
|
addr = ide_get_sector(ide) * 512;
|
|
|
|
|
fseeko64(ide->hdfile, ide->base + addr, SEEK_SET);
|
|
|
|
|
fwrite(ide->buffer, 512, 1, ide->hdfile);
|
|
|
|
|
ide->blockcount++;
|
|
|
|
|
if (ide->blockcount >= ide->blocksize || ide->secount == 1)
|
|
|
|
|
{
|
|
|
|
|
ide->blockcount = 0;
|
|
|
|
|
ide_irq_raise(ide);
|
|
|
|
|
}
|
|
|
|
|
ide->secount = (ide->secount - 1) & 0xff;
|
|
|
|
|
if (ide->secount)
|
|
|
|
|
{
|
|
|
|
|
ide->atastat = DRQ_STAT | READY_STAT | DSC_STAT;
|
|
|
|
|
ide->pos=0;
|
|
|
|
|
ide_next_sector(ide);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
ide->atastat = READY_STAT | DSC_STAT;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
readflash=1;
|
|
|
|
|
return;
|
2016-06-26 00:34:39 +02:00
|
|
|
|
|
|
|
|
case WIN_VERIFY:
|
|
|
|
|
case WIN_VERIFY_ONCE:
|
2016-12-29 20:40:24 +01:00
|
|
|
if (IDE_DRIVE_IS_CDROM(ide))
|
|
|
|
|
{
|
|
|
|
|
goto abort_cmd;
|
|
|
|
|
}
|
|
|
|
|
ide->pos=0;
|
|
|
|
|
ide->atastat = READY_STAT | DSC_STAT;
|
|
|
|
|
ide_irq_raise(ide);
|
|
|
|
|
readflash=1;
|
|
|
|
|
return;
|
2016-06-26 00:34:39 +02:00
|
|
|
|
|
|
|
|
case WIN_FORMAT:
|
2016-12-29 20:40:24 +01:00
|
|
|
if (IDE_DRIVE_IS_CDROM(ide))
|
|
|
|
|
{
|
|
|
|
|
goto abort_cmd;
|
|
|
|
|
}
|
|
|
|
|
addr = ide_get_sector(ide) * 512;
|
|
|
|
|
// pclog("Format cyl %i head %i offset %08X %08X %08X secount %i\n",ide.cylinder,ide.head,addr,addr>>32,addr,ide.secount);
|
|
|
|
|
fseeko64(ide->hdfile, ide->base + addr, SEEK_SET);
|
|
|
|
|
memset(ide->buffer, 0, 512);
|
|
|
|
|
for (c=0;c<ide->secount;c++)
|
|
|
|
|
{
|
|
|
|
|
fwrite(ide->buffer, 512, 1, ide->hdfile);
|
|
|
|
|
}
|
2016-06-26 00:34:39 +02:00
|
|
|
ide->atastat = READY_STAT | DSC_STAT;
|
|
|
|
|
ide_irq_raise(ide);
|
2016-12-29 20:40:24 +01:00
|
|
|
|
|
|
|
|
readflash=1;
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
case WIN_DRIVE_DIAGNOSTICS:
|
|
|
|
|
ide_set_signature(ide);
|
|
|
|
|
ide->error=1; /*No error detected*/
|
|
|
|
|
|
|
|
|
|
if (IDE_DRIVE_IS_CDROM(ide))
|
|
|
|
|
{
|
|
|
|
|
ide->atastat = 0;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
ide->atastat = READY_STAT | DSC_STAT;
|
|
|
|
|
ide_irq_raise(ide);
|
|
|
|
|
}
|
|
|
|
|
return;
|
2016-06-26 00:34:39 +02:00
|
|
|
|
|
|
|
|
case WIN_SPECIFY: /* Initialize Drive Parameters */
|
2016-12-29 20:40:24 +01:00
|
|
|
if (IDE_DRIVE_IS_CDROM(ide))
|
|
|
|
|
{
|
|
|
|
|
goto abort_cmd;
|
|
|
|
|
}
|
|
|
|
|
ide->spt=ide->secount;
|
|
|
|
|
ide->hpc=ide->head+1;
|
|
|
|
|
ide->atastat = READY_STAT | DSC_STAT;
|
|
|
|
|
ide_irq_raise(ide);
|
|
|
|
|
return;
|
2016-06-26 00:34:39 +02:00
|
|
|
|
|
|
|
|
case WIN_PIDENTIFY: /* Identify Packet Device */
|
2016-12-29 20:40:24 +01:00
|
|
|
if (IDE_DRIVE_IS_CDROM(ide))
|
|
|
|
|
{
|
|
|
|
|
ide_atapi_identify(ide);
|
|
|
|
|
ide->pos=0;
|
|
|
|
|
ide->error=0;
|
|
|
|
|
ide->atastat = DRQ_STAT | READY_STAT | DSC_STAT;
|
|
|
|
|
ide_irq_raise(ide);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
goto abort_cmd;
|
2016-06-26 00:34:39 +02:00
|
|
|
|
|
|
|
|
case WIN_SET_MULTIPLE_MODE:
|
2016-12-29 20:40:24 +01:00
|
|
|
if (IDE_DRIVE_IS_CDROM(ide))
|
|
|
|
|
{
|
|
|
|
|
goto abort_cmd;
|
|
|
|
|
}
|
|
|
|
|
ide->blocksize = ide->secount;
|
|
|
|
|
ide->atastat = READY_STAT | DSC_STAT;
|
|
|
|
|
// pclog("Set multiple mode - %i\n", ide->blocksize);
|
|
|
|
|
ide_irq_raise(ide);
|
|
|
|
|
return;
|
2016-08-10 00:46:56 +02:00
|
|
|
|
|
|
|
|
case WIN_SET_FEATURES:
|
2016-12-29 20:40:24 +01:00
|
|
|
if (!(ide_set_features(ide)))
|
|
|
|
|
{
|
|
|
|
|
goto abort_cmd;
|
|
|
|
|
}
|
|
|
|
|
ide->atastat = READY_STAT | DSC_STAT;
|
|
|
|
|
ide_irq_raise(ide);
|
|
|
|
|
return;
|
2016-08-10 00:46:56 +02:00
|
|
|
|
|
|
|
|
case WIN_READ_NATIVE_MAX:
|
2016-12-29 20:40:24 +01:00
|
|
|
if (ide->type != IDE_HDD)
|
|
|
|
|
{
|
|
|
|
|
goto abort_cmd;
|
|
|
|
|
}
|
|
|
|
|
snum = hdc[cur_ide[ide->board]].spt;
|
|
|
|
|
snum *= hdc[cur_ide[ide->board]].hpc;
|
|
|
|
|
snum *= hdc[cur_ide[ide->board]].tracks;
|
|
|
|
|
ide_set_sector(ide, snum - 1);
|
|
|
|
|
ide->atastat = READY_STAT | DSC_STAT;
|
|
|
|
|
ide_irq_raise(ide);
|
|
|
|
|
return;
|
2016-08-10 00:46:56 +02:00
|
|
|
|
2016-06-26 00:34:39 +02:00
|
|
|
case WIN_IDENTIFY: /* Identify Device */
|
2016-12-29 20:40:24 +01:00
|
|
|
if (ide->type == IDE_NONE)
|
|
|
|
|
{
|
|
|
|
|
ide_set_signature(ide);
|
|
|
|
|
goto abort_cmd;
|
|
|
|
|
}
|
|
|
|
|
if (IDE_DRIVE_IS_CDROM(ide))
|
|
|
|
|
{
|
|
|
|
|
ide_set_signature(ide);
|
|
|
|
|
goto abort_cmd;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
ide_identify(ide);
|
|
|
|
|
ide->pos=0;
|
|
|
|
|
ide->atastat = DRQ_STAT | READY_STAT | DSC_STAT;
|
|
|
|
|
ide_irq_raise(ide);
|
|
|
|
|
}
|
|
|
|
|
return;
|
2016-06-26 00:34:39 +02:00
|
|
|
|
|
|
|
|
case WIN_PACKETCMD: /* ATAPI Packet */
|
2016-12-29 20:40:24 +01:00
|
|
|
if (!IDE_DRIVE_IS_CDROM(ide))
|
|
|
|
|
{
|
|
|
|
|
goto abort_cmd;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (ide->packetstatus == ATAPI_STATUS_IDLE)
|
|
|
|
|
{
|
2017-01-04 20:37:31 +01:00
|
|
|
// pclog("ATAPI_STATUS_IDLE\n");
|
2016-12-29 20:40:24 +01:00
|
|
|
readcdmode=0;
|
|
|
|
|
ide->pos=0;
|
|
|
|
|
ide->secount = 1;
|
|
|
|
|
ide->atastat = READY_STAT | DRQ_STAT |(ide->atastat&ERR_STAT);
|
|
|
|
|
}
|
|
|
|
|
else if (ide->packetstatus == ATAPI_STATUS_COMMAND)
|
|
|
|
|
{
|
2017-01-04 20:37:31 +01:00
|
|
|
// pclog("ATAPI_STATUS_COMMAND\n");
|
2016-12-29 20:40:24 +01:00
|
|
|
ide->atastat = BUSY_STAT|(ide->atastat&ERR_STAT);
|
|
|
|
|
atapicommand(ide_board);
|
|
|
|
|
}
|
|
|
|
|
else if (ide->packetstatus == ATAPI_STATUS_COMPLETE)
|
|
|
|
|
{
|
2017-01-04 20:37:31 +01:00
|
|
|
// pclog("ATAPI_STATUS_COMPLETE\n");
|
2016-12-29 20:40:24 +01:00
|
|
|
ide->atastat = READY_STAT;
|
|
|
|
|
ide->secount=3;
|
|
|
|
|
ide_irq_raise(ide);
|
|
|
|
|
}
|
|
|
|
|
else if (ide->packetstatus == ATAPI_STATUS_DATA)
|
|
|
|
|
{
|
2017-01-04 20:37:31 +01:00
|
|
|
// pclog("ATAPI_STATUS_DATA\n");
|
2016-12-29 20:40:24 +01:00
|
|
|
ide->atastat = READY_STAT|DRQ_STAT|(ide->atastat&ERR_STAT);
|
|
|
|
|
ide_irq_raise(ide);
|
|
|
|
|
ide->packetstatus=0xFF;
|
|
|
|
|
}
|
|
|
|
|
else if (ide->packetstatus == ATAPI_STATUS_PACKET_REQ)
|
|
|
|
|
{
|
2017-01-04 20:37:31 +01:00
|
|
|
// pclog("ATAPI_STATUS_PACKET_REQ\n");
|
2016-12-29 20:40:24 +01:00
|
|
|
ide->atastat = 0x58 | (ide->atastat & ERR_STAT);
|
|
|
|
|
ide_irq_raise(ide);
|
|
|
|
|
ide->pos=2;
|
|
|
|
|
}
|
|
|
|
|
else if (ide->packetstatus == ATAPI_STATUS_PACKET_RECEIVED)
|
|
|
|
|
{
|
2017-01-04 20:37:31 +01:00
|
|
|
// pclog("ATAPI_STATUS_PACKET_RECEIVED\n");
|
2016-12-29 20:40:24 +01:00
|
|
|
atapicommand(ide_board);
|
|
|
|
|
}
|
|
|
|
|
else if (ide->packetstatus == ATAPI_STATUS_READCD) /*READ CD callback*/
|
|
|
|
|
{
|
2017-01-04 20:37:31 +01:00
|
|
|
// pclog("ATAPI_STATUS_READCD\n");
|
2016-12-29 20:40:24 +01:00
|
|
|
ide->atastat = DRQ_STAT|(ide->atastat&ERR_STAT);
|
|
|
|
|
ide_irq_raise(ide);
|
|
|
|
|
}
|
|
|
|
|
else if (ide->packetstatus == ATAPI_STATUS_REQ_SENSE) /*REQUEST SENSE callback #1*/
|
|
|
|
|
{
|
2017-01-04 20:37:31 +01:00
|
|
|
// pclog("ATAPI_STATUS_REQ_SENSE\n");
|
2016-12-29 20:40:24 +01:00
|
|
|
ide->atastat = 0x58 | (ide->atastat & ERR_STAT);
|
|
|
|
|
ide_irq_raise(ide);
|
|
|
|
|
}
|
|
|
|
|
else if (ide->packetstatus == ATAPI_STATUS_ERROR) /*Error callback*/
|
|
|
|
|
{
|
2017-01-04 20:37:31 +01:00
|
|
|
// pclog("ATAPI_STATUS_ERROR\n");
|
2016-12-29 20:40:24 +01:00
|
|
|
ide->atastat = READY_STAT | ERR_STAT;
|
|
|
|
|
ide_irq_raise(ide);
|
|
|
|
|
}
|
|
|
|
|
else if (ide->packetstatus == ATAPI_STATUS_ERROR_2) /*Error callback with atastat already set - needed for the disc change stuff.*/
|
|
|
|
|
{
|
2017-01-04 20:37:31 +01:00
|
|
|
// pclog("ATAPI_STATUS_ERROR_2\n");
|
2016-12-29 20:40:24 +01:00
|
|
|
ide->atastat = ERR_STAT;
|
|
|
|
|
ide_irq_raise(ide);
|
|
|
|
|
}
|
|
|
|
|
return;
|
|
|
|
|
}
|
2016-06-26 00:34:39 +02:00
|
|
|
|
|
|
|
|
abort_cmd:
|
|
|
|
|
ide->command = 0;
|
|
|
|
|
ide->atastat = READY_STAT | ERR_STAT | DSC_STAT;
|
|
|
|
|
ide->error = ABRT_ERR;
|
|
|
|
|
ide->pos = 0;
|
|
|
|
|
ide_irq_raise(ide);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void ide_callback_pri()
|
|
|
|
|
{
|
|
|
|
|
idecallback[0] = 0;
|
|
|
|
|
callbackide(0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void ide_callback_sec()
|
|
|
|
|
{
|
|
|
|
|
idecallback[1] = 0;
|
|
|
|
|
callbackide(1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void ide_callback_ter()
|
|
|
|
|
{
|
|
|
|
|
idecallback[2] = 0;
|
|
|
|
|
callbackide(2);
|
|
|
|
|
}
|
|
|
|
|
|
2016-12-28 23:34:00 +01:00
|
|
|
void ide_callback_qua()
|
|
|
|
|
{
|
|
|
|
|
idecallback[3] = 0;
|
|
|
|
|
callbackide(3);
|
|
|
|
|
}
|
|
|
|
|
|
2016-06-26 00:34:39 +02:00
|
|
|
/*ATAPI CD-ROM emulation*/
|
|
|
|
|
uint8_t atapi_prev;
|
|
|
|
|
int toctimes=0;
|
|
|
|
|
|
|
|
|
|
void atapi_command_send_init(IDE *ide, uint8_t command, int req_length, int alloc_length)
|
|
|
|
|
{
|
|
|
|
|
if (ide->cylinder == 0xffff)
|
2016-12-29 20:40:24 +01:00
|
|
|
{
|
2016-06-26 00:34:39 +02:00
|
|
|
ide->cylinder = 0xfffe;
|
2016-12-29 20:40:24 +01:00
|
|
|
}
|
2016-06-26 00:34:39 +02:00
|
|
|
|
|
|
|
|
if ((ide->cylinder & 1) && !(alloc_length <= ide->cylinder))
|
|
|
|
|
{
|
|
|
|
|
ide->cylinder--;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (alloc_length < 0)
|
2016-12-29 20:40:24 +01:00
|
|
|
{
|
2016-06-26 00:34:39 +02:00
|
|
|
fatal("Allocation length < 0\n");
|
2016-12-29 20:40:24 +01:00
|
|
|
}
|
2016-06-26 00:34:39 +02:00
|
|
|
if (alloc_length == 0)
|
2016-12-29 20:40:24 +01:00
|
|
|
{
|
2016-06-26 00:34:39 +02:00
|
|
|
alloc_length = ide->cylinder;
|
2016-12-29 20:40:24 +01:00
|
|
|
}
|
2016-06-26 00:34:39 +02:00
|
|
|
|
|
|
|
|
/* No atastat setting: PCem actually emulates the callback cycle. */
|
2017-01-05 04:36:37 +01:00
|
|
|
if (alloc_length != 0)
|
|
|
|
|
{
|
|
|
|
|
ide->secount = 2;
|
|
|
|
|
}
|
2016-06-26 00:34:39 +02:00
|
|
|
|
|
|
|
|
// no bytes transferred yet
|
|
|
|
|
ide->pos = 0;
|
|
|
|
|
|
|
|
|
|
if ((ide->cylinder > req_length) || (ide->cylinder == 0))
|
2016-12-29 20:40:24 +01:00
|
|
|
{
|
2016-06-26 00:34:39 +02:00
|
|
|
ide->cylinder = req_length;
|
2016-12-29 20:40:24 +01:00
|
|
|
}
|
2016-06-26 00:34:39 +02:00
|
|
|
if (ide->cylinder > alloc_length)
|
2016-12-29 20:40:24 +01:00
|
|
|
{
|
2016-06-26 00:34:39 +02:00
|
|
|
ide->cylinder = alloc_length;
|
2016-12-29 20:40:24 +01:00
|
|
|
}
|
2016-06-26 00:34:39 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void atapi_command_ready(int ide_board, int packlen)
|
|
|
|
|
{
|
|
|
|
|
IDE *ide = &ide_drives[cur_ide[ide_board]];
|
|
|
|
|
ide->packetstatus = ATAPI_STATUS_REQ_SENSE;
|
|
|
|
|
idecallback[ide_board]=60*IDE_TIME;
|
|
|
|
|
ide->packlen=packlen;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void atapi_sense_clear(int command, int ignore_ua)
|
|
|
|
|
{
|
2016-11-12 15:06:38 +01:00
|
|
|
if ((SCSISense.SenseKey == SENSE_UNIT_ATTENTION) || ignore_ua)
|
2016-06-26 00:34:39 +02:00
|
|
|
{
|
|
|
|
|
atapi_prev=command;
|
2016-11-12 15:06:38 +01:00
|
|
|
SCSISense.SenseKey=0;
|
|
|
|
|
SCSISense.Asc=0;
|
|
|
|
|
SCSISense.Ascq=0;
|
2016-06-26 00:34:39 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2016-12-29 20:40:24 +01:00
|
|
|
void atapi_cmd_error(IDE *ide, uint8_t sensekey, uint8_t asc, uint8_t ascq)
|
|
|
|
|
{
|
|
|
|
|
ide->error = (sensekey << 4) | ABRT_ERR;
|
|
|
|
|
if (SCSISense.UnitAttention)
|
|
|
|
|
{
|
|
|
|
|
ide->error |= MCR_ERR;
|
|
|
|
|
}
|
|
|
|
|
ide->atastat = READY_STAT | ERR_STAT;
|
|
|
|
|
ide->secount = (ide->secount & ~7) | 3;
|
|
|
|
|
ide->packetstatus = 0x80;
|
|
|
|
|
idecallback[ide->board]=50*IDE_TIME;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void atapi_not_ready(IDE *ide)
|
|
|
|
|
{
|
|
|
|
|
SCSISense.SenseKey = SENSE_NOT_READY;
|
|
|
|
|
SCSISense.Asc = ASC_MEDIUM_NOT_PRESENT;
|
|
|
|
|
SCSISense.Ascq = 0;
|
|
|
|
|
atapi_cmd_error(ide, SENSE_NOT_READY, ASC_MEDIUM_NOT_PRESENT, 0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void atapi_illegal_opcode(IDE *ide)
|
|
|
|
|
{
|
|
|
|
|
SCSISense.SenseKey = SENSE_ILLEGAL_REQUEST;
|
|
|
|
|
SCSISense.Asc = ASC_ILLEGAL_OPCODE;
|
|
|
|
|
SCSISense.Ascq = 0;
|
|
|
|
|
atapi_cmd_error(ide, SENSE_ILLEGAL_REQUEST, ASC_ILLEGAL_OPCODE, 0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void atapi_invalid_field(IDE *ide)
|
|
|
|
|
{
|
|
|
|
|
SCSISense.SenseKey = SENSE_ILLEGAL_REQUEST;
|
2016-12-30 00:42:54 +01:00
|
|
|
SCSISense.Asc = ASC_INV_FIELD_IN_CMD_PACKET;
|
2016-12-29 20:40:24 +01:00
|
|
|
SCSISense.Ascq = 0;
|
|
|
|
|
atapi_cmd_error(ide, SENSE_ILLEGAL_REQUEST, ASC_INV_FIELD_IN_CMD_PACKET, 0);
|
|
|
|
|
ide->atastat = 0x53;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void atapi_illegal_mode(IDE *ide)
|
|
|
|
|
{
|
|
|
|
|
SCSISense.SenseKey = SENSE_ILLEGAL_REQUEST;
|
2017-01-02 04:38:53 +01:00
|
|
|
SCSISense.Asc = ASC_ILLEGAL_MODE_FOR_THIS_TRACK;
|
2016-12-29 20:40:24 +01:00
|
|
|
SCSISense.Ascq = 0;
|
|
|
|
|
atapi_cmd_error(ide, SENSE_ILLEGAL_REQUEST, ASC_ILLEGAL_MODE_FOR_THIS_TRACK, 0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void atapi_incompatible_format(IDE *ide)
|
|
|
|
|
{
|
|
|
|
|
SCSISense.SenseKey = SENSE_ILLEGAL_REQUEST;
|
2017-01-02 04:38:53 +01:00
|
|
|
SCSISense.Asc = ASC_INCOMPATIBLE_FORMAT;
|
2016-12-29 20:40:24 +01:00
|
|
|
SCSISense.Ascq = 0;
|
|
|
|
|
atapi_cmd_error(ide, SENSE_ILLEGAL_REQUEST, ASC_INCOMPATIBLE_FORMAT, 0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void atapi_data_phase_error(IDE *ide)
|
|
|
|
|
{
|
|
|
|
|
SCSISense.SenseKey = SENSE_ILLEGAL_REQUEST;
|
2017-01-02 04:38:53 +01:00
|
|
|
SCSISense.Asc = ASC_DATA_PHASE_ERROR;
|
2016-12-29 20:40:24 +01:00
|
|
|
SCSISense.Ascq = 0;
|
|
|
|
|
atapi_cmd_error(ide, SENSE_ILLEGAL_REQUEST, ASC_DATA_PHASE_ERROR, 0);
|
|
|
|
|
}
|
|
|
|
|
|
2016-06-26 00:34:39 +02:00
|
|
|
static void atapicommand(int ide_board)
|
|
|
|
|
{
|
2016-11-12 15:06:38 +01:00
|
|
|
IDE *ide = &ide_drives[cur_ide[ide_board]];
|
|
|
|
|
uint8_t *idebufferb = (uint8_t *) ide->buffer;
|
2016-06-26 00:34:39 +02:00
|
|
|
uint8_t rcdmode = 0;
|
2016-11-12 15:06:38 +01:00
|
|
|
int c;
|
|
|
|
|
int len;
|
|
|
|
|
int msf;
|
|
|
|
|
int pos=0;
|
|
|
|
|
unsigned char temp;
|
|
|
|
|
uint32_t size;
|
2016-06-26 00:34:39 +02:00
|
|
|
uint8_t page_code;
|
|
|
|
|
int max_len;
|
|
|
|
|
unsigned idx = 0;
|
|
|
|
|
unsigned size_idx;
|
|
|
|
|
unsigned preamble_len;
|
|
|
|
|
int toc_format;
|
|
|
|
|
int temp_command;
|
|
|
|
|
int alloc_length;
|
|
|
|
|
int completed;
|
2016-08-01 19:14:54 +02:00
|
|
|
uint8_t index = 0;
|
|
|
|
|
int media;
|
|
|
|
|
int format;
|
|
|
|
|
int ret;
|
2016-12-23 03:16:24 +01:00
|
|
|
int real_pos;
|
2016-12-25 17:46:06 +01:00
|
|
|
int track = 0;
|
2017-01-05 04:36:37 +01:00
|
|
|
uint8_t cdb[12];
|
2016-06-26 00:34:39 +02:00
|
|
|
|
2017-01-04 20:37:31 +01:00
|
|
|
#if 0
|
2016-12-29 20:40:24 +01:00
|
|
|
pclog("ATAPI command 0x%02X, Sense Key %02X, Asc %02X, Ascq %02X, %i, Unit attention: %i\n",idebufferb[0],SCSISense.SenseKey,SCSISense.Asc,SCSISense.Ascq,ins,SCSISense.UnitAttention);
|
|
|
|
|
|
2016-11-12 15:06:38 +01:00
|
|
|
int CdbLength;
|
|
|
|
|
for (CdbLength = 1; CdbLength < 12; CdbLength++)
|
2016-12-29 20:40:24 +01:00
|
|
|
{
|
2016-11-12 15:06:38 +01:00
|
|
|
pclog("ATAPI CDB[%d] = 0x%02X\n", CdbLength, idebufferb[CdbLength]);
|
2016-12-29 20:40:24 +01:00
|
|
|
}
|
2016-06-26 00:34:39 +02:00
|
|
|
#endif
|
2016-11-12 15:06:38 +01:00
|
|
|
|
2017-01-05 04:36:37 +01:00
|
|
|
memcpy(cdb, idebufferb, 12);
|
|
|
|
|
|
2016-11-12 15:06:38 +01:00
|
|
|
msf=idebufferb[1]&2;
|
2016-12-23 17:11:59 +01:00
|
|
|
SectorLen=0;
|
2016-06-26 00:34:39 +02:00
|
|
|
|
2016-11-12 15:06:38 +01:00
|
|
|
if (cdrom->medium_changed())
|
2016-06-26 00:34:39 +02:00
|
|
|
{
|
2016-12-23 03:16:24 +01:00
|
|
|
// pclog("Medium has changed...\n");
|
2016-11-12 15:06:38 +01:00
|
|
|
SCSICDROM_Insert();
|
2016-06-26 00:34:39 +02:00
|
|
|
}
|
2016-11-17 20:41:27 +01:00
|
|
|
|
|
|
|
|
if (!cdrom->ready() && SCSISense.UnitAttention)
|
2016-06-26 00:34:39 +02:00
|
|
|
{
|
2016-11-17 20:41:27 +01:00
|
|
|
/* If the drive is not ready, there is no reason to keep the
|
2016-12-29 20:40:24 +01:00
|
|
|
UNIT ATTENTION condition present, as we only use it to mark
|
|
|
|
|
disc changes. */
|
2016-11-17 20:41:27 +01:00
|
|
|
SCSISense.UnitAttention = 0;
|
2016-06-26 00:34:39 +02:00
|
|
|
}
|
2016-11-17 20:41:27 +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-01-02 04:38:53 +01:00
|
|
|
if (SCSISense.UnitAttention == 1)
|
2016-06-26 00:34:39 +02:00
|
|
|
{
|
2017-01-05 04:36:37 +01:00
|
|
|
// pclog("Unit attention now 2\n");
|
2017-01-02 04:38:53 +01:00
|
|
|
SCSISense.UnitAttention = 2;
|
|
|
|
|
if (!(SCSICommandTable[idebufferb[0]] & ALLOW_UA))
|
|
|
|
|
{
|
|
|
|
|
// pclog("UNIT ATTENTION: Command not allowed to pass through\n");
|
|
|
|
|
atapi_cmd_error(ide, SENSE_UNIT_ATTENTION, ASC_MEDIUM_MAY_HAVE_CHANGED, 0);
|
|
|
|
|
return;
|
|
|
|
|
}
|
2016-06-26 00:34:39 +02:00
|
|
|
}
|
2017-01-02 04:38:53 +01:00
|
|
|
else if (SCSISense.UnitAttention == 2)
|
2016-06-26 00:34:39 +02:00
|
|
|
{
|
2017-01-02 04:38:53 +01:00
|
|
|
if (idebufferb[0]!=GPCMD_REQUEST_SENSE)
|
|
|
|
|
{
|
2017-01-05 04:36:37 +01:00
|
|
|
// pclog("Unit attention now 0\n");
|
2017-01-02 04:38:53 +01:00
|
|
|
SCSISense.UnitAttention = 0;
|
|
|
|
|
}
|
2016-06-26 00:34:39 +02:00
|
|
|
}
|
2016-11-17 20:41:27 +01:00
|
|
|
|
|
|
|
|
/* Unless the command is REQUEST SENSE, clear the sense. This will *NOT*
|
|
|
|
|
the UNIT ATTENTION condition if it's set. */
|
|
|
|
|
if (idebufferb[0]!=GPCMD_REQUEST_SENSE)
|
|
|
|
|
{
|
|
|
|
|
atapi_sense_clear(idebufferb[0], 1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Next it's time for NOT READY. */
|
2016-11-12 15:06:38 +01:00
|
|
|
if ((SCSICommandTable[idebufferb[0]] & CHECK_READY) && !cdrom->ready())
|
2016-06-26 00:34:39 +02:00
|
|
|
{
|
2016-12-29 20:40:24 +01:00
|
|
|
atapi_not_ready(ide);
|
2016-06-26 00:34:39 +02:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2016-11-17 20:41:27 +01:00
|
|
|
// pclog("Continuing with command\n");
|
|
|
|
|
|
2016-06-26 00:34:39 +02:00
|
|
|
prev_status = cd_status;
|
2016-11-12 15:06:38 +01:00
|
|
|
cd_status = cdrom->status();
|
2016-06-26 00:34:39 +02:00
|
|
|
if (((prev_status == CD_STATUS_PLAYING) || (prev_status == CD_STATUS_PAUSED)) && ((cd_status != CD_STATUS_PLAYING) && (cd_status != CD_STATUS_PAUSED)))
|
|
|
|
|
{
|
|
|
|
|
completed = 1;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
completed = 0;
|
|
|
|
|
}
|
|
|
|
|
|
2016-11-12 15:06:38 +01:00
|
|
|
switch (idebufferb[0])
|
|
|
|
|
{
|
2016-12-29 20:40:24 +01:00
|
|
|
case GPCMD_TEST_UNIT_READY:
|
|
|
|
|
ide->packetstatus = ATAPI_STATUS_COMPLETE;
|
|
|
|
|
idecallback[ide_board]=50*IDE_TIME;
|
|
|
|
|
break;
|
2016-06-26 00:34:39 +02:00
|
|
|
|
2016-12-29 20:40:24 +01:00
|
|
|
case GPCMD_REQUEST_SENSE: /* Used by ROS 4+ */
|
|
|
|
|
alloc_length = idebufferb[4];
|
|
|
|
|
temp_command = idebufferb[0];
|
2016-06-26 00:34:39 +02:00
|
|
|
|
2016-12-29 20:40:24 +01:00
|
|
|
/*Will return 18 bytes of 0*/
|
2017-01-05 04:46:50 +01:00
|
|
|
if (alloc_length != 0)
|
|
|
|
|
{
|
|
|
|
|
memset(idebufferb, 0, alloc_length);
|
|
|
|
|
}
|
2016-06-26 00:34:39 +02:00
|
|
|
|
2016-12-29 20:40:24 +01:00
|
|
|
idebufferb[0]=0x80|0x70;
|
2016-06-26 00:34:39 +02:00
|
|
|
|
2016-12-29 20:40:24 +01:00
|
|
|
if ((SCSISense.SenseKey > 0) && ((cd_status < CD_STATUS_PLAYING) || (cd_status == CD_STATUS_STOPPED)))
|
|
|
|
|
{
|
|
|
|
|
if (completed)
|
|
|
|
|
{
|
|
|
|
|
idebufferb[2]=SENSE_ILLEGAL_REQUEST;
|
|
|
|
|
idebufferb[12]=ASC_AUDIO_PLAY_OPERATION;
|
|
|
|
|
idebufferb[13]=ASCQ_AUDIO_PLAY_OPERATION_COMPLETED;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
idebufferb[2]=SCSISense.SenseKey;
|
|
|
|
|
idebufferb[12]=SCSISense.Asc;
|
|
|
|
|
idebufferb[13]=SCSISense.Ascq;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if ((SCSISense.SenseKey == 0) && (cd_status >= CD_STATUS_PLAYING) && (cd_status != CD_STATUS_STOPPED))
|
2016-06-26 00:34:39 +02:00
|
|
|
{
|
|
|
|
|
idebufferb[2]=SENSE_ILLEGAL_REQUEST;
|
|
|
|
|
idebufferb[12]=ASC_AUDIO_PLAY_OPERATION;
|
2016-12-29 20:40:24 +01:00
|
|
|
idebufferb[13]=(cd_status == CD_STATUS_PLAYING) ? ASCQ_AUDIO_PLAY_OPERATION_IN_PROGRESS : ASCQ_AUDIO_PLAY_OPERATION_PAUSED;
|
2016-06-26 00:34:39 +02:00
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2016-12-29 20:40:24 +01:00
|
|
|
if (SCSISense.UnitAttention)
|
|
|
|
|
{
|
|
|
|
|
idebufferb[2]=SENSE_UNIT_ATTENTION;
|
|
|
|
|
idebufferb[12]=ASC_MEDIUM_MAY_HAVE_CHANGED;
|
|
|
|
|
idebufferb[13]=0;
|
|
|
|
|
}
|
2016-06-26 00:34:39 +02:00
|
|
|
}
|
2016-12-29 20:40:24 +01:00
|
|
|
|
2017-01-05 04:36:37 +01:00
|
|
|
// pclog("Reporting sense: %02X %02X %02X\n", idebufferb[2], idebufferb[12], idebufferb[13]);
|
2016-12-29 20:40:24 +01:00
|
|
|
|
2017-01-05 04:36:37 +01:00
|
|
|
idebufferb[7]=10;
|
2016-12-29 20:40:24 +01:00
|
|
|
|
|
|
|
|
if (idebufferb[2] == SENSE_UNIT_ATTENTION)
|
2016-11-17 20:41:27 +01:00
|
|
|
{
|
2016-12-29 20:40:24 +01:00
|
|
|
/* If the last remaining sense is unit attention, clear
|
|
|
|
|
that condition. */
|
|
|
|
|
SCSISense.UnitAttention = 0;
|
2016-11-17 20:41:27 +01:00
|
|
|
}
|
2016-06-26 00:34:39 +02:00
|
|
|
|
2016-12-29 20:40:24 +01:00
|
|
|
/* Clear the sense stuff as per the spec. */
|
|
|
|
|
atapi_sense_clear(temp_command, 0);
|
2017-01-04 06:33:18 +01:00
|
|
|
|
2017-01-05 04:36:37 +01:00
|
|
|
if (alloc_length == 0)
|
2017-01-04 06:33:18 +01:00
|
|
|
{
|
2017-01-05 04:36:37 +01:00
|
|
|
// pclog("REQUEST SENSE - empty allocation\n");
|
2017-01-04 06:33:18 +01:00
|
|
|
ide->packetstatus = ATAPI_STATUS_COMPLETE;
|
|
|
|
|
idecallback[ide_board]=50*IDE_TIME;
|
|
|
|
|
}
|
2017-01-05 04:36:37 +01:00
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
atapi_command_send_init(ide, temp_command, 18, alloc_length);
|
|
|
|
|
atapi_command_ready(ide_board, 18);
|
|
|
|
|
}
|
2016-12-29 20:40:24 +01:00
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case GPCMD_SET_SPEED:
|
|
|
|
|
ide->packetstatus = ATAPI_STATUS_COMPLETE;
|
|
|
|
|
idecallback[ide_board]=50*IDE_TIME;
|
|
|
|
|
break;
|
2016-06-26 00:34:39 +02:00
|
|
|
|
2016-12-29 20:40:24 +01:00
|
|
|
case GPCMD_MECHANISM_STATUS:
|
|
|
|
|
len=(idebufferb[7]<<16)|(idebufferb[8]<<8)|idebufferb[9];
|
2016-06-26 00:34:39 +02:00
|
|
|
|
2016-12-29 20:40:24 +01:00
|
|
|
memset(idebufferb, 0, 8);
|
|
|
|
|
idebufferb[5] = 1;
|
2016-06-26 00:34:39 +02:00
|
|
|
|
2017-01-05 04:36:37 +01:00
|
|
|
if (len == 0)
|
|
|
|
|
{
|
|
|
|
|
ide->packetstatus = ATAPI_STATUS_COMPLETE;
|
|
|
|
|
idecallback[ide_board]=50*IDE_TIME;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
atapi_command_send_init(ide, cdb[0], 8, alloc_length);
|
|
|
|
|
atapi_command_ready(ide_board, 8);
|
|
|
|
|
}
|
2016-12-29 20:40:24 +01:00
|
|
|
break;
|
2016-06-26 00:34:39 +02:00
|
|
|
|
2016-12-29 20:40:24 +01:00
|
|
|
case GPCMD_READ_TOC_PMA_ATIP:
|
|
|
|
|
toctimes++;
|
|
|
|
|
toc_format = idebufferb[2] & 0xf;
|
2016-06-26 00:34:39 +02:00
|
|
|
|
2016-12-29 20:40:24 +01:00
|
|
|
if (toc_format == 0)
|
|
|
|
|
{
|
|
|
|
|
toc_format = (idebufferb[9]>>6) & 3;
|
|
|
|
|
}
|
2016-06-26 00:34:39 +02:00
|
|
|
|
2016-12-29 20:40:24 +01:00
|
|
|
switch (toc_format)
|
|
|
|
|
{
|
|
|
|
|
case 0: /*Normal*/
|
|
|
|
|
len=idebufferb[8]+(idebufferb[7]<<8);
|
|
|
|
|
len=cdrom->readtoc(idebufferb,idebufferb[6],msf,len,0);
|
|
|
|
|
break;
|
|
|
|
|
case 1: /*Multi session*/
|
|
|
|
|
len=idebufferb[8]+(idebufferb[7]<<8);
|
|
|
|
|
len=cdrom->readtoc_session(idebufferb,msf,len);
|
|
|
|
|
idebufferb[0]=0; idebufferb[1]=0xA;
|
|
|
|
|
break;
|
|
|
|
|
case 2: /*Raw*/
|
|
|
|
|
len=idebufferb[8]+(idebufferb[7]<<8);
|
|
|
|
|
len=cdrom->readtoc_raw(idebufferb,msf,len);
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
atapi_invalid_field(ide);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ide->packetstatus = ATAPI_STATUS_DATA;
|
|
|
|
|
ide->cylinder=len;
|
|
|
|
|
ide->secount=2;
|
|
|
|
|
ide->pos=0;
|
|
|
|
|
idecallback[ide_board]=60*IDE_TIME;
|
|
|
|
|
ide->packlen=len;
|
|
|
|
|
// pclog("READ_TOC_PMA_ATIP format %02X, length %i (%i)\n", toc_format, ide->cylinder, idebufferb[1]);
|
2017-01-04 06:33:18 +01:00
|
|
|
|
|
|
|
|
if (len == 0)
|
|
|
|
|
{
|
|
|
|
|
ide->packetstatus = ATAPI_STATUS_COMPLETE;
|
|
|
|
|
idecallback[ide_board]=50*IDE_TIME;
|
|
|
|
|
}
|
2016-12-29 20:40:24 +01:00
|
|
|
return;
|
2016-06-26 00:34:39 +02:00
|
|
|
|
2016-12-29 20:40:24 +01:00
|
|
|
case GPCMD_READ_CD:
|
2016-11-17 20:41:27 +01:00
|
|
|
case GPCMD_READ_CD_MSF:
|
2016-12-29 20:40:24 +01:00
|
|
|
// pclog("Read CD : start LBA %02X%02X%02X%02X Length %02X%02X%02X Flags %02X\n",idebufferb[2],idebufferb[3],idebufferb[4],idebufferb[5],idebufferb[6],idebufferb[7],idebufferb[8],idebufferb[9]);
|
2016-11-17 20:41:27 +01:00
|
|
|
if (idebufferb[0] == GPCMD_READ_CD_MSF)
|
|
|
|
|
{
|
2016-12-23 17:11:59 +01:00
|
|
|
SectorLBA=MSFtoLBA(idebufferb[3],idebufferb[4],idebufferb[5]);
|
|
|
|
|
SectorLen=MSFtoLBA(idebufferb[6],idebufferb[7],idebufferb[8]);
|
2016-11-17 20:41:27 +01:00
|
|
|
|
2016-12-23 17:11:59 +01:00
|
|
|
SectorLen -= SectorLBA;
|
|
|
|
|
SectorLen++;
|
2016-11-17 20:41:27 +01:00
|
|
|
|
|
|
|
|
cdrom_sector_ismsf = 1;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2016-12-23 17:11:59 +01:00
|
|
|
SectorLen=(idebufferb[6]<<16)|(idebufferb[7]<<8)|idebufferb[8];
|
|
|
|
|
SectorLBA=(idebufferb[2]<<24)|(idebufferb[3]<<16)|(idebufferb[4]<<8)|idebufferb[5];
|
2016-11-17 20:41:27 +01:00
|
|
|
|
|
|
|
|
cdrom_sector_ismsf = 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
cdrom_sector_type = (idebufferb[1] >> 2) & 7;
|
|
|
|
|
cdrom_sector_flags = idebufferb[9] || (((uint32_t) idebufferb[10]) << 8);
|
|
|
|
|
|
2016-12-23 17:11:59 +01:00
|
|
|
if (SectorLBA > (cdrom->size() - 1))
|
2016-11-17 20:41:27 +01:00
|
|
|
{
|
2017-01-04 20:37:31 +01:00
|
|
|
// pclog("Trying to read beyond the end of disc\n");
|
2016-12-29 20:40:24 +01:00
|
|
|
atapi_invalid_field(ide);
|
2016-11-17 20:41:27 +01:00
|
|
|
break;
|
2016-12-23 03:16:24 +01:00
|
|
|
}
|
|
|
|
|
|
2016-12-23 17:11:59 +01:00
|
|
|
ret = cdrom_read_data(idebufferb);
|
2016-12-23 03:16:24 +01:00
|
|
|
|
|
|
|
|
if (!ret)
|
|
|
|
|
{
|
2016-12-29 20:40:24 +01:00
|
|
|
atapi_invalid_field(ide);
|
2016-12-23 03:16:24 +01:00
|
|
|
break;
|
2016-11-17 20:41:27 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
readflash=1;
|
|
|
|
|
|
2016-12-23 17:11:59 +01:00
|
|
|
SectorLBA++;
|
|
|
|
|
SectorLen--;
|
|
|
|
|
if (SectorLen >= 0)
|
2016-12-29 20:40:24 +01:00
|
|
|
{
|
2016-11-17 20:41:27 +01:00
|
|
|
ide->packetstatus = ATAPI_STATUS_READCD;
|
2016-12-29 20:40:24 +01:00
|
|
|
}
|
2016-11-17 20:41:27 +01:00
|
|
|
else
|
2016-12-29 20:40:24 +01:00
|
|
|
{
|
2016-11-17 20:41:27 +01:00
|
|
|
ide->packetstatus = ATAPI_STATUS_DATA;
|
2016-12-29 20:40:24 +01:00
|
|
|
}
|
2016-11-17 20:41:27 +01:00
|
|
|
ide->cylinder=cdrom_sector_size;
|
|
|
|
|
ide->secount=2;
|
|
|
|
|
ide->pos=0;
|
|
|
|
|
idecallback[ide_board]=60*IDE_TIME;
|
|
|
|
|
ide->packlen=cdrom_sector_size;
|
|
|
|
|
return;
|
2016-06-26 00:34:39 +02:00
|
|
|
|
|
|
|
|
case GPCMD_READ_6:
|
|
|
|
|
case GPCMD_READ_10:
|
|
|
|
|
case GPCMD_READ_12:
|
2016-12-29 20:40:24 +01:00
|
|
|
// pclog("Read 10 : start LBA %02X%02X%02X%02X Length %02X%02X%02X Flags %02X\n",idebufferb[2],idebufferb[3],idebufferb[4],idebufferb[5],idebufferb[6],idebufferb[7],idebufferb[8],idebufferb[9]);
|
|
|
|
|
cdrom_sector_ismsf = 0;
|
2016-06-26 00:34:39 +02:00
|
|
|
|
2016-12-29 20:40:24 +01:00
|
|
|
if (idebufferb[0] == GPCMD_READ_6)
|
|
|
|
|
{
|
|
|
|
|
SectorLen=idebufferb[4];
|
|
|
|
|
SectorLBA=((((uint32_t) idebufferb[1]) & 0x1f)<<16)|(((uint32_t) idebufferb[2])<<8)|((uint32_t) idebufferb[3]);
|
|
|
|
|
}
|
|
|
|
|
else if (idebufferb[0] == GPCMD_READ_10)
|
|
|
|
|
{
|
|
|
|
|
SectorLen=(idebufferb[7]<<8)|idebufferb[8];
|
|
|
|
|
SectorLBA=(idebufferb[2]<<24)|(idebufferb[3]<<16)|(idebufferb[4]<<8)|idebufferb[5];
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
SectorLen=(((uint32_t) idebufferb[6])<<24)|(((uint32_t) idebufferb[7])<<16)|(((uint32_t) idebufferb[8])<<8)|((uint32_t) idebufferb[9]);
|
|
|
|
|
SectorLBA=(((uint32_t) idebufferb[2])<<24)|(((uint32_t) idebufferb[3])<<16)|(((uint32_t) idebufferb[4])<<8)|((uint32_t) idebufferb[5]);
|
|
|
|
|
}
|
2016-11-17 20:41:27 +01:00
|
|
|
|
2017-01-04 20:37:31 +01:00
|
|
|
// pclog("Reading sector: %i, length: %i\n", SectorLen, SectorLBA);
|
|
|
|
|
|
2016-12-23 17:11:59 +01:00
|
|
|
if (SectorLBA > (cdrom->size() - 1))
|
2016-12-29 20:40:24 +01:00
|
|
|
{
|
|
|
|
|
// pclog("Trying to read beyond the end of disc\n");
|
|
|
|
|
atapi_invalid_field(ide);
|
|
|
|
|
break;
|
2016-12-23 03:16:24 +01:00
|
|
|
}
|
2016-06-26 00:34:39 +02:00
|
|
|
|
2016-12-29 20:40:24 +01:00
|
|
|
if (!SectorLen)
|
|
|
|
|
{
|
|
|
|
|
// pclog("All done - callback set\n");
|
|
|
|
|
ide->packetstatus = ATAPI_STATUS_COMPLETE;
|
|
|
|
|
idecallback[ide_board]=20*IDE_TIME;
|
|
|
|
|
break;
|
|
|
|
|
}
|
2016-11-17 20:41:27 +01:00
|
|
|
|
2016-12-29 20:40:24 +01:00
|
|
|
cdrom_sector_type = 6;
|
|
|
|
|
cdrom_sector_flags = 0x10;
|
2016-11-17 20:41:27 +01:00
|
|
|
|
2016-12-29 20:40:24 +01:00
|
|
|
ret = cdrom_read_data(idebufferb);
|
2016-12-23 03:16:24 +01:00
|
|
|
|
2016-12-29 20:40:24 +01:00
|
|
|
if (!ret)
|
|
|
|
|
{
|
|
|
|
|
atapi_invalid_field(ide);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
readflash=1;
|
|
|
|
|
SectorLBA++;
|
|
|
|
|
SectorLen--;
|
|
|
|
|
if (SectorLen >= 0)
|
|
|
|
|
{
|
|
|
|
|
ide->packetstatus = ATAPI_STATUS_READCD;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
ide->packetstatus = ATAPI_STATUS_DATA;
|
|
|
|
|
}
|
|
|
|
|
ide->cylinder=2048;
|
|
|
|
|
ide->secount=2;
|
|
|
|
|
ide->pos=0;
|
|
|
|
|
idecallback[ide_board]=60*IDE_TIME;
|
|
|
|
|
ide->packlen=2048;
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
case GPCMD_READ_HEADER:
|
|
|
|
|
if (cdrom->read_header)
|
|
|
|
|
{
|
|
|
|
|
cdrom->read_header(idebufferb, idebufferb);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
SectorLen=(idebufferb[7]<<8)|idebufferb[8];
|
|
|
|
|
SectorLBA=(idebufferb[2]<<24)|(idebufferb[3]<<16)|(idebufferb[4]<<8)|idebufferb[5];
|
|
|
|
|
if (msf)
|
2016-12-23 03:16:24 +01:00
|
|
|
{
|
2016-12-29 20:40:24 +01:00
|
|
|
real_pos = cdrom_LBAtoMSF_accurate(ide);
|
2016-12-23 03:16:24 +01:00
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2016-12-29 20:40:24 +01:00
|
|
|
real_pos = SectorLBA;
|
2016-12-23 03:16:24 +01:00
|
|
|
}
|
2016-12-29 20:40:24 +01:00
|
|
|
idebufferb[4] = (real_pos >> 24);
|
|
|
|
|
idebufferb[5] = ((real_pos >> 16) & 0xff);
|
|
|
|
|
idebufferb[6] = ((real_pos >> 8) & 0xff);
|
|
|
|
|
idebufferb[7] = real_pos & 0xff;
|
|
|
|
|
idebufferb[0]=1; /*2048 bytes user data*/
|
|
|
|
|
idebufferb[1]=idebufferb[2]=idebufferb[3]=0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
len = 8;
|
|
|
|
|
ide->packetstatus = ATAPI_STATUS_DATA;
|
|
|
|
|
ide->cylinder=8;
|
|
|
|
|
ide->secount=2;
|
|
|
|
|
ide->pos=0;
|
|
|
|
|
idecallback[ide_board]=60*IDE_TIME;
|
|
|
|
|
ide->packlen=8;
|
|
|
|
|
return;
|
2016-06-26 00:34:39 +02:00
|
|
|
|
|
|
|
|
case GPCMD_MODE_SENSE_6:
|
|
|
|
|
case GPCMD_MODE_SENSE_10:
|
2016-12-29 20:40:24 +01:00
|
|
|
temp_command = idebufferb[0];
|
|
|
|
|
|
|
|
|
|
if (temp_command == GPCMD_MODE_SENSE_6)
|
|
|
|
|
{
|
|
|
|
|
len=idebufferb[4];
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
len=(idebufferb[8]|(idebufferb[7]<<8));
|
|
|
|
|
}
|
2016-06-26 00:34:39 +02:00
|
|
|
|
2016-12-29 20:40:24 +01:00
|
|
|
temp=idebufferb[2] & 0x3F;
|
2016-12-25 01:57:56 +01:00
|
|
|
|
2016-12-29 20:40:24 +01:00
|
|
|
memset(idebufferb, 0, len);
|
|
|
|
|
alloc_length = len;
|
|
|
|
|
|
|
|
|
|
if (!(mode_sense_pages[temp] & IMPLEMENTED))
|
|
|
|
|
{
|
|
|
|
|
atapi_invalid_field(ide);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (temp_command == GPCMD_MODE_SENSE_6)
|
|
|
|
|
{
|
|
|
|
|
len = SCSICDROMModeSense(idebufferb,4,temp);
|
2017-01-04 06:33:18 +01:00
|
|
|
if (len > alloc_length)
|
|
|
|
|
{
|
|
|
|
|
len = alloc_length;
|
|
|
|
|
}
|
2016-12-29 20:40:24 +01:00
|
|
|
idebufferb[0] = len - 1;
|
|
|
|
|
idebufferb[1]=3; /*120mm data CD-ROM*/
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
len = SCSICDROMModeSense(idebufferb,8,temp);
|
2017-01-04 06:33:18 +01:00
|
|
|
if (len > alloc_length)
|
|
|
|
|
{
|
|
|
|
|
len = alloc_length;
|
|
|
|
|
}
|
2016-12-29 20:40:24 +01:00
|
|
|
idebufferb[0]=(len - 2)>>8;
|
|
|
|
|
idebufferb[1]=(len - 2)&255;
|
|
|
|
|
idebufferb[2]=3; /*120mm data CD-ROM*/
|
|
|
|
|
}
|
2016-06-26 00:34:39 +02:00
|
|
|
|
2016-12-29 20:40:24 +01:00
|
|
|
atapi_command_send_init(ide, temp_command, len, alloc_length);
|
2016-06-26 00:34:39 +02:00
|
|
|
|
2016-12-29 20:40:24 +01:00
|
|
|
atapi_command_ready(ide_board, len);
|
2017-01-04 06:33:18 +01:00
|
|
|
|
|
|
|
|
if (len == 0)
|
|
|
|
|
{
|
|
|
|
|
ide->packetstatus = ATAPI_STATUS_COMPLETE;
|
|
|
|
|
idecallback[ide_board]=50*IDE_TIME;
|
|
|
|
|
}
|
2016-12-29 20:40:24 +01:00
|
|
|
return;
|
2016-06-26 00:34:39 +02:00
|
|
|
|
|
|
|
|
case GPCMD_MODE_SELECT_6:
|
2016-11-12 15:06:38 +01:00
|
|
|
case GPCMD_MODE_SELECT_10:
|
2016-12-29 20:40:24 +01:00
|
|
|
if (ide->packetstatus == ATAPI_STATUS_PACKET_RECEIVED)
|
2016-06-26 00:34:39 +02:00
|
|
|
{
|
2016-12-29 20:40:24 +01:00
|
|
|
ide->atastat = READY_STAT;
|
|
|
|
|
ide->secount=3;
|
|
|
|
|
// pclog("Recieve data packet!\n");
|
|
|
|
|
ide_irq_raise(ide);
|
|
|
|
|
ide->packetstatus=0xFF;
|
|
|
|
|
ide->pos=0;
|
2016-06-26 00:34:39 +02:00
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2016-12-29 20:40:24 +01:00
|
|
|
if (idebufferb[0] == GPCMD_MODE_SELECT_6)
|
|
|
|
|
{
|
|
|
|
|
len=idebufferb[4];
|
|
|
|
|
prefix_len = 6;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
len=(idebufferb[7]<<8)|idebufferb[8];
|
|
|
|
|
prefix_len = 10;
|
|
|
|
|
}
|
|
|
|
|
page_current = idebufferb[2];
|
|
|
|
|
if (page_flags[page_current] & PAGE_CHANGEABLE)
|
|
|
|
|
{
|
|
|
|
|
page_flags[page_current] |= PAGE_CHANGED;
|
|
|
|
|
}
|
|
|
|
|
ide->packetstatus = ATAPI_STATUS_PACKET_REQ;
|
|
|
|
|
ide->cylinder=len;
|
|
|
|
|
ide->secount=0;
|
|
|
|
|
ide->pos=0;
|
|
|
|
|
idecallback[ide_board]=60*IDE_TIME;
|
|
|
|
|
ide->packlen=len;
|
2017-01-04 06:33:18 +01:00
|
|
|
|
|
|
|
|
if (len == 0)
|
|
|
|
|
{
|
|
|
|
|
ide->packetstatus = ATAPI_STATUS_COMPLETE;
|
|
|
|
|
idecallback[ide_board]=50*IDE_TIME;
|
|
|
|
|
}
|
2016-12-29 20:40:24 +01:00
|
|
|
}
|
|
|
|
|
return;
|
2016-06-26 00:34:39 +02:00
|
|
|
|
|
|
|
|
case GPCMD_GET_CONFIGURATION:
|
2016-12-29 20:40:24 +01:00
|
|
|
temp_command = idebufferb[0];
|
|
|
|
|
/* XXX: could result in alignment problems in some architectures */
|
|
|
|
|
len = (idebufferb[7]<<8)|idebufferb[8];
|
|
|
|
|
alloc_length = len;
|
2016-06-26 00:34:39 +02:00
|
|
|
|
2016-12-29 20:40:24 +01:00
|
|
|
index = 0;
|
2016-06-26 00:34:39 +02:00
|
|
|
|
2016-12-29 20:40:24 +01:00
|
|
|
/* only feature 0 is supported */
|
|
|
|
|
if (idebufferb[2] != 0 || idebufferb[3] != 0)
|
2016-12-25 17:52:17 +01:00
|
|
|
{
|
2016-12-29 20:40:24 +01:00
|
|
|
atapi_invalid_field(ide);
|
2016-12-25 17:52:17 +01:00
|
|
|
return;
|
|
|
|
|
}
|
2016-12-29 20:40:24 +01:00
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* XXX: avoid overflow for io_buffer if len is bigger than
|
|
|
|
|
* the size of that buffer (dimensioned to max number of
|
|
|
|
|
* sectors to transfer at once)
|
|
|
|
|
*
|
|
|
|
|
* Only a problem if the feature/profiles grow.
|
|
|
|
|
*/
|
|
|
|
|
if (alloc_length > 512) /* XXX: assume 1 sector */
|
2016-12-25 17:38:01 +01:00
|
|
|
{
|
2016-12-29 20:40:24 +01:00
|
|
|
alloc_length = 512;
|
2016-12-25 17:38:01 +01:00
|
|
|
}
|
|
|
|
|
|
2016-12-29 20:40:24 +01:00
|
|
|
memset(idebufferb, 0, alloc_length);
|
|
|
|
|
/*
|
|
|
|
|
* the number of sectors from the media tells us which profile
|
|
|
|
|
* to use as current. 0 means there is no media
|
|
|
|
|
*/
|
|
|
|
|
if (len > CD_MAX_SECTORS)
|
|
|
|
|
{
|
|
|
|
|
idebufferb[6] = (MMC_PROFILE_DVD_ROM >> 8) & 0xff;
|
|
|
|
|
idebufferb[7] = MMC_PROFILE_DVD_ROM & 0xff;
|
|
|
|
|
}
|
|
|
|
|
else if (len <= CD_MAX_SECTORS)
|
|
|
|
|
{
|
|
|
|
|
idebufferb[6] = (MMC_PROFILE_CD_ROM >> 8) & 0xff;
|
|
|
|
|
idebufferb[7] = MMC_PROFILE_CD_ROM & 0xff;
|
|
|
|
|
}
|
|
|
|
|
idebufferb[10] = 0x02 | 0x01; /* persistent and current */
|
|
|
|
|
alloc_length = 12; /* headers: 8 + 4 */
|
|
|
|
|
alloc_length += SCSICDROMSetProfile(idebufferb, &index, MMC_PROFILE_DVD_ROM);
|
|
|
|
|
alloc_length += SCSICDROMSetProfile(idebufferb, &index, MMC_PROFILE_CD_ROM);
|
|
|
|
|
idebufferb[0] = ((alloc_length-4) >> 24) & 0xff;
|
|
|
|
|
idebufferb[1] = ((alloc_length-4) >> 16) & 0xff;
|
|
|
|
|
idebufferb[2] = ((alloc_length-4) >> 8) & 0xff;
|
|
|
|
|
idebufferb[3] = (alloc_length-4) & 0xff;
|
|
|
|
|
|
2017-01-04 06:33:18 +01:00
|
|
|
if (len == 0)
|
|
|
|
|
{
|
|
|
|
|
ide->packetstatus = ATAPI_STATUS_COMPLETE;
|
|
|
|
|
idecallback[ide_board]=50*IDE_TIME;
|
|
|
|
|
}
|
2017-01-05 04:36:37 +01:00
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
atapi_command_send_init(ide, temp_command, len, alloc_length);
|
|
|
|
|
atapi_command_ready(ide_board, len);
|
|
|
|
|
}
|
2016-12-29 20:40:24 +01:00
|
|
|
break;
|
2016-12-25 17:38:01 +01:00
|
|
|
|
2016-12-29 20:40:24 +01:00
|
|
|
case GPCMD_GET_EVENT_STATUS_NOTIFICATION:
|
2017-01-05 04:36:37 +01:00
|
|
|
gesn_cdb = (void *)idebufferb;
|
|
|
|
|
gesn_event_header = (void *)idebufferb;
|
2016-06-26 00:34:39 +02:00
|
|
|
|
2017-01-05 04:36:37 +01:00
|
|
|
/* It is fine by the MMC spec to not support async mode operations. */
|
|
|
|
|
if (!(gesn_cdb->polled & 0x01))
|
|
|
|
|
{ /* asynchronous mode */
|
|
|
|
|
/* Only polling is supported, asynchronous mode is not. */
|
|
|
|
|
atapi_invalid_field(ide);
|
|
|
|
|
return;
|
2016-12-29 20:40:24 +01:00
|
|
|
}
|
2016-06-26 00:34:39 +02:00
|
|
|
|
2017-01-05 04:36:37 +01:00
|
|
|
/* polling mode operation */
|
2016-06-26 00:34:39 +02:00
|
|
|
|
2017-01-05 04:36:37 +01:00
|
|
|
/*
|
|
|
|
|
* 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.
|
|
|
|
|
*/
|
|
|
|
|
if (gesn_cdb->class & (1 << GESN_MEDIA))
|
|
|
|
|
{
|
|
|
|
|
gesn_event_header->notification_class |= GESN_MEDIA;
|
|
|
|
|
used_len = SCSICDROMEventStatus(idebufferb);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
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);
|
|
|
|
|
|
|
|
|
|
atapi_command_send_init(ide, cdb[0], used_len, used_len);
|
|
|
|
|
atapi_command_ready(ide_board, used_len);
|
2016-12-29 20:40:24 +01:00
|
|
|
break;
|
2016-06-26 00:34:39 +02:00
|
|
|
|
2016-12-29 20:40:24 +01:00
|
|
|
case GPCMD_READ_DISC_INFORMATION:
|
|
|
|
|
if (cdrom->read_disc_information)
|
|
|
|
|
{
|
|
|
|
|
cdrom->read_disc_information(idebufferb);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
memset(idebufferb, 0, 34);
|
|
|
|
|
memset(idebufferb, 1, 9);
|
|
|
|
|
idebufferb[0] = 0;
|
|
|
|
|
idebufferb[1] = 32;
|
|
|
|
|
idebufferb[2] = 0xe; /* last session complete, disc finalized */
|
|
|
|
|
idebufferb[7] = 0x20; /* unrestricted use */
|
|
|
|
|
idebufferb[8] = 0x00; /* CD-ROM */
|
|
|
|
|
}
|
2016-06-26 00:34:39 +02:00
|
|
|
|
2016-12-29 20:40:24 +01:00
|
|
|
len=34;
|
2017-01-04 06:33:18 +01:00
|
|
|
if (len > alloc_length)
|
|
|
|
|
{
|
2017-01-04 06:35:11 +01:00
|
|
|
len = alloc_length;
|
2017-01-04 06:33:18 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (len == 0)
|
|
|
|
|
{
|
|
|
|
|
ide->packetstatus = ATAPI_STATUS_COMPLETE;
|
|
|
|
|
idecallback[ide_board]=50*IDE_TIME;
|
|
|
|
|
}
|
2017-01-05 04:36:37 +01:00
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
ide->packetstatus = ATAPI_STATUS_DATA;
|
|
|
|
|
ide->secount=2;
|
|
|
|
|
ide->cylinder=len;
|
|
|
|
|
ide->pos=0;
|
|
|
|
|
ide->packlen=len;
|
|
|
|
|
idecallback[ide_board]=60*IDE_TIME;
|
|
|
|
|
}
|
2016-12-29 20:40:24 +01:00
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case GPCMD_READ_TRACK_INFORMATION:
|
|
|
|
|
max_len = idebufferb[7];
|
|
|
|
|
max_len <<= 8;
|
|
|
|
|
max_len |= idebufferb[8];
|
|
|
|
|
|
|
|
|
|
track = ((uint32_t) idebufferb[2]) << 24;
|
|
|
|
|
track |= ((uint32_t) idebufferb[3]) << 16;
|
|
|
|
|
track |= ((uint32_t) idebufferb[4]) << 8;
|
|
|
|
|
track |= (uint32_t) idebufferb[5];
|
|
|
|
|
|
|
|
|
|
if (cdrom->read_track_information)
|
2016-06-26 00:34:39 +02:00
|
|
|
{
|
2016-12-29 20:40:24 +01:00
|
|
|
ret = cdrom->read_track_information(idebufferb, idebufferb);
|
|
|
|
|
|
|
|
|
|
if (!ret)
|
2016-06-26 00:34:39 +02:00
|
|
|
{
|
2016-12-29 20:40:24 +01:00
|
|
|
atapi_invalid_field(ide);
|
2016-06-26 00:34:39 +02:00
|
|
|
return;
|
|
|
|
|
}
|
2016-12-29 20:40:24 +01:00
|
|
|
|
|
|
|
|
len = idebufferb[0];
|
|
|
|
|
len <<= 8;
|
|
|
|
|
len |= idebufferb[1];
|
|
|
|
|
len += 2;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
if (((idebufferb[1] & 0x03) != 1) || (track != 1))
|
2016-06-26 00:34:39 +02:00
|
|
|
{
|
2016-12-29 20:40:24 +01:00
|
|
|
atapi_invalid_field(ide);
|
|
|
|
|
return;
|
2016-06-26 00:34:39 +02:00
|
|
|
}
|
|
|
|
|
|
2016-12-29 20:40:24 +01:00
|
|
|
len = 36;
|
|
|
|
|
|
|
|
|
|
memset(idebufferb, 0, 36);
|
|
|
|
|
idebufferb[1] = 34;
|
|
|
|
|
idebufferb[2] = 1; /* track number (LSB) */
|
|
|
|
|
idebufferb[3] = 1; /* session number (LSB) */
|
|
|
|
|
idebufferb[5] = (0 << 5) | (0 << 4) | (4 << 0); /* not damaged, primary copy, data track */
|
|
|
|
|
idebufferb[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 */
|
|
|
|
|
idebufferb[7] = (0 << 1) | (0 << 0); /* last recorded address not valid, next recordable address not valid */
|
|
|
|
|
idebufferb[24] = (cdrom->size() >> 24) & 0xff; /* track size */
|
|
|
|
|
idebufferb[25] = (cdrom->size() >> 16) & 0xff; /* track size */
|
|
|
|
|
idebufferb[26] = (cdrom->size() >> 8) & 0xff; /* track size */
|
|
|
|
|
idebufferb[27] = cdrom->size() & 0xff; /* track size */
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (len > max_len)
|
|
|
|
|
{
|
|
|
|
|
len = max_len;
|
|
|
|
|
idebufferb[0] = ((max_len - 2) >> 8) & 0xff;
|
|
|
|
|
idebufferb[1] = (max_len - 2) & 0xff;
|
|
|
|
|
}
|
|
|
|
|
|
2017-01-04 06:33:18 +01:00
|
|
|
if (len == 0)
|
|
|
|
|
{
|
|
|
|
|
ide->packetstatus = ATAPI_STATUS_COMPLETE;
|
|
|
|
|
idecallback[ide_board]=50*IDE_TIME;
|
|
|
|
|
}
|
2017-01-05 04:36:37 +01:00
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
ide->packetstatus = ATAPI_STATUS_DATA;
|
|
|
|
|
ide->cylinder=len;
|
|
|
|
|
ide->secount=2;
|
|
|
|
|
ide->pos=0;
|
|
|
|
|
idecallback[ide_board]=60*IDE_TIME;
|
|
|
|
|
ide->packlen=len;
|
|
|
|
|
}
|
2017-01-04 06:33:18 +01:00
|
|
|
break;
|
2016-12-29 20:40:24 +01:00
|
|
|
|
|
|
|
|
case GPCMD_PLAY_AUDIO_10:
|
|
|
|
|
case GPCMD_PLAY_AUDIO_12:
|
|
|
|
|
case GPCMD_PLAY_AUDIO_MSF:
|
|
|
|
|
if (idebufferb[0] == GPCMD_PLAY_AUDIO_10)
|
|
|
|
|
{
|
|
|
|
|
pos=(idebufferb[2]<<24)|(idebufferb[3]<<16)|(idebufferb[4]<<8)|idebufferb[5];
|
|
|
|
|
len=(idebufferb[7]<<8)|idebufferb[8];
|
|
|
|
|
}
|
|
|
|
|
else if (idebufferb[0] == 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. */
|
|
|
|
|
pos=(idebufferb[3]<<16)|(idebufferb[4]<<8)|idebufferb[5];
|
|
|
|
|
len=(idebufferb[6]<<16)|(idebufferb[7]<<8)|idebufferb[8];
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
pos=(idebufferb[3]<<16)|(idebufferb[4]<<8)|idebufferb[5];
|
|
|
|
|
len=(idebufferb[7]<<16)|(idebufferb[8]<<8)|idebufferb[9];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ((cdrom_drive < 1) || (cdrom_drive == CDROM_ISO) || (cd_status <= CD_STATUS_DATA_ONLY) ||
|
|
|
|
|
!cdrom->is_track_audio(pos, (idebufferb[0] == GPCMD_PLAY_AUDIO_MSF) ? 1 : 0))
|
|
|
|
|
{
|
|
|
|
|
atapi_illegal_mode(ide);
|
|
|
|
|
break;
|
|
|
|
|
}
|
2016-06-26 00:34:39 +02:00
|
|
|
|
2016-12-29 20:40:24 +01:00
|
|
|
cdrom->playaudio(pos, len, (idebufferb[0] == GPCMD_PLAY_AUDIO_MSF) ? 1 : 0);
|
|
|
|
|
ide->packetstatus = ATAPI_STATUS_COMPLETE;
|
|
|
|
|
idecallback[ide_board]=50*IDE_TIME;
|
|
|
|
|
break;
|
2016-06-26 00:34:39 +02:00
|
|
|
|
2016-12-29 20:40:24 +01:00
|
|
|
case GPCMD_READ_SUBCHANNEL:
|
2017-01-04 22:33:49 +01:00
|
|
|
if (idebufferb[3] > 3)
|
2016-12-29 20:40:24 +01:00
|
|
|
{
|
|
|
|
|
// pclog("Read subchannel check condition %02X\n",idebufferb[3]);
|
2017-01-04 21:44:01 +01:00
|
|
|
atapi_invalid_field(ide);
|
2016-12-29 20:40:24 +01:00
|
|
|
break;
|
|
|
|
|
}
|
2016-06-26 00:34:39 +02:00
|
|
|
|
2017-01-04 22:33:49 +01:00
|
|
|
switch(idebufferb[3])
|
2016-12-29 20:40:24 +01:00
|
|
|
{
|
2017-01-04 22:33:49 +01:00
|
|
|
case 0:
|
|
|
|
|
alloc_length = 4;
|
|
|
|
|
break;
|
|
|
|
|
case 1:
|
|
|
|
|
alloc_length = 16;
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
alloc_length = 24;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (cdrom->read_subchannel)
|
|
|
|
|
{
|
|
|
|
|
cdrom->read_subchannel(idebufferb, idebufferb);
|
|
|
|
|
len = alloc_length;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
temp = idebufferb[3] & 3;
|
|
|
|
|
temp |= (idebufferb[2] & 0x40);
|
|
|
|
|
memset(idebufferb, 24, 0);
|
|
|
|
|
pos = 0;
|
|
|
|
|
idebufferb[pos++]=0;
|
|
|
|
|
idebufferb[pos++]=0; /*Audio status*/
|
|
|
|
|
idebufferb[pos++]=0; idebufferb[pos++]=0; /*Subchannel length*/
|
|
|
|
|
idebufferb[pos++]=temp & 3; /*Format code*/
|
|
|
|
|
if ((temp & 3) == 1)
|
|
|
|
|
{
|
|
|
|
|
idebufferb[1]=cdrom->getcurrentsubchannel(&idebufferb[5],msf);
|
|
|
|
|
}
|
|
|
|
|
if (!(temp & 0x40) || ((temp & 3) == 0))
|
|
|
|
|
{
|
|
|
|
|
len=4;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
len = alloc_length;
|
|
|
|
|
}
|
2016-12-29 20:40:24 +01:00
|
|
|
}
|
|
|
|
|
ide->packetstatus = ATAPI_STATUS_DATA;
|
|
|
|
|
ide->cylinder=len;
|
|
|
|
|
ide->secount=2;
|
|
|
|
|
ide->pos=0;
|
|
|
|
|
idecallback[ide_board]=1000*IDE_TIME;
|
|
|
|
|
ide->packlen=len;
|
|
|
|
|
break;
|
2016-06-26 00:34:39 +02:00
|
|
|
|
2016-12-29 20:40:24 +01:00
|
|
|
case GPCMD_READ_DVD_STRUCTURE:
|
|
|
|
|
temp_command = idebufferb[0];
|
|
|
|
|
media = idebufferb[1];
|
|
|
|
|
format = idebufferb[7];
|
2016-06-26 00:34:39 +02:00
|
|
|
|
2016-12-29 20:40:24 +01:00
|
|
|
len = (((uint32_t) idebufferb[6])<<24)|(((uint32_t) idebufferb[7])<<16)|(((uint32_t) idebufferb[8])<<8)|((uint32_t) idebufferb[9]);
|
|
|
|
|
alloc_length = len;
|
2016-06-26 00:34:39 +02:00
|
|
|
|
2016-12-29 20:40:24 +01:00
|
|
|
if (format < 0xff)
|
|
|
|
|
{
|
|
|
|
|
if (len <= CD_MAX_SECTORS)
|
2016-12-23 03:16:24 +01:00
|
|
|
{
|
2016-12-29 20:40:24 +01:00
|
|
|
atapi_incompatible_format(ide);
|
|
|
|
|
break;
|
2016-12-23 03:16:24 +01:00
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2016-12-29 20:40:24 +01:00
|
|
|
atapi_invalid_field(ide);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
memset(idebufferb, 0, (alloc_length > 256 * 512 + 4) ? (256 * 512 + 4) : alloc_length);
|
|
|
|
|
|
|
|
|
|
switch (format)
|
|
|
|
|
{
|
|
|
|
|
case 0x00 ... 0x7f:
|
|
|
|
|
case 0xff:
|
|
|
|
|
|
|
|
|
|
if (media == 0)
|
|
|
|
|
{
|
|
|
|
|
ret = SCSICDROMReadDVDStructure(format, idebufferb, idebufferb);
|
|
|
|
|
|
|
|
|
|
if (ret < 0)
|
|
|
|
|
{
|
|
|
|
|
atapi_cmd_error(ide, SENSE_ILLEGAL_REQUEST, -ret, 0);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
atapi_command_send_init(ide, temp_command, len, alloc_length);
|
|
|
|
|
atapi_command_ready(ide_board, len);
|
|
|
|
|
}
|
|
|
|
|
break;
|
2016-12-23 03:16:24 +01:00
|
|
|
}
|
2016-12-29 20:40:24 +01:00
|
|
|
/* TODO: BD support, fall through for now */
|
|
|
|
|
|
|
|
|
|
/* Generic disk structures */
|
|
|
|
|
case 0x80: /* TODO: AACS volume identifier */
|
|
|
|
|
case 0x81: /* TODO: AACS media serial number */
|
|
|
|
|
case 0x82: /* TODO: AACS media identifier */
|
|
|
|
|
case 0x83: /* TODO: AACS media key block */
|
|
|
|
|
case 0x90: /* TODO: List of recognized format layers */
|
|
|
|
|
case 0xc0: /* TODO: Write protection status */
|
|
|
|
|
default:
|
|
|
|
|
atapi_invalid_field(ide);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case GPCMD_START_STOP_UNIT:
|
2017-01-04 05:58:44 +01:00
|
|
|
switch(idebufferb[4] & 3)
|
2016-12-29 20:40:24 +01:00
|
|
|
{
|
2017-01-04 05:58:44 +01:00
|
|
|
case 0: /* Stop the disc. */
|
|
|
|
|
cdrom->stop();
|
|
|
|
|
break;
|
|
|
|
|
case 1: /* Start the disc and read the TOC. */
|
|
|
|
|
cdrom->medium_changed(); /* This causes a TOC reload. */
|
|
|
|
|
break;
|
|
|
|
|
case 2: /* Eject the disc if possible. */
|
|
|
|
|
cdrom->stop();
|
|
|
|
|
#ifndef __unix
|
|
|
|
|
win_cdrom_eject();
|
|
|
|
|
#endif
|
|
|
|
|
break;
|
|
|
|
|
case 3: /* Load the disc (close tray). */
|
|
|
|
|
#ifndef __unix
|
|
|
|
|
win_cdrom_reload();
|
|
|
|
|
#else
|
|
|
|
|
cdrom->load();
|
|
|
|
|
#endif
|
|
|
|
|
break;
|
2016-12-29 20:40:24 +01:00
|
|
|
}
|
2017-01-04 05:58:44 +01:00
|
|
|
|
2016-12-29 20:40:24 +01:00
|
|
|
ide->packetstatus = ATAPI_STATUS_COMPLETE;
|
|
|
|
|
idecallback[ide_board]=50*IDE_TIME;
|
|
|
|
|
break;
|
2016-06-26 00:34:39 +02:00
|
|
|
|
2016-12-29 20:40:24 +01:00
|
|
|
case GPCMD_INQUIRY:
|
|
|
|
|
page_code = idebufferb[2];
|
|
|
|
|
max_len = idebufferb[4];
|
|
|
|
|
alloc_length = max_len;
|
|
|
|
|
temp_command = idebufferb[0];
|
2016-06-26 00:34:39 +02:00
|
|
|
|
2016-12-29 20:40:24 +01:00
|
|
|
if (idebufferb[1] & 1)
|
|
|
|
|
{
|
|
|
|
|
preamble_len = 4;
|
|
|
|
|
size_idx = 3;
|
|
|
|
|
|
|
|
|
|
idebufferb[idx++] = 05;
|
|
|
|
|
idebufferb[idx++] = page_code;
|
|
|
|
|
idebufferb[idx++] = 0;
|
|
|
|
|
|
|
|
|
|
idx++;
|
|
|
|
|
|
|
|
|
|
switch (page_code)
|
|
|
|
|
{
|
|
|
|
|
case 0x00:
|
|
|
|
|
idebufferb[idx++] = 0x00;
|
|
|
|
|
idebufferb[idx++] = 0x83;
|
|
|
|
|
break;
|
|
|
|
|
case 0x83:
|
|
|
|
|
if (idx + 24 > max_len)
|
|
|
|
|
{
|
|
|
|
|
atapi_data_phase_error(ide);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
idebufferb[idx++] = 0x02;
|
|
|
|
|
idebufferb[idx++] = 0x00;
|
|
|
|
|
idebufferb[idx++] = 0x00;
|
|
|
|
|
idebufferb[idx++] = 20;
|
|
|
|
|
ide_padstr8(idebufferb + idx, 20, "53R141"); /* Serial */
|
|
|
|
|
idx += 20;
|
|
|
|
|
|
|
|
|
|
if (idx + 72 > max_len)
|
|
|
|
|
{
|
|
|
|
|
goto atapi_out;
|
|
|
|
|
}
|
|
|
|
|
idebufferb[idx++] = 0x02;
|
|
|
|
|
idebufferb[idx++] = 0x01;
|
|
|
|
|
idebufferb[idx++] = 0x00;
|
|
|
|
|
idebufferb[idx++] = 68;
|
|
|
|
|
ide_padstr8(idebufferb + idx, 8, "86Box"); /* Vendor */
|
|
|
|
|
idx += 8;
|
|
|
|
|
ide_padstr8(idebufferb + idx, 40, "86BoxCD v1.0"); /* Product */
|
|
|
|
|
idx += 40;
|
|
|
|
|
ide_padstr8(idebufferb + idx, 20, "53R141"); /* Product */
|
|
|
|
|
idx += 20;
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
atapi_invalid_field(ide);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
preamble_len = 5;
|
|
|
|
|
size_idx = 4;
|
|
|
|
|
|
|
|
|
|
memset(idebufferb, 0, 8);
|
|
|
|
|
idebufferb[0] = 5; /*CD-ROM*/
|
|
|
|
|
idebufferb[1] = 0x80; /*Removable*/
|
|
|
|
|
idebufferb[3] = 0x21;
|
|
|
|
|
idebufferb[4] = 31;
|
|
|
|
|
|
|
|
|
|
ide_padstr8(idebufferb + 8, 8, "86Box"); /* Vendor */
|
|
|
|
|
ide_padstr8(idebufferb + 16, 16, "86BoxCD"); /* Product */
|
|
|
|
|
ide_padstr8(idebufferb + 32, 4, emulator_version); /* Revision */
|
|
|
|
|
idx = 36;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
atapi_out:
|
|
|
|
|
idebufferb[size_idx] = idx - preamble_len;
|
|
|
|
|
len=idx;
|
2017-01-04 05:58:44 +01:00
|
|
|
if (len > alloc_length)
|
|
|
|
|
{
|
|
|
|
|
len = alloc_length;
|
|
|
|
|
}
|
2016-12-29 20:40:24 +01:00
|
|
|
|
2017-01-04 06:33:18 +01:00
|
|
|
if (len == 0)
|
|
|
|
|
{
|
|
|
|
|
ide->packetstatus = ATAPI_STATUS_COMPLETE;
|
|
|
|
|
idecallback[ide_board]=50*IDE_TIME;
|
|
|
|
|
}
|
2017-01-05 04:36:37 +01:00
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
atapi_command_send_init(ide, temp_command, len, alloc_length);
|
|
|
|
|
atapi_command_ready(ide_board, len);
|
|
|
|
|
}
|
2016-12-29 20:40:24 +01:00
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case GPCMD_PREVENT_REMOVAL:
|
|
|
|
|
ide->packetstatus = ATAPI_STATUS_COMPLETE;
|
|
|
|
|
idecallback[ide_board]=50*IDE_TIME;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case GPCMD_PAUSE_RESUME:
|
|
|
|
|
if (idebufferb[8] & 1)
|
|
|
|
|
{
|
|
|
|
|
cdrom->resume();
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
cdrom->pause();
|
|
|
|
|
}
|
|
|
|
|
ide->packetstatus = ATAPI_STATUS_COMPLETE;
|
|
|
|
|
idecallback[ide_board]=50*IDE_TIME;
|
|
|
|
|
break;
|
|
|
|
|
|
2016-12-29 20:49:01 +01:00
|
|
|
case GPCMD_SEEK_6:
|
2016-12-30 00:42:54 +01:00
|
|
|
case GPCMD_SEEK_10:
|
2016-12-29 20:49:01 +01:00
|
|
|
if (idebufferb[0] == GPCMD_SEEK_6)
|
|
|
|
|
{
|
|
|
|
|
pos=(idebufferb[2]<<8)|idebufferb[3];
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
pos=(idebufferb[2]<<24)|(idebufferb[3]<<16)|(idebufferb[4]<<8)|idebufferb[5];
|
|
|
|
|
}
|
2016-12-29 20:40:24 +01:00
|
|
|
cdrom->seek(pos);
|
|
|
|
|
ide->packetstatus = ATAPI_STATUS_COMPLETE;
|
|
|
|
|
idecallback[ide_board]=50*IDE_TIME;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case GPCMD_READ_CDROM_CAPACITY:
|
|
|
|
|
atapi_command_send_init(ide, temp_command, 8, 8);
|
|
|
|
|
if (cdrom->read_capacity)
|
|
|
|
|
{
|
|
|
|
|
cdrom->read_capacity(idebufferb);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
size = cdrom->size() - 1; /* IMPORTANT: What's returned is the last LBA block. */
|
|
|
|
|
memset(idebufferb, 0, 8);
|
|
|
|
|
idebufferb[0] = (size >> 24) & 0xff;
|
|
|
|
|
idebufferb[1] = (size >> 16) & 0xff;
|
|
|
|
|
idebufferb[2] = (size >> 8) & 0xff;
|
|
|
|
|
idebufferb[3] = size & 0xff;
|
|
|
|
|
idebufferb[6] = 8; /* 2048 = 0x0800 */
|
|
|
|
|
}
|
|
|
|
|
len=8;
|
|
|
|
|
atapi_command_ready(ide_board, len);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case GPCMD_STOP_PLAY_SCAN:
|
|
|
|
|
cdrom->stop();
|
|
|
|
|
ide->packetstatus = ATAPI_STATUS_COMPLETE;
|
|
|
|
|
idecallback[ide_board]=50*IDE_TIME;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
atapi_illegal_opcode(ide);
|
|
|
|
|
break;
|
|
|
|
|
}
|
2017-01-04 05:58:44 +01:00
|
|
|
|
2017-01-04 20:37:31 +01:00
|
|
|
// pclog("SCSI phase: %02X, length: %i\n", ide->secount, ide->cylinder);
|
2016-06-26 00:34:39 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void callnonreadcd(IDE *ide) /* Callabck for non-Read CD commands */
|
|
|
|
|
{
|
|
|
|
|
ide_irq_lower(ide);
|
|
|
|
|
if (ide->pos >= ide->packlen)
|
|
|
|
|
{
|
|
|
|
|
// pclog("Command finished, setting callback\n");
|
|
|
|
|
ide->packetstatus = ATAPI_STATUS_COMPLETE;
|
|
|
|
|
idecallback[ide->board]=20*IDE_TIME;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
// pclog("Command not finished, keep sending data\n");
|
|
|
|
|
ide->atastat = BUSY_STAT;
|
|
|
|
|
ide->packetstatus = ATAPI_STATUS_REQ_SENSE;
|
|
|
|
|
ide->cylinder=2;
|
|
|
|
|
ide->secount=2;
|
|
|
|
|
idecallback[ide->board]=60*IDE_TIME;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void callreadcd(IDE *ide)
|
|
|
|
|
{
|
2016-12-29 20:40:24 +01:00
|
|
|
int ret;
|
2016-11-17 20:41:27 +01:00
|
|
|
|
2016-12-29 20:40:24 +01:00
|
|
|
ide_irq_lower(ide);
|
|
|
|
|
if (SectorLen<=0)
|
|
|
|
|
{
|
|
|
|
|
// pclog("All done - callback set\n");
|
|
|
|
|
ide->packetstatus = ATAPI_STATUS_COMPLETE;
|
|
|
|
|
idecallback[ide->board]=20*IDE_TIME;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
// pclog("Continue readcd! %i blocks left\n",SectorLen);
|
2017-01-04 20:37:31 +01:00
|
|
|
// pclog("Reading sector: %i, length: %i\n", SectorLen, SectorLBA);
|
2016-12-29 20:40:24 +01:00
|
|
|
ide->atastat = BUSY_STAT;
|
|
|
|
|
|
|
|
|
|
ret = cdrom_read_data((uint8_t *) ide->buffer);
|
|
|
|
|
readflash=1;
|
|
|
|
|
|
|
|
|
|
SectorLBA++;
|
|
|
|
|
SectorLen--;
|
|
|
|
|
ide->packetstatus = ATAPI_STATUS_READCD;
|
|
|
|
|
ide->cylinder=cdrom_sector_size;
|
|
|
|
|
ide->secount=2;
|
|
|
|
|
ide->pos=0;
|
|
|
|
|
idecallback[ide->board]=60*IDE_TIME;
|
|
|
|
|
ide->packlen=cdrom_sector_size;
|
2016-06-26 00:34:39 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void ide_write_pri(uint16_t addr, uint8_t val, void *priv)
|
|
|
|
|
{
|
|
|
|
|
writeide(0, addr, val);
|
|
|
|
|
}
|
|
|
|
|
void ide_write_pri_w(uint16_t addr, uint16_t val, void *priv)
|
|
|
|
|
{
|
|
|
|
|
writeidew(0, val);
|
|
|
|
|
}
|
|
|
|
|
void ide_write_pri_l(uint16_t addr, uint32_t val, void *priv)
|
|
|
|
|
{
|
|
|
|
|
writeidel(0, val);
|
|
|
|
|
}
|
|
|
|
|
uint8_t ide_read_pri(uint16_t addr, void *priv)
|
|
|
|
|
{
|
|
|
|
|
return readide(0, addr);
|
|
|
|
|
}
|
|
|
|
|
uint16_t ide_read_pri_w(uint16_t addr, void *priv)
|
|
|
|
|
{
|
|
|
|
|
return readidew(0);
|
|
|
|
|
}
|
|
|
|
|
uint32_t ide_read_pri_l(uint16_t addr, void *priv)
|
|
|
|
|
{
|
|
|
|
|
return readidel(0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void ide_write_sec(uint16_t addr, uint8_t val, void *priv)
|
|
|
|
|
{
|
|
|
|
|
writeide(1, addr, val);
|
|
|
|
|
}
|
|
|
|
|
void ide_write_sec_w(uint16_t addr, uint16_t val, void *priv)
|
|
|
|
|
{
|
|
|
|
|
writeidew(1, val);
|
|
|
|
|
}
|
|
|
|
|
void ide_write_sec_l(uint16_t addr, uint32_t val, void *priv)
|
|
|
|
|
{
|
|
|
|
|
writeidel(1, val);
|
|
|
|
|
}
|
|
|
|
|
uint8_t ide_read_sec(uint16_t addr, void *priv)
|
|
|
|
|
{
|
|
|
|
|
return readide(1, addr);
|
|
|
|
|
}
|
|
|
|
|
uint16_t ide_read_sec_w(uint16_t addr, void *priv)
|
|
|
|
|
{
|
|
|
|
|
return readidew(1);
|
|
|
|
|
}
|
|
|
|
|
uint32_t ide_read_sec_l(uint16_t addr, void *priv)
|
|
|
|
|
{
|
|
|
|
|
return readidel(1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* *** REMOVE FROM CODE SUBMITTED TO MAINLINE - START *** */
|
|
|
|
|
void ide_write_ter(uint16_t addr, uint8_t val, void *priv)
|
|
|
|
|
{
|
|
|
|
|
writeide(2, addr, val);
|
|
|
|
|
}
|
|
|
|
|
void ide_write_ter_w(uint16_t addr, uint16_t val, void *priv)
|
|
|
|
|
{
|
|
|
|
|
writeidew(2, val);
|
|
|
|
|
}
|
|
|
|
|
void ide_write_ter_l(uint16_t addr, uint32_t val, void *priv)
|
|
|
|
|
{
|
|
|
|
|
writeidel(2, val);
|
|
|
|
|
}
|
|
|
|
|
uint8_t ide_read_ter(uint16_t addr, void *priv)
|
|
|
|
|
{
|
|
|
|
|
return readide(2, addr);
|
|
|
|
|
}
|
|
|
|
|
uint16_t ide_read_ter_w(uint16_t addr, void *priv)
|
|
|
|
|
{
|
|
|
|
|
return readidew(2);
|
|
|
|
|
}
|
|
|
|
|
uint32_t ide_read_ter_l(uint16_t addr, void *priv)
|
|
|
|
|
{
|
|
|
|
|
return readidel(2);
|
|
|
|
|
}
|
2016-12-28 23:34:00 +01:00
|
|
|
|
|
|
|
|
void ide_write_qua(uint16_t addr, uint8_t val, void *priv)
|
|
|
|
|
{
|
|
|
|
|
writeide(3, addr, val);
|
|
|
|
|
}
|
|
|
|
|
void ide_write_qua_w(uint16_t addr, uint16_t val, void *priv)
|
|
|
|
|
{
|
|
|
|
|
writeidew(3, val);
|
|
|
|
|
}
|
|
|
|
|
void ide_write_qua_l(uint16_t addr, uint32_t val, void *priv)
|
|
|
|
|
{
|
|
|
|
|
writeidel(3, val);
|
|
|
|
|
}
|
|
|
|
|
uint8_t ide_read_qua(uint16_t addr, void *priv)
|
|
|
|
|
{
|
|
|
|
|
return readide(3, addr);
|
|
|
|
|
}
|
|
|
|
|
uint16_t ide_read_qua_w(uint16_t addr, void *priv)
|
|
|
|
|
{
|
|
|
|
|
return readidew(3);
|
|
|
|
|
}
|
|
|
|
|
uint32_t ide_read_qua_l(uint16_t addr, void *priv)
|
|
|
|
|
{
|
|
|
|
|
return readidel(3);
|
|
|
|
|
}
|
2016-06-26 00:34:39 +02:00
|
|
|
/* *** REMOVE FROM CODE SUBMITTED TO MAINLINE - END *** */
|
|
|
|
|
|
|
|
|
|
void ide_pri_enable()
|
|
|
|
|
{
|
|
|
|
|
io_sethandler(0x01f0, 0x0008, ide_read_pri, ide_read_pri_w, ide_read_pri_l, ide_write_pri, ide_write_pri_w, ide_write_pri_l, NULL);
|
|
|
|
|
io_sethandler(0x03f6, 0x0001, ide_read_pri, NULL, NULL, ide_write_pri, NULL, NULL , NULL);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void ide_pri_disable()
|
|
|
|
|
{
|
|
|
|
|
io_removehandler(0x01f0, 0x0008, ide_read_pri, ide_read_pri_w, ide_read_pri_l, ide_write_pri, ide_write_pri_w, ide_write_pri_l, NULL);
|
|
|
|
|
io_removehandler(0x03f6, 0x0001, ide_read_pri, NULL, NULL, ide_write_pri, NULL, NULL , NULL);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void ide_sec_enable()
|
|
|
|
|
{
|
|
|
|
|
io_sethandler(0x0170, 0x0008, ide_read_sec, ide_read_sec_w, ide_read_sec_l, ide_write_sec, ide_write_sec_w, ide_write_sec_l, NULL);
|
|
|
|
|
io_sethandler(0x0376, 0x0001, ide_read_sec, NULL, NULL, ide_write_sec, NULL, NULL , NULL);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void ide_sec_disable()
|
|
|
|
|
{
|
|
|
|
|
io_removehandler(0x0170, 0x0008, ide_read_sec, ide_read_sec_w, ide_read_sec_l, ide_write_sec, ide_write_sec_w, ide_write_sec_l, NULL);
|
|
|
|
|
io_removehandler(0x0376, 0x0001, ide_read_sec, NULL, NULL, ide_write_sec, NULL, NULL , NULL);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* *** REMOVE FROM CODE SUBMITTED TO MAINLINE - START *** */
|
|
|
|
|
void ide_ter_enable()
|
|
|
|
|
{
|
|
|
|
|
io_sethandler(0x0168, 0x0008, ide_read_ter, ide_read_ter_w, ide_read_ter_l, ide_write_ter, ide_write_ter_w, ide_write_ter_l, NULL);
|
|
|
|
|
io_sethandler(0x036e, 0x0001, ide_read_ter, NULL, NULL, ide_write_ter, NULL, NULL , NULL);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void ide_ter_disable()
|
|
|
|
|
{
|
|
|
|
|
io_removehandler(0x0168, 0x0008, ide_read_ter, ide_read_ter_w, ide_read_ter_l, ide_write_ter, ide_write_ter_w, ide_write_ter_l, NULL);
|
|
|
|
|
io_removehandler(0x036e, 0x0001, ide_read_ter, NULL, NULL, ide_write_ter, NULL, NULL , NULL);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void ide_ter_init()
|
|
|
|
|
{
|
|
|
|
|
ide_ter_enable();
|
|
|
|
|
|
|
|
|
|
timer_add(ide_callback_ter, &idecallback[2], &idecallback[2], NULL);
|
|
|
|
|
}
|
2016-12-28 23:34:00 +01:00
|
|
|
|
|
|
|
|
void ide_qua_enable()
|
|
|
|
|
{
|
|
|
|
|
io_sethandler(0x01e8, 0x0008, ide_read_qua, ide_read_qua_w, ide_read_qua_l, ide_write_qua, ide_write_qua_w, ide_write_qua_l, NULL);
|
|
|
|
|
io_sethandler(0x03ee, 0x0001, ide_read_qua, NULL, NULL, ide_write_qua, NULL, NULL , NULL);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void ide_qua_disable()
|
|
|
|
|
{
|
|
|
|
|
io_removehandler(0x01e8, 0x0008, ide_read_qua, ide_read_qua_w, ide_read_qua_l, ide_write_qua, ide_write_qua_w, ide_write_qua_l, NULL);
|
|
|
|
|
io_removehandler(0x03ee, 0x0001, ide_read_qua, NULL, NULL, ide_write_qua, NULL, NULL , NULL);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void ide_qua_init()
|
|
|
|
|
{
|
|
|
|
|
ide_qua_enable();
|
|
|
|
|
|
|
|
|
|
timer_add(ide_callback_qua, &idecallback[3], &idecallback[3], NULL);
|
|
|
|
|
}
|
2016-06-26 00:34:39 +02:00
|
|
|
/* *** REMOVE FROM CODE SUBMITTED TO MAINLINE - END *** */
|
|
|
|
|
|
|
|
|
|
void ide_init()
|
|
|
|
|
{
|
|
|
|
|
ide_pri_enable();
|
|
|
|
|
ide_sec_enable();
|
|
|
|
|
ide_bus_master_read_sector = ide_bus_master_write_sector = NULL;
|
|
|
|
|
|
|
|
|
|
timer_add(ide_callback_pri, &idecallback[0], &idecallback[0], NULL);
|
|
|
|
|
timer_add(ide_callback_sec, &idecallback[1], &idecallback[1], NULL);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void ide_set_bus_master(int (*read_sector)(int channel, uint8_t *data), int (*write_sector)(int channel, uint8_t *data), void (*set_irq)(int channel))
|
|
|
|
|
{
|
|
|
|
|
ide_bus_master_read_sector = read_sector;
|
|
|
|
|
ide_bus_master_write_sector = write_sector;
|
|
|
|
|
ide_bus_master_set_irq = set_irq;
|
|
|
|
|
}
|