]> git.proxmox.com Git - mirror_qemu.git/blame - hw/block/fdc-isa.c
linux-user/alpha: Set FPE_FLTUNK for gentrap ROPRAND
[mirror_qemu.git] / hw / block / fdc-isa.c
CommitLineData
72ea60e4
PMD
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/aml-build.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
52OBJECT_DECLARE_SIMPLE_TYPE(FDCtrlISABus, ISA_FDC)
53
54struct 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
67static 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
75void isa_fdc_init_drives(ISADevice *fdc, DriveInfo **fds)
76{
77 fdctrl_init_drives(&ISA_FDC(fdc)->state.bus, fds);
78}
79
80static 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
86static 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 isa_init_irq(isadev, &fdctrl->irq, 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
120FloppyDriveType 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
127static 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
150static 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
192int 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
217static void fdc_isa_build_aml(ISADevice *isadev, Aml *scope)
218{
219 Aml *dev;
220 Aml *crs;
221 int i;
222
223#define ACPI_FDE_MAX_FD 4
224 uint32_t fde_buf[5] = {
225 0, 0, 0, 0, /* presence of floppy drives #0 - #3 */
226 cpu_to_le32(2) /* tape presence (2 == never present) */
227 };
228
229 crs = aml_resource_template();
230 aml_append(crs, aml_io(AML_DECODE16, 0x03F2, 0x03F2, 0x00, 0x04));
231 aml_append(crs, aml_io(AML_DECODE16, 0x03F7, 0x03F7, 0x00, 0x01));
232 aml_append(crs, aml_irq_no_flags(6));
233 aml_append(crs,
234 aml_dma(AML_COMPATIBILITY, AML_NOTBUSMASTER, AML_TRANSFER8, 2));
235
236 dev = aml_device("FDC0");
237 aml_append(dev, aml_name_decl("_HID", aml_eisaid("PNP0700")));
238 aml_append(dev, aml_name_decl("_CRS", crs));
239
240 for (i = 0; i < MIN(MAX_FD, ACPI_FDE_MAX_FD); i++) {
241 FloppyDriveType type = isa_fdc_get_drive_type(isadev, i);
242
243 if (type < FLOPPY_DRIVE_TYPE_NONE) {
244 fde_buf[i] = cpu_to_le32(1); /* drive present */
245 aml_append(dev, build_fdinfo_aml(i, type));
246 }
247 }
248 aml_append(dev, aml_name_decl("_FDE",
249 aml_buffer(sizeof(fde_buf), (uint8_t *)fde_buf)));
250
251 aml_append(scope, dev);
252}
253
254static const VMStateDescription vmstate_isa_fdc = {
255 .name = "fdc",
256 .version_id = 2,
257 .minimum_version_id = 2,
258 .fields = (VMStateField[]) {
259 VMSTATE_STRUCT(state, FDCtrlISABus, 0, vmstate_fdc, FDCtrl),
260 VMSTATE_END_OF_LIST()
261 }
262};
263
264static Property isa_fdc_properties[] = {
265 DEFINE_PROP_UINT32("iobase", FDCtrlISABus, iobase, 0x3f0),
266 DEFINE_PROP_UINT32("irq", FDCtrlISABus, irq, 6),
267 DEFINE_PROP_UINT32("dma", FDCtrlISABus, dma, 2),
268 DEFINE_PROP_SIGNED("fdtypeA", FDCtrlISABus, state.qdev_for_drives[0].type,
269 FLOPPY_DRIVE_TYPE_AUTO, qdev_prop_fdc_drive_type,
270 FloppyDriveType),
271 DEFINE_PROP_SIGNED("fdtypeB", FDCtrlISABus, state.qdev_for_drives[1].type,
272 FLOPPY_DRIVE_TYPE_AUTO, qdev_prop_fdc_drive_type,
273 FloppyDriveType),
274 DEFINE_PROP_SIGNED("fallback", FDCtrlISABus, state.fallback,
275 FLOPPY_DRIVE_TYPE_288, qdev_prop_fdc_drive_type,
276 FloppyDriveType),
277 DEFINE_PROP_END_OF_LIST(),
278};
279
280static void isabus_fdc_class_init(ObjectClass *klass, void *data)
281{
282 DeviceClass *dc = DEVICE_CLASS(klass);
283 ISADeviceClass *isa = ISA_DEVICE_CLASS(klass);
284
9362984f 285 dc->desc = "virtual floppy controller";
72ea60e4
PMD
286 dc->realize = isabus_fdc_realize;
287 dc->fw_name = "fdc";
288 dc->reset = fdctrl_external_reset_isa;
289 dc->vmsd = &vmstate_isa_fdc;
290 isa->build_aml = fdc_isa_build_aml;
291 device_class_set_props(dc, isa_fdc_properties);
292 set_bit(DEVICE_CATEGORY_STORAGE, dc->categories);
293}
294
295static void isabus_fdc_instance_init(Object *obj)
296{
297 FDCtrlISABus *isa = ISA_FDC(obj);
298
299 device_add_bootindex_property(obj, &isa->bootindexA,
300 "bootindexA", "/floppy@0",
301 DEVICE(obj));
302 device_add_bootindex_property(obj, &isa->bootindexB,
303 "bootindexB", "/floppy@1",
304 DEVICE(obj));
305}
306
307static const TypeInfo isa_fdc_info = {
308 .name = TYPE_ISA_FDC,
309 .parent = TYPE_ISA_DEVICE,
310 .instance_size = sizeof(FDCtrlISABus),
311 .class_init = isabus_fdc_class_init,
312 .instance_init = isabus_fdc_instance_init,
313};
314
315static void isa_fdc_register_types(void)
316{
317 type_register_static(&isa_fdc_info);
318}
319
320type_init(isa_fdc_register_types)