fdc.c revision c28fa006ba669ad8f26ae31d00a338379c04ea1b
#ifdef VBOX
/* $Id: $ */
/** @file
* VBox storage devices: Floppy disk controller
*/
/*
* Copyright (C) 2006-2007 Sun Microsystems, Inc.
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
* General Public License (GPL) as published by the Free Software
* Foundation, in version 2 as it comes in the "COPYING" file of the
* VirtualBox OSE distribution. VirtualBox OSE is distributed in the
* hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
*
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
* Clara, CA 95054 USA or visit http://www.sun.com if you need
* additional information or have any questions.
* --------------------------------------------------------------------
*
* This code is based on:
*
* QEMU Floppy disk emulator (Intel 82078)
*
* Copyright (c) 2003 Jocelyn Mayer
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*/
/*******************************************************************************
* Header Files *
*******************************************************************************/
#define LOG_GROUP LOG_GROUP_DEV_FDC
#include "Builtins.h"
#include "../vl_vbox.h"
#define MAX_FD 2
#define PDMIBASE_2_FDRIVE(pInterface) \
#define PDMIMOUNTNOTIFY_2_FDRIVE(p) \
#endif /* VBOX */
#ifndef VBOX
#include "vl.h"
#endif /* !VBOX */
/********************************************************/
/* debug Floppy devices */
/* #define DEBUG_FLOPPY */
#ifndef VBOX
#ifdef DEBUG_FLOPPY
#endif
#else /* !VBOX */
# ifdef LOG_ENABLED
static void FLOPPY_DPRINTF (const char *fmt, ...)
{
if (LogIsEnabled ()) {
RTLogLogger (NULL, NULL, "floppy: %N", fmt, &args); /* %N - nested va_list * type formatting call. */
}
}
# else
# endif
#endif /* !VBOX */
#ifndef VBOX
#else /* VBOX */
# define FLOPPY_ERROR RTLogPrintf
#endif /* VBOX */
#ifdef VBOX
#endif /* VBOX */
/********************************************************/
/* Floppy drive emulation */
/* Will always be a fixed parameter for us */
#define FD_SECTOR_LEN 512
/* Floppy disk drive emulation */
typedef enum fdisk_type_t {
} fdisk_type_t;
typedef enum fdrive_type_t {
typedef enum fdrive_flags_t {
typedef enum fdisk_flags_t {
FDISK_DBL_SIDES = 0x01
#ifdef VBOX
/**
* The status for one drive.
*
* @implements PDMIBASE
* @implements PDMIBLOCKPORT
* @implements PDMIMOUNTNOTIFY
*/
#endif
typedef struct fdrive_t {
#ifndef VBOX
#else /* VBOX */
/** Pointer to the attached driver's base interface. */
/** Pointer to the attached driver's block interface. */
/** Pointer to the attached driver's block bios interface. */
/** Pointer to the attached driver's mount interface.
* This is NULL if the driver isn't a removable unit. */
/** The base interface. */
/** The block port interface. */
/** The mount notify interface. */
/** The LUN #. */
/** The LED for this LUN. */
bool fMediaPresent;
#endif
/* Drive status */
/* Position */
/* Last operation status */
/* Media */
} fdrive_t;
#ifndef VBOX
{
/* Drive */
drv->perpendicular = 0;
/* Disk */
}
#endif
{
}
/* Returns current position, in sectors, for given drive */
{
}
int enable_seek)
{
int ret;
FLOPPY_DPRINTF("try to read %d %02x %02x (max=%d %d %02x %02x)\n",
return 2;
}
FLOPPY_DPRINTF("try to read %d %02x %02x (max=%d %d %02x %02x)\n",
return 3;
}
ret = 0;
#if 0
if (!enable_seek) {
FLOPPY_ERROR("no implicit seek %d %02x %02x (max=%d %02x %02x)\n",
return 4;
}
#endif
ret = 1;
}
return ret;
}
/* Set drive back to track 0 */
{
FLOPPY_DPRINTF("recalibrate\n");
}
/* Recognize floppy formats */
typedef struct fd_format_t {
const char *str;
} fd_format_t;
static fd_format_t fd_formats[] = {
/* First entry is default format */
/* 1.44 MB 3"1/2 floppy disks */
/* 2.88 MB 3"1/2 floppy disks */
/* 720 kB 3"1/2 floppy disks */
/* 1.2 MB 5"1/4 floppy disks */
/* 720 kB 5"1/4 floppy disks */
/* 360 kB 5"1/4 floppy disks */
/* 320 kB 5"1/4 floppy disks */
/* 360 kB must match 5"1/4 better than 3"1/2... */
/* end */
};
/* Revalidate a disk drive after a disk change */
{
int i, first_match, match;
FLOPPY_DPRINTF("revalidate\n");
#ifndef VBOX
#else /* VBOX */
/** @todo */ /** @todo r=bird: todo what exactly? */
nb_heads = 0;
max_track = 0;
last_sect = 0;
#endif /* VBOX */
FLOPPY_DPRINTF("User defined disk (%d %d %d)",
} else {
#ifndef VBOX
#else /* VBOX */
/* @todo */ /** @todo r=bird: todo what exactly?!?!? */
{
}
#endif /* VBOX */
match = -1;
first_match = -1;
for (i = 0;; i++) {
parse = &fd_formats[i];
break;
if (nb_sectors == size) {
match = i;
break;
}
if (first_match == -1)
first_match = i;
}
}
if (match == -1) {
if (first_match == -1)
match = 1;
else
match = first_match;
}
}
if (nb_heads == 1) {
} else {
}
#ifdef VBOX
drv->fMediaPresent = true;
#endif
} else {
FLOPPY_DPRINTF("No disk in drive\n");
#ifdef VBOX
drv->fMediaPresent = false;
#endif
}
}
/* Motor control */
{
}
{
}
/* Re-initialise a drives (motor off, repositioned) */
{
}
/********************************************************/
/* Intel 82078 floppy disk controller emulation */
#define target_ulong uint32_t
#ifndef VBOX
#else /* VBOX: */
void *opaque,
unsigned nchan,
#endif /* VBOX */
static void fdctrl_result_timer(void *opaque);
enum {
FD_CTRL_RESET = 0x02,
FD_CTRL_INTR = 0x10
};
enum {
FD_DIR_WRITE = 0,
FD_DIR_READ = 1,
FD_DIR_SCANE = 2,
FD_DIR_SCANL = 3,
FD_DIR_SCANH = 4
};
enum {
FD_STATE_CMD = 0x00,
FD_STATE_STATUS = 0x01,
FD_STATE_DATA = 0x02,
FD_STATE_STATE = 0x03,
FD_STATE_MULTI = 0x10,
FD_STATE_SEEK = 0x20,
FD_STATE_FORMAT = 0x40
};
#ifdef VBOX
/**
* Floppy controller state.
*
* @implements PDMILEDPORTS
*/
#endif
struct fdctrl_t {
#ifndef VBOX
#endif
/* Controller's identification */
/* HW */
#ifndef VBOX
int irq_lvl;
int dma_chann;
#else
#endif
/* Controller state */
/* Command FIFO */
/* States kept only to be returned back */
/* Timers state */
/* precompensation */
/* Power down config (also with status regB access mode */
/* Floppy drives */
#ifdef VBOX
/** Pointer to device instance. */
/** Status LUN: The base interface. */
/** Status LUN: The Leds interface. */
/** Status LUN: The Partner of ILeds. */
#endif
};
{
switch (reg & 0x07) {
case 0x01:
break;
case 0x02:
break;
case 0x03:
break;
case 0x04:
break;
case 0x05:
break;
case 0x07:
break;
default:
break;
}
return retval;
}
{
switch (reg & 0x07) {
case 0x02:
break;
case 0x03:
break;
case 0x04:
break;
case 0x05:
break;
default:
break;
}
}
#ifndef VBOX
static void fd_change_cb (void *opaque)
{
FLOPPY_DPRINTF("disk change\n");
#if 0
#endif
}
#else /* VBOX */
/**
* Called when a media is mounted.
*
* @param pInterface Pointer to the interface structure
* containing the called function pointer.
*/
{
LogFlow(("fdMountNotify:\n"));
fd_revalidate (drv);
}
/**
* Called when a media is unmounted
* @param pInterface Pointer to the interface structure containing the called function pointer.
*/
{
LogFlow(("fdUnmountNotify:\n"));
fd_revalidate (drv);
}
#endif
#ifndef VBOX
{
/* // int io_mem; */
int i;
FLOPPY_DPRINTF("init controller\n");
if (!fdctrl)
return NULL;
} else {
}
for (i = 0; i < 2; i++) {
if (fds[i]) {
}
}
fdctrl_reset(fdctrl, 0);
if (mem_mapped) {
FLOPPY_ERROR("memory mapped floppy not supported by now !\n");
#if 0
#endif
} else {
}
for (i = 0; i < 2; i++) {
}
return fdctrl;
}
/* XXX: may change if moved to bdrv */
{
}
#endif
/* Change IRQ state */
{
FLOPPY_DPRINTF("Reset interrupt\n");
#ifdef VBOX
#else
#endif
}
{
#ifdef VBOX
#else
#endif
}
}
/* Reset controller */
{
int i;
FLOPPY_DPRINTF("reset controller\n");
/* Initialise controller */
/* FIFO state */
for (i = 0; i < MAX_FD; i++)
if (do_irq)
}
{
}
{
}
{
}
/* Status B register : 0x01 (read-only) */
{
FLOPPY_DPRINTF("status register: 0x00\n");
return 0;
}
/* Digital output register : 0x02 */
{
/* Drive motors state indicators */
#ifndef VBOX
#else
/* bit4: 0 = drive 0 motor off/1 = on */
/* bit5: 0 = drive 1 motor off/1 = on */
#endif
/* DMA enable */
/* Reset indicator */
/* Selected drive */
return retval;
}
{
/* Reset mode */
if (!(value & 0x04)) {
FLOPPY_DPRINTF("Floppy controller in RESET state !\n");
return;
}
}
/* Drive motors state indicators */
if (value & 0x20)
else
if (value & 0x10)
else
/* DMA enable */
#if 0
#endif
/* Reset */
if (!(value & 0x04)) {
FLOPPY_DPRINTF("controller enter RESET state\n");
}
} else {
FLOPPY_DPRINTF("controller out of RESET state\n");
}
}
/* Selected drive */
}
/* Tape drive register : 0x03 */
{
/* Disk boot selection indicator */
/* Tape indicators: never allowed */
return retval;
}
{
/* Reset mode */
FLOPPY_DPRINTF("Floppy controller in RESET state !\n");
return;
}
/* Disk boot selection indicator */
/* Tape indicators: never allow */
}
/* Main status register : 0x04 (read) */
{
/* Data transfer allowed */
retval |= 0x80;
/* Data transfer direction indicator */
retval |= 0x40;
}
/* Should handle 0x20 for SPECIFY command */
/* Command busy indicator */
retval |= 0x10;
return retval;
}
/* Data select rate register : 0x04 (write) */
{
/* Reset mode */
FLOPPY_DPRINTF("Floppy controller in RESET state !\n");
return;
}
/* Reset: autoclear */
if (value & 0x80) {
}
if (value & 0x40) {
}
/* // fdctrl.precomp = (value >> 2) & 0x07; */
}
/* Digital input register : 0x07 (read-only) */
{
#ifndef VBOX
#else
|| !cur_drv->fMediaPresent)
#endif
retval |= 0x80;
if (retval != 0)
return retval;
}
/* FIFO state control */
{
}
/* Set FIFO status for the host to read */
{
if (do_irq)
}
/* Set an error: unimplemented/unknown command */
{
#if 0
#else
/* // fdctrl_reset_fifo(fdctrl); */
#endif
}
/* Callback for transfer end (stop or abort) */
{
FLOPPY_DPRINTF("transfer status: %02x %02x %02x (%02x)\n",
#ifdef VBOX
#else
#endif
}
}
/* Prepare a data transfer (either DMA or FIFO) */
{
int did_seek;
FLOPPY_DPRINTF("Start transfer at %d %d %02x %02x (%d)\n",
did_seek = 0;
case 2:
/* sect too big */
return;
case 3:
/* track too big */
return;
case 4:
/* No seek enabled */
return;
case 1:
did_seek = 1;
break;
default:
break;
}
/* Set the FIFO state */
else
if (did_seek)
else
} else {
int tmp;
}
int dma_mode;
/* DMA transfer are enabled. Check if DMA channel is well programmed */
#ifndef VBOX
#else
#endif
FLOPPY_DPRINTF("dma_mode=%d direction=%d (%d - %d)\n",
/* No access is allowed until DMA transfer has completed */
/* Now, we just have to wait for the DMA controller to
* recall us...
*/
#ifndef VBOX
#else
#endif
return;
} else {
}
}
FLOPPY_DPRINTF("start non-DMA transfer\n");
/* IO based transfer: calculate len */
return;
}
/* Prepare a transfer of deleted data */
{
/* We don't handle deleted data,
* so we don't return *ANYTHING*
*/
}
#if 0
#include <stdio.h>
#include <stdlib.h>
static FILE * f;
{
size_t n;
if (!f) {
if (!f)
exit (0);
}
if (n != 1) {
AssertMsgFailed (("failed to dump\n"));
exit (0);
}
}
#else
#define dump(a,b) do { } while (0)
#endif
/* handlers for DMA transfers */
#ifdef VBOX
void *opaque,
unsigned nchan,
#else
#endif
{
#ifdef VBOX
int rc;
#else
#endif
FLOPPY_DPRINTF("Not in DMA transfer mode !\n");
return 0;
}
status2 = 0x04;
#ifndef VBOX
#else /* !VBOX */
#endif
else
len = 0;
goto transfer_error;
}
FLOPPY_DPRINTF("copy %d bytes (%d %d %d) %d pos %d %02x "
/* READ & SCAN commands and realign to a sector for WRITE */
#ifndef VBOX
FLOPPY_DPRINTF("Floppy: error getting sector %d\n",
/* Sure, image size is too small... */
}
#else
1 * 512
);
if (RT_FAILURE (rc)) {
("Floppy: error getting sector %d, rc = %Rrc",
}
#endif
}
case FD_DIR_READ:
/* READ commands */
#ifdef VBOX
{
}
#else
#endif
/* cpu_physical_memory_write(addr + fdctrl->data_pos, */
/* fdctrl->fifo + rel_pos, len); */
break;
case FD_DIR_WRITE:
/* WRITE commands */
#ifdef VBOX
{
}
#else
#endif
/* cpu_physical_memory_read(addr + fdctrl->data_pos, */
/* fdctrl->fifo + rel_pos, len); */
#ifndef VBOX
goto transfer_error;
}
#else /* VBOX */
1 * 512
);
if (RT_FAILURE (rc)) {
AssertMsgFailed (("Floppy: error writing sector %d. rc=%Rrc",
goto transfer_error;
}
#endif
break;
default:
/* SCAN commands */
{
int ret;
#ifdef VBOX
#else
#endif
/* cpu_physical_memory_read(addr + fdctrl->data_pos, */
/* tmpbuf, len); */
if (ret == 0) {
status2 = 0x08;
goto end_transfer;
}
status2 = 0x00;
goto end_transfer;
}
}
break;
}
if (rel_pos == 0) {
/* Seek to next sector */
FLOPPY_DPRINTF("seek to next sector (%d %02x %02x => %d) (%d)\n",
/* XXX: cur_drv->sect >= cur_drv->last_sect should be an
error in fact */
} else {
break;
}
} else {
break;
}
FLOPPY_DPRINTF("seek to next track (%d %02x %02x => %d)\n",
} else {
}
}
}
FLOPPY_DPRINTF("end transfer %d %d %d\n",
status2 = 0x08;
status0 |= 0x20;
/* if (fdctrl->data_len == 0) */
return len;
}
#if 0
{
FLOPPY_DPRINTF("Not in DMA transfer mode !\n");
return 0;
}
status2 = 0x04;
#ifndef VBOX
#else
#endif
else
len = 0;
goto transfer_error;
}
FLOPPY_DPRINTF("copy %d bytes (%d %d %d) %d pos %d %02x %02x "
/* READ & SCAN commands and realign to a sector for WRITE */
#ifndef VBOX
FLOPPY_DPRINTF("Floppy: error getting sector %d\n",
/* Sure, image size is too small... */
}
#else
int rc;
1 * 512
);
if (RT_FAILURE (rc)) {
("Floppy: error getting sector %d. rc=%Rrc\n",
/* Sure, image size is too small... */
}
/* *p_fd_activity = 1; */
#endif
}
case FD_DIR_READ:
/* READ commands */
#ifdef VBOX
#else
#endif
break;
case FD_DIR_WRITE:
/* WRITE commands */
#ifdef VBOX
{
int rc;
1 * 512
);
if (RT_FAILURE (rc)) {
("Floppy: error writting sector %d. rc=%Rrc\n",
goto transfer_error;
}
}
/* *p_fd_activity = 2; */
#else /* !VBOX */
goto transfer_error;
}
#endif
break;
default:
/* SCAN commands */
{
int ret;
#ifdef VBOX
#else
#endif
if (ret == 0) {
status2 = 0x08;
goto end_transfer;
}
status2 = 0x00;
goto end_transfer;
}
}
break;
}
if (rel_pos == 0) {
/* Seek to next sector */
FLOPPY_DPRINTF("seek to next sector (%d %02x %02x => %d) (%d)\n",
/* XXX: cur_drv->sect >= cur_drv->last_sect should be an
error in fact */
} else {
break;
}
} else {
break;
}
FLOPPY_DPRINTF("seek to next track (%d %02x %02x => %d)\n",
} else {
}
}
}
FLOPPY_DPRINTF("end transfer %d %d %d\n",
status2 = 0x08;
status0 |= 0x20;
/* // if (fdctrl->data_len == 0) */
return len;
}
#endif
/* Data register : 0x05 */
{
#ifdef VBOX
int rc;
#endif
FLOPPY_ERROR("can't read data in CMD state\n");
return 0;
}
pos %= FD_SECTOR_LEN;
if (pos == 0) {
if (len > FD_SECTOR_LEN)
len = FD_SECTOR_LEN;
#ifdef VBOX
);
if (RT_FAILURE (rc)) {
("Floppy: Failure to read sector %d. rc=%Rrc",
}
#else
#endif
}
}
/* Switch from transfer mode to status mode
* then from status mode to command mode
*/
} else {
}
}
return retval;
}
{
int did_seek;
#ifdef VBOX
#endif
FLOPPY_DPRINTF("format sector at %d %d %02x %02x (%d)\n",
did_seek = 0;
case 2:
/* sect too big */
return;
case 3:
/* track too big */
return;
case 4:
/* No seek enabled */
return;
case 1:
did_seek = 1;
break;
default:
break;
}
#ifdef VBOX
/* *p_fd_activity = 2; */
1 * 512
);
if (RT_FAILURE (rc)) {
AssertMsgFailed (("Floppy: error formating sector %d. rc=%Rrc\n",
}
else {
ok = 1;
}
}
if (ok) {
#else
} else {
#endif
/* Last sector done */
else
} else {
/* More to do */
}
}
}
{
/* Reset mode */
FLOPPY_DPRINTF("Floppy controller in RESET state !\n");
return;
}
FLOPPY_ERROR("can't write data in status mode\n");
return;
}
/* Is it write command time ? */
/* FIFO data write */
#ifdef VBOX
int rc;
/* *p_fd_activity = 2; */
);
if (RT_FAILURE (rc)) {
("Floppy: failed to write sector %d. rc=%Rrc\n",
}
#else
#endif
}
/* Switch from transfer mode to status mode
* then from status mode to command mode
*/
return;
}
/* Command */
switch (value & 0x5F) {
case 0x46:
/* READ variants */
FLOPPY_DPRINTF("READ command\n");
/* 8 parameters cmd */
goto enqueue;
case 0x4C:
/* READ_DELETED variants */
FLOPPY_DPRINTF("READ_DELETED command\n");
/* 8 parameters cmd */
goto enqueue;
case 0x50:
/* SCAN_EQUAL variants */
FLOPPY_DPRINTF("SCAN_EQUAL command\n");
/* 8 parameters cmd */
goto enqueue;
case 0x56:
/* VERIFY variants */
FLOPPY_DPRINTF("VERIFY command\n");
/* 8 parameters cmd */
goto enqueue;
case 0x59:
/* SCAN_LOW_OR_EQUAL variants */
FLOPPY_DPRINTF("SCAN_LOW_OR_EQUAL command\n");
/* 8 parameters cmd */
goto enqueue;
case 0x5D:
/* SCAN_HIGH_OR_EQUAL variants */
FLOPPY_DPRINTF("SCAN_HIGH_OR_EQUAL command\n");
/* 8 parameters cmd */
goto enqueue;
default:
break;
}
switch (value & 0x7F) {
case 0x45:
/* WRITE variants */
FLOPPY_DPRINTF("WRITE command\n");
/* 8 parameters cmd */
goto enqueue;
case 0x49:
/* WRITE_DELETED variants */
FLOPPY_DPRINTF("WRITE_DELETED command\n");
/* 8 parameters cmd */
goto enqueue;
default:
break;
}
switch (value) {
case 0x03:
/* SPECIFY */
FLOPPY_DPRINTF("SPECIFY command\n");
/* 1 parameter cmd */
goto enqueue;
case 0x04:
/* SENSE_DRIVE_STATUS */
FLOPPY_DPRINTF("SENSE_DRIVE_STATUS command\n");
/* 1 parameter cmd */
goto enqueue;
case 0x07:
/* RECALIBRATE */
FLOPPY_DPRINTF("RECALIBRATE command\n");
/* 1 parameter cmd */
goto enqueue;
case 0x08:
/* SENSE_INTERRUPT_STATUS */
FLOPPY_DPRINTF("SENSE_INTERRUPT_STATUS command (%02x)\n",
fdctrl->int_status);
/* No parameters cmd: returns status if no interrupt */
#if 0
#else
commands, so we do this hack. It should be suppressed
ASAP */
#endif
return;
case 0x0E:
/* DUMPREG */
FLOPPY_DPRINTF("DUMPREG command\n");
/* Drives position */
/* timers */
return;
case 0x0F:
/* SEEK */
FLOPPY_DPRINTF("SEEK command\n");
/* 2 parameters cmd */
goto enqueue;
case 0x10:
/* VERSION */
FLOPPY_DPRINTF("VERSION command\n");
/* No parameters cmd */
/* Controller's version */
return;
case 0x12:
/* PERPENDICULAR_MODE */
FLOPPY_DPRINTF("PERPENDICULAR_MODE command\n");
/* 1 parameter cmd */
goto enqueue;
case 0x13:
/* CONFIGURE */
FLOPPY_DPRINTF("CONFIGURE command\n");
/* 3 parameters cmd */
goto enqueue;
case 0x14:
/* UNLOCK */
FLOPPY_DPRINTF("UNLOCK command\n");
/* No parameters cmd */
return;
case 0x17:
/* POWERDOWN_MODE */
FLOPPY_DPRINTF("POWERDOWN_MODE command\n");
/* 2 parameters cmd */
goto enqueue;
case 0x18:
/* PART_ID */
FLOPPY_DPRINTF("PART_ID command\n");
/* No parameters cmd */
return;
case 0x2C:
/* SAVE */
FLOPPY_DPRINTF("SAVE command\n");
/* No parameters cmd */
/* Drives position */
/* timers */
return;
case 0x33:
/* OPTION */
FLOPPY_DPRINTF("OPTION command\n");
/* 1 parameter cmd */
goto enqueue;
case 0x42:
/* READ_TRACK */
FLOPPY_DPRINTF("READ_TRACK command\n");
/* 8 parameters cmd */
goto enqueue;
case 0x4A:
/* READ_ID */
FLOPPY_DPRINTF("READ_ID command\n");
/* 1 parameter cmd */
goto enqueue;
case 0x4C:
/* RESTORE */
FLOPPY_DPRINTF("RESTORE command\n");
/* 17 parameters cmd */
goto enqueue;
case 0x4D:
/* FORMAT_TRACK */
FLOPPY_DPRINTF("FORMAT_TRACK command\n");
/* 5 parameters cmd */
goto enqueue;
case 0x8E:
/* DRIVE_SPECIFICATION_COMMAND */
FLOPPY_DPRINTF("DRIVE_SPECIFICATION_COMMAND command\n");
/* 5 parameters cmd */
goto enqueue;
case 0x8F:
/* RELATIVE_SEEK_OUT */
FLOPPY_DPRINTF("RELATIVE_SEEK_OUT command\n");
/* 2 parameters cmd */
goto enqueue;
case 0x94:
/* LOCK */
FLOPPY_DPRINTF("LOCK command\n");
/* No parameters cmd */
return;
case 0xCD:
/* FORMAT_AND_WRITE */
FLOPPY_DPRINTF("FORMAT_AND_WRITE command\n");
/* 10 parameters cmd */
goto enqueue;
case 0xCF:
/* RELATIVE_SEEK_IN */
FLOPPY_DPRINTF("RELATIVE_SEEK_IN command\n");
/* 2 parameters cmd */
goto enqueue;
default:
/* Unknown command */
return;
}
}
/* We now have all parameters
* and will be able to treat the command
*/
return;
}
case 0x06:
{
/* READ variants */
FLOPPY_DPRINTF("treat READ command\n");
return;
}
case 0x0C:
/* READ_DELETED variants */
/* // FLOPPY_DPRINTF("treat READ_DELETED command\n"); */
FLOPPY_ERROR("treat READ_DELETED command\n");
return;
case 0x16:
/* VERIFY variants */
/* // FLOPPY_DPRINTF("treat VERIFY command\n"); */
FLOPPY_ERROR("treat VERIFY command\n");
return;
case 0x10:
/* SCAN_EQUAL variants */
/* // FLOPPY_DPRINTF("treat SCAN_EQUAL command\n"); */
FLOPPY_ERROR("treat SCAN_EQUAL command\n");
return;
case 0x19:
/* SCAN_LOW_OR_EQUAL variants */
/* // FLOPPY_DPRINTF("treat SCAN_LOW_OR_EQUAL command\n"); */
FLOPPY_ERROR("treat SCAN_LOW_OR_EQUAL command\n");
return;
case 0x1D:
/* SCAN_HIGH_OR_EQUAL variants */
/* // FLOPPY_DPRINTF("treat SCAN_HIGH_OR_EQUAL command\n"); */
FLOPPY_ERROR("treat SCAN_HIGH_OR_EQUAL command\n");
return;
default:
break;
}
case 0x05:
/* WRITE variants */
return;
case 0x09:
/* WRITE_DELETED variants */
/* // FLOPPY_DPRINTF("treat WRITE_DELETED command\n"); */
FLOPPY_ERROR("treat WRITE_DELETED command\n");
return;
default:
break;
}
case 0x03:
/* SPECIFY */
FLOPPY_DPRINTF("treat SPECIFY command\n");
/* No result back */
break;
case 0x04:
/* SENSE_DRIVE_STATUS */
FLOPPY_DPRINTF("treat SENSE_DRIVE_STATUS command\n");
/* 1 Byte status back */
0x28;
break;
case 0x07:
/* RECALIBRATE */
FLOPPY_DPRINTF("treat RECALIBRATE command\n");
/* Raise Interrupt */
break;
case 0x0F:
/* SEEK */
FLOPPY_DPRINTF("treat SEEK command\n");
else
#ifndef VBOX
#else
&& cur_drv->fMediaPresent) {
#endif
} else {
/* Raise Interrupt */
}
break;
case 0x12:
/* PERPENDICULAR_MODE */
FLOPPY_DPRINTF("treat PERPENDICULAR_MODE command\n");
/* No result back */
break;
case 0x13:
/* CONFIGURE */
FLOPPY_DPRINTF("treat CONFIGURE command\n");
/* No result back */
break;
case 0x17:
/* POWERDOWN_MODE */
FLOPPY_DPRINTF("treat POWERDOWN_MODE command\n");
break;
case 0x33:
/* OPTION */
FLOPPY_DPRINTF("treat OPTION command\n");
/* No result back */
break;
case 0x42:
/* READ_TRACK */
/* // FLOPPY_DPRINTF("treat READ_TRACK command\n"); */
FLOPPY_ERROR("treat READ_TRACK command\n");
break;
case 0x4A:
/* READ_ID */
FLOPPY_DPRINTF("treat READ_ID command\n");
/* XXX: should set main status register to busy */
#ifdef VBOX
#else
#endif
break;
case 0x4C:
/* RESTORE */
FLOPPY_DPRINTF("treat RESTORE command\n");
/* Drives position */
/* timers */
break;
case 0x4D:
/* FORMAT_TRACK */
FLOPPY_DPRINTF("treat FORMAT_TRACK command\n");
else
#if 0
#else
#endif
/* Bochs BIOS is buggy and don't send format informations
* for each sector. So, pretend all's done right now...
*/
break;
case 0x8E:
/* DRIVE_SPECIFICATION_COMMAND */
FLOPPY_DPRINTF("treat DRIVE_SPECIFICATION_COMMAND command\n");
/* Command parameters done */
} else {
}
/* ERROR */
}
break;
case 0x8F:
/* RELATIVE_SEEK_OUT */
FLOPPY_DPRINTF("treat RELATIVE_SEEK_OUT command\n");
} else {
}
break;
case 0xCD:
/* FORMAT_AND_WRITE */
/* // FLOPPY_DPRINTF("treat FORMAT_AND_WRITE command\n"); */
FLOPPY_ERROR("treat FORMAT_AND_WRITE command\n");
break;
case 0xCF:
/* RELATIVE_SEEK_IN */
FLOPPY_DPRINTF("treat RELATIVE_SEEK_IN command\n");
} else {
}
/* Raise Interrupt */
break;
}
}
}
static void fdctrl_result_timer(void *opaque)
{
}
#ifdef VBOX
{
}
void *pvUser,
unsigned cb)
{
if (cb == 1) {
}
else {
}
return VINF_SUCCESS;
}
void *pvUser,
unsigned cb)
{
if (cb == 1) {
return VINF_SUCCESS;
}
else {
return VERR_IOM_IOPORT_UNUSED;
}
}
{
QEMUFile *f = pSSMHandle;
unsigned int i;
qemu_put_8s (f, &s->version);
qemu_put_8s (f, &s->irq_lvl);
qemu_put_8s (f, &s->dma_chann);
qemu_put_be32s (f, &s->io_base);
qemu_put_8s (f, &s->state);
qemu_put_8s (f, &s->dma_en);
qemu_put_8s (f, &s->cur_drv);
qemu_put_8s (f, &s->bootsel);
qemu_put_be32s (f, &s->data_pos);
qemu_put_be32s (f, &s->data_len);
qemu_put_8s (f, &s->data_state);
qemu_put_8s (f, &s->data_dir);
qemu_put_8s (f, &s->int_status);
qemu_put_8s (f, &s->eot);
qemu_put_8s (f, &s->timer0);
qemu_put_8s (f, &s->timer1);
qemu_put_8s (f, &s->precomp_trk);
qemu_put_8s (f, &s->config);
qemu_put_8s (f, &s->lock);
qemu_put_8s (f, &s->pwrd);
qemu_put_be32s (f, &d->drive);
qemu_put_be32s (f, &d->drflags);
qemu_put_8s (f, &d->perpendicular);
qemu_put_8s (f, &d->head);
qemu_put_8s (f, &d->track);
qemu_put_8s (f, &d->sect);
qemu_put_8s (f, &d->dir);
qemu_put_8s (f, &d->rw);
qemu_put_be32s (f, &d->flags);
qemu_put_8s (f, &d->last_sect);
qemu_put_8s (f, &d->max_track);
qemu_put_be16s (f, &d->bps);
qemu_put_8s (f, &d->ro);
}
}
{
QEMUFile *f = pSSMHandle;
unsigned int i;
qemu_get_8s (f, &s->version);
qemu_get_8s (f, &s->irq_lvl);
qemu_get_8s (f, &s->dma_chann);
qemu_get_be32s (f, &s->io_base);
qemu_get_8s (f, &s->state);
qemu_get_8s (f, &s->dma_en);
qemu_get_8s (f, &s->cur_drv);
qemu_get_8s (f, &s->bootsel);
qemu_get_be32s (f, &s->data_pos);
qemu_get_be32s (f, &s->data_len);
qemu_get_8s (f, &s->data_state);
qemu_get_8s (f, &s->data_dir);
qemu_get_8s (f, &s->int_status);
qemu_get_8s (f, &s->eot);
qemu_get_8s (f, &s->timer0);
qemu_get_8s (f, &s->timer1);
qemu_get_8s (f, &s->precomp_trk);
qemu_get_8s (f, &s->config);
qemu_get_8s (f, &s->lock);
qemu_get_8s (f, &s->pwrd);
qemu_get_be32s (f, &d->drive);
qemu_get_be32s (f, &d->drflags);
qemu_get_8s (f, &d->perpendicular);
qemu_get_8s (f, &d->head);
qemu_get_8s (f, &d->track);
qemu_get_8s (f, &d->sect);
qemu_get_8s (f, &d->dir);
qemu_get_8s (f, &d->rw);
qemu_get_be32s (f, &d->flags);
qemu_get_8s (f, &d->last_sect);
qemu_get_8s (f, &d->max_track);
qemu_get_be16s (f, &d->bps);
qemu_get_8s (f, &d->ro);
}
}
/**
* @interface_method_impl{PDMIBASE,pfnQueryInterface}
*/
{
return NULL;
}
/**
* Gets the pointer to the status LED of a unit.
*
* @returns VBox status code.
* @param pInterface Pointer to the interface structure containing the called function pointer.
* @param iLUN The unit which status LED we desire.
* @param ppLed Where to store the LED pointer.
*/
unsigned iLUN,
{
return VINF_SUCCESS;
}
return VERR_PDM_LUN_NOT_FOUND;
}
/**
* @interface_method_impl{PDMIBASE,pfnQueryInterface}
*/
{
return NULL;
}
/**
* Configure a drive.
*
* @returns VBox status code.
* @param drv The drive in question.
* @param pDevIns The driver instance.
*/
{
int rc;
/*
* Reset the LED just to be on the safe side.
*/
/*
* Try attach the block device and get the interfaces.
*/
if (RT_SUCCESS (rc)) {
if (drv->pDrvBlockBios) {
/*
* Init the state.
*/
drv->perpendicular = 0;
/* Disk */
drv->fMediaPresent = false;
} else {
}
} else {
}
} else {
}
} else {
switch (rc) {
case VERR_ACCESS_DENIED:
/* Error already catched by DrvHostBase */
break;
/* Legal on architectures without a floppy controller */
break;
default:
N_ ("The floppy controller cannot attach to the floppy drive"));
break;
}
}
if (RT_FAILURE (rc)) {
}
return rc;
}
/**
* Attach command.
*
* This is called when we change block driver for a floppy drive.
*
* @returns VBox status code.
* @param pDevIns The device instance.
* @param iLUN The logical unit which is being detached.
*/
{
int rc;
("The FDC device does not support hotplugging\n"),
/*
* Validate.
*/
if (iLUN > 2) {
AssertMsgFailed (("Configuration error: cannot attach or detach any but the first two LUNs - iLUN=%u\n",
iLUN));
return VERR_PDM_DEVINS_NO_ATTACH;
}
/*
* Locate the drive and stuff.
*/
/* the usual paranoia */
("Configuration error: failed to configure drive %d, rc=%Rrc\n", rc));
if (RT_SUCCESS(rc)) {
fd_revalidate (drv);
}
return rc;
}
/**
* Detach notification.
*
* The floppy drive has been temporarily 'unplugged'.
*
* @param pDevIns The device instance.
* @param iLUN The logical unit which is being detached.
*/
{
switch (iLUN) {
case 0:
case 1: {
break;
}
default:
break;
}
}
/**
* Handle reset.
*
* I haven't check the specs on what's supposed to happen on reset, but we
* should get any 'FATAL: floppy recal:f07 ctrl not ready' when resetting
* at wrong time like we do if this was all void.
*
* @param pDevIns The device instance.
*/
{
unsigned i;
LogFlow (("fdcReset:\n"));
fdctrl_reset(fdctrl, 0);
}
}
/**
* @interface_method_impl{PDMDEVREG,pfnConstruct}
*/
int iInstance,
{
int rc;
unsigned i;
bool mem_mapped;
/*
* Validate configuration.
*/
/*
* Read the configuration.
*/
if (rc == VERR_CFGM_VALUE_NOT_FOUND)
irq_lvl = 6;
else if (RT_FAILURE (rc)) {
return rc;
}
if (rc == VERR_CFGM_VALUE_NOT_FOUND)
dma_chann = 2;
else if (RT_FAILURE (rc)) {
return rc;
}
if (rc == VERR_CFGM_VALUE_NOT_FOUND)
io_base = 0x3f0;
else if (RT_FAILURE (rc)) {
return rc;
}
if (rc == VERR_CFGM_VALUE_NOT_FOUND)
mem_mapped = false;
else if (RT_FAILURE (rc)) {
return rc;
}
/*
* Initialize data.
*/
}
/*
* Create the FDC timer.
*/
if (RT_FAILURE (rc))
return rc;
/*
* Register DMA channel.
*/
if (RT_FAILURE (rc))
return rc;
} else
/*
* IO / MMIO.
*/
if (mem_mapped) {
AssertMsgFailed (("Memory mapped floppy not support by now\n"));
return VERR_NOT_SUPPORTED;
#if 0
FLOPPY_ERROR("memory mapped floppy not supported by now !\n");
#endif
} else {
if (RT_FAILURE (rc))
return rc;
if (RT_FAILURE (rc))
return rc;
}
/*
* Register the saved state data unit.
*/
if (RT_FAILURE(rc))
return rc;
/*
* Attach the status port (optional).
*/
if (RT_SUCCESS (rc)) {
} else if (rc != VERR_PDM_NO_ATTACHED_DRIVER) {
AssertMsgFailed (("Failed to attach to status driver. rc=%Rrc\n",
rc));
return rc;
}
/*
* Initialize drives.
*/
if ( RT_FAILURE (rc)
&& rc != VERR_PDM_NO_ATTACHED_DRIVER) {
return rc;
}
}
fdctrl_reset(fdctrl, 0);
return VINF_SUCCESS;
}
/**
* The device registration structure.
*/
const PDMDEVREG g_DeviceFloppyController =
{
/* u32Version */
/* szName */
"i82078",
/* szRCMod */
"",
/* szR0Mod */
"",
/* pszDescription */
"Floppy drive controller (Intel 82078)",
/* fFlags */
/* fClass */
/* cMaxInstances */
1,
/* cbInstance */
sizeof(fdctrl_t),
/* pfnConstruct */
/* pfnDestruct */
NULL,
/* pfnRelocate */
NULL,
/* pfnIOCtl */
NULL,
/* pfnPowerOn */
NULL,
/* pfnReset */
/* pfnSuspend */
NULL,
/* pfnResume */
NULL,
/* pfnAttach */
/* pfnDetach */
/* pfnQueryInterface. */
NULL,
/* pfnInitComplete */
NULL,
/* pfnPowerOff */
NULL,
/* pfnSoftReset */
NULL,
/* u32VersionEnd */
};
#endif /* VBOX */
/*
* Local Variables:
* mode: c
* c-file-style: "k&r"
* indent-tabs-mode: nil
* End:
*/