fdc-isa.c 11 KB

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