2 * QEMU Floppy disk emulator (Intel 82078)
4 * Copyright (c) 2003, 2007 Jocelyn Mayer
5 * Copyright (c) 2008 Hervé Poussineau
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:
14 * The above copyright notice and this permission notice shall be included in
15 * all copies or substantial portions of the Software.
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
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.
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"
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 "exec/ioport.h"
47 #include "qemu/main-loop.h"
48 #include "qemu/module.h"
50 #include "qom/object.h"
51 #include "fdc-internal.h"
53 OBJECT_DECLARE_SIMPLE_TYPE(FDCtrlISABus
, ISA_FDC
)
64 PortioList portio_list
;
69 static void fdctrl_external_reset_isa(DeviceState
*d
)
71 FDCtrlISABus
*isa
= ISA_FDC(d
);
72 FDCtrl
*s
= &isa
->state
;
77 void isa_fdc_init_drives(ISADevice
*fdc
, DriveInfo
**fds
)
79 fdctrl_init_drives(&ISA_FDC(fdc
)->state
.bus
, fds
);
82 static const MemoryRegionPortio fdc_portio_list
[] = {
83 { 1, 5, 1, .read
= fdctrl_read
, .write
= fdctrl_write
},
84 { 7, 1, 1, .read
= fdctrl_read
, .write
= fdctrl_write
},
88 static void isabus_fdc_realize(DeviceState
*dev
, Error
**errp
)
90 ISADevice
*isadev
= ISA_DEVICE(dev
);
91 ISABus
*bus
= isa_bus_from_device(isadev
);
92 FDCtrlISABus
*isa
= ISA_FDC(dev
);
93 FDCtrl
*fdctrl
= &isa
->state
;
96 isa_register_portio_list(isadev
, &isa
->portio_list
,
97 isa
->iobase
, fdc_portio_list
, fdctrl
,
100 fdctrl
->irq
= isa_bus_get_irq(bus
, isa
->irq
);
101 fdctrl
->dma_chann
= isa
->dma
;
102 if (fdctrl
->dma_chann
!= -1) {
104 fdctrl
->dma
= isa_bus_get_dma(bus
, isa
->dma
);
106 error_setg(errp
, "ISA controller does not support DMA");
109 k
= ISADMA_GET_CLASS(fdctrl
->dma
);
110 k
->register_channel(fdctrl
->dma
, fdctrl
->dma_chann
,
111 &fdctrl_transfer_handler
, fdctrl
);
114 qdev_set_legacy_instance_id(dev
, isa
->iobase
, 2);
116 fdctrl_realize_common(dev
, fdctrl
, &err
);
118 error_propagate(errp
, err
);
123 FloppyDriveType
isa_fdc_get_drive_type(ISADevice
*fdc
, int i
)
125 FDCtrlISABus
*isa
= ISA_FDC(fdc
);
127 return isa
->state
.drives
[i
].drive
;
130 static void isa_fdc_get_drive_max_chs(FloppyDriveType type
, uint8_t *maxc
,
131 uint8_t *maxh
, uint8_t *maxs
)
135 *maxc
= *maxh
= *maxs
= 0;
136 for (fdf
= fd_formats
; fdf
->drive
!= FLOPPY_DRIVE_TYPE_NONE
; fdf
++) {
137 if (fdf
->drive
!= type
) {
140 if (*maxc
< fdf
->max_track
) {
141 *maxc
= fdf
->max_track
;
143 if (*maxh
< fdf
->max_head
) {
144 *maxh
= fdf
->max_head
;
146 if (*maxs
< fdf
->last_sect
) {
147 *maxs
= fdf
->last_sect
;
150 /* fd_formats must contain at least one entry per FloppyDriveType */
155 static Aml
*build_fdinfo_aml(int idx
, FloppyDriveType type
)
158 uint8_t maxc
, maxh
, maxs
;
160 isa_fdc_get_drive_max_chs(type
, &maxc
, &maxh
, &maxs
);
162 dev
= aml_device("FLP%c", 'A' + idx
);
164 aml_append(dev
, aml_name_decl("_ADR", aml_int(idx
)));
166 fdi
= aml_package(16);
167 aml_append(fdi
, aml_int(idx
)); /* Drive Number */
169 aml_int(cmos_get_fd_drive_type(type
))); /* Device Type */
171 * the values below are the limits of the drive, and are thus independent
172 * of the inserted media
174 aml_append(fdi
, aml_int(maxc
)); /* Maximum Cylinder Number */
175 aml_append(fdi
, aml_int(maxs
)); /* Maximum Sector Number */
176 aml_append(fdi
, aml_int(maxh
)); /* Maximum Head Number */
178 * SeaBIOS returns the below values for int 0x13 func 0x08 regardless of
179 * the drive type, so shall we
181 aml_append(fdi
, aml_int(0xAF)); /* disk_specify_1 */
182 aml_append(fdi
, aml_int(0x02)); /* disk_specify_2 */
183 aml_append(fdi
, aml_int(0x25)); /* disk_motor_wait */
184 aml_append(fdi
, aml_int(0x02)); /* disk_sector_siz */
185 aml_append(fdi
, aml_int(0x12)); /* disk_eot */
186 aml_append(fdi
, aml_int(0x1B)); /* disk_rw_gap */
187 aml_append(fdi
, aml_int(0xFF)); /* disk_dtl */
188 aml_append(fdi
, aml_int(0x6C)); /* disk_formt_gap */
189 aml_append(fdi
, aml_int(0xF6)); /* disk_fill */
190 aml_append(fdi
, aml_int(0x0F)); /* disk_head_sttl */
191 aml_append(fdi
, aml_int(0x08)); /* disk_motor_strt */
193 aml_append(dev
, aml_name_decl("_FDI", fdi
));
197 void isa_fdc_set_iobase(ISADevice
*fdc
, hwaddr iobase
)
199 FDCtrlISABus
*isa
= ISA_FDC(fdc
);
201 fdc
->ioport_id
= iobase
;
202 isa
->iobase
= iobase
;
203 portio_list_set_address(&isa
->portio_list
, isa
->iobase
);
206 void isa_fdc_set_enabled(ISADevice
*fdc
, bool enabled
)
208 portio_list_set_enabled(&ISA_FDC(fdc
)->portio_list
, enabled
);
211 int cmos_get_fd_drive_type(FloppyDriveType fd0
)
216 case FLOPPY_DRIVE_TYPE_144
:
217 /* 1.44 Mb 3"5 drive */
220 case FLOPPY_DRIVE_TYPE_288
:
221 /* 2.88 Mb 3"5 drive */
224 case FLOPPY_DRIVE_TYPE_120
:
225 /* 1.2 Mb 5"5 drive */
228 case FLOPPY_DRIVE_TYPE_NONE
:
236 static void build_fdc_aml(AcpiDevAmlIf
*adev
, Aml
*scope
)
238 FDCtrlISABus
*isa
= ISA_FDC(adev
);
243 #define ACPI_FDE_MAX_FD 4
244 uint32_t fde_buf
[5] = {
245 0, 0, 0, 0, /* presence of floppy drives #0 - #3 */
246 cpu_to_le32(2) /* tape presence (2 == never present) */
249 crs
= aml_resource_template();
251 aml_io(AML_DECODE16
, isa
->iobase
+ 2, isa
->iobase
+ 2, 0x00, 0x04));
253 aml_io(AML_DECODE16
, isa
->iobase
+ 7, isa
->iobase
+ 7, 0x00, 0x01));
254 aml_append(crs
, aml_irq_no_flags(isa
->irq
));
256 aml_dma(AML_COMPATIBILITY
, AML_NOTBUSMASTER
, AML_TRANSFER8
, isa
->dma
));
258 dev
= aml_device("FDC0");
259 aml_append(dev
, aml_name_decl("_HID", aml_eisaid("PNP0700")));
260 aml_append(dev
, aml_name_decl("_CRS", crs
));
262 for (i
= 0; i
< MIN(MAX_FD
, ACPI_FDE_MAX_FD
); i
++) {
263 FloppyDriveType type
= isa_fdc_get_drive_type(ISA_DEVICE(adev
), i
);
265 if (type
< FLOPPY_DRIVE_TYPE_NONE
) {
266 fde_buf
[i
] = cpu_to_le32(1); /* drive present */
267 aml_append(dev
, build_fdinfo_aml(i
, type
));
270 aml_append(dev
, aml_name_decl("_FDE",
271 aml_buffer(sizeof(fde_buf
), (uint8_t *)fde_buf
)));
273 aml_append(scope
, dev
);
276 static const VMStateDescription vmstate_isa_fdc
= {
279 .minimum_version_id
= 2,
280 .fields
= (const VMStateField
[]) {
281 VMSTATE_STRUCT(state
, FDCtrlISABus
, 0, vmstate_fdc
, FDCtrl
),
282 VMSTATE_END_OF_LIST()
286 static Property isa_fdc_properties
[] = {
287 DEFINE_PROP_UINT32("iobase", FDCtrlISABus
, iobase
, 0x3f0),
288 DEFINE_PROP_UINT32("irq", FDCtrlISABus
, irq
, 6),
289 DEFINE_PROP_UINT32("dma", FDCtrlISABus
, dma
, 2),
290 DEFINE_PROP_SIGNED("fdtypeA", FDCtrlISABus
, state
.qdev_for_drives
[0].type
,
291 FLOPPY_DRIVE_TYPE_AUTO
, qdev_prop_fdc_drive_type
,
293 DEFINE_PROP_SIGNED("fdtypeB", FDCtrlISABus
, state
.qdev_for_drives
[1].type
,
294 FLOPPY_DRIVE_TYPE_AUTO
, qdev_prop_fdc_drive_type
,
296 DEFINE_PROP_SIGNED("fallback", FDCtrlISABus
, state
.fallback
,
297 FLOPPY_DRIVE_TYPE_288
, qdev_prop_fdc_drive_type
,
299 DEFINE_PROP_END_OF_LIST(),
302 static void isabus_fdc_class_init(ObjectClass
*klass
, void *data
)
304 DeviceClass
*dc
= DEVICE_CLASS(klass
);
305 AcpiDevAmlIfClass
*adevc
= ACPI_DEV_AML_IF_CLASS(klass
);
307 dc
->desc
= "virtual floppy controller";
308 dc
->realize
= isabus_fdc_realize
;
310 device_class_set_legacy_reset(dc
, fdctrl_external_reset_isa
);
311 dc
->vmsd
= &vmstate_isa_fdc
;
312 adevc
->build_dev_aml
= build_fdc_aml
;
313 device_class_set_props(dc
, isa_fdc_properties
);
314 set_bit(DEVICE_CATEGORY_STORAGE
, dc
->categories
);
317 static void isabus_fdc_instance_init(Object
*obj
)
319 FDCtrlISABus
*isa
= ISA_FDC(obj
);
321 device_add_bootindex_property(obj
, &isa
->bootindexA
,
322 "bootindexA", "/floppy@0",
324 device_add_bootindex_property(obj
, &isa
->bootindexB
,
325 "bootindexB", "/floppy@1",
329 static const TypeInfo isa_fdc_info
= {
330 .name
= TYPE_ISA_FDC
,
331 .parent
= TYPE_ISA_DEVICE
,
332 .instance_size
= sizeof(FDCtrlISABus
),
333 .class_init
= isabus_fdc_class_init
,
334 .instance_init
= isabus_fdc_instance_init
,
335 .interfaces
= (InterfaceInfo
[]) {
336 { TYPE_ACPI_DEV_AML_IF
},
341 static void isa_fdc_register_types(void)
343 type_register_static(&isa_fdc_info
);
346 type_init(isa_fdc_register_types
)