serial-pci.c 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274
  1. /*
  2. * QEMU 16550A UART emulation
  3. *
  4. * Copyright (c) 2003-2004 Fabrice Bellard
  5. * Copyright (c) 2008 Citrix Systems, Inc.
  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. /* see docs/specs/pci-serial.txt */
  26. #include "hw/char/serial.h"
  27. #include "hw/pci/pci.h"
  28. #define PCI_SERIAL_MAX_PORTS 4
  29. typedef struct PCISerialState {
  30. PCIDevice dev;
  31. SerialState state;
  32. uint8_t prog_if;
  33. } PCISerialState;
  34. typedef struct PCIMultiSerialState {
  35. PCIDevice dev;
  36. MemoryRegion iobar;
  37. uint32_t ports;
  38. char *name[PCI_SERIAL_MAX_PORTS];
  39. SerialState state[PCI_SERIAL_MAX_PORTS];
  40. uint32_t level[PCI_SERIAL_MAX_PORTS];
  41. qemu_irq *irqs;
  42. uint8_t prog_if;
  43. } PCIMultiSerialState;
  44. static void multi_serial_pci_exit(PCIDevice *dev);
  45. static void serial_pci_realize(PCIDevice *dev, Error **errp)
  46. {
  47. PCISerialState *pci = DO_UPCAST(PCISerialState, dev, dev);
  48. SerialState *s = &pci->state;
  49. Error *err = NULL;
  50. s->baudbase = 115200;
  51. serial_realize_core(s, &err);
  52. if (err != NULL) {
  53. error_propagate(errp, err);
  54. return;
  55. }
  56. pci->dev.config[PCI_CLASS_PROG] = pci->prog_if;
  57. pci->dev.config[PCI_INTERRUPT_PIN] = 0x01;
  58. s->irq = pci_allocate_irq(&pci->dev);
  59. memory_region_init_io(&s->io, OBJECT(pci), &serial_io_ops, s, "serial", 8);
  60. pci_register_bar(&pci->dev, 0, PCI_BASE_ADDRESS_SPACE_IO, &s->io);
  61. }
  62. static void multi_serial_irq_mux(void *opaque, int n, int level)
  63. {
  64. PCIMultiSerialState *pci = opaque;
  65. int i, pending = 0;
  66. pci->level[n] = level;
  67. for (i = 0; i < pci->ports; i++) {
  68. if (pci->level[i]) {
  69. pending = 1;
  70. }
  71. }
  72. pci_set_irq(&pci->dev, pending);
  73. }
  74. static void multi_serial_pci_realize(PCIDevice *dev, Error **errp)
  75. {
  76. PCIDeviceClass *pc = PCI_DEVICE_GET_CLASS(dev);
  77. PCIMultiSerialState *pci = DO_UPCAST(PCIMultiSerialState, dev, dev);
  78. SerialState *s;
  79. Error *err = NULL;
  80. int i, nr_ports = 0;
  81. switch (pc->device_id) {
  82. case 0x0003:
  83. nr_ports = 2;
  84. break;
  85. case 0x0004:
  86. nr_ports = 4;
  87. break;
  88. }
  89. assert(nr_ports > 0);
  90. assert(nr_ports <= PCI_SERIAL_MAX_PORTS);
  91. pci->dev.config[PCI_CLASS_PROG] = pci->prog_if;
  92. pci->dev.config[PCI_INTERRUPT_PIN] = 0x01;
  93. memory_region_init(&pci->iobar, OBJECT(pci), "multiserial", 8 * nr_ports);
  94. pci_register_bar(&pci->dev, 0, PCI_BASE_ADDRESS_SPACE_IO, &pci->iobar);
  95. pci->irqs = qemu_allocate_irqs(multi_serial_irq_mux, pci,
  96. nr_ports);
  97. for (i = 0; i < nr_ports; i++) {
  98. s = pci->state + i;
  99. s->baudbase = 115200;
  100. serial_realize_core(s, &err);
  101. if (err != NULL) {
  102. error_propagate(errp, err);
  103. multi_serial_pci_exit(dev);
  104. return;
  105. }
  106. s->irq = pci->irqs[i];
  107. pci->name[i] = g_strdup_printf("uart #%d", i+1);
  108. memory_region_init_io(&s->io, OBJECT(pci), &serial_io_ops, s,
  109. pci->name[i], 8);
  110. memory_region_add_subregion(&pci->iobar, 8 * i, &s->io);
  111. pci->ports++;
  112. }
  113. }
  114. static void serial_pci_exit(PCIDevice *dev)
  115. {
  116. PCISerialState *pci = DO_UPCAST(PCISerialState, dev, dev);
  117. SerialState *s = &pci->state;
  118. serial_exit_core(s);
  119. qemu_free_irq(s->irq);
  120. }
  121. static void multi_serial_pci_exit(PCIDevice *dev)
  122. {
  123. PCIMultiSerialState *pci = DO_UPCAST(PCIMultiSerialState, dev, dev);
  124. SerialState *s;
  125. int i;
  126. for (i = 0; i < pci->ports; i++) {
  127. s = pci->state + i;
  128. serial_exit_core(s);
  129. memory_region_del_subregion(&pci->iobar, &s->io);
  130. g_free(pci->name[i]);
  131. }
  132. qemu_free_irqs(pci->irqs, pci->ports);
  133. }
  134. static const VMStateDescription vmstate_pci_serial = {
  135. .name = "pci-serial",
  136. .version_id = 1,
  137. .minimum_version_id = 1,
  138. .fields = (VMStateField[]) {
  139. VMSTATE_PCI_DEVICE(dev, PCISerialState),
  140. VMSTATE_STRUCT(state, PCISerialState, 0, vmstate_serial, SerialState),
  141. VMSTATE_END_OF_LIST()
  142. }
  143. };
  144. static const VMStateDescription vmstate_pci_multi_serial = {
  145. .name = "pci-serial-multi",
  146. .version_id = 1,
  147. .minimum_version_id = 1,
  148. .fields = (VMStateField[]) {
  149. VMSTATE_PCI_DEVICE(dev, PCIMultiSerialState),
  150. VMSTATE_STRUCT_ARRAY(state, PCIMultiSerialState, PCI_SERIAL_MAX_PORTS,
  151. 0, vmstate_serial, SerialState),
  152. VMSTATE_UINT32_ARRAY(level, PCIMultiSerialState, PCI_SERIAL_MAX_PORTS),
  153. VMSTATE_END_OF_LIST()
  154. }
  155. };
  156. static Property serial_pci_properties[] = {
  157. DEFINE_PROP_CHR("chardev", PCISerialState, state.chr),
  158. DEFINE_PROP_UINT8("prog_if", PCISerialState, prog_if, 0x02),
  159. DEFINE_PROP_END_OF_LIST(),
  160. };
  161. static Property multi_2x_serial_pci_properties[] = {
  162. DEFINE_PROP_CHR("chardev1", PCIMultiSerialState, state[0].chr),
  163. DEFINE_PROP_CHR("chardev2", PCIMultiSerialState, state[1].chr),
  164. DEFINE_PROP_UINT8("prog_if", PCIMultiSerialState, prog_if, 0x02),
  165. DEFINE_PROP_END_OF_LIST(),
  166. };
  167. static Property multi_4x_serial_pci_properties[] = {
  168. DEFINE_PROP_CHR("chardev1", PCIMultiSerialState, state[0].chr),
  169. DEFINE_PROP_CHR("chardev2", PCIMultiSerialState, state[1].chr),
  170. DEFINE_PROP_CHR("chardev3", PCIMultiSerialState, state[2].chr),
  171. DEFINE_PROP_CHR("chardev4", PCIMultiSerialState, state[3].chr),
  172. DEFINE_PROP_UINT8("prog_if", PCIMultiSerialState, prog_if, 0x02),
  173. DEFINE_PROP_END_OF_LIST(),
  174. };
  175. static void serial_pci_class_initfn(ObjectClass *klass, void *data)
  176. {
  177. DeviceClass *dc = DEVICE_CLASS(klass);
  178. PCIDeviceClass *pc = PCI_DEVICE_CLASS(klass);
  179. pc->realize = serial_pci_realize;
  180. pc->exit = serial_pci_exit;
  181. pc->vendor_id = PCI_VENDOR_ID_REDHAT;
  182. pc->device_id = PCI_DEVICE_ID_REDHAT_SERIAL;
  183. pc->revision = 1;
  184. pc->class_id = PCI_CLASS_COMMUNICATION_SERIAL;
  185. dc->vmsd = &vmstate_pci_serial;
  186. dc->props = serial_pci_properties;
  187. set_bit(DEVICE_CATEGORY_INPUT, dc->categories);
  188. }
  189. static void multi_2x_serial_pci_class_initfn(ObjectClass *klass, void *data)
  190. {
  191. DeviceClass *dc = DEVICE_CLASS(klass);
  192. PCIDeviceClass *pc = PCI_DEVICE_CLASS(klass);
  193. pc->realize = multi_serial_pci_realize;
  194. pc->exit = multi_serial_pci_exit;
  195. pc->vendor_id = PCI_VENDOR_ID_REDHAT;
  196. pc->device_id = PCI_DEVICE_ID_REDHAT_SERIAL2;
  197. pc->revision = 1;
  198. pc->class_id = PCI_CLASS_COMMUNICATION_SERIAL;
  199. dc->vmsd = &vmstate_pci_multi_serial;
  200. dc->props = multi_2x_serial_pci_properties;
  201. set_bit(DEVICE_CATEGORY_INPUT, dc->categories);
  202. }
  203. static void multi_4x_serial_pci_class_initfn(ObjectClass *klass, void *data)
  204. {
  205. DeviceClass *dc = DEVICE_CLASS(klass);
  206. PCIDeviceClass *pc = PCI_DEVICE_CLASS(klass);
  207. pc->realize = multi_serial_pci_realize;
  208. pc->exit = multi_serial_pci_exit;
  209. pc->vendor_id = PCI_VENDOR_ID_REDHAT;
  210. pc->device_id = PCI_DEVICE_ID_REDHAT_SERIAL4;
  211. pc->revision = 1;
  212. pc->class_id = PCI_CLASS_COMMUNICATION_SERIAL;
  213. dc->vmsd = &vmstate_pci_multi_serial;
  214. dc->props = multi_4x_serial_pci_properties;
  215. set_bit(DEVICE_CATEGORY_INPUT, dc->categories);
  216. }
  217. static const TypeInfo serial_pci_info = {
  218. .name = "pci-serial",
  219. .parent = TYPE_PCI_DEVICE,
  220. .instance_size = sizeof(PCISerialState),
  221. .class_init = serial_pci_class_initfn,
  222. };
  223. static const TypeInfo multi_2x_serial_pci_info = {
  224. .name = "pci-serial-2x",
  225. .parent = TYPE_PCI_DEVICE,
  226. .instance_size = sizeof(PCIMultiSerialState),
  227. .class_init = multi_2x_serial_pci_class_initfn,
  228. };
  229. static const TypeInfo multi_4x_serial_pci_info = {
  230. .name = "pci-serial-4x",
  231. .parent = TYPE_PCI_DEVICE,
  232. .instance_size = sizeof(PCIMultiSerialState),
  233. .class_init = multi_4x_serial_pci_class_initfn,
  234. };
  235. static void serial_pci_register_types(void)
  236. {
  237. type_register_static(&serial_pci_info);
  238. type_register_static(&multi_2x_serial_pci_info);
  239. type_register_static(&multi_4x_serial_pci_info);
  240. }
  241. type_init(serial_pci_register_types)