qemu

FORK: QEMU emulator
git clone https://git.neptards.moe/neptards/qemu.git
Log | Files | Refs | Submodules | LICENSE

fdc-isa.c (10338B)


      1 /*
      2  * QEMU Floppy disk emulator (Intel 82078)
      3  *
      4  * Copyright (c) 2003, 2007 Jocelyn Mayer
      5  * Copyright (c) 2008 Hervé Poussineau
      6  *
      7  * Permission is hereby granted, free of charge, to any person obtaining a copy
      8  * of this software and associated documentation files (the "Software"), to deal
      9  * in the Software without restriction, including without limitation the rights
     10  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
     11  * copies of the Software, and to permit persons to whom the Software is
     12  * furnished to do so, subject to the following conditions:
     13  *
     14  * The above copyright notice and this permission notice shall be included in
     15  * all copies or substantial portions of the Software.
     16  *
     17  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     18  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     19  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
     20  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
     21  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
     22  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
     23  * THE SOFTWARE.
     24  */
     25 /*
     26  * The controller is used in Sun4m systems in a slightly different
     27  * way. There are changes in DOR register and DMA is not available.
     28  */
     29 
     30 #include "qemu/osdep.h"
     31 #include "hw/block/fdc.h"
     32 #include "qapi/error.h"
     33 #include "qemu/error-report.h"
     34 #include "qemu/timer.h"
     35 #include "hw/acpi/acpi_aml_interface.h"
     36 #include "hw/irq.h"
     37 #include "hw/isa/isa.h"
     38 #include "hw/qdev-properties.h"
     39 #include "hw/qdev-properties-system.h"
     40 #include "migration/vmstate.h"
     41 #include "hw/block/block.h"
     42 #include "sysemu/block-backend.h"
     43 #include "sysemu/blockdev.h"
     44 #include "sysemu/sysemu.h"
     45 #include "qemu/log.h"
     46 #include "qemu/main-loop.h"
     47 #include "qemu/module.h"
     48 #include "trace.h"
     49 #include "qom/object.h"
     50 #include "fdc-internal.h"
     51 
     52 OBJECT_DECLARE_SIMPLE_TYPE(FDCtrlISABus, ISA_FDC)
     53 
     54 struct FDCtrlISABus {
     55     /*< private >*/
     56     ISADevice parent_obj;
     57     /*< public >*/
     58 
     59     uint32_t iobase;
     60     uint32_t irq;
     61     uint32_t dma;
     62     struct FDCtrl state;
     63     int32_t bootindexA;
     64     int32_t bootindexB;
     65 };
     66 
     67 static void fdctrl_external_reset_isa(DeviceState *d)
     68 {
     69     FDCtrlISABus *isa = ISA_FDC(d);
     70     FDCtrl *s = &isa->state;
     71 
     72     fdctrl_reset(s, 0);
     73 }
     74 
     75 void isa_fdc_init_drives(ISADevice *fdc, DriveInfo **fds)
     76 {
     77     fdctrl_init_drives(&ISA_FDC(fdc)->state.bus, fds);
     78 }
     79 
     80 static const MemoryRegionPortio fdc_portio_list[] = {
     81     { 1, 5, 1, .read = fdctrl_read, .write = fdctrl_write },
     82     { 7, 1, 1, .read = fdctrl_read, .write = fdctrl_write },
     83     PORTIO_END_OF_LIST(),
     84 };
     85 
     86 static void isabus_fdc_realize(DeviceState *dev, Error **errp)
     87 {
     88     ISADevice *isadev = ISA_DEVICE(dev);
     89     FDCtrlISABus *isa = ISA_FDC(dev);
     90     FDCtrl *fdctrl = &isa->state;
     91     Error *err = NULL;
     92 
     93     isa_register_portio_list(isadev, &fdctrl->portio_list,
     94                              isa->iobase, fdc_portio_list, fdctrl,
     95                              "fdc");
     96 
     97     fdctrl->irq = isa_get_irq(isadev, isa->irq);
     98     fdctrl->dma_chann = isa->dma;
     99     if (fdctrl->dma_chann != -1) {
    100         IsaDmaClass *k;
    101         fdctrl->dma = isa_get_dma(isa_bus_from_device(isadev), isa->dma);
    102         if (!fdctrl->dma) {
    103             error_setg(errp, "ISA controller does not support DMA");
    104             return;
    105         }
    106         k = ISADMA_GET_CLASS(fdctrl->dma);
    107         k->register_channel(fdctrl->dma, fdctrl->dma_chann,
    108                             &fdctrl_transfer_handler, fdctrl);
    109     }
    110 
    111     qdev_set_legacy_instance_id(dev, isa->iobase, 2);
    112 
    113     fdctrl_realize_common(dev, fdctrl, &err);
    114     if (err != NULL) {
    115         error_propagate(errp, err);
    116         return;
    117     }
    118 }
    119 
    120 FloppyDriveType isa_fdc_get_drive_type(ISADevice *fdc, int i)
    121 {
    122     FDCtrlISABus *isa = ISA_FDC(fdc);
    123 
    124     return isa->state.drives[i].drive;
    125 }
    126 
    127 static void isa_fdc_get_drive_max_chs(FloppyDriveType type, uint8_t *maxc,
    128                                       uint8_t *maxh, uint8_t *maxs)
    129 {
    130     const FDFormat *fdf;
    131 
    132     *maxc = *maxh = *maxs = 0;
    133     for (fdf = fd_formats; fdf->drive != FLOPPY_DRIVE_TYPE_NONE; fdf++) {
    134         if (fdf->drive != type) {
    135             continue;
    136         }
    137         if (*maxc < fdf->max_track) {
    138             *maxc = fdf->max_track;
    139         }
    140         if (*maxh < fdf->max_head) {
    141             *maxh = fdf->max_head;
    142         }
    143         if (*maxs < fdf->last_sect) {
    144             *maxs = fdf->last_sect;
    145         }
    146     }
    147     (*maxc)--;
    148 }
    149 
    150 static Aml *build_fdinfo_aml(int idx, FloppyDriveType type)
    151 {
    152     Aml *dev, *fdi;
    153     uint8_t maxc, maxh, maxs;
    154 
    155     isa_fdc_get_drive_max_chs(type, &maxc, &maxh, &maxs);
    156 
    157     dev = aml_device("FLP%c", 'A' + idx);
    158 
    159     aml_append(dev, aml_name_decl("_ADR", aml_int(idx)));
    160 
    161     fdi = aml_package(16);
    162     aml_append(fdi, aml_int(idx));  /* Drive Number */
    163     aml_append(fdi,
    164         aml_int(cmos_get_fd_drive_type(type)));  /* Device Type */
    165     /*
    166      * the values below are the limits of the drive, and are thus independent
    167      * of the inserted media
    168      */
    169     aml_append(fdi, aml_int(maxc));  /* Maximum Cylinder Number */
    170     aml_append(fdi, aml_int(maxs));  /* Maximum Sector Number */
    171     aml_append(fdi, aml_int(maxh));  /* Maximum Head Number */
    172     /*
    173      * SeaBIOS returns the below values for int 0x13 func 0x08 regardless of
    174      * the drive type, so shall we
    175      */
    176     aml_append(fdi, aml_int(0xAF));  /* disk_specify_1 */
    177     aml_append(fdi, aml_int(0x02));  /* disk_specify_2 */
    178     aml_append(fdi, aml_int(0x25));  /* disk_motor_wait */
    179     aml_append(fdi, aml_int(0x02));  /* disk_sector_siz */
    180     aml_append(fdi, aml_int(0x12));  /* disk_eot */
    181     aml_append(fdi, aml_int(0x1B));  /* disk_rw_gap */
    182     aml_append(fdi, aml_int(0xFF));  /* disk_dtl */
    183     aml_append(fdi, aml_int(0x6C));  /* disk_formt_gap */
    184     aml_append(fdi, aml_int(0xF6));  /* disk_fill */
    185     aml_append(fdi, aml_int(0x0F));  /* disk_head_sttl */
    186     aml_append(fdi, aml_int(0x08));  /* disk_motor_strt */
    187 
    188     aml_append(dev, aml_name_decl("_FDI", fdi));
    189     return dev;
    190 }
    191 
    192 int cmos_get_fd_drive_type(FloppyDriveType fd0)
    193 {
    194     int val;
    195 
    196     switch (fd0) {
    197     case FLOPPY_DRIVE_TYPE_144:
    198         /* 1.44 Mb 3"5 drive */
    199         val = 4;
    200         break;
    201     case FLOPPY_DRIVE_TYPE_288:
    202         /* 2.88 Mb 3"5 drive */
    203         val = 5;
    204         break;
    205     case FLOPPY_DRIVE_TYPE_120:
    206         /* 1.2 Mb 5"5 drive */
    207         val = 2;
    208         break;
    209     case FLOPPY_DRIVE_TYPE_NONE:
    210     default:
    211         val = 0;
    212         break;
    213     }
    214     return val;
    215 }
    216 
    217 static void build_fdc_aml(AcpiDevAmlIf *adev, Aml *scope)
    218 {
    219     FDCtrlISABus *isa = ISA_FDC(adev);
    220     Aml *dev;
    221     Aml *crs;
    222     int i;
    223 
    224 #define ACPI_FDE_MAX_FD 4
    225     uint32_t fde_buf[5] = {
    226         0, 0, 0, 0,     /* presence of floppy drives #0 - #3 */
    227         cpu_to_le32(2)  /* tape presence (2 == never present) */
    228     };
    229 
    230     crs = aml_resource_template();
    231     aml_append(crs,
    232         aml_io(AML_DECODE16, isa->iobase + 2, isa->iobase + 2, 0x00, 0x04));
    233     aml_append(crs,
    234         aml_io(AML_DECODE16, isa->iobase + 7, isa->iobase + 7, 0x00, 0x01));
    235     aml_append(crs, aml_irq_no_flags(isa->irq));
    236     aml_append(crs,
    237         aml_dma(AML_COMPATIBILITY, AML_NOTBUSMASTER, AML_TRANSFER8, isa->dma));
    238 
    239     dev = aml_device("FDC0");
    240     aml_append(dev, aml_name_decl("_HID", aml_eisaid("PNP0700")));
    241     aml_append(dev, aml_name_decl("_CRS", crs));
    242 
    243     for (i = 0; i < MIN(MAX_FD, ACPI_FDE_MAX_FD); i++) {
    244         FloppyDriveType type = isa_fdc_get_drive_type(ISA_DEVICE(adev), i);
    245 
    246         if (type < FLOPPY_DRIVE_TYPE_NONE) {
    247             fde_buf[i] = cpu_to_le32(1);  /* drive present */
    248             aml_append(dev, build_fdinfo_aml(i, type));
    249         }
    250     }
    251     aml_append(dev, aml_name_decl("_FDE",
    252                aml_buffer(sizeof(fde_buf), (uint8_t *)fde_buf)));
    253 
    254     aml_append(scope, dev);
    255 }
    256 
    257 static const VMStateDescription vmstate_isa_fdc = {
    258     .name = "fdc",
    259     .version_id = 2,
    260     .minimum_version_id = 2,
    261     .fields = (VMStateField[]) {
    262         VMSTATE_STRUCT(state, FDCtrlISABus, 0, vmstate_fdc, FDCtrl),
    263         VMSTATE_END_OF_LIST()
    264     }
    265 };
    266 
    267 static Property isa_fdc_properties[] = {
    268     DEFINE_PROP_UINT32("iobase", FDCtrlISABus, iobase, 0x3f0),
    269     DEFINE_PROP_UINT32("irq", FDCtrlISABus, irq, 6),
    270     DEFINE_PROP_UINT32("dma", FDCtrlISABus, dma, 2),
    271     DEFINE_PROP_SIGNED("fdtypeA", FDCtrlISABus, state.qdev_for_drives[0].type,
    272                         FLOPPY_DRIVE_TYPE_AUTO, qdev_prop_fdc_drive_type,
    273                         FloppyDriveType),
    274     DEFINE_PROP_SIGNED("fdtypeB", FDCtrlISABus, state.qdev_for_drives[1].type,
    275                         FLOPPY_DRIVE_TYPE_AUTO, qdev_prop_fdc_drive_type,
    276                         FloppyDriveType),
    277     DEFINE_PROP_SIGNED("fallback", FDCtrlISABus, state.fallback,
    278                         FLOPPY_DRIVE_TYPE_288, qdev_prop_fdc_drive_type,
    279                         FloppyDriveType),
    280     DEFINE_PROP_END_OF_LIST(),
    281 };
    282 
    283 static void isabus_fdc_class_init(ObjectClass *klass, void *data)
    284 {
    285     DeviceClass *dc = DEVICE_CLASS(klass);
    286     AcpiDevAmlIfClass *adevc = ACPI_DEV_AML_IF_CLASS(klass);
    287 
    288     dc->desc = "virtual floppy controller";
    289     dc->realize = isabus_fdc_realize;
    290     dc->fw_name = "fdc";
    291     dc->reset = fdctrl_external_reset_isa;
    292     dc->vmsd = &vmstate_isa_fdc;
    293     adevc->build_dev_aml = build_fdc_aml;
    294     device_class_set_props(dc, isa_fdc_properties);
    295     set_bit(DEVICE_CATEGORY_STORAGE, dc->categories);
    296 }
    297 
    298 static void isabus_fdc_instance_init(Object *obj)
    299 {
    300     FDCtrlISABus *isa = ISA_FDC(obj);
    301 
    302     device_add_bootindex_property(obj, &isa->bootindexA,
    303                                   "bootindexA", "/floppy@0",
    304                                   DEVICE(obj));
    305     device_add_bootindex_property(obj, &isa->bootindexB,
    306                                   "bootindexB", "/floppy@1",
    307                                   DEVICE(obj));
    308 }
    309 
    310 static const TypeInfo isa_fdc_info = {
    311     .name          = TYPE_ISA_FDC,
    312     .parent        = TYPE_ISA_DEVICE,
    313     .instance_size = sizeof(FDCtrlISABus),
    314     .class_init    = isabus_fdc_class_init,
    315     .instance_init = isabus_fdc_instance_init,
    316     .interfaces = (InterfaceInfo[]) {
    317         { TYPE_ACPI_DEV_AML_IF },
    318         { },
    319     },
    320 };
    321 
    322 static void isa_fdc_register_types(void)
    323 {
    324     type_register_static(&isa_fdc_info);
    325 }
    326 
    327 type_init(isa_fdc_register_types)