11430759eSPhilippe Mathieu-Daudé /* 21430759eSPhilippe Mathieu-Daudé * QEMU Floppy disk emulator (Intel 82078) 31430759eSPhilippe Mathieu-Daudé * 41430759eSPhilippe Mathieu-Daudé * Copyright (c) 2003, 2007 Jocelyn Mayer 51430759eSPhilippe Mathieu-Daudé * Copyright (c) 2008 Hervé Poussineau 61430759eSPhilippe Mathieu-Daudé * 71430759eSPhilippe Mathieu-Daudé * Permission is hereby granted, free of charge, to any person obtaining a copy 81430759eSPhilippe Mathieu-Daudé * of this software and associated documentation files (the "Software"), to deal 91430759eSPhilippe Mathieu-Daudé * in the Software without restriction, including without limitation the rights 101430759eSPhilippe Mathieu-Daudé * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 111430759eSPhilippe Mathieu-Daudé * copies of the Software, and to permit persons to whom the Software is 121430759eSPhilippe Mathieu-Daudé * furnished to do so, subject to the following conditions: 131430759eSPhilippe Mathieu-Daudé * 141430759eSPhilippe Mathieu-Daudé * The above copyright notice and this permission notice shall be included in 151430759eSPhilippe Mathieu-Daudé * all copies or substantial portions of the Software. 161430759eSPhilippe Mathieu-Daudé * 171430759eSPhilippe Mathieu-Daudé * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 181430759eSPhilippe Mathieu-Daudé * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 191430759eSPhilippe Mathieu-Daudé * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 201430759eSPhilippe Mathieu-Daudé * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 211430759eSPhilippe Mathieu-Daudé * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 221430759eSPhilippe Mathieu-Daudé * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 231430759eSPhilippe Mathieu-Daudé * THE SOFTWARE. 241430759eSPhilippe Mathieu-Daudé */ 251430759eSPhilippe Mathieu-Daudé 261430759eSPhilippe Mathieu-Daudé #include "qemu/osdep.h" 271430759eSPhilippe Mathieu-Daudé #include "qapi/error.h" 281430759eSPhilippe Mathieu-Daudé #include "qom/object.h" 291430759eSPhilippe Mathieu-Daudé #include "hw/sysbus.h" 301430759eSPhilippe Mathieu-Daudé #include "hw/block/fdc.h" 311430759eSPhilippe Mathieu-Daudé #include "migration/vmstate.h" 321430759eSPhilippe Mathieu-Daudé #include "fdc-internal.h" 331430759eSPhilippe Mathieu-Daudé #include "trace.h" 341430759eSPhilippe Mathieu-Daudé 351430759eSPhilippe Mathieu-Daudé #define TYPE_SYSBUS_FDC "base-sysbus-fdc" 361430759eSPhilippe Mathieu-Daudé typedef struct FDCtrlSysBusClass FDCtrlSysBusClass; 371430759eSPhilippe Mathieu-Daudé typedef struct FDCtrlSysBus FDCtrlSysBus; 381430759eSPhilippe Mathieu-Daudé DECLARE_OBJ_CHECKERS(FDCtrlSysBus, FDCtrlSysBusClass, 391430759eSPhilippe Mathieu-Daudé SYSBUS_FDC, TYPE_SYSBUS_FDC) 401430759eSPhilippe Mathieu-Daudé 411430759eSPhilippe Mathieu-Daudé struct FDCtrlSysBusClass { 421430759eSPhilippe Mathieu-Daudé /*< private >*/ 431430759eSPhilippe Mathieu-Daudé SysBusDeviceClass parent_class; 441430759eSPhilippe Mathieu-Daudé /*< public >*/ 451430759eSPhilippe Mathieu-Daudé 461430759eSPhilippe Mathieu-Daudé bool use_strict_io; 471430759eSPhilippe Mathieu-Daudé }; 481430759eSPhilippe Mathieu-Daudé 491430759eSPhilippe Mathieu-Daudé struct FDCtrlSysBus { 501430759eSPhilippe Mathieu-Daudé /*< private >*/ 511430759eSPhilippe Mathieu-Daudé SysBusDevice parent_obj; 521430759eSPhilippe Mathieu-Daudé /*< public >*/ 531430759eSPhilippe Mathieu-Daudé 541430759eSPhilippe Mathieu-Daudé struct FDCtrl state; 551430759eSPhilippe Mathieu-Daudé }; 561430759eSPhilippe Mathieu-Daudé 571430759eSPhilippe Mathieu-Daudé static uint64_t fdctrl_read_mem(void *opaque, hwaddr reg, unsigned ize) 581430759eSPhilippe Mathieu-Daudé { 591430759eSPhilippe Mathieu-Daudé return fdctrl_read(opaque, (uint32_t)reg); 601430759eSPhilippe Mathieu-Daudé } 611430759eSPhilippe Mathieu-Daudé 621430759eSPhilippe Mathieu-Daudé static void fdctrl_write_mem(void *opaque, hwaddr reg, 631430759eSPhilippe Mathieu-Daudé uint64_t value, unsigned size) 641430759eSPhilippe Mathieu-Daudé { 651430759eSPhilippe Mathieu-Daudé fdctrl_write(opaque, (uint32_t)reg, value); 661430759eSPhilippe Mathieu-Daudé } 671430759eSPhilippe Mathieu-Daudé 681430759eSPhilippe Mathieu-Daudé static const MemoryRegionOps fdctrl_mem_ops = { 691430759eSPhilippe Mathieu-Daudé .read = fdctrl_read_mem, 701430759eSPhilippe Mathieu-Daudé .write = fdctrl_write_mem, 711430759eSPhilippe Mathieu-Daudé .endianness = DEVICE_NATIVE_ENDIAN, 721430759eSPhilippe Mathieu-Daudé }; 731430759eSPhilippe Mathieu-Daudé 741430759eSPhilippe Mathieu-Daudé static const MemoryRegionOps fdctrl_mem_strict_ops = { 751430759eSPhilippe Mathieu-Daudé .read = fdctrl_read_mem, 761430759eSPhilippe Mathieu-Daudé .write = fdctrl_write_mem, 771430759eSPhilippe Mathieu-Daudé .endianness = DEVICE_NATIVE_ENDIAN, 781430759eSPhilippe Mathieu-Daudé .valid = { 791430759eSPhilippe Mathieu-Daudé .min_access_size = 1, 801430759eSPhilippe Mathieu-Daudé .max_access_size = 1, 811430759eSPhilippe Mathieu-Daudé }, 821430759eSPhilippe Mathieu-Daudé }; 831430759eSPhilippe Mathieu-Daudé 841430759eSPhilippe Mathieu-Daudé static void fdctrl_external_reset_sysbus(DeviceState *d) 851430759eSPhilippe Mathieu-Daudé { 861430759eSPhilippe Mathieu-Daudé FDCtrlSysBus *sys = SYSBUS_FDC(d); 871430759eSPhilippe Mathieu-Daudé FDCtrl *s = &sys->state; 881430759eSPhilippe Mathieu-Daudé 891430759eSPhilippe Mathieu-Daudé fdctrl_reset(s, 0); 901430759eSPhilippe Mathieu-Daudé } 911430759eSPhilippe Mathieu-Daudé 921430759eSPhilippe Mathieu-Daudé static void fdctrl_handle_tc(void *opaque, int irq, int level) 931430759eSPhilippe Mathieu-Daudé { 941430759eSPhilippe Mathieu-Daudé trace_fdctrl_tc_pulse(level); 951430759eSPhilippe Mathieu-Daudé } 961430759eSPhilippe Mathieu-Daudé 970c285e01SPeter Maydell void fdctrl_init_sysbus(qemu_irq irq, hwaddr mmio_base, DriveInfo **fds) 981430759eSPhilippe Mathieu-Daudé { 991430759eSPhilippe Mathieu-Daudé DeviceState *dev; 1001430759eSPhilippe Mathieu-Daudé SysBusDevice *sbd; 1011430759eSPhilippe Mathieu-Daudé FDCtrlSysBus *sys; 1021430759eSPhilippe Mathieu-Daudé 1031430759eSPhilippe Mathieu-Daudé dev = qdev_new("sysbus-fdc"); 1041430759eSPhilippe Mathieu-Daudé sys = SYSBUS_FDC(dev); 1051430759eSPhilippe Mathieu-Daudé sbd = SYS_BUS_DEVICE(dev); 1061430759eSPhilippe Mathieu-Daudé sysbus_realize_and_unref(sbd, &error_fatal); 1071430759eSPhilippe Mathieu-Daudé sysbus_connect_irq(sbd, 0, irq); 1081430759eSPhilippe Mathieu-Daudé sysbus_mmio_map(sbd, 0, mmio_base); 1091430759eSPhilippe Mathieu-Daudé 1101430759eSPhilippe Mathieu-Daudé fdctrl_init_drives(&sys->state.bus, fds); 1111430759eSPhilippe Mathieu-Daudé } 1121430759eSPhilippe Mathieu-Daudé 1131430759eSPhilippe Mathieu-Daudé void sun4m_fdctrl_init(qemu_irq irq, hwaddr io_base, 1141430759eSPhilippe Mathieu-Daudé DriveInfo **fds, qemu_irq *fdc_tc) 1151430759eSPhilippe Mathieu-Daudé { 1161430759eSPhilippe Mathieu-Daudé DeviceState *dev; 1171430759eSPhilippe Mathieu-Daudé FDCtrlSysBus *sys; 1181430759eSPhilippe Mathieu-Daudé 1191430759eSPhilippe Mathieu-Daudé dev = qdev_new("sun-fdtwo"); 1201430759eSPhilippe Mathieu-Daudé sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); 1211430759eSPhilippe Mathieu-Daudé sys = SYSBUS_FDC(dev); 1221430759eSPhilippe Mathieu-Daudé sysbus_connect_irq(SYS_BUS_DEVICE(sys), 0, irq); 1231430759eSPhilippe Mathieu-Daudé sysbus_mmio_map(SYS_BUS_DEVICE(sys), 0, io_base); 1241430759eSPhilippe Mathieu-Daudé *fdc_tc = qdev_get_gpio_in(dev, 0); 1251430759eSPhilippe Mathieu-Daudé 1261430759eSPhilippe Mathieu-Daudé fdctrl_init_drives(&sys->state.bus, fds); 1271430759eSPhilippe Mathieu-Daudé } 1281430759eSPhilippe Mathieu-Daudé 1291430759eSPhilippe Mathieu-Daudé static void sysbus_fdc_common_instance_init(Object *obj) 1301430759eSPhilippe Mathieu-Daudé { 1311430759eSPhilippe Mathieu-Daudé DeviceState *dev = DEVICE(obj); 1321430759eSPhilippe Mathieu-Daudé FDCtrlSysBusClass *sbdc = SYSBUS_FDC_GET_CLASS(obj); 1331430759eSPhilippe Mathieu-Daudé SysBusDevice *sbd = SYS_BUS_DEVICE(dev); 1341430759eSPhilippe Mathieu-Daudé FDCtrlSysBus *sys = SYSBUS_FDC(obj); 1351430759eSPhilippe Mathieu-Daudé FDCtrl *fdctrl = &sys->state; 1361430759eSPhilippe Mathieu-Daudé 1370c285e01SPeter Maydell /* 1380c285e01SPeter Maydell * DMA is not currently supported for sysbus floppy controllers. 1390c285e01SPeter Maydell * If we wanted to add support then probably the best approach is 1400c285e01SPeter Maydell * to have a QOM link property 'dma-controller' which the board 1410c285e01SPeter Maydell * code can set to an instance of IsaDmaClass, and an integer 1420c285e01SPeter Maydell * property 'dma-channel', so that we can set fdctrl->dma and 1430c285e01SPeter Maydell * fdctrl->dma_chann accordingly. 1440c285e01SPeter Maydell */ 1450c285e01SPeter Maydell fdctrl->dma_chann = -1; 1460c285e01SPeter Maydell 1471430759eSPhilippe Mathieu-Daudé qdev_set_legacy_instance_id(dev, 0 /* io */, 2); /* FIXME */ 1481430759eSPhilippe Mathieu-Daudé 1491430759eSPhilippe Mathieu-Daudé memory_region_init_io(&fdctrl->iomem, obj, 1501430759eSPhilippe Mathieu-Daudé sbdc->use_strict_io ? &fdctrl_mem_strict_ops 1511430759eSPhilippe Mathieu-Daudé : &fdctrl_mem_ops, 1521430759eSPhilippe Mathieu-Daudé fdctrl, "fdc", 0x08); 1531430759eSPhilippe Mathieu-Daudé sysbus_init_mmio(sbd, &fdctrl->iomem); 1541430759eSPhilippe Mathieu-Daudé 1551430759eSPhilippe Mathieu-Daudé sysbus_init_irq(sbd, &fdctrl->irq); 1561430759eSPhilippe Mathieu-Daudé qdev_init_gpio_in(dev, fdctrl_handle_tc, 1); 1571430759eSPhilippe Mathieu-Daudé } 1581430759eSPhilippe Mathieu-Daudé 1591430759eSPhilippe Mathieu-Daudé static void sysbus_fdc_realize(DeviceState *dev, Error **errp) 1601430759eSPhilippe Mathieu-Daudé { 1611430759eSPhilippe Mathieu-Daudé FDCtrlSysBus *sys = SYSBUS_FDC(dev); 1621430759eSPhilippe Mathieu-Daudé FDCtrl *fdctrl = &sys->state; 1631430759eSPhilippe Mathieu-Daudé 1641430759eSPhilippe Mathieu-Daudé fdctrl_realize_common(dev, fdctrl, errp); 1651430759eSPhilippe Mathieu-Daudé } 1661430759eSPhilippe Mathieu-Daudé 1671430759eSPhilippe Mathieu-Daudé static const VMStateDescription vmstate_sysbus_fdc = { 1681430759eSPhilippe Mathieu-Daudé .name = "fdc", 1691430759eSPhilippe Mathieu-Daudé .version_id = 2, 1701430759eSPhilippe Mathieu-Daudé .minimum_version_id = 2, 171*7d5dc0a3SRichard Henderson .fields = (const VMStateField[]) { 1721430759eSPhilippe Mathieu-Daudé VMSTATE_STRUCT(state, FDCtrlSysBus, 0, vmstate_fdc, FDCtrl), 1731430759eSPhilippe Mathieu-Daudé VMSTATE_END_OF_LIST() 1741430759eSPhilippe Mathieu-Daudé } 1751430759eSPhilippe Mathieu-Daudé }; 1761430759eSPhilippe Mathieu-Daudé 1771430759eSPhilippe Mathieu-Daudé static void sysbus_fdc_common_class_init(ObjectClass *klass, void *data) 1781430759eSPhilippe Mathieu-Daudé { 1791430759eSPhilippe Mathieu-Daudé DeviceClass *dc = DEVICE_CLASS(klass); 1801430759eSPhilippe Mathieu-Daudé 1811430759eSPhilippe Mathieu-Daudé dc->realize = sysbus_fdc_realize; 1821430759eSPhilippe Mathieu-Daudé dc->reset = fdctrl_external_reset_sysbus; 1831430759eSPhilippe Mathieu-Daudé dc->vmsd = &vmstate_sysbus_fdc; 1841430759eSPhilippe Mathieu-Daudé set_bit(DEVICE_CATEGORY_STORAGE, dc->categories); 1851430759eSPhilippe Mathieu-Daudé } 1861430759eSPhilippe Mathieu-Daudé 1871430759eSPhilippe Mathieu-Daudé static const TypeInfo sysbus_fdc_common_typeinfo = { 1881430759eSPhilippe Mathieu-Daudé .name = TYPE_SYSBUS_FDC, 1891430759eSPhilippe Mathieu-Daudé .parent = TYPE_SYS_BUS_DEVICE, 1901430759eSPhilippe Mathieu-Daudé .instance_size = sizeof(FDCtrlSysBus), 1911430759eSPhilippe Mathieu-Daudé .instance_init = sysbus_fdc_common_instance_init, 1921430759eSPhilippe Mathieu-Daudé .abstract = true, 1931430759eSPhilippe Mathieu-Daudé .class_init = sysbus_fdc_common_class_init, 1941430759eSPhilippe Mathieu-Daudé .class_size = sizeof(FDCtrlSysBusClass), 1951430759eSPhilippe Mathieu-Daudé }; 1961430759eSPhilippe Mathieu-Daudé 1971430759eSPhilippe Mathieu-Daudé static Property sysbus_fdc_properties[] = { 1981430759eSPhilippe Mathieu-Daudé DEFINE_PROP_SIGNED("fdtypeA", FDCtrlSysBus, state.qdev_for_drives[0].type, 1991430759eSPhilippe Mathieu-Daudé FLOPPY_DRIVE_TYPE_AUTO, qdev_prop_fdc_drive_type, 2001430759eSPhilippe Mathieu-Daudé FloppyDriveType), 2011430759eSPhilippe Mathieu-Daudé DEFINE_PROP_SIGNED("fdtypeB", FDCtrlSysBus, state.qdev_for_drives[1].type, 2021430759eSPhilippe Mathieu-Daudé FLOPPY_DRIVE_TYPE_AUTO, qdev_prop_fdc_drive_type, 2031430759eSPhilippe Mathieu-Daudé FloppyDriveType), 2041430759eSPhilippe Mathieu-Daudé DEFINE_PROP_SIGNED("fallback", FDCtrlSysBus, state.fallback, 2051430759eSPhilippe Mathieu-Daudé FLOPPY_DRIVE_TYPE_144, qdev_prop_fdc_drive_type, 2061430759eSPhilippe Mathieu-Daudé FloppyDriveType), 2071430759eSPhilippe Mathieu-Daudé DEFINE_PROP_END_OF_LIST(), 2081430759eSPhilippe Mathieu-Daudé }; 2091430759eSPhilippe Mathieu-Daudé 2101430759eSPhilippe Mathieu-Daudé static void sysbus_fdc_class_init(ObjectClass *klass, void *data) 2111430759eSPhilippe Mathieu-Daudé { 2121430759eSPhilippe Mathieu-Daudé DeviceClass *dc = DEVICE_CLASS(klass); 2131430759eSPhilippe Mathieu-Daudé 2149362984fSPhilippe Mathieu-Daudé dc->desc = "virtual floppy controller"; 2151430759eSPhilippe Mathieu-Daudé device_class_set_props(dc, sysbus_fdc_properties); 2161430759eSPhilippe Mathieu-Daudé } 2171430759eSPhilippe Mathieu-Daudé 2181430759eSPhilippe Mathieu-Daudé static const TypeInfo sysbus_fdc_typeinfo = { 2191430759eSPhilippe Mathieu-Daudé .name = "sysbus-fdc", 2201430759eSPhilippe Mathieu-Daudé .parent = TYPE_SYSBUS_FDC, 2211430759eSPhilippe Mathieu-Daudé .class_init = sysbus_fdc_class_init, 2221430759eSPhilippe Mathieu-Daudé }; 2231430759eSPhilippe Mathieu-Daudé 2241430759eSPhilippe Mathieu-Daudé static Property sun4m_fdc_properties[] = { 2251430759eSPhilippe Mathieu-Daudé DEFINE_PROP_SIGNED("fdtype", FDCtrlSysBus, state.qdev_for_drives[0].type, 2261430759eSPhilippe Mathieu-Daudé FLOPPY_DRIVE_TYPE_AUTO, qdev_prop_fdc_drive_type, 2271430759eSPhilippe Mathieu-Daudé FloppyDriveType), 2281430759eSPhilippe Mathieu-Daudé DEFINE_PROP_SIGNED("fallback", FDCtrlSysBus, state.fallback, 2291430759eSPhilippe Mathieu-Daudé FLOPPY_DRIVE_TYPE_144, qdev_prop_fdc_drive_type, 2301430759eSPhilippe Mathieu-Daudé FloppyDriveType), 2311430759eSPhilippe Mathieu-Daudé DEFINE_PROP_END_OF_LIST(), 2321430759eSPhilippe Mathieu-Daudé }; 2331430759eSPhilippe Mathieu-Daudé 2341430759eSPhilippe Mathieu-Daudé static void sun4m_fdc_class_init(ObjectClass *klass, void *data) 2351430759eSPhilippe Mathieu-Daudé { 2361430759eSPhilippe Mathieu-Daudé FDCtrlSysBusClass *sbdc = SYSBUS_FDC_CLASS(klass); 2371430759eSPhilippe Mathieu-Daudé DeviceClass *dc = DEVICE_CLASS(klass); 2381430759eSPhilippe Mathieu-Daudé 2391430759eSPhilippe Mathieu-Daudé sbdc->use_strict_io = true; 2409362984fSPhilippe Mathieu-Daudé dc->desc = "virtual floppy controller"; 2411430759eSPhilippe Mathieu-Daudé device_class_set_props(dc, sun4m_fdc_properties); 2421430759eSPhilippe Mathieu-Daudé } 2431430759eSPhilippe Mathieu-Daudé 2441430759eSPhilippe Mathieu-Daudé static const TypeInfo sun4m_fdc_typeinfo = { 2451430759eSPhilippe Mathieu-Daudé .name = "sun-fdtwo", 2461430759eSPhilippe Mathieu-Daudé .parent = TYPE_SYSBUS_FDC, 2471430759eSPhilippe Mathieu-Daudé .class_init = sun4m_fdc_class_init, 2481430759eSPhilippe Mathieu-Daudé }; 2491430759eSPhilippe Mathieu-Daudé 2501430759eSPhilippe Mathieu-Daudé static void sysbus_fdc_register_types(void) 2511430759eSPhilippe Mathieu-Daudé { 2521430759eSPhilippe Mathieu-Daudé type_register_static(&sysbus_fdc_common_typeinfo); 2531430759eSPhilippe Mathieu-Daudé type_register_static(&sysbus_fdc_typeinfo); 2541430759eSPhilippe Mathieu-Daudé type_register_static(&sun4m_fdc_typeinfo); 2551430759eSPhilippe Mathieu-Daudé } 2561430759eSPhilippe Mathieu-Daudé 2571430759eSPhilippe Mathieu-Daudé type_init(sysbus_fdc_register_types) 258