xref: /openbmc/qemu/hw/usb/hcd-uhci-pci.c (revision 5759a6ac4c6ea784e08675db55cc02771998a018)
1 /*
2  * USB UHCI controller emulation
3  * PCI code
4  *
5  * Copyright (c) 2005 Fabrice Bellard
6  *
7  * Copyright (c) 2008 Max Krasnyansky
8  *     Magor rewrite of the UHCI data structures parser and frame processor
9  *     Support for fully async operation and multiple outstanding transactions
10  *
11  * Permission is hereby granted, free of charge, to any person obtaining a copy
12  * of this software and associated documentation files (the "Software"), to deal
13  * in the Software without restriction, including without limitation the rights
14  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
15  * copies of the Software, and to permit persons to whom the Software is
16  * furnished to do so, subject to the following conditions:
17  *
18  * The above copyright notice and this permission notice shall be included in
19  * all copies or substantial portions of the Software.
20  *
21  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
22  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
24  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
26  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
27  * THE SOFTWARE.
28  */
29 
30 #include "qemu/osdep.h"
31 #include "hw/irq.h"
32 #include "hw/usb.h"
33 #include "migration/vmstate.h"
34 #include "hw/pci/pci.h"
35 #include "hw/qdev-properties.h"
36 #include "qapi/error.h"
37 #include "qemu/main-loop.h"
38 #include "qemu/module.h"
39 #include "qom/object.h"
40 #include "hcd-uhci-pci.h"
41 
42 struct UHCIPCIDeviceClass {
43     PCIDeviceClass parent_class;
44     UHCIPCIInfo info;
45 };
46 
47 static const VMStateDescription vmstate_uhci = {
48     .name = "pci_uhci",
49     .version_id = 1,
50     .minimum_version_id = 1,
51     .fields = (const VMStateField[]) {
52         VMSTATE_PCI_DEVICE(dev, UHCIPCIState),
53         VMSTATE_STRUCT(state, UHCIPCIState, 1, vmstate_uhci_state, UHCIState),
54         VMSTATE_END_OF_LIST()
55     }
56 };
57 
uhci_pci_reset(UHCIState * uhci)58 static void uhci_pci_reset(UHCIState *uhci)
59 {
60     UHCIPCIState *pstate = container_of(uhci, UHCIPCIState, state);
61     PCIDevice *d = &pstate->dev;
62 
63     d->config[0x6a] = 0x01; /* usb clock */
64     d->config[0x6b] = 0x00;
65 
66     uhci_state_reset(uhci);
67 }
68 
usb_uhci_common_realize_pci(PCIDevice * dev,Error ** errp)69 void usb_uhci_common_realize_pci(PCIDevice *dev, Error **errp)
70 {
71     Error *err = NULL;
72     UHCIPCIDeviceClass *u = UHCI_PCI_GET_CLASS(dev);
73     UHCIPCIState *uhci = UHCI_PCI(dev);
74     UHCIState *s = &uhci->state;
75     uint8_t *pci_conf = dev->config;
76 
77     pci_conf[PCI_CLASS_PROG] = 0x00;
78     /* TODO: reset value should be 0. */
79     pci_conf[USB_SBRN] = USB_RELEASE_1; /* release number */
80     pci_config_set_interrupt_pin(pci_conf, u->info.irq_pin + 1);
81 
82     s->irq = pci_allocate_irq(dev);
83     s->masterbus = uhci->masterbus;
84     s->firstport = uhci->firstport;
85     s->maxframes = uhci->maxframes;
86     s->frame_bandwidth = uhci->frame_bandwidth;
87     s->as = pci_get_address_space(dev);
88     s->uhci_reset = uhci_pci_reset;
89 
90     usb_uhci_init(s, DEVICE(dev), &err);
91 
92     /*
93      * Use region 4 for consistency with real hardware.  BSD guests seem
94      * to rely on this.
95      */
96     pci_register_bar(dev, 4, PCI_BASE_ADDRESS_SPACE_IO, &s->mem);
97 }
98 
uhci_pci_reset_pci(DeviceState * dev)99 static void uhci_pci_reset_pci(DeviceState *dev)
100 {
101     PCIDevice *d = PCI_DEVICE(dev);
102     UHCIPCIState *uhci = UHCI_PCI(d);
103 
104     uhci_pci_reset(&uhci->state);
105 }
106 
usb_uhci_pci_exit(PCIDevice * dev)107 static void usb_uhci_pci_exit(PCIDevice *dev)
108 {
109     UHCIPCIState *uhci = UHCI_PCI(dev);
110     UHCIState *s = &uhci->state;
111 
112     usb_uhci_exit(s);
113 
114     qemu_free_irq(s->irq);
115 }
116 
117 static const Property uhci_properties_companion[] = {
118     DEFINE_PROP_STRING("masterbus", UHCIPCIState, masterbus),
119     DEFINE_PROP_UINT32("firstport", UHCIPCIState, firstport, 0),
120     DEFINE_PROP_UINT32("bandwidth", UHCIPCIState, frame_bandwidth, 1280),
121     DEFINE_PROP_UINT32("maxframes", UHCIPCIState, maxframes, 128),
122 };
123 static const Property uhci_properties_standalone[] = {
124     DEFINE_PROP_UINT32("bandwidth", UHCIPCIState, frame_bandwidth, 1280),
125     DEFINE_PROP_UINT32("maxframes", UHCIPCIState, maxframes, 128),
126 };
127 
uhci_pci_class_init(ObjectClass * klass,void * data)128 static void uhci_pci_class_init(ObjectClass *klass, void *data)
129 {
130     DeviceClass *dc = DEVICE_CLASS(klass);
131     PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
132 
133     k->class_id  = PCI_CLASS_SERIAL_USB;
134     dc->vmsd = &vmstate_uhci;
135     device_class_set_legacy_reset(dc, uhci_pci_reset_pci);
136     set_bit(DEVICE_CATEGORY_USB, dc->categories);
137 }
138 
139 static const TypeInfo uhci_pci_type_info = {
140     .name = TYPE_UHCI_PCI,
141     .parent = TYPE_PCI_DEVICE,
142     .instance_size = sizeof(UHCIPCIState),
143     .class_size    = sizeof(UHCIPCIDeviceClass),
144     .class_init    = uhci_pci_class_init,
145     .interfaces = (InterfaceInfo[]) {
146         { INTERFACE_CONVENTIONAL_PCI_DEVICE },
147         { },
148     },
149 };
150 
uhci_pci_data_class_init(ObjectClass * klass,void * data)151 void uhci_pci_data_class_init(ObjectClass *klass, void *data)
152 {
153     PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
154     DeviceClass *dc = DEVICE_CLASS(klass);
155     UHCIPCIDeviceClass *u = UHCI_PCI_CLASS(klass);
156     const UHCIPCIInfo *info = data;
157 
158     k->realize = info->realize ? info->realize : usb_uhci_common_realize_pci;
159     k->exit = info->unplug ? usb_uhci_pci_exit : NULL;
160     k->vendor_id = info->vendor_id;
161     k->device_id = info->device_id;
162     k->revision  = info->revision;
163     if (!info->unplug) {
164         /* uhci controllers in companion setups can't be hotplugged */
165         dc->hotpluggable = false;
166         device_class_set_props(dc, uhci_properties_companion);
167     } else {
168         device_class_set_props(dc, uhci_properties_standalone);
169     }
170     if (info->notuser) {
171         dc->user_creatable = false;
172     }
173     u->info = *info;
174 }
175 
176 static UHCIPCIInfo uhci_pci_info[] = {
177     {
178         .name      = TYPE_PIIX3_USB_UHCI,
179         .vendor_id = PCI_VENDOR_ID_INTEL,
180         .device_id = PCI_DEVICE_ID_INTEL_82371SB_2,
181         .revision  = 0x01,
182         .irq_pin   = 3,
183         .unplug    = true,
184     },{
185         .name      = TYPE_PIIX4_USB_UHCI,
186         .vendor_id = PCI_VENDOR_ID_INTEL,
187         .device_id = PCI_DEVICE_ID_INTEL_82371AB_2,
188         .revision  = 0x01,
189         .irq_pin   = 3,
190         .unplug    = true,
191     },{
192         .name      = TYPE_ICH9_USB_UHCI(1), /* 00:1d.0 */
193         .vendor_id = PCI_VENDOR_ID_INTEL,
194         .device_id = PCI_DEVICE_ID_INTEL_82801I_UHCI1,
195         .revision  = 0x03,
196         .irq_pin   = 0,
197         .unplug    = false,
198     },{
199         .name      = TYPE_ICH9_USB_UHCI(2), /* 00:1d.1 */
200         .vendor_id = PCI_VENDOR_ID_INTEL,
201         .device_id = PCI_DEVICE_ID_INTEL_82801I_UHCI2,
202         .revision  = 0x03,
203         .irq_pin   = 1,
204         .unplug    = false,
205     },{
206         .name      = TYPE_ICH9_USB_UHCI(3), /* 00:1d.2 */
207         .vendor_id = PCI_VENDOR_ID_INTEL,
208         .device_id = PCI_DEVICE_ID_INTEL_82801I_UHCI3,
209         .revision  = 0x03,
210         .irq_pin   = 2,
211         .unplug    = false,
212     },{
213         .name      = TYPE_ICH9_USB_UHCI(4), /* 00:1a.0 */
214         .vendor_id = PCI_VENDOR_ID_INTEL,
215         .device_id = PCI_DEVICE_ID_INTEL_82801I_UHCI4,
216         .revision  = 0x03,
217         .irq_pin   = 0,
218         .unplug    = false,
219     },{
220         .name      = TYPE_ICH9_USB_UHCI(5), /* 00:1a.1 */
221         .vendor_id = PCI_VENDOR_ID_INTEL,
222         .device_id = PCI_DEVICE_ID_INTEL_82801I_UHCI5,
223         .revision  = 0x03,
224         .irq_pin   = 1,
225         .unplug    = false,
226     },{
227         .name      = TYPE_ICH9_USB_UHCI(6), /* 00:1a.2 */
228         .vendor_id = PCI_VENDOR_ID_INTEL,
229         .device_id = PCI_DEVICE_ID_INTEL_82801I_UHCI6,
230         .revision  = 0x03,
231         .irq_pin   = 2,
232         .unplug    = false,
233     }
234 };
235 
uhci_pci_register_types(void)236 static void uhci_pci_register_types(void)
237 {
238     TypeInfo type_info = {
239         .parent        = TYPE_UHCI_PCI,
240         .class_init    = uhci_pci_data_class_init,
241     };
242     int i;
243 
244     type_register_static(&uhci_pci_type_info);
245 
246     for (i = 0; i < ARRAY_SIZE(uhci_pci_info); i++) {
247         type_info.name = uhci_pci_info[i].name;
248         type_info.class_data = uhci_pci_info + i;
249         type_register_static(&type_info);
250     }
251 }
252 
253 type_init(uhci_pci_register_types)
254