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 "exec/ioport.h"
46 #include "qemu/log.h"
47 #include "qemu/main-loop.h"
48 #include "qemu/module.h"
49 #include "trace.h"
50 #include "qom/object.h"
51 #include "fdc-internal.h"
52
53 OBJECT_DECLARE_SIMPLE_TYPE(FDCtrlISABus, ISA_FDC)
54
55 struct FDCtrlISABus {
56 /*< private >*/
57 ISADevice parent_obj;
58 /*< public >*/
59
60 uint32_t iobase;
61 uint32_t irq;
62 uint32_t dma;
63 struct FDCtrl state;
64 PortioList portio_list;
65 int32_t bootindexA;
66 int32_t bootindexB;
67 };
68
fdctrl_external_reset_isa(DeviceState * d)69 static void fdctrl_external_reset_isa(DeviceState *d)
70 {
71 FDCtrlISABus *isa = ISA_FDC(d);
72 FDCtrl *s = &isa->state;
73
74 fdctrl_reset(s, 0);
75 }
76
isa_fdc_init_drives(ISADevice * fdc,DriveInfo ** fds)77 void isa_fdc_init_drives(ISADevice *fdc, DriveInfo **fds)
78 {
79 fdctrl_init_drives(&ISA_FDC(fdc)->state.bus, fds);
80 }
81
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 },
85 PORTIO_END_OF_LIST(),
86 };
87
isabus_fdc_realize(DeviceState * dev,Error ** errp)88 static void isabus_fdc_realize(DeviceState *dev, Error **errp)
89 {
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;
94 Error *err = NULL;
95
96 isa_register_portio_list(isadev, &isa->portio_list,
97 isa->iobase, fdc_portio_list, fdctrl,
98 "fdc");
99
100 fdctrl->irq = isa_bus_get_irq(bus, isa->irq);
101 fdctrl->dma_chann = isa->dma;
102 if (fdctrl->dma_chann != -1) {
103 IsaDmaClass *k;
104 fdctrl->dma = isa_bus_get_dma(bus, isa->dma);
105 if (!fdctrl->dma) {
106 error_setg(errp, "ISA controller does not support DMA");
107 return;
108 }
109 k = ISADMA_GET_CLASS(fdctrl->dma);
110 k->register_channel(fdctrl->dma, fdctrl->dma_chann,
111 &fdctrl_transfer_handler, fdctrl);
112 }
113
114 qdev_set_legacy_instance_id(dev, isa->iobase, 2);
115
116 fdctrl_realize_common(dev, fdctrl, &err);
117 if (err != NULL) {
118 error_propagate(errp, err);
119 return;
120 }
121 }
122
isa_fdc_get_drive_type(ISADevice * fdc,int i)123 FloppyDriveType isa_fdc_get_drive_type(ISADevice *fdc, int i)
124 {
125 FDCtrlISABus *isa = ISA_FDC(fdc);
126
127 return isa->state.drives[i].drive;
128 }
129
isa_fdc_get_drive_max_chs(FloppyDriveType type,uint8_t * maxc,uint8_t * maxh,uint8_t * maxs)130 static void isa_fdc_get_drive_max_chs(FloppyDriveType type, uint8_t *maxc,
131 uint8_t *maxh, uint8_t *maxs)
132 {
133 const FDFormat *fdf;
134
135 *maxc = *maxh = *maxs = 0;
136 for (fdf = fd_formats; fdf->drive != FLOPPY_DRIVE_TYPE_NONE; fdf++) {
137 if (fdf->drive != type) {
138 continue;
139 }
140 if (*maxc < fdf->max_track) {
141 *maxc = fdf->max_track;
142 }
143 if (*maxh < fdf->max_head) {
144 *maxh = fdf->max_head;
145 }
146 if (*maxs < fdf->last_sect) {
147 *maxs = fdf->last_sect;
148 }
149 }
150 (*maxc)--;
151 }
152
build_fdinfo_aml(int idx,FloppyDriveType type)153 static Aml *build_fdinfo_aml(int idx, FloppyDriveType type)
154 {
155 Aml *dev, *fdi;
156 uint8_t maxc, maxh, maxs;
157
158 isa_fdc_get_drive_max_chs(type, &maxc, &maxh, &maxs);
159
160 dev = aml_device("FLP%c", 'A' + idx);
161
162 aml_append(dev, aml_name_decl("_ADR", aml_int(idx)));
163
164 fdi = aml_package(16);
165 aml_append(fdi, aml_int(idx)); /* Drive Number */
166 aml_append(fdi,
167 aml_int(cmos_get_fd_drive_type(type))); /* Device Type */
168 /*
169 * the values below are the limits of the drive, and are thus independent
170 * of the inserted media
171 */
172 aml_append(fdi, aml_int(maxc)); /* Maximum Cylinder Number */
173 aml_append(fdi, aml_int(maxs)); /* Maximum Sector Number */
174 aml_append(fdi, aml_int(maxh)); /* Maximum Head Number */
175 /*
176 * SeaBIOS returns the below values for int 0x13 func 0x08 regardless of
177 * the drive type, so shall we
178 */
179 aml_append(fdi, aml_int(0xAF)); /* disk_specify_1 */
180 aml_append(fdi, aml_int(0x02)); /* disk_specify_2 */
181 aml_append(fdi, aml_int(0x25)); /* disk_motor_wait */
182 aml_append(fdi, aml_int(0x02)); /* disk_sector_siz */
183 aml_append(fdi, aml_int(0x12)); /* disk_eot */
184 aml_append(fdi, aml_int(0x1B)); /* disk_rw_gap */
185 aml_append(fdi, aml_int(0xFF)); /* disk_dtl */
186 aml_append(fdi, aml_int(0x6C)); /* disk_formt_gap */
187 aml_append(fdi, aml_int(0xF6)); /* disk_fill */
188 aml_append(fdi, aml_int(0x0F)); /* disk_head_sttl */
189 aml_append(fdi, aml_int(0x08)); /* disk_motor_strt */
190
191 aml_append(dev, aml_name_decl("_FDI", fdi));
192 return dev;
193 }
194
isa_fdc_set_iobase(ISADevice * fdc,hwaddr iobase)195 void isa_fdc_set_iobase(ISADevice *fdc, hwaddr iobase)
196 {
197 FDCtrlISABus *isa = ISA_FDC(fdc);
198
199 fdc->ioport_id = iobase;
200 isa->iobase = iobase;
201 portio_list_set_address(&isa->portio_list, isa->iobase);
202 }
203
isa_fdc_set_enabled(ISADevice * fdc,bool enabled)204 void isa_fdc_set_enabled(ISADevice *fdc, bool enabled)
205 {
206 portio_list_set_enabled(&ISA_FDC(fdc)->portio_list, enabled);
207 }
208
cmos_get_fd_drive_type(FloppyDriveType fd0)209 int cmos_get_fd_drive_type(FloppyDriveType fd0)
210 {
211 int val;
212
213 switch (fd0) {
214 case FLOPPY_DRIVE_TYPE_144:
215 /* 1.44 Mb 3"5 drive */
216 val = 4;
217 break;
218 case FLOPPY_DRIVE_TYPE_288:
219 /* 2.88 Mb 3"5 drive */
220 val = 5;
221 break;
222 case FLOPPY_DRIVE_TYPE_120:
223 /* 1.2 Mb 5"5 drive */
224 val = 2;
225 break;
226 case FLOPPY_DRIVE_TYPE_NONE:
227 default:
228 val = 0;
229 break;
230 }
231 return val;
232 }
233
build_fdc_aml(AcpiDevAmlIf * adev,Aml * scope)234 static void build_fdc_aml(AcpiDevAmlIf *adev, Aml *scope)
235 {
236 FDCtrlISABus *isa = ISA_FDC(adev);
237 Aml *dev;
238 Aml *crs;
239 int i;
240
241 #define ACPI_FDE_MAX_FD 4
242 uint32_t fde_buf[5] = {
243 0, 0, 0, 0, /* presence of floppy drives #0 - #3 */
244 cpu_to_le32(2) /* tape presence (2 == never present) */
245 };
246
247 crs = aml_resource_template();
248 aml_append(crs,
249 aml_io(AML_DECODE16, isa->iobase + 2, isa->iobase + 2, 0x00, 0x04));
250 aml_append(crs,
251 aml_io(AML_DECODE16, isa->iobase + 7, isa->iobase + 7, 0x00, 0x01));
252 aml_append(crs, aml_irq_no_flags(isa->irq));
253 aml_append(crs,
254 aml_dma(AML_COMPATIBILITY, AML_NOTBUSMASTER, AML_TRANSFER8, isa->dma));
255
256 dev = aml_device("FDC0");
257 aml_append(dev, aml_name_decl("_HID", aml_eisaid("PNP0700")));
258 aml_append(dev, aml_name_decl("_CRS", crs));
259
260 for (i = 0; i < MIN(MAX_FD, ACPI_FDE_MAX_FD); i++) {
261 FloppyDriveType type = isa_fdc_get_drive_type(ISA_DEVICE(adev), i);
262
263 if (type < FLOPPY_DRIVE_TYPE_NONE) {
264 fde_buf[i] = cpu_to_le32(1); /* drive present */
265 aml_append(dev, build_fdinfo_aml(i, type));
266 }
267 }
268 aml_append(dev, aml_name_decl("_FDE",
269 aml_buffer(sizeof(fde_buf), (uint8_t *)fde_buf)));
270
271 aml_append(scope, dev);
272 }
273
274 static const VMStateDescription vmstate_isa_fdc = {
275 .name = "fdc",
276 .version_id = 2,
277 .minimum_version_id = 2,
278 .fields = (const VMStateField[]) {
279 VMSTATE_STRUCT(state, FDCtrlISABus, 0, vmstate_fdc, FDCtrl),
280 VMSTATE_END_OF_LIST()
281 }
282 };
283
284 static Property isa_fdc_properties[] = {
285 DEFINE_PROP_UINT32("iobase", FDCtrlISABus, iobase, 0x3f0),
286 DEFINE_PROP_UINT32("irq", FDCtrlISABus, irq, 6),
287 DEFINE_PROP_UINT32("dma", FDCtrlISABus, dma, 2),
288 DEFINE_PROP_SIGNED("fdtypeA", FDCtrlISABus, state.qdev_for_drives[0].type,
289 FLOPPY_DRIVE_TYPE_AUTO, qdev_prop_fdc_drive_type,
290 FloppyDriveType),
291 DEFINE_PROP_SIGNED("fdtypeB", FDCtrlISABus, state.qdev_for_drives[1].type,
292 FLOPPY_DRIVE_TYPE_AUTO, qdev_prop_fdc_drive_type,
293 FloppyDriveType),
294 DEFINE_PROP_SIGNED("fallback", FDCtrlISABus, state.fallback,
295 FLOPPY_DRIVE_TYPE_288, qdev_prop_fdc_drive_type,
296 FloppyDriveType),
297 DEFINE_PROP_END_OF_LIST(),
298 };
299
isabus_fdc_class_init(ObjectClass * klass,void * data)300 static void isabus_fdc_class_init(ObjectClass *klass, void *data)
301 {
302 DeviceClass *dc = DEVICE_CLASS(klass);
303 AcpiDevAmlIfClass *adevc = ACPI_DEV_AML_IF_CLASS(klass);
304
305 dc->desc = "virtual floppy controller";
306 dc->realize = isabus_fdc_realize;
307 dc->fw_name = "fdc";
308 dc->reset = fdctrl_external_reset_isa;
309 dc->vmsd = &vmstate_isa_fdc;
310 adevc->build_dev_aml = build_fdc_aml;
311 device_class_set_props(dc, isa_fdc_properties);
312 set_bit(DEVICE_CATEGORY_STORAGE, dc->categories);
313 }
314
isabus_fdc_instance_init(Object * obj)315 static void isabus_fdc_instance_init(Object *obj)
316 {
317 FDCtrlISABus *isa = ISA_FDC(obj);
318
319 device_add_bootindex_property(obj, &isa->bootindexA,
320 "bootindexA", "/floppy@0",
321 DEVICE(obj));
322 device_add_bootindex_property(obj, &isa->bootindexB,
323 "bootindexB", "/floppy@1",
324 DEVICE(obj));
325 }
326
327 static const TypeInfo isa_fdc_info = {
328 .name = TYPE_ISA_FDC,
329 .parent = TYPE_ISA_DEVICE,
330 .instance_size = sizeof(FDCtrlISABus),
331 .class_init = isabus_fdc_class_init,
332 .instance_init = isabus_fdc_instance_init,
333 .interfaces = (InterfaceInfo[]) {
334 { TYPE_ACPI_DEV_AML_IF },
335 { },
336 },
337 };
338
isa_fdc_register_types(void)339 static void isa_fdc_register_types(void)
340 {
341 type_register_static(&isa_fdc_info);
342 }
343
344 type_init(isa_fdc_register_types)
345