ESDI MCA: implement HDD timings and fix status icon updating (#2538)
* esdi_mca: clang-format * esdi_mca: implement hdd timings * esdi_mca: fix drive status icon updating
This commit is contained in:
@@ -60,12 +60,14 @@
|
||||
* Copyright 2008-2018 Sarah Walker.
|
||||
* Copyright 2017,2018 Fred N. van Kempen.
|
||||
*/
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <wchar.h>
|
||||
#include <inttypes.h>
|
||||
#define HAVE_STDARG_H
|
||||
#include <86box/86box.h>
|
||||
#include <86box/device.h>
|
||||
@@ -80,7 +82,6 @@
|
||||
#include <86box/hdc.h>
|
||||
#include <86box/hdd.h>
|
||||
|
||||
|
||||
/* These are hardwired. */
|
||||
#define ESDI_IOADDR_PRI 0x3510
|
||||
#define ESDI_IOADDR_SEC 0x3518
|
||||
@@ -89,11 +90,9 @@
|
||||
#define BIOS_FILE_L "roms/hdd/esdi/90x8969.bin"
|
||||
#define BIOS_FILE_H "roms/hdd/esdi/90x8970.bin"
|
||||
|
||||
|
||||
#define ESDI_TIME 512
|
||||
#define ESDI_TIME 512.0
|
||||
#define CMD_ADAPTER 0
|
||||
|
||||
|
||||
typedef struct esdi_drive_t {
|
||||
int spt, hpc;
|
||||
int tracks;
|
||||
@@ -134,7 +133,6 @@ typedef struct esdi_t {
|
||||
int cmd_state;
|
||||
|
||||
int in_reset;
|
||||
uint64_t callback;
|
||||
pc_timer_t timer;
|
||||
|
||||
uint32_t rba;
|
||||
@@ -196,11 +194,9 @@ typedef struct esdi_t {
|
||||
#define STATUS_DEVICE(x) ((x) << 5)
|
||||
#define STATUS_DEVICE_HOST_ADAPTER (7 << 5)
|
||||
|
||||
|
||||
#ifdef ENABLE_ESDI_MCA_LOG
|
||||
int esdi_mca_do_log = ENABLE_ESDI_MCA_LOG;
|
||||
|
||||
|
||||
static void
|
||||
esdi_mca_log(const char *fmt, ...)
|
||||
{
|
||||
@@ -216,7 +212,6 @@ esdi_mca_log(const char *fmt, ...)
|
||||
# define esdi_mca_log(fmt, ...)
|
||||
#endif
|
||||
|
||||
|
||||
static __inline void
|
||||
set_irq(esdi_t *dev)
|
||||
{
|
||||
@@ -224,7 +219,6 @@ set_irq(esdi_t *dev)
|
||||
picint(1 << 14);
|
||||
}
|
||||
|
||||
|
||||
static __inline void
|
||||
clear_irq(esdi_t *dev)
|
||||
{
|
||||
@@ -232,21 +226,25 @@ clear_irq(esdi_t *dev)
|
||||
}
|
||||
|
||||
static void
|
||||
esdi_mca_set_callback(esdi_t *dev, uint64_t callback)
|
||||
esdi_mca_set_callback(esdi_t *dev, double callback)
|
||||
{
|
||||
if (!dev) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (callback) {
|
||||
dev->callback = callback;
|
||||
timer_on_auto(&dev->timer, dev->callback);
|
||||
timer_on_auto(&dev->timer, callback);
|
||||
} else {
|
||||
dev->callback = 0;
|
||||
timer_stop(&dev->timer);
|
||||
}
|
||||
}
|
||||
|
||||
static double
|
||||
esdi_mca_get_xfer_time(esdi_t *esdi, int size)
|
||||
{
|
||||
/* 390.625 us per sector at 10 Mbit/s = 1280 kB/s. */
|
||||
return (3125.0 / 8.0) * (double)size;
|
||||
}
|
||||
|
||||
static void
|
||||
cmd_unsupported(esdi_t *dev)
|
||||
@@ -266,9 +264,9 @@ cmd_unsupported(esdi_t *dev)
|
||||
dev->irq_status = dev->cmd_dev | IRQ_CMD_COMPLETE_FAILURE;
|
||||
dev->irq_in_progress = 1;
|
||||
set_irq(dev);
|
||||
ui_sb_update_icon(SB_HDD | HDD_BUS_ESDI, 0);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
device_not_present(esdi_t *dev)
|
||||
{
|
||||
@@ -287,9 +285,9 @@ device_not_present(esdi_t *dev)
|
||||
dev->irq_status = dev->cmd_dev | IRQ_CMD_COMPLETE_FAILURE;
|
||||
dev->irq_in_progress = 1;
|
||||
set_irq(dev);
|
||||
ui_sb_update_icon(SB_HDD | HDD_BUS_ESDI, 0);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
rba_out_of_range(esdi_t *dev)
|
||||
{
|
||||
@@ -308,9 +306,9 @@ rba_out_of_range(esdi_t *dev)
|
||||
dev->irq_status = dev->cmd_dev | IRQ_CMD_COMPLETE_FAILURE;
|
||||
dev->irq_in_progress = 1;
|
||||
set_irq(dev);
|
||||
ui_sb_update_icon(SB_HDD | HDD_BUS_ESDI, 0);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
complete_command_status(esdi_t *dev)
|
||||
{
|
||||
@@ -325,21 +323,20 @@ complete_command_status(esdi_t *dev)
|
||||
dev->status_data[4] = (dev->rba - 1) & 0xffff; /*Last RBA processed*/
|
||||
dev->status_data[5] = (dev->rba - 1) >> 8;
|
||||
dev->status_data[6] = 0; /*Number of blocks requiring error recovery*/
|
||||
ui_sb_update_icon(SB_HDD | HDD_BUS_ESDI, 0);
|
||||
}
|
||||
|
||||
#define ESDI_ADAPTER_ONLY() do \
|
||||
{ \
|
||||
if (dev->cmd_dev != ATTN_HOST_ADAPTER) \
|
||||
{ \
|
||||
#define ESDI_ADAPTER_ONLY() \
|
||||
do { \
|
||||
if (dev->cmd_dev != ATTN_HOST_ADAPTER) { \
|
||||
cmd_unsupported(dev); \
|
||||
return; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define ESDI_DRIVE_ONLY() do \
|
||||
{ \
|
||||
if (dev->cmd_dev != ATTN_DEVICE_0 && dev->cmd_dev != ATTN_DEVICE_1) \
|
||||
{ \
|
||||
#define ESDI_DRIVE_ONLY() \
|
||||
do { \
|
||||
if (dev->cmd_dev != ATTN_DEVICE_0 && dev->cmd_dev != ATTN_DEVICE_1) { \
|
||||
cmd_unsupported(dev); \
|
||||
return; \
|
||||
} \
|
||||
@@ -349,13 +346,13 @@ complete_command_status(esdi_t *dev)
|
||||
drive = &dev->drives[1]; \
|
||||
} while (0)
|
||||
|
||||
|
||||
static void
|
||||
esdi_callback(void *priv)
|
||||
{
|
||||
esdi_t *dev = (esdi_t *) priv;
|
||||
drive_t *drive;
|
||||
int val;
|
||||
double cmd_time = 0.0;
|
||||
|
||||
esdi_mca_set_callback(dev, 0);
|
||||
|
||||
@@ -410,14 +407,15 @@ esdi_callback(void *priv)
|
||||
if (dev->rba >= drive->sectors)
|
||||
fatal("Read past end of drive\n");
|
||||
hdd_image_read(drive->hdd_num, dev->rba, 1, (uint8_t *) dev->data);
|
||||
ui_sb_update_icon(SB_HDD | HDD_BUS_ESDI, 1);
|
||||
cmd_time += hdd_timing_read(&hdd[drive->hdd_num], dev->rba, 1);
|
||||
cmd_time += esdi_mca_get_xfer_time(dev, 1);
|
||||
}
|
||||
|
||||
while (dev->data_pos < 256) {
|
||||
val = dma_channel_write(dev->dma, dev->data[dev->data_pos]);
|
||||
|
||||
if (val == DMA_NODATA) {
|
||||
esdi_mca_set_callback(dev, ESDI_TIME);
|
||||
esdi_mca_set_callback(dev, ESDI_TIME + cmd_time);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -431,7 +429,7 @@ esdi_callback(void *priv)
|
||||
|
||||
dev->status = STATUS_CMD_IN_PROGRESS;
|
||||
dev->cmd_state = 2;
|
||||
esdi_mca_set_callback(dev, ESDI_TIME);
|
||||
esdi_mca_set_callback(dev, cmd_time);
|
||||
break;
|
||||
|
||||
case 2:
|
||||
@@ -485,7 +483,7 @@ esdi_callback(void *priv)
|
||||
val = dma_channel_read(dev->dma);
|
||||
|
||||
if (val == DMA_NODATA) {
|
||||
esdi_mca_set_callback(dev, ESDI_TIME);
|
||||
esdi_mca_set_callback(dev, ESDI_TIME + cmd_time);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -495,17 +493,16 @@ esdi_callback(void *priv)
|
||||
if (dev->rba >= drive->sectors)
|
||||
fatal("Write past end of drive\n");
|
||||
hdd_image_write(drive->hdd_num, dev->rba, 1, (uint8_t *) dev->data);
|
||||
cmd_time += hdd_timing_write(&hdd[drive->hdd_num], dev->rba, 1);
|
||||
cmd_time += esdi_mca_get_xfer_time(dev, 1);
|
||||
dev->rba++;
|
||||
dev->sector_pos++;
|
||||
ui_sb_update_icon(SB_HDD | HDD_BUS_ESDI,
|
||||
dev->cmd_dev == ATTN_DEVICE_0 ? 0 : 1);
|
||||
|
||||
dev->data_pos = 0;
|
||||
}
|
||||
|
||||
dev->status = STATUS_CMD_IN_PROGRESS;
|
||||
dev->cmd_state = 2;
|
||||
esdi_mca_set_callback(dev, ESDI_TIME);
|
||||
esdi_mca_set_callback(dev, cmd_time);
|
||||
break;
|
||||
|
||||
case 2:
|
||||
@@ -526,18 +523,30 @@ esdi_callback(void *priv)
|
||||
return;
|
||||
}
|
||||
|
||||
switch (dev->cmd_state) {
|
||||
case 0:
|
||||
dev->rba = (dev->cmd_data[2] | (dev->cmd_data[3] << 16)) & 0x0fffffff;
|
||||
dev->sector_count = dev->cmd_data[1];
|
||||
|
||||
if ((dev->rba + dev->sector_count) > hdd_image_get_last_sector(drive->hdd_num)) {
|
||||
rba_out_of_range(dev);
|
||||
return;
|
||||
}
|
||||
|
||||
dev->rba += dev->sector_count;
|
||||
cmd_time = hdd_timing_read(&hdd[drive->hdd_num], dev->rba, dev->sector_count);
|
||||
esdi_mca_set_callback(dev, ESDI_TIME + cmd_time);
|
||||
dev->cmd_state = 1;
|
||||
break;
|
||||
|
||||
case 1:
|
||||
complete_command_status(dev);
|
||||
dev->status = STATUS_IRQ | STATUS_STATUS_OUT_FULL;
|
||||
dev->irq_status = dev->cmd_dev | IRQ_CMD_COMPLETE_SUCCESS;
|
||||
dev->irq_in_progress = 1;
|
||||
set_irq(dev);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case CMD_SEEK:
|
||||
ESDI_DRIVE_ONLY();
|
||||
@@ -547,12 +556,28 @@ esdi_callback(void *priv)
|
||||
return;
|
||||
}
|
||||
|
||||
if ((dev->rba + dev->sector_count) > hdd_image_get_last_sector(drive->hdd_num)) {
|
||||
rba_out_of_range(dev);
|
||||
return;
|
||||
}
|
||||
|
||||
switch (dev->cmd_state) {
|
||||
case 0:
|
||||
dev->rba = (dev->cmd_data[2] | (dev->cmd_data[3] << 16)) & 0x0fffffff;
|
||||
cmd_time = hdd_seek_get_time(&hdd[drive->hdd_num], dev->rba, HDD_OP_SEEK, 0, 0.0);
|
||||
esdi_mca_set_callback(dev, ESDI_TIME + cmd_time);
|
||||
dev->cmd_state = 1;
|
||||
break;
|
||||
|
||||
case 1:
|
||||
complete_command_status(dev);
|
||||
dev->status = STATUS_IRQ | STATUS_STATUS_OUT_FULL;
|
||||
dev->irq_status = dev->cmd_dev | IRQ_CMD_COMPLETE_SUCCESS;
|
||||
dev->irq_in_progress = 1;
|
||||
set_irq(dev);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case CMD_GET_DEV_STATUS:
|
||||
ESDI_DRIVE_ONLY();
|
||||
@@ -580,6 +605,7 @@ esdi_callback(void *priv)
|
||||
dev->irq_status = dev->cmd_dev | IRQ_CMD_COMPLETE_SUCCESS;
|
||||
dev->irq_in_progress = 1;
|
||||
set_irq(dev);
|
||||
ui_sb_update_icon(SB_HDD | HDD_BUS_ESDI, 0);
|
||||
break;
|
||||
|
||||
case CMD_GET_DEV_CONFIG:
|
||||
@@ -611,6 +637,7 @@ esdi_callback(void *priv)
|
||||
dev->irq_status = dev->cmd_dev | IRQ_CMD_COMPLETE_SUCCESS;
|
||||
dev->irq_in_progress = 1;
|
||||
set_irq(dev);
|
||||
ui_sb_update_icon(SB_HDD | HDD_BUS_ESDI, 0);
|
||||
break;
|
||||
|
||||
case CMD_GET_POS_INFO:
|
||||
@@ -622,8 +649,7 @@ esdi_callback(void *priv)
|
||||
dev->status_len = 5;
|
||||
dev->status_data[0] = CMD_GET_POS_INFO | STATUS_LEN(5) | STATUS_DEVICE_HOST_ADAPTER;
|
||||
dev->status_data[1] = 0xffdd; /*MCA ID*/
|
||||
dev->status_data[2] = dev->pos_regs[3] |
|
||||
(dev->pos_regs[2] << 8);
|
||||
dev->status_data[2] = dev->pos_regs[3] | (dev->pos_regs[2] << 8);
|
||||
dev->status_data[3] = 0xff;
|
||||
dev->status_data[4] = 0xff;
|
||||
|
||||
@@ -631,6 +657,7 @@ esdi_callback(void *priv)
|
||||
dev->irq_status = IRQ_HOST_ADAPTER | IRQ_CMD_COMPLETE_SUCCESS;
|
||||
dev->irq_in_progress = 1;
|
||||
set_irq(dev);
|
||||
ui_sb_update_icon(SB_HDD | HDD_BUS_ESDI, 0);
|
||||
break;
|
||||
|
||||
case 0x10:
|
||||
@@ -666,7 +693,8 @@ esdi_callback(void *priv)
|
||||
return;
|
||||
}
|
||||
|
||||
dev->data[dev->data_pos++] = val & 0xffff;;
|
||||
dev->data[dev->data_pos++] = val & 0xffff;
|
||||
;
|
||||
}
|
||||
|
||||
memcpy(dev->sector_buffer[dev->sector_pos++], dev->data, 512);
|
||||
@@ -683,6 +711,7 @@ esdi_callback(void *priv)
|
||||
dev->irq_status = IRQ_HOST_ADAPTER | IRQ_CMD_COMPLETE_SUCCESS;
|
||||
dev->irq_in_progress = 1;
|
||||
set_irq(dev);
|
||||
ui_sb_update_icon(SB_HDD | HDD_BUS_ESDI, 0);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
@@ -739,6 +768,7 @@ esdi_callback(void *priv)
|
||||
dev->irq_status = IRQ_HOST_ADAPTER | IRQ_CMD_COMPLETE_SUCCESS;
|
||||
dev->irq_in_progress = 1;
|
||||
set_irq(dev);
|
||||
ui_sb_update_icon(SB_HDD | HDD_BUS_ESDI, 0);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
@@ -756,6 +786,7 @@ esdi_callback(void *priv)
|
||||
dev->irq_status = IRQ_HOST_ADAPTER | IRQ_CMD_COMPLETE_SUCCESS;
|
||||
dev->irq_in_progress = 1;
|
||||
set_irq(dev);
|
||||
ui_sb_update_icon(SB_HDD | HDD_BUS_ESDI, 0);
|
||||
break;
|
||||
|
||||
case CMD_FORMAT_UNIT:
|
||||
@@ -794,7 +825,6 @@ esdi_callback(void *priv)
|
||||
}
|
||||
|
||||
hdd_image_zero(drive->hdd_num, dev->rba, dev->sector_count);
|
||||
ui_sb_update_icon(SB_HDD | HDD_BUS_ESDI, 1);
|
||||
|
||||
dev->status = STATUS_CMD_IN_PROGRESS;
|
||||
dev->cmd_state = 2;
|
||||
@@ -816,7 +846,6 @@ esdi_callback(void *priv)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static uint8_t
|
||||
esdi_read(uint16_t port, void *priv)
|
||||
{
|
||||
@@ -840,7 +869,6 @@ esdi_read(uint16_t port, void *priv)
|
||||
return (ret);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
esdi_write(uint16_t port, uint8_t val, void *priv)
|
||||
{
|
||||
@@ -948,7 +976,6 @@ esdi_write(uint16_t port, uint8_t val, void *priv)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static uint16_t
|
||||
esdi_readw(uint16_t port, void *priv)
|
||||
{
|
||||
@@ -959,7 +986,8 @@ esdi_readw(uint16_t port, void *priv)
|
||||
case 0: /*Status Interface Register*/
|
||||
if (dev->status_pos >= dev->status_len)
|
||||
return (0);
|
||||
ret = dev->status_data[dev->status_pos++]; if (dev->status_pos >= dev->status_len) {
|
||||
ret = dev->status_data[dev->status_pos++];
|
||||
if (dev->status_pos >= dev->status_len) {
|
||||
dev->status &= ~STATUS_STATUS_OUT_FULL;
|
||||
dev->status_pos = dev->status_len = 0;
|
||||
}
|
||||
@@ -972,7 +1000,6 @@ esdi_readw(uint16_t port, void *priv)
|
||||
return (ret);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
esdi_writew(uint16_t port, uint16_t val, void *priv)
|
||||
{
|
||||
@@ -985,8 +1012,7 @@ esdi_writew(uint16_t port, uint16_t val, void *priv)
|
||||
if (dev->cmd_pos >= 4)
|
||||
fatal("CIR pos 4\n");
|
||||
dev->cmd_data[dev->cmd_pos++] = val;
|
||||
if (((dev->cmd_data[0] & CMD_SIZE_4) && dev->cmd_pos == 4) ||
|
||||
(!(dev->cmd_data[0] & CMD_SIZE_4) && dev->cmd_pos == 2)) {
|
||||
if (((dev->cmd_data[0] & CMD_SIZE_4) && dev->cmd_pos == 4) || (!(dev->cmd_data[0] & CMD_SIZE_4) && dev->cmd_pos == 2)) {
|
||||
dev->cmd_pos = 0;
|
||||
dev->cmd_req_in_progress = 0;
|
||||
dev->cmd_state = 0;
|
||||
@@ -997,6 +1023,7 @@ esdi_writew(uint16_t port, uint16_t val, void *priv)
|
||||
esdi_mca_set_callback(dev, ESDI_TIME);
|
||||
dev->status = STATUS_BUSY;
|
||||
dev->data_pos = 0;
|
||||
ui_sb_update_icon(SB_HDD | HDD_BUS_ESDI, 1);
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -1005,7 +1032,6 @@ esdi_writew(uint16_t port, uint16_t val, void *priv)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static uint8_t
|
||||
esdi_mca_read(int port, void *priv)
|
||||
{
|
||||
@@ -1016,7 +1042,6 @@ esdi_mca_read(int port, void *priv)
|
||||
return (dev->pos_regs[port & 7]);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
esdi_mca_write(int port, uint8_t val, void *priv)
|
||||
{
|
||||
@@ -1077,7 +1102,6 @@ esdi_mca_write(int port, uint8_t val, void *priv)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static uint8_t
|
||||
esdi_mca_feedb(void *priv)
|
||||
{
|
||||
@@ -1086,7 +1110,6 @@ esdi_mca_feedb(void *priv)
|
||||
return (dev->pos_regs[2] & 1);
|
||||
}
|
||||
|
||||
|
||||
static void *
|
||||
esdi_init(const device_t *info)
|
||||
{
|
||||
@@ -1095,7 +1118,8 @@ esdi_init(const device_t *info)
|
||||
int c, i;
|
||||
|
||||
dev = malloc(sizeof(esdi_t));
|
||||
if (dev == NULL) return(NULL);
|
||||
if (dev == NULL)
|
||||
return (NULL);
|
||||
memset(dev, 0x00, sizeof(esdi_t));
|
||||
|
||||
/* Mark as unconfigured. */
|
||||
@@ -1120,6 +1144,8 @@ esdi_init(const device_t *info)
|
||||
continue;
|
||||
}
|
||||
|
||||
hdd_preset_apply(i);
|
||||
|
||||
/* OK, so fill in geometry info. */
|
||||
drive->spt = hdd[i].spt;
|
||||
drive->hpc = hdd[i].hpc;
|
||||
@@ -1131,7 +1157,8 @@ esdi_init(const device_t *info)
|
||||
drive->present = 1;
|
||||
}
|
||||
|
||||
if (++c >= ESDI_NUM) break;
|
||||
if (++c >= ESDI_NUM)
|
||||
break;
|
||||
}
|
||||
|
||||
/* Set the MCA ID for this controller, 0xFFDD. */
|
||||
@@ -1152,7 +1179,6 @@ esdi_init(const device_t *info)
|
||||
return (dev);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
esdi_close(void *priv)
|
||||
{
|
||||
@@ -1171,7 +1197,6 @@ esdi_close(void *priv)
|
||||
free(dev);
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
esdi_available(void)
|
||||
{
|
||||
|
Reference in New Issue
Block a user