mirror of https://gitee.com/openkylin/qemu.git
fdc: Add a floppy drive qdev
Floppy controllers automatically create two floppy drive devices in qdev now. (They always created two drives, but managed them only internally.) Signed-off-by: Kevin Wolf <kwolf@redhat.com> Reviewed-by: John Snow <jsnow@redhat.com> Message-id: 1477386868-21826-3-git-send-email-kwolf@redhat.com Signed-off-by: John Snow <jsnow@redhat.com>
This commit is contained in:
parent
51e6e90e72
commit
394ea2cac4
151
hw/block/fdc.c
151
hw/block/fdc.c
|
@ -60,6 +60,8 @@
|
||||||
#define FLOPPY_BUS(obj) OBJECT_CHECK(FloppyBus, (obj), TYPE_FLOPPY_BUS)
|
#define FLOPPY_BUS(obj) OBJECT_CHECK(FloppyBus, (obj), TYPE_FLOPPY_BUS)
|
||||||
|
|
||||||
typedef struct FDCtrl FDCtrl;
|
typedef struct FDCtrl FDCtrl;
|
||||||
|
typedef struct FDrive FDrive;
|
||||||
|
static FDrive *get_drv(FDCtrl *fdctrl, int unit);
|
||||||
|
|
||||||
typedef struct FloppyBus {
|
typedef struct FloppyBus {
|
||||||
BusState bus;
|
BusState bus;
|
||||||
|
@ -180,7 +182,7 @@ typedef enum FDiskFlags {
|
||||||
FDISK_DBL_SIDES = 0x01,
|
FDISK_DBL_SIDES = 0x01,
|
||||||
} FDiskFlags;
|
} FDiskFlags;
|
||||||
|
|
||||||
typedef struct FDrive {
|
struct FDrive {
|
||||||
FDCtrl *fdctrl;
|
FDCtrl *fdctrl;
|
||||||
BlockBackend *blk;
|
BlockBackend *blk;
|
||||||
/* Drive status */
|
/* Drive status */
|
||||||
|
@ -201,7 +203,7 @@ typedef struct FDrive {
|
||||||
uint8_t media_rate; /* Data rate of medium */
|
uint8_t media_rate; /* Data rate of medium */
|
||||||
|
|
||||||
bool media_validated; /* Have we validated the media? */
|
bool media_validated; /* Have we validated the media? */
|
||||||
} FDrive;
|
};
|
||||||
|
|
||||||
|
|
||||||
static FloppyDriveType get_fallback_drive_type(FDrive *drv);
|
static FloppyDriveType get_fallback_drive_type(FDrive *drv);
|
||||||
|
@ -466,6 +468,100 @@ static void fd_revalidate(FDrive *drv)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void fd_change_cb(void *opaque, bool load)
|
||||||
|
{
|
||||||
|
FDrive *drive = opaque;
|
||||||
|
|
||||||
|
drive->media_changed = 1;
|
||||||
|
drive->media_validated = false;
|
||||||
|
fd_revalidate(drive);
|
||||||
|
}
|
||||||
|
|
||||||
|
static const BlockDevOps fd_block_ops = {
|
||||||
|
.change_media_cb = fd_change_cb,
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#define TYPE_FLOPPY_DRIVE "floppy"
|
||||||
|
#define FLOPPY_DRIVE(obj) \
|
||||||
|
OBJECT_CHECK(FloppyDrive, (obj), TYPE_FLOPPY_DRIVE)
|
||||||
|
|
||||||
|
typedef struct FloppyDrive {
|
||||||
|
DeviceState qdev;
|
||||||
|
uint32_t unit;
|
||||||
|
} FloppyDrive;
|
||||||
|
|
||||||
|
static Property floppy_drive_properties[] = {
|
||||||
|
DEFINE_PROP_UINT32("unit", FloppyDrive, unit, -1),
|
||||||
|
DEFINE_PROP_END_OF_LIST(),
|
||||||
|
};
|
||||||
|
|
||||||
|
static int floppy_drive_init(DeviceState *qdev)
|
||||||
|
{
|
||||||
|
FloppyDrive *dev = FLOPPY_DRIVE(qdev);
|
||||||
|
FloppyBus *bus = FLOPPY_BUS(qdev->parent_bus);
|
||||||
|
FDrive *drive;
|
||||||
|
|
||||||
|
if (dev->unit == -1) {
|
||||||
|
for (dev->unit = 0; dev->unit < MAX_FD; dev->unit++) {
|
||||||
|
drive = get_drv(bus->fdc, dev->unit);
|
||||||
|
if (!drive->blk) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dev->unit >= MAX_FD) {
|
||||||
|
error_report("Can't create floppy unit %d, bus supports only %d units",
|
||||||
|
dev->unit, MAX_FD);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* TODO Check whether unit is in use */
|
||||||
|
|
||||||
|
drive = get_drv(bus->fdc, dev->unit);
|
||||||
|
|
||||||
|
if (drive->blk) {
|
||||||
|
if (blk_get_on_error(drive->blk, 0) != BLOCKDEV_ON_ERROR_ENOSPC) {
|
||||||
|
error_report("fdc doesn't support drive option werror");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (blk_get_on_error(drive->blk, 1) != BLOCKDEV_ON_ERROR_REPORT) {
|
||||||
|
error_report("fdc doesn't support drive option rerror");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
/* Anonymous BlockBackend for an empty drive */
|
||||||
|
drive->blk = blk_new();
|
||||||
|
}
|
||||||
|
|
||||||
|
fd_init(drive);
|
||||||
|
if (drive->blk) {
|
||||||
|
blk_set_dev_ops(drive->blk, &fd_block_ops, drive);
|
||||||
|
pick_drive_type(drive);
|
||||||
|
}
|
||||||
|
fd_revalidate(drive);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void floppy_drive_class_init(ObjectClass *klass, void *data)
|
||||||
|
{
|
||||||
|
DeviceClass *k = DEVICE_CLASS(klass);
|
||||||
|
k->init = floppy_drive_init;
|
||||||
|
set_bit(DEVICE_CATEGORY_STORAGE, k->categories);
|
||||||
|
k->bus_type = TYPE_FLOPPY_BUS;
|
||||||
|
k->props = floppy_drive_properties;
|
||||||
|
k->desc = "virtual floppy drive";
|
||||||
|
}
|
||||||
|
|
||||||
|
static const TypeInfo floppy_drive_info = {
|
||||||
|
.name = TYPE_FLOPPY_DRIVE,
|
||||||
|
.parent = TYPE_DEVICE,
|
||||||
|
.instance_size = sizeof(FloppyDrive),
|
||||||
|
.class_init = floppy_drive_class_init,
|
||||||
|
};
|
||||||
|
|
||||||
/********************************************************/
|
/********************************************************/
|
||||||
/* Intel 82078 floppy disk controller emulation */
|
/* Intel 82078 floppy disk controller emulation */
|
||||||
|
|
||||||
|
@ -1185,9 +1281,9 @@ static inline FDrive *drv3(FDCtrl *fdctrl)
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static FDrive *get_cur_drv(FDCtrl *fdctrl)
|
static FDrive *get_drv(FDCtrl *fdctrl, int unit)
|
||||||
{
|
{
|
||||||
switch (fdctrl->cur_drv) {
|
switch (unit) {
|
||||||
case 0: return drv0(fdctrl);
|
case 0: return drv0(fdctrl);
|
||||||
case 1: return drv1(fdctrl);
|
case 1: return drv1(fdctrl);
|
||||||
#if MAX_FD == 4
|
#if MAX_FD == 4
|
||||||
|
@ -1198,6 +1294,11 @@ static FDrive *get_cur_drv(FDCtrl *fdctrl)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static FDrive *get_cur_drv(FDCtrl *fdctrl)
|
||||||
|
{
|
||||||
|
return get_drv(fdctrl, fdctrl->cur_drv);
|
||||||
|
}
|
||||||
|
|
||||||
/* Status A register : 0x00 (read-only) */
|
/* Status A register : 0x00 (read-only) */
|
||||||
static uint32_t fdctrl_read_statusA(FDCtrl *fdctrl)
|
static uint32_t fdctrl_read_statusA(FDCtrl *fdctrl)
|
||||||
{
|
{
|
||||||
|
@ -2357,46 +2458,33 @@ static void fdctrl_result_timer(void *opaque)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void fdctrl_change_cb(void *opaque, bool load)
|
|
||||||
{
|
|
||||||
FDrive *drive = opaque;
|
|
||||||
|
|
||||||
drive->media_changed = 1;
|
|
||||||
drive->media_validated = false;
|
|
||||||
fd_revalidate(drive);
|
|
||||||
}
|
|
||||||
|
|
||||||
static const BlockDevOps fdctrl_block_ops = {
|
|
||||||
.change_media_cb = fdctrl_change_cb,
|
|
||||||
};
|
|
||||||
|
|
||||||
/* Init functions */
|
/* Init functions */
|
||||||
static void fdctrl_connect_drives(FDCtrl *fdctrl, Error **errp)
|
static void fdctrl_connect_drives(FDCtrl *fdctrl, Error **errp)
|
||||||
{
|
{
|
||||||
unsigned int i;
|
unsigned int i;
|
||||||
FDrive *drive;
|
FDrive *drive;
|
||||||
|
DeviceState *dev;
|
||||||
|
Error *local_err = NULL;
|
||||||
|
|
||||||
for (i = 0; i < MAX_FD; i++) {
|
for (i = 0; i < MAX_FD; i++) {
|
||||||
drive = &fdctrl->drives[i];
|
drive = &fdctrl->drives[i];
|
||||||
drive->fdctrl = fdctrl;
|
drive->fdctrl = fdctrl;
|
||||||
|
|
||||||
if (drive->blk) {
|
/* If the drive is not present, we skip creating the qdev device, but
|
||||||
if (blk_get_on_error(drive->blk, 0) != BLOCKDEV_ON_ERROR_ENOSPC) {
|
* still have to initialise the controller. */
|
||||||
error_setg(errp, "fdc doesn't support drive option werror");
|
if (!fdctrl->drives[i].blk) {
|
||||||
return;
|
fd_init(drive);
|
||||||
}
|
fd_revalidate(drive);
|
||||||
if (blk_get_on_error(drive->blk, 1) != BLOCKDEV_ON_ERROR_REPORT) {
|
continue;
|
||||||
error_setg(errp, "fdc doesn't support drive option rerror");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fd_init(drive);
|
dev = qdev_create(&fdctrl->bus.bus, "floppy");
|
||||||
if (drive->blk) {
|
qdev_prop_set_uint32(dev, "unit", i);
|
||||||
blk_set_dev_ops(drive->blk, &fdctrl_block_ops, drive);
|
object_property_set_bool(OBJECT(dev), true, "realized", &local_err);
|
||||||
pick_drive_type(drive);
|
if (local_err) {
|
||||||
|
error_propagate(errp, local_err);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
fd_revalidate(drive);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2774,6 +2862,7 @@ static void fdc_register_types(void)
|
||||||
type_register_static(&sysbus_fdc_info);
|
type_register_static(&sysbus_fdc_info);
|
||||||
type_register_static(&sun4m_fdc_info);
|
type_register_static(&sun4m_fdc_info);
|
||||||
type_register_static(&floppy_bus_info);
|
type_register_static(&floppy_bus_info);
|
||||||
|
type_register_static(&floppy_drive_info);
|
||||||
}
|
}
|
||||||
|
|
||||||
type_init(fdc_register_types)
|
type_init(fdc_register_types)
|
||||||
|
|
Loading…
Reference in New Issue