1 /////////////////////////////////////////////////////////////////////////
2 // $Id: usb_ehci.cc 14296 2021-06-30 15:50:49Z vruppert $
3 /////////////////////////////////////////////////////////////////////////
4 //
5 // Experimental USB EHCI adapter (partly ported from Qemu)
6 //
7 // Copyright (C) 2015-2021 The Bochs Project
8 //
9 // Copyright(c) 2008 Emutex Ltd. (address@hidden)
10 // Copyright(c) 2011-2012 Red Hat, Inc.
11 //
12 // Red Hat Authors:
13 // Gerd Hoffmann <kraxel@redhat.com>
14 // Hans de Goede <hdegoede@redhat.com>
15 //
16 // EHCI project was started by Mark Burkley, with contributions by
17 // Niels de Vos. David S. Ahern continued working on it. Kevin Wolf,
18 // Jan Kiszka and Vincent Palatin contributed bugfixes.
19 //
20 //
21 // This library is free software; you can redistribute it and/or
22 // modify it under the terms of the GNU Lesser General Public
23 // License as published by the Free Software Foundation; either
24 // version 2 of the License, or (at your option) any later version.
25 //
26 // This library is distributed in the hope that it will be useful,
27 // but WITHOUT ANY WARRANTY; without even the implied warranty of
28 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
29 // Lesser General Public License for more details.
30 //
31 // You should have received a copy of the GNU Lesser General Public
32 // License along with this library; if not, write to the Free Software
33 // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
34 /////////////////////////////////////////////////////////////////////////
35
36 // Define BX_PLUGGABLE in files that can be compiled into plugins. For
37 // platforms that require a special tag on exported symbols, BX_PLUGGABLE
38 // is used to know when we are exporting symbols and when we are importing.
39 #define BX_PLUGGABLE
40
41 #include "iodev.h"
42
43 #if BX_SUPPORT_PCI && BX_SUPPORT_USB_EHCI
44
45 #include "pci.h"
46 #include "usb_common.h"
47 #include "uhci_core.h"
48 #include "qemu-queue.h"
49 #include "usb_ehci.h"
50
51 #define LOG_THIS theUSB_EHCI->
52
53 bx_usb_ehci_c* theUSB_EHCI = NULL;
54
55 #define USB_RET_PROCERR (-99)
56
57 #define IO_SPACE_SIZE 256
58
59 #define OPS_REGS_OFFSET 0x20
60
61 #define USBSTS_INT (1 << 0) // USB Interrupt
62 #define USBSTS_ERRINT (1 << 1) // Error Interrupt
63 #define USBSTS_PCD (1 << 2) // Port Change Detect
64 #define USBSTS_FLR (1 << 3) // Frame List Rollover
65 #define USBSTS_HSE (1 << 4) // Host System Error
66 #define USBSTS_IAA (1 << 5) // Interrupt on Async Advance
67
68 #define USBINTR_MASK 0x0000003f
69
70 #define FRAME_TIMER_FREQ 1000
71 #define FRAME_TIMER_USEC (1000000 / FRAME_TIMER_FREQ)
72
73 #define BUFF_SIZE 5*4096 // Max bytes to transfer per transaction
74 #define MAX_QH 100 // Max allowable queue heads in a chain
75 #define MIN_FR_PER_TICK 3 // Min frames to process when catching up
76
77 /* Internal periodic / asynchronous schedule state machine states
78 */
79 typedef enum {
80 EST_INACTIVE = 1000,
81 EST_ACTIVE,
82 EST_EXECUTING,
83 EST_SLEEPING,
84 /* The following states are internal to the state machine function
85 */
86 EST_WAITLISTHEAD,
87 EST_FETCHENTRY,
88 EST_FETCHQH,
89 EST_FETCHITD,
90 EST_FETCHSITD,
91 EST_ADVANCEQUEUE,
92 EST_FETCHQTD,
93 EST_EXECUTE,
94 EST_WRITEBACK,
95 EST_HORIZONTALQH
96 } EHCI_STATES;
97
98 /* macros for accessing fields within next link pointer entry */
99 #define NLPTR_GET(x) ((x) & 0xffffffe0)
100 #define NLPTR_TYPE_GET(x) (((x) >> 1) & 3)
101 #define NLPTR_TBIT(x) ((x) & 1) // 1=invalid, 0=valid
102
103 /* link pointer types */
104 #define NLPTR_TYPE_ITD 0 // isoc xfer descriptor
105 #define NLPTR_TYPE_QH 1 // queue head
106 #define NLPTR_TYPE_STITD 2 // split xaction, isoc xfer descriptor
107 #define NLPTR_TYPE_FSTN 3 // frame span traversal node
108
109 /* nifty macros from Arnon's EHCI version */
110 #define get_field(data, field) \
111 (((data) & field##_MASK) >> field##_SH)
112
113 #define set_field(data, newval, field) do { \
114 Bit32u val = *data; \
115 val &= ~ field##_MASK; \
116 val |= ((newval) << field##_SH) & field##_MASK; \
117 *data = val; \
118 } while(0)
119
ehci_container_of_usb_packet(void * ptr)120 static inline struct EHCIPacket *ehci_container_of_usb_packet(void *ptr)
121 {
122 return reinterpret_cast<struct EHCIPacket*>(static_cast<char*>(ptr) -
123 reinterpret_cast<size_t>(&(static_cast<struct EHCIPacket*>(0)->packet)));
124 }
125
126 void ehci_event_handler(int event, USBPacket *packet, void *dev, int port);
127
128 // builtin configuration handling functions
129
usb_ehci_options_parser(const char * context,int num_params,char * params[])130 Bit32s usb_ehci_options_parser(const char *context, int num_params, char *params[])
131 {
132 if (!strcmp(params[0], "usb_ehci")) {
133 bx_list_c *base = (bx_list_c*) SIM->get_param(BXPN_USB_EHCI);
134 for (int i = 1; i < num_params; i++) {
135 if (!strncmp(params[i], "enabled=", 8)) {
136 SIM->get_param_bool(BXPN_EHCI_ENABLED)->set(atol(¶ms[i][8]));
137 } else if (!strncmp(params[i], "port", 4) || !strncmp(params[i], "options", 7)) {
138 if (SIM->parse_usb_port_params(context, params[i], USB_EHCI_PORTS, base) < 0) {
139 return -1;
140 }
141 } else {
142 BX_ERROR(("%s: unknown parameter '%s' for usb_ehci ignored.", context, params[i]));
143 }
144 }
145 } else {
146 BX_PANIC(("%s: unknown directive '%s'", context, params[0]));
147 }
148 return 0;
149 }
150
usb_ehci_options_save(FILE * fp)151 Bit32s usb_ehci_options_save(FILE *fp)
152 {
153 bx_list_c *base = (bx_list_c*) SIM->get_param(BXPN_USB_EHCI);
154 SIM->write_usb_options(fp, USB_EHCI_PORTS, base);
155 return 0;
156 }
157
158 // device plugin entry point
159
PLUGIN_ENTRY_FOR_MODULE(usb_ehci)160 PLUGIN_ENTRY_FOR_MODULE(usb_ehci)
161 {
162 if (mode == PLUGIN_INIT) {
163 theUSB_EHCI = new bx_usb_ehci_c();
164 BX_REGISTER_DEVICE_DEVMODEL(plugin, type, theUSB_EHCI, BX_PLUGIN_USB_EHCI);
165 // add new configuration parameter for the config interface
166 SIM->init_usb_options("EHCI", "ehci", USB_EHCI_PORTS);
167 // register add-on option for bochsrc and command line
168 SIM->register_addon_option("usb_ehci", usb_ehci_options_parser, usb_ehci_options_save);
169 } else if (mode == PLUGIN_FINI) {
170 SIM->unregister_addon_option("usb_ehci");
171 bx_list_c *menu = (bx_list_c*)SIM->get_param("ports.usb");
172 delete theUSB_EHCI;
173 menu->remove("ehci");
174 } else if (mode == PLUGIN_PROBE) {
175 return (int)PLUGTYPE_OPTIONAL;
176 } else if (mode == PLUGIN_FLAGS) {
177 return PLUGFLAG_PCI;
178 }
179 return 0; // Success
180 }
181
182 // the device object
183
bx_usb_ehci_c()184 bx_usb_ehci_c::bx_usb_ehci_c()
185 {
186 put("usb_ehci", "EHCI");
187 memset((void*)&hub, 0, sizeof(bx_usb_ehci_t));
188 for (int i = 0; i < 3; i++) {
189 uhci[i] = NULL;
190 }
191 rt_conf_id = -1;
192 hub.frame_timer_index = BX_NULL_TIMER_HANDLE;
193 }
194
~bx_usb_ehci_c()195 bx_usb_ehci_c::~bx_usb_ehci_c()
196 {
197 char pname[16];
198 int i;
199
200 SIM->unregister_runtime_config_handler(rt_conf_id);
201
202 for (i = 0; i < 3; i++) {
203 if (BX_EHCI_THIS uhci[i] != NULL)
204 delete BX_EHCI_THIS uhci[i];
205 }
206
207 for (i=0; i<USB_EHCI_PORTS; i++) {
208 sprintf(pname, "port%d.device", i+1);
209 SIM->get_param_enum(pname, SIM->get_param(BXPN_USB_EHCI))->set_handler(NULL);
210 sprintf(pname, "port%d.options", i+1);
211 SIM->get_param_string(pname, SIM->get_param(BXPN_USB_EHCI))->set_enable_handler(NULL);
212 remove_device(i);
213 }
214
215 SIM->get_bochs_root()->remove("usb_ehci");
216 bx_list_c *usb_rt = (bx_list_c*)SIM->get_param(BXPN_MENU_RUNTIME_USB);
217 usb_rt->remove("ehci");
218 BX_DEBUG(("Exit"));
219 }
220
init(void)221 void bx_usb_ehci_c::init(void)
222 {
223 unsigned i;
224 char pname[6], lfname[10];
225 bx_list_c *ehci, *port;
226 bx_param_enum_c *device;
227 bx_param_string_c *options;
228 Bit8u devfunc;
229
230 // Read in values from config interface
231 ehci = (bx_list_c*) SIM->get_param(BXPN_USB_EHCI);
232 // Check if the device is disabled or not configured
233 if (!SIM->get_param_bool("enabled", ehci)->get()) {
234 BX_INFO(("USB EHCI disabled"));
235 // mark unused plugin for removal
236 ((bx_param_bool_c*)((bx_list_c*)SIM->get_param(BXPN_PLUGIN_CTRL))->get_by_name("usb_ehci"))->set(0);
237 return;
238 }
239
240 // Call our frame timer routine every 1mS (1,024uS)
241 // Continuous and active
242 BX_EHCI_THIS hub.frame_timer_index = DEV_register_timer(this, ehci_frame_handler,
243 FRAME_TIMER_USEC, 1, 1, "ehci.frame_timer");
244
245 BX_EHCI_THIS devfunc = 0x07;
246 DEV_register_pci_handlers(this, &BX_EHCI_THIS devfunc, BX_PLUGIN_USB_EHCI,
247 "Experimental USB EHCI");
248
249 // initialize readonly registers (same as QEMU)
250 // 0x8086 = vendor (Intel)
251 // 0x24cd = device (82801D)
252 // revision number (0x10)
253 init_pci_conf(0x8086, 0x24cd, 0x10, 0x0c0320, 0x00, BX_PCI_INTD);
254 BX_EHCI_THIS pci_conf[0x60] = 0x20;
255 BX_EHCI_THIS init_bar_mem(0, IO_SPACE_SIZE, read_handler, write_handler);
256
257 for (i = 0; i < 3; i++) {
258 BX_EHCI_THIS uhci[i] = new bx_uhci_core_c();
259 sprintf(lfname, "usb_uchi%d", i);
260 sprintf(pname, "UHCI%d", i);
261 BX_EHCI_THIS uhci[i]->put(lfname, pname);
262 }
263 devfunc = BX_EHCI_THIS devfunc & 0xf8;
264 BX_EHCI_THIS uhci[0]->init_uhci(devfunc, 0x24c2, 0x80, BX_PCI_INTA);
265 BX_EHCI_THIS uhci[1]->init_uhci(devfunc | 0x01, 0x24c4, 0x00, BX_PCI_INTB);
266 BX_EHCI_THIS uhci[2]->init_uhci(devfunc | 0x02, 0x24c7, 0x00, BX_PCI_INTC);
267
268 // initialize capability registers
269 BX_EHCI_THIS hub.cap_regs.CapLength = OPS_REGS_OFFSET;
270 BX_EHCI_THIS hub.cap_regs.HciVersion = 0x0100;
271 BX_EHCI_THIS hub.cap_regs.HcsParams = 0x00103200 | USB_EHCI_PORTS;
272 BX_EHCI_THIS hub.cap_regs.HccParams = 0x00006871;
273
274 // initialize runtime configuration
275 bx_list_c *usb_rt = (bx_list_c*)SIM->get_param(BXPN_MENU_RUNTIME_USB);
276 bx_list_c *ehci_rt = new bx_list_c(usb_rt, "ehci", "EHCI Runtime Options");
277 ehci_rt->set_options(ehci_rt->SHOW_PARENT | ehci_rt->USE_BOX_TITLE);
278 for (i=0; i<USB_EHCI_PORTS; i++) {
279 sprintf(pname, "port%d", i+1);
280 port = (bx_list_c*)SIM->get_param(pname, ehci);
281 ehci_rt->add(port);
282 device = (bx_param_enum_c*)port->get_by_name("device");
283 device->set_handler(usb_param_handler);
284 options = (bx_param_string_c*)port->get_by_name("options");
285 options->set_enable_handler(usb_param_enable_handler);
286 BX_EHCI_THIS hub.usb_port[i].device = NULL;
287 BX_EHCI_THIS hub.usb_port[i].owner_change = 0;
288 BX_EHCI_THIS hub.usb_port[i].portsc.ccs = 0;
289 BX_EHCI_THIS hub.usb_port[i].portsc.csc = 0;
290 }
291
292 // register handler for correct device connect handling after runtime config
293 BX_EHCI_THIS rt_conf_id = SIM->register_runtime_config_handler(BX_EHCI_THIS_PTR, runtime_config_handler);
294 BX_EHCI_THIS device_change = 0;
295 BX_EHCI_THIS maxframes = 128;
296 QTAILQ_INIT(&BX_EHCI_THIS hub.aqueues);
297 QTAILQ_INIT(&BX_EHCI_THIS hub.pqueues);
298
299 BX_INFO(("USB EHCI initialized"));
300 }
301
reset(unsigned type)302 void bx_usb_ehci_c::reset(unsigned type)
303 {
304 unsigned i;
305
306 for (i = 0; i < 3; i++) {
307 uhci[i]->reset_uhci(type);
308 }
309 if (type == BX_RESET_HARDWARE) {
310 static const struct reset_vals_t {
311 unsigned addr;
312 unsigned char val;
313 } reset_vals[] = {
314 { 0x04, 0x00 }, { 0x05, 0x00 }, // command_io
315 { 0x06, 0x90 }, { 0x07, 0x02 }, // status
316 { 0x0C, 0x08 }, // cache line size (should be done by BIOS)
317 { 0x0D, 0x00 }, // bus latency
318 { 0x0F, 0x00 }, // BIST is not supported
319
320 // address space 0x10 - 0x17
321 { 0x10, 0x00 }, { 0x11, 0x00 },
322 { 0x12, 0x00 }, { 0x13, 0x00 }, //
323
324 { 0x34, 0x50 }, // Capabilities Pointer
325 { 0x50, 0x01 }, // PCI Power Management Capability ID
326 { 0x51, 0x58 }, // Next Item Pointer
327 { 0x52, 0xc2 }, // Power Management Capabilities
328 { 0x53, 0xc9 }, //
329 { 0x54, 0x00 }, // Power Management Control/Status
330 { 0x55, 0x00 }, //
331 { 0x58, 0x0a }, // Debug Port Capability ID
332 { 0x59, 0x00 }, // Next Item Pointer
333 { 0x5a, 0x80 }, // Debug Port Base Offset
334 { 0x5b, 0x20 }, //
335
336 { 0x61, 0x20 }, // Frame Length Adjustment
337
338 { 0x62, 0x7f }, // Port Wake Capability
339
340 { 0x68, 0x01 }, // USB EHCI Legacy Support Extended Capability
341 { 0x69, 0x00 }, //
342 { 0x6a, 0x00 }, //
343 { 0x6b, 0x00 }, //
344 { 0x6c, 0x00 }, // USB EHCI Legacy Support Extended Control/Status
345 { 0x6d, 0x00 }, //
346 { 0x6e, 0x00 }, //
347 { 0x6f, 0x00 }, //
348
349 { 0x70, 0x00 }, // Intel Specific USB EHCI SMI
350 { 0x71, 0x00 }, //
351 { 0x72, 0x00 }, //
352 { 0x73, 0x00 }, //
353
354 { 0x80, 0x00 }, // Access Control Register
355
356 { 0xdc, 0x00 }, // USB HS Reference Voltage
357 { 0xdd, 0x00 }, //
358 { 0xde, 0x00 }, //
359 { 0xdf, 0x00 } //
360 };
361
362 for (i = 0; i < sizeof(reset_vals) / sizeof(*reset_vals); i++) {
363 BX_EHCI_THIS pci_conf[reset_vals[i].addr] = reset_vals[i].val;
364 }
365 }
366
367 BX_EHCI_THIS reset_hc();
368 }
369
register_state(void)370 void bx_usb_ehci_c::register_state(void)
371 {
372 unsigned i;
373 char tmpname[16];
374 bx_list_c *hub, *op_regs, *port, *reg, *uhcic;
375
376 bx_list_c *list = new bx_list_c(SIM->get_bochs_root(), "usb_ehci", "USB EHCI State");
377 hub = new bx_list_c(list, "hub");
378 BXRS_DEC_PARAM_FIELD(hub, usbsts_pending, BX_EHCI_THIS hub.usbsts_pending);
379 BXRS_DEC_PARAM_FIELD(hub, usbsts_frindex, BX_EHCI_THIS hub.usbsts_frindex);
380 BXRS_DEC_PARAM_FIELD(hub, pstate, BX_EHCI_THIS hub.pstate);
381 BXRS_DEC_PARAM_FIELD(hub, astate, BX_EHCI_THIS hub.astate);
382 BXRS_DEC_PARAM_FIELD(hub, last_run_usec, BX_EHCI_THIS hub.last_run_usec);
383 BXRS_DEC_PARAM_FIELD(hub, async_stepdown, BX_EHCI_THIS hub.async_stepdown);
384 op_regs = new bx_list_c(hub, "op_regs");
385 reg = new bx_list_c(op_regs, "UsbCmd");
386 BXRS_HEX_PARAM_FIELD(reg, itc, BX_EHCI_THIS hub.op_regs.UsbCmd.itc);
387 BXRS_PARAM_BOOL(reg, iaad, BX_EHCI_THIS hub.op_regs.UsbCmd.iaad);
388 BXRS_PARAM_BOOL(reg, ase, BX_EHCI_THIS hub.op_regs.UsbCmd.ase);
389 BXRS_PARAM_BOOL(reg, pse, BX_EHCI_THIS hub.op_regs.UsbCmd.pse);
390 BXRS_PARAM_BOOL(reg, hcreset, BX_EHCI_THIS hub.op_regs.UsbCmd.hcreset);
391 BXRS_PARAM_BOOL(reg, rs, BX_EHCI_THIS hub.op_regs.UsbCmd.rs);
392 reg = new bx_list_c(op_regs, "UsbSts");
393 BXRS_PARAM_BOOL(reg, ass, BX_EHCI_THIS hub.op_regs.UsbSts.ass);
394 BXRS_PARAM_BOOL(reg, pss, BX_EHCI_THIS hub.op_regs.UsbSts.pss);
395 BXRS_PARAM_BOOL(reg, recl, BX_EHCI_THIS hub.op_regs.UsbSts.recl);
396 BXRS_PARAM_BOOL(reg, hchalted, BX_EHCI_THIS hub.op_regs.UsbSts.hchalted);
397 BXRS_HEX_PARAM_FIELD(reg, inti, BX_EHCI_THIS hub.op_regs.UsbSts.inti);
398 BXRS_HEX_PARAM_FIELD(op_regs, UsbIntr, BX_EHCI_THIS hub.op_regs.UsbIntr);
399 BXRS_HEX_PARAM_FIELD(op_regs, FrIndex, BX_EHCI_THIS hub.op_regs.FrIndex);
400 BXRS_HEX_PARAM_FIELD(op_regs, CtrlDsSegment, BX_EHCI_THIS hub.op_regs.CtrlDsSegment);
401 BXRS_HEX_PARAM_FIELD(op_regs, PeriodicListBase, BX_EHCI_THIS hub.op_regs.PeriodicListBase);
402 BXRS_HEX_PARAM_FIELD(op_regs, AsyncListAddr, BX_EHCI_THIS hub.op_regs.AsyncListAddr);
403 BXRS_HEX_PARAM_FIELD(op_regs, ConfigFlag, BX_EHCI_THIS hub.op_regs.ConfigFlag);
404 for (i = 0; i < USB_EHCI_PORTS; i++) {
405 sprintf(tmpname, "port%d", i+1);
406 port = new bx_list_c(hub, tmpname);
407 reg = new bx_list_c(port, "portsc");
408 BXRS_PARAM_BOOL(reg, woe, BX_EHCI_THIS hub.usb_port[i].portsc.woe);
409 BXRS_PARAM_BOOL(reg, wde, BX_EHCI_THIS hub.usb_port[i].portsc.wde);
410 BXRS_PARAM_BOOL(reg, wce, BX_EHCI_THIS hub.usb_port[i].portsc.wce);
411 BXRS_HEX_PARAM_FIELD(reg, ptc, BX_EHCI_THIS hub.usb_port[i].portsc.ptc);
412 BXRS_HEX_PARAM_FIELD(reg, pic, BX_EHCI_THIS hub.usb_port[i].portsc.pic);
413 BXRS_PARAM_BOOL(reg, po, BX_EHCI_THIS hub.usb_port[i].portsc.po);
414 BXRS_HEX_PARAM_FIELD(reg, ls, BX_EHCI_THIS hub.usb_port[i].portsc.ls);
415 BXRS_PARAM_BOOL(reg, pr, BX_EHCI_THIS hub.usb_port[i].portsc.pr);
416 BXRS_PARAM_BOOL(reg, sus, BX_EHCI_THIS hub.usb_port[i].portsc.sus);
417 BXRS_PARAM_BOOL(reg, fpr, BX_EHCI_THIS hub.usb_port[i].portsc.fpr);
418 BXRS_PARAM_BOOL(reg, occ, BX_EHCI_THIS hub.usb_port[i].portsc.occ);
419 BXRS_PARAM_BOOL(reg, oca, BX_EHCI_THIS hub.usb_port[i].portsc.oca);
420 BXRS_PARAM_BOOL(reg, pec, BX_EHCI_THIS hub.usb_port[i].portsc.pec);
421 BXRS_PARAM_BOOL(reg, ped, BX_EHCI_THIS hub.usb_port[i].portsc.ped);
422 BXRS_PARAM_BOOL(reg, csc, BX_EHCI_THIS hub.usb_port[i].portsc.csc);
423 BXRS_PARAM_BOOL(reg, ccs, BX_EHCI_THIS hub.usb_port[i].portsc.ccs);
424 // empty list for USB device state
425 new bx_list_c(port, "device");
426 }
427 for (i = 0; i < 3; i++) {
428 sprintf(tmpname, "uhci%d", i);
429 uhcic = new bx_list_c(list, tmpname);
430 uhci[i]->uhci_register_state(uhcic);
431 }
432
433 register_pci_state(hub);
434 }
435
after_restore_state(void)436 void bx_usb_ehci_c::after_restore_state(void)
437 {
438 int i;
439
440 bx_pci_device_c::after_restore_pci_state(NULL);
441 for (i=0; i<USB_EHCI_PORTS; i++) {
442 if (BX_EHCI_THIS hub.usb_port[i].device != NULL) {
443 BX_EHCI_THIS hub.usb_port[i].device->after_restore_state();
444 }
445 }
446 for (i = 0; i < 3; i++) {
447 uhci[i]->after_restore_state();
448 }
449 }
450
reset_hc()451 void bx_usb_ehci_c::reset_hc()
452 {
453 int i;
454 char pname[6];
455
456 BX_EHCI_THIS hub.op_regs.UsbCmd.itc = 0x08;
457 BX_EHCI_THIS hub.op_regs.UsbCmd.iaad = 0;
458 BX_EHCI_THIS hub.op_regs.UsbCmd.ase = 0;
459 BX_EHCI_THIS hub.op_regs.UsbCmd.pse = 0;
460 BX_EHCI_THIS hub.op_regs.UsbCmd.hcreset = 0;
461 BX_EHCI_THIS hub.op_regs.UsbCmd.rs = 0;
462 BX_EHCI_THIS hub.op_regs.UsbSts.ass = 0;
463 BX_EHCI_THIS hub.op_regs.UsbSts.pss = 0;
464 BX_EHCI_THIS hub.op_regs.UsbSts.recl = 0;
465 BX_EHCI_THIS hub.op_regs.UsbSts.hchalted = 1;
466 BX_EHCI_THIS hub.op_regs.UsbSts.inti = 0;
467 BX_EHCI_THIS hub.op_regs.UsbIntr = 0x0;
468 BX_EHCI_THIS hub.op_regs.FrIndex = 0x0;
469 BX_EHCI_THIS hub.op_regs.CtrlDsSegment = 0x0;
470 BX_EHCI_THIS hub.op_regs.PeriodicListBase = 0x0;
471 BX_EHCI_THIS hub.op_regs.AsyncListAddr = 0x0;
472 BX_EHCI_THIS hub.op_regs.ConfigFlag = 0x0;
473
474 // Ports[x]
475 for (i=0; i<USB_EHCI_PORTS; i++) {
476 reset_port(i);
477 if (BX_EHCI_THIS hub.usb_port[i].device == NULL) {
478 sprintf(pname, "port%d", i+1);
479 init_device(i, (bx_list_c*)SIM->get_param(pname, SIM->get_param(BXPN_USB_EHCI)));
480 } else {
481 set_connect_status(i, 1);
482 }
483 }
484
485 BX_EHCI_THIS hub.usbsts_pending = 0;
486 BX_EHCI_THIS hub.usbsts_frindex = 0;
487 BX_EHCI_THIS hub.astate = EST_INACTIVE;
488 BX_EHCI_THIS hub.pstate = EST_INACTIVE;
489 BX_EHCI_THIS queues_rip_all(0);
490 BX_EHCI_THIS queues_rip_all(1);
491 BX_EHCI_THIS update_irq();
492 }
493
reset_port(int p)494 void bx_usb_ehci_c::reset_port(int p)
495 {
496 BX_EHCI_THIS hub.usb_port[p].portsc.woe = 0;
497 BX_EHCI_THIS hub.usb_port[p].portsc.wde = 0;
498 BX_EHCI_THIS hub.usb_port[p].portsc.wce = 0;
499 BX_EHCI_THIS hub.usb_port[p].portsc.ptc = 0;
500 BX_EHCI_THIS hub.usb_port[p].portsc.pic = 0;
501 if (!BX_EHCI_THIS hub.usb_port[p].portsc.po) {
502 BX_EHCI_THIS hub.usb_port[p].owner_change = 1;
503 BX_EHCI_THIS change_port_owner(p);
504 }
505 BX_EHCI_THIS hub.usb_port[p].portsc.pp = 1;
506 BX_EHCI_THIS hub.usb_port[p].portsc.ls = 0;
507 BX_EHCI_THIS hub.usb_port[p].portsc.pr = 0;
508 BX_EHCI_THIS hub.usb_port[p].portsc.sus = 0;
509 BX_EHCI_THIS hub.usb_port[p].portsc.fpr = 0;
510 BX_EHCI_THIS hub.usb_port[p].portsc.occ = 0;
511 BX_EHCI_THIS hub.usb_port[p].portsc.oca = 0;
512 BX_EHCI_THIS hub.usb_port[p].portsc.pec = 0;
513 BX_EHCI_THIS hub.usb_port[p].portsc.ped = 0;
514 BX_EHCI_THIS hub.usb_port[p].portsc.csc = 0;
515 }
516
init_device(Bit8u port,bx_list_c * portconf)517 void bx_usb_ehci_c::init_device(Bit8u port, bx_list_c *portconf)
518 {
519 char pname[BX_PATHNAME_LEN];
520
521 if (BX_EHCI_THIS hub.usb_port[port].device != NULL) {
522 return;
523 }
524 if (DEV_usb_init_device(portconf, BX_EHCI_THIS_PTR, &BX_EHCI_THIS hub.usb_port[port].device)) {
525 if (set_connect_status(port, 1)) {
526 portconf->get_by_name("options")->set_enabled(0);
527 sprintf(pname, "usb_ehci.hub.port%d.device", port+1);
528 bx_list_c *sr_list = (bx_list_c*)SIM->get_param(pname, SIM->get_bochs_root());
529 BX_EHCI_THIS hub.usb_port[port].device->register_state(sr_list);
530 } else {
531 ((bx_param_enum_c*)portconf->get_by_name("device"))->set_by_name("none");
532 ((bx_param_string_c*)portconf->get_by_name("options"))->set("none");
533 set_connect_status(port, 0);
534 }
535 }
536 }
537
remove_device(Bit8u port)538 void bx_usb_ehci_c::remove_device(Bit8u port)
539 {
540 if (BX_EHCI_THIS hub.usb_port[port].device != NULL) {
541 delete BX_EHCI_THIS hub.usb_port[port].device;
542 BX_EHCI_THIS hub.usb_port[port].device = NULL;
543 }
544 }
545
set_connect_status(Bit8u port,bool connected)546 bool bx_usb_ehci_c::set_connect_status(Bit8u port, bool connected)
547 {
548 const bool ccs_org = BX_EHCI_THIS hub.usb_port[port].portsc.ccs;
549 const bool ped_org = BX_EHCI_THIS hub.usb_port[port].portsc.ped;
550
551 usb_device_c *device = BX_EHCI_THIS hub.usb_port[port].device;
552 if (device != NULL) {
553 if (connected) {
554 if (BX_EHCI_THIS hub.usb_port[port].portsc.po) {
555 BX_EHCI_THIS uhci[port >> 1]->set_port_device(port & 1, device);
556 return 1;
557 }
558 if (device->get_speed() == USB_SPEED_SUPER) {
559 BX_PANIC(("Super-speed device not supported on USB2 port."));
560 return 0;
561 }
562 switch (device->get_speed()) {
563 case USB_SPEED_LOW:
564 BX_INFO(("Low speed device connected to port #%d", port+1));
565 BX_EHCI_THIS hub.usb_port[port].portsc.ls = 0x1;
566 BX_EHCI_THIS hub.usb_port[port].portsc.ped = 0;
567 break;
568 case USB_SPEED_FULL:
569 BX_INFO(("Full speed device connected to port #%d", port+1));
570 BX_EHCI_THIS hub.usb_port[port].portsc.ls = 0x2;
571 BX_EHCI_THIS hub.usb_port[port].portsc.ped = 0;
572 break;
573 case USB_SPEED_HIGH:
574 BX_INFO(("High speed device connected to port #%d", port+1));
575 BX_EHCI_THIS hub.usb_port[port].portsc.ls = 0x0;
576 BX_EHCI_THIS hub.usb_port[port].portsc.ped = 1;
577 break;
578 default:
579 BX_ERROR(("device->get_speed() returned invalid speed value"));
580 return 0;
581 }
582 BX_EHCI_THIS hub.usb_port[port].portsc.ccs = 1;
583 if (!device->get_connected()) {
584 if (!device->init()) {
585 BX_ERROR(("port #%d: connect failed", port+1));
586 return 0;
587 } else {
588 BX_INFO(("port #%d: connect: %s", port+1, device->get_info()));
589 }
590 }
591 device->set_event_handler(BX_EHCI_THIS_PTR, ehci_event_handler, port);
592 } else { // not connected
593 BX_INFO(("port #%d: device disconnect", port+1));
594 if (BX_EHCI_THIS hub.usb_port[port].portsc.po) {
595 BX_EHCI_THIS uhci[port >> 1]->set_port_device(port & 1, NULL);
596 if ((!BX_EHCI_THIS hub.usb_port[port].owner_change) &&
597 (BX_EHCI_THIS hub.op_regs.ConfigFlag & 1)) {
598 BX_EHCI_THIS hub.usb_port[port].portsc.po = 0;
599 BX_EHCI_THIS hub.usb_port[port].portsc.csc = 1;
600 }
601 } else {
602 BX_EHCI_THIS hub.usb_port[port].portsc.ccs = 0;
603 BX_EHCI_THIS hub.usb_port[port].portsc.ped = 0;
604 BX_EHCI_THIS queues_rip_device(device, 0);
605 BX_EHCI_THIS queues_rip_device(device, 1);
606 device->set_async_mode(0);
607 }
608 if (!BX_EHCI_THIS hub.usb_port[port].owner_change) {
609 remove_device(port);
610 }
611 if (BX_EHCI_THIS hub.usb_port[port].portsc.po)
612 return 0;
613 }
614 if (ccs_org != BX_EHCI_THIS hub.usb_port[port].portsc.ccs)
615 BX_EHCI_THIS hub.usb_port[port].portsc.csc = 1;
616 if (ped_org != BX_EHCI_THIS hub.usb_port[port].portsc.ped)
617 BX_EHCI_THIS hub.usb_port[port].portsc.pec = 1;
618
619 BX_EHCI_THIS hub.op_regs.UsbSts.inti |= USBSTS_PCD;
620 BX_EHCI_THIS update_irq();
621 }
622 return connected;
623 }
624
change_port_owner(int port)625 void bx_usb_ehci_c::change_port_owner(int port)
626 {
627 if (port < 0) {
628 for (int i=0; i<USB_EHCI_PORTS; i++) {
629 change_port_owner(i);
630 }
631 } else {
632 usb_device_c *device = BX_EHCI_THIS hub.usb_port[port].device;
633 if (BX_EHCI_THIS hub.usb_port[port].owner_change) {
634 BX_INFO(("port #%d: owner change to %s", port+1,
635 BX_EHCI_THIS hub.usb_port[port].portsc.po ? "EHCI":"UHCI"));
636 if (device != NULL) {
637 set_connect_status(port, 0);
638 }
639 BX_EHCI_THIS hub.usb_port[port].portsc.po ^= 1;
640 if (device != NULL) {
641 set_connect_status(port, 1);
642 }
643 }
644 BX_EHCI_THIS hub.usb_port[port].owner_change = 0;
645 }
646 }
647
read_handler(bx_phy_address addr,unsigned len,void * data,void * param)648 bool bx_usb_ehci_c::read_handler(bx_phy_address addr, unsigned len, void *data, void *param)
649 {
650 Bit32u val = 0, val_hi = 0;
651 int port;
652 const Bit32u offset = (Bit32u) (addr - BX_EHCI_THIS pci_bar[0].addr);
653
654 if (offset < OPS_REGS_OFFSET) {
655 switch (offset) {
656 case 0x00:
657 val = BX_EHCI_THIS hub.cap_regs.CapLength;
658 if (len == 4) val |= (BX_EHCI_THIS hub.cap_regs.HciVersion << 16);
659 break;
660 case 0x02:
661 if (len == 2) val = BX_EHCI_THIS hub.cap_regs.HciVersion;
662 break;
663 case 0x04:
664 val = BX_EHCI_THIS hub.cap_regs.HcsParams;
665 break;
666 case 0x08:
667 val = BX_EHCI_THIS hub.cap_regs.HccParams;
668 break;
669 }
670 } else {
671 // Specs say that we should read dwords only
672 if (len == 4) {
673 switch (offset - OPS_REGS_OFFSET) {
674 case 0x00:
675 val = ((BX_EHCI_THIS hub.op_regs.UsbCmd.itc << 16)
676 | (BX_EHCI_THIS hub.op_regs.UsbCmd.iaad << 6)
677 | (BX_EHCI_THIS hub.op_regs.UsbCmd.ase << 5)
678 | (BX_EHCI_THIS hub.op_regs.UsbCmd.pse << 4)
679 | (BX_EHCI_THIS hub.op_regs.UsbCmd.hcreset << 1)
680 | (Bit8u)BX_EHCI_THIS hub.op_regs.UsbCmd.rs);
681 break;
682 case 0x04:
683 val = ((BX_EHCI_THIS hub.op_regs.UsbSts.ass << 15)
684 | (BX_EHCI_THIS hub.op_regs.UsbSts.pss << 14)
685 | (BX_EHCI_THIS hub.op_regs.UsbSts.recl << 13)
686 | (BX_EHCI_THIS hub.op_regs.UsbSts.hchalted << 12)
687 | BX_EHCI_THIS hub.op_regs.UsbSts.inti);
688 break;
689 case 0x08:
690 val = BX_EHCI_THIS hub.op_regs.UsbIntr;
691 break;
692 case 0x0c:
693 val = BX_EHCI_THIS hub.op_regs.FrIndex;
694 break;
695 case 0x10:
696 val = BX_EHCI_THIS hub.op_regs.CtrlDsSegment;
697 break;
698 case 0x14:
699 val = BX_EHCI_THIS hub.op_regs.PeriodicListBase;
700 break;
701 case 0x18:
702 val = BX_EHCI_THIS hub.op_regs.AsyncListAddr;
703 break;
704 case 0x40:
705 val = BX_EHCI_THIS hub.op_regs.ConfigFlag;
706 break;
707 default:
708 port = (offset - OPS_REGS_OFFSET - 0x44) / 4;
709 if (port < USB_EHCI_PORTS) {
710 val = ((BX_EHCI_THIS hub.usb_port[port].portsc.woe << 22)
711 | (BX_EHCI_THIS hub.usb_port[port].portsc.wde << 21)
712 | (BX_EHCI_THIS hub.usb_port[port].portsc.wce << 20)
713 | (BX_EHCI_THIS hub.usb_port[port].portsc.ptc << 16)
714 | (BX_EHCI_THIS hub.usb_port[port].portsc.pic << 14)
715 | (BX_EHCI_THIS hub.usb_port[port].portsc.po << 13)
716 | (BX_EHCI_THIS hub.usb_port[port].portsc.pp << 12)
717 | (BX_EHCI_THIS hub.usb_port[port].portsc.ls << 10)
718 | (BX_EHCI_THIS hub.usb_port[port].portsc.pr << 8)
719 | (BX_EHCI_THIS hub.usb_port[port].portsc.sus << 7)
720 | (BX_EHCI_THIS hub.usb_port[port].portsc.fpr << 6)
721 | (BX_EHCI_THIS hub.usb_port[port].portsc.occ << 5)
722 | (BX_EHCI_THIS hub.usb_port[port].portsc.oca << 4)
723 | (BX_EHCI_THIS hub.usb_port[port].portsc.pec << 3)
724 | (BX_EHCI_THIS hub.usb_port[port].portsc.ped << 2)
725 | (BX_EHCI_THIS hub.usb_port[port].portsc.csc << 1)
726 | (Bit8u)BX_EHCI_THIS hub.usb_port[port].portsc.ccs);
727 }
728 }
729 } else {
730 // a non-dword read from an operational register is undefined.
731 BX_ERROR(("Read non-dword read from offset 0x%08X", offset));
732 // we return -1 for easier debugging purposes.
733 val_hi = val = 0xFFFFFFFF;
734 }
735 }
736
737 switch (len) {
738 case 1:
739 val &= 0xFF;
740 *((Bit8u *) data) = (Bit8u) val;
741 break;
742 case 2:
743 val &= 0xFFFF;
744 *((Bit16u *) data) = (Bit16u) val;
745 break;
746 case 8:
747 *((Bit32u *) ((Bit8u *) data + 4)) = val_hi;
748 case 4:
749 *((Bit32u *) data) = val;
750 break;
751 }
752 #if BX_PHY_ADDRESS_LONG
753 BX_DEBUG(("register read from offset 0x%04X: 0x%08X%08X (len=%i)", offset, (Bit32u) val_hi, (Bit32u) val, len));
754 #else
755 BX_DEBUG(("register read from offset 0x%04X: 0x%08X (len=%i)", offset, (Bit32u) val, len));
756 #endif
757
758 return 1;
759 }
760
write_handler(bx_phy_address addr,unsigned len,void * data,void * param)761 bool bx_usb_ehci_c::write_handler(bx_phy_address addr, unsigned len, void *data, void *param)
762 {
763 Bit32u value = *((Bit32u *) data);
764 Bit32u value_hi = *((Bit32u *) ((Bit8u *) data + 4));
765 bool oldcfg, oldpo, oldpr, oldfpr;
766 int i, port;
767 const Bit32u offset = (Bit32u) (addr - BX_EHCI_THIS pci_bar[0].addr);
768
769 // modify val and val_hi per len of data to write
770 switch (len) {
771 case 1:
772 value &= 0xFF;
773 case 2:
774 value &= 0xFFFF;
775 case 4:
776 value_hi = 0;
777 break;
778 }
779
780 #if BX_PHY_ADDRESS_LONG
781 BX_DEBUG(("register write to offset 0x%04X: 0x%08X%08X (len=%i)", offset, value_hi, value, len));
782 #else
783 BX_DEBUG(("register write to offset 0x%04X: 0x%08X (len=%i)", offset, value, len));
784 #endif
785
786 if (offset >= OPS_REGS_OFFSET) {
787 // Specs say that we should write dwords only
788 if (len == 4) {
789 switch (offset - OPS_REGS_OFFSET) {
790 case 0x00:
791 BX_EHCI_THIS hub.op_regs.UsbCmd.itc = (value >> 16) & 0x7f;
792 BX_EHCI_THIS hub.op_regs.UsbCmd.iaad = (value >> 6) & 1;
793 BX_EHCI_THIS hub.op_regs.UsbCmd.ase = (value >> 5) & 1;
794 BX_EHCI_THIS hub.op_regs.UsbCmd.pse = (value >> 4) & 1;
795 BX_EHCI_THIS hub.op_regs.UsbCmd.hcreset = (value >> 1) & 1;
796 BX_EHCI_THIS hub.op_regs.UsbCmd.rs = (value & 1);
797 if (BX_EHCI_THIS hub.op_regs.UsbCmd.iaad) {
798 BX_EHCI_THIS hub.async_stepdown = 0;
799 // TODO
800 }
801 if (BX_EHCI_THIS hub.op_regs.UsbCmd.hcreset) {
802 BX_EHCI_THIS reset_hc();
803 BX_EHCI_THIS hub.op_regs.UsbCmd.hcreset = 0;
804 }
805 if (BX_EHCI_THIS hub.op_regs.UsbCmd.rs) {
806 BX_EHCI_THIS hub.op_regs.UsbSts.hchalted = 0;
807 } else {
808 BX_EHCI_THIS hub.op_regs.UsbSts.hchalted = 1;
809 }
810 break;
811 case 0x04:
812 BX_EHCI_THIS hub.op_regs.UsbSts.inti ^= (value & USBINTR_MASK);
813 BX_EHCI_THIS update_irq();
814 break;
815 case 0x08:
816 BX_EHCI_THIS hub.op_regs.UsbIntr = (Bit8u)(value & USBINTR_MASK);
817 break;
818 case 0x0c:
819 if (!BX_EHCI_THIS hub.op_regs.UsbCmd.rs) {
820 BX_EHCI_THIS hub.op_regs.FrIndex = (value & 0x1fff);
821 }
822 break;
823 case 0x10:
824 BX_EHCI_THIS hub.op_regs.CtrlDsSegment = value;
825 break;
826 case 0x14:
827 BX_EHCI_THIS hub.op_regs.PeriodicListBase = (value & 0xfffff000);
828 break;
829 case 0x18:
830 BX_EHCI_THIS hub.op_regs.AsyncListAddr = (value & 0xffffffe0);
831 break;
832 case 0x40:
833 oldcfg = (BX_EHCI_THIS hub.op_regs.ConfigFlag & 1);
834 BX_EHCI_THIS hub.op_regs.ConfigFlag = (value & 1);
835 if (!oldcfg && (value & 1)) {
836 for (i=0; i<USB_EHCI_PORTS; i++) {
837 BX_EHCI_THIS hub.usb_port[i].owner_change = BX_EHCI_THIS hub.usb_port[i].portsc.po;
838 }
839 } else if (!(value & 1)) {
840 for (i=0; i<USB_EHCI_PORTS; i++) {
841 BX_EHCI_THIS hub.usb_port[i].owner_change = !BX_EHCI_THIS hub.usb_port[i].portsc.po;
842 }
843 }
844 BX_EHCI_THIS change_port_owner(-1);
845 break;
846 default:
847 port = (offset - OPS_REGS_OFFSET - 0x44) / 4;
848 if (port < USB_EHCI_PORTS) {
849 oldpo = BX_EHCI_THIS hub.usb_port[port].portsc.po;
850 oldpr = BX_EHCI_THIS hub.usb_port[port].portsc.pr;
851 oldfpr = BX_EHCI_THIS hub.usb_port[port].portsc.fpr;
852 BX_EHCI_THIS hub.usb_port[port].portsc.woe = (value >> 22) & 1;
853 BX_EHCI_THIS hub.usb_port[port].portsc.wde = (value >> 21) & 1;
854 BX_EHCI_THIS hub.usb_port[port].portsc.wce = (value >> 20) & 1;
855 BX_EHCI_THIS hub.usb_port[port].portsc.ptc = (value >> 16) & 0xf;
856 BX_EHCI_THIS hub.usb_port[port].portsc.pic = (value >> 14) & 3;
857 BX_EHCI_THIS hub.usb_port[port].portsc.pr = (value >> 8) & 1;
858 if ((value >> 7) & 1) BX_EHCI_THIS hub.usb_port[port].portsc.sus = 1;
859 BX_EHCI_THIS hub.usb_port[port].portsc.fpr = (value >> 6) & 1;
860 if ((value >> 5) & 1) BX_EHCI_THIS hub.usb_port[port].portsc.occ = 0;
861 if ((value >> 3) & 1) BX_EHCI_THIS hub.usb_port[port].portsc.pec = 0;
862 if (!((value >> 2) & 1)) BX_EHCI_THIS hub.usb_port[port].portsc.ped = 0;
863 if ((value >> 1) & 1) BX_EHCI_THIS hub.usb_port[port].portsc.csc = 0;
864 if (oldpo != ((value >> 13) & 1)) {
865 BX_EHCI_THIS hub.usb_port[port].owner_change = 1;
866 BX_EHCI_THIS change_port_owner(port);
867 }
868 if (oldpr && !BX_EHCI_THIS hub.usb_port[port].portsc.pr) {
869 if (BX_EHCI_THIS hub.usb_port[port].device != NULL) {
870 BX_EHCI_THIS hub.usb_port[port].device->usb_send_msg(USB_MSG_RESET);
871 BX_EHCI_THIS hub.usb_port[port].portsc.csc = 0;
872 if (BX_EHCI_THIS hub.usb_port[port].device->get_speed() == USB_SPEED_HIGH) {
873 BX_EHCI_THIS hub.usb_port[port].portsc.ped = 1;
874 }
875 }
876 }
877 if (oldfpr && !BX_EHCI_THIS hub.usb_port[port].portsc.fpr) {
878 BX_EHCI_THIS hub.usb_port[port].portsc.sus = 0;
879 }
880 }
881 }
882 } else {
883 // a non-dword write to an operational register is undefined.
884 BX_ERROR(("Write non-dword to offset 0x%08X", offset));
885 }
886 }
887
888 return 1;
889 }
890
891 // EHCI core methods ported from QEMU 1.2.2
892
update_irq(void)893 void bx_usb_ehci_c::update_irq(void)
894 {
895 bool level = 0;
896
897 if ((BX_EHCI_THIS hub.op_regs.UsbSts.inti & BX_EHCI_THIS hub.op_regs.UsbIntr) > 0) {
898 level = 1;
899 BX_DEBUG(("Interrupt Fired."));
900 }
901 DEV_pci_set_irq(BX_EHCI_THIS devfunc, BX_EHCI_THIS pci_conf[0x3d], level);
902 }
903
raise_irq(Bit8u intr)904 void bx_usb_ehci_c::raise_irq(Bit8u intr)
905 {
906 if (intr & (USBSTS_PCD | USBSTS_FLR | USBSTS_HSE)) {
907 BX_EHCI_THIS hub.op_regs.UsbSts.inti |= intr;
908 BX_EHCI_THIS update_irq();
909 } else {
910 BX_EHCI_THIS hub.usbsts_pending |= intr;
911 }
912 }
913
commit_irq(void)914 void bx_usb_ehci_c::commit_irq(void)
915 {
916 Bit32u itc;
917
918 if (!BX_EHCI_THIS hub.usbsts_pending) {
919 return;
920 }
921 if (BX_EHCI_THIS hub.usbsts_frindex > BX_EHCI_THIS hub.op_regs.FrIndex) {
922 return;
923 }
924
925 itc = BX_EHCI_THIS hub.op_regs.UsbCmd.itc;
926 BX_EHCI_THIS hub.op_regs.UsbSts.inti |= BX_EHCI_THIS hub.usbsts_pending;
927 BX_EHCI_THIS hub.usbsts_pending = 0;
928 BX_EHCI_THIS hub.usbsts_frindex = BX_EHCI_THIS hub.op_regs.FrIndex + itc;
929 BX_EHCI_THIS update_irq();
930 }
931
update_halt(void)932 void bx_usb_ehci_c::update_halt(void)
933 {
934 if (BX_EHCI_THIS hub.op_regs.UsbCmd.rs) {
935 BX_EHCI_THIS hub.op_regs.UsbSts.hchalted = 0;
936 } else {
937 if (BX_EHCI_THIS hub.astate == EST_INACTIVE && BX_EHCI_THIS hub.pstate == EST_INACTIVE) {
938 BX_EHCI_THIS hub.op_regs.UsbSts.hchalted = 1;
939 }
940 }
941 }
942
set_state(int async,int state)943 void bx_usb_ehci_c::set_state(int async, int state)
944 {
945 if (async) {
946 BX_EHCI_THIS hub.astate = state;
947 if (BX_EHCI_THIS hub.astate == EST_INACTIVE) {
948 BX_EHCI_THIS hub.op_regs.UsbSts.ass = 0;
949 BX_EHCI_THIS update_halt();
950 } else {
951 BX_EHCI_THIS hub.op_regs.UsbSts.ass = 1;
952 }
953 } else {
954 BX_EHCI_THIS hub.pstate = state;
955 if (BX_EHCI_THIS hub.pstate == EST_INACTIVE) {
956 BX_EHCI_THIS hub.op_regs.UsbSts.pss = 0;
957 BX_EHCI_THIS update_halt();
958 } else {
959 BX_EHCI_THIS hub.op_regs.UsbSts.pss = 1;
960 }
961 }
962 }
963
get_state(int async)964 int bx_usb_ehci_c::get_state(int async)
965 {
966 return async ? BX_EHCI_THIS hub.astate : BX_EHCI_THIS hub.pstate;
967 }
968
set_fetch_addr(int async,Bit32u addr)969 void bx_usb_ehci_c::set_fetch_addr(int async, Bit32u addr)
970 {
971 if (async) {
972 BX_EHCI_THIS hub.a_fetch_addr = addr;
973 } else {
974 BX_EHCI_THIS hub.p_fetch_addr = addr;
975 }
976 }
977
get_fetch_addr(int async)978 Bit32u bx_usb_ehci_c::get_fetch_addr(int async)
979 {
980 return async ? BX_EHCI_THIS hub.a_fetch_addr : BX_EHCI_THIS hub.p_fetch_addr;
981 }
982
async_enabled(void)983 bool bx_usb_ehci_c::async_enabled(void)
984 {
985 return (BX_EHCI_THIS hub.op_regs.UsbCmd.rs && BX_EHCI_THIS hub.op_regs.UsbCmd.ase);
986 }
987
periodic_enabled(void)988 bool bx_usb_ehci_c::periodic_enabled(void)
989 {
990 return (BX_EHCI_THIS hub.op_regs.UsbCmd.rs && BX_EHCI_THIS hub.op_regs.UsbCmd.pse);
991 }
992
alloc_packet(EHCIQueue * q)993 EHCIPacket *bx_usb_ehci_c::alloc_packet(EHCIQueue *q)
994 {
995 EHCIPacket *p = new EHCIPacket;
996 memset(p, 0, sizeof(EHCIPacket));
997 p->queue = q;
998 usb_packet_init(&p->packet, BUFF_SIZE);
999 QTAILQ_INSERT_TAIL(&q->packets, p, next);
1000 return p;
1001 }
1002
free_packet(EHCIPacket * p)1003 void bx_usb_ehci_c::free_packet(EHCIPacket *p)
1004 {
1005 if (p->async == EHCI_ASYNC_FINISHED) {
1006 int state = BX_EHCI_THIS get_state(p->queue->async);
1007 /* This is a normal, but rare condition (cancel racing completion) */
1008 BX_ERROR(("EHCI: Warning packet completed but not processed"));
1009 BX_EHCI_THIS state_executing(p->queue);
1010 BX_EHCI_THIS state_writeback(p->queue);
1011 BX_EHCI_THIS set_state(p->queue->async, state);
1012 /* state_writeback recurses into us with async == EHCI_ASYNC_NONE!! */
1013 return;
1014 }
1015 if (p->async == EHCI_ASYNC_INFLIGHT) {
1016 usb_cancel_packet(&p->packet);
1017 }
1018 QTAILQ_REMOVE(&p->queue->packets, p, next);
1019 usb_packet_cleanup(&p->packet);
1020 delete p;
1021 }
1022
alloc_queue(Bit32u addr,int async)1023 EHCIQueue *bx_usb_ehci_c::alloc_queue(Bit32u addr, int async)
1024 {
1025 EHCIQueueHead *head = async ? &BX_EHCI_THIS hub.aqueues : &BX_EHCI_THIS hub.pqueues;
1026 EHCIQueue *q;
1027
1028 q = new EHCIQueue;
1029 memset(q, 0, sizeof(EHCIQueue));
1030 q->ehci = &BX_EHCI_THIS hub;
1031 q->qhaddr = addr;
1032 q->async = async;
1033 QTAILQ_INIT(&q->packets);
1034 QTAILQ_INSERT_HEAD(head, q, next);
1035 return q;
1036 }
1037
cancel_queue(EHCIQueue * q)1038 int bx_usb_ehci_c::cancel_queue(EHCIQueue *q)
1039 {
1040 EHCIPacket *p;
1041 int packets = 0;
1042
1043 p = QTAILQ_FIRST(&q->packets);
1044 if (p == NULL) {
1045 return 0;
1046 }
1047
1048 do {
1049 free_packet(p);
1050 packets++;
1051 } while ((p = QTAILQ_FIRST(&q->packets)) != NULL);
1052 return packets;
1053 }
1054
reset_queue(EHCIQueue * q)1055 int bx_usb_ehci_c::reset_queue(EHCIQueue *q)
1056 {
1057 int packets = BX_EHCI_THIS cancel_queue(q);
1058 q->dev = NULL;
1059 q->qtdaddr = 0;
1060 return packets;
1061 }
1062
free_queue(EHCIQueue * q,const char * warn)1063 void bx_usb_ehci_c::free_queue(EHCIQueue *q, const char *warn)
1064 {
1065 EHCIQueueHead *head = q->async ? &q->ehci->aqueues : &q->ehci->pqueues;
1066 int cancelled;
1067
1068 cancelled = BX_EHCI_THIS cancel_queue(q);
1069 if (warn && cancelled > 0) {
1070 BX_ERROR(("%s", warn));
1071 }
1072 QTAILQ_REMOVE(head, q, next);
1073 free(q);
1074 }
1075
find_queue_by_qh(Bit32u addr,int async)1076 EHCIQueue *bx_usb_ehci_c::find_queue_by_qh(Bit32u addr, int async)
1077 {
1078 EHCIQueueHead *head = async ? &BX_EHCI_THIS hub.aqueues : &BX_EHCI_THIS hub.pqueues;
1079 EHCIQueue *q;
1080
1081 QTAILQ_FOREACH(q, head, next) {
1082 if (addr == q->qhaddr) {
1083 return q;
1084 }
1085 }
1086 return NULL;
1087 }
1088
queues_rip_unused(int async)1089 void bx_usb_ehci_c::queues_rip_unused(int async)
1090 {
1091 EHCIQueueHead *head = async ? &BX_EHCI_THIS hub.aqueues : &BX_EHCI_THIS hub.pqueues;
1092 const char *warn = async ? "guest unlinked busy QH" : NULL;
1093 Bit64u maxage = FRAME_TIMER_USEC * BX_EHCI_THIS maxframes * 4;
1094 EHCIQueue *q, *tmp;
1095
1096 QTAILQ_FOREACH_SAFE(q, head, next, tmp) {
1097 if (q->seen) {
1098 q->seen = 0;
1099 q->ts = BX_EHCI_THIS hub.last_run_usec;
1100 continue;
1101 }
1102 if (BX_EHCI_THIS hub.last_run_usec < q->ts + maxage) {
1103 continue;
1104 }
1105 BX_EHCI_THIS free_queue(q, warn);
1106 }
1107 }
1108
queues_rip_unseen(int async)1109 void bx_usb_ehci_c::queues_rip_unseen(int async)
1110 {
1111 EHCIQueueHead *head = async ? &BX_EHCI_THIS hub.aqueues : &BX_EHCI_THIS hub.pqueues;
1112 EHCIQueue *q, *tmp;
1113
1114 QTAILQ_FOREACH_SAFE(q, head, next, tmp) {
1115 if (!q->seen) {
1116 BX_EHCI_THIS free_queue(q, NULL);
1117 }
1118 }
1119 }
1120
queues_rip_device(usb_device_c * dev,int async)1121 void bx_usb_ehci_c::queues_rip_device(usb_device_c *dev, int async)
1122 {
1123 EHCIQueueHead *head = async ? &BX_EHCI_THIS hub.aqueues : &BX_EHCI_THIS hub.pqueues;
1124 EHCIQueue *q, *tmp;
1125
1126 QTAILQ_FOREACH_SAFE(q, head, next, tmp) {
1127 if (q->dev != dev) {
1128 continue;
1129 }
1130 BX_EHCI_THIS free_queue(q, NULL);
1131 }
1132 }
1133
queues_rip_all(int async)1134 void bx_usb_ehci_c::queues_rip_all(int async)
1135 {
1136 EHCIQueueHead *head = async ? &BX_EHCI_THIS hub.aqueues : &BX_EHCI_THIS hub.pqueues;
1137 const char *warn = async ? "guest stopped busy async schedule" : NULL;
1138 EHCIQueue *q, *tmp;
1139
1140 QTAILQ_FOREACH_SAFE(q, head, next, tmp) {
1141 BX_EHCI_THIS free_queue(q, warn);
1142 }
1143 }
1144
find_device(Bit8u addr)1145 usb_device_c *bx_usb_ehci_c::find_device(Bit8u addr)
1146 {
1147 usb_device_c *dev = NULL;
1148
1149 for (int i = 0; i < USB_EHCI_PORTS; i++) {
1150 if (!BX_EHCI_THIS hub.usb_port[i].portsc.ped) {
1151 BX_DEBUG(("Port %d not enabled", i));
1152 continue;
1153 }
1154 if (BX_EHCI_THIS hub.usb_port[i].device != NULL) {
1155 dev = BX_EHCI_THIS hub.usb_port[i].device->find_device(addr);
1156 }
1157 if (dev != NULL) {
1158 return dev;
1159 }
1160 }
1161 return NULL;
1162 }
1163
flush_qh(EHCIQueue * q)1164 void bx_usb_ehci_c::flush_qh(EHCIQueue *q)
1165 {
1166 Bit32u *qh = (Bit32u *) &q->qh;
1167 Bit32u dwords = sizeof(EHCIqh) >> 2;
1168 Bit32u addr = NLPTR_GET(q->qhaddr);
1169
1170 put_dwords(addr + 3 * sizeof(Bit32u), qh + 3, dwords - 3);
1171 }
1172
qh_do_overlay(EHCIQueue * q)1173 int bx_usb_ehci_c::qh_do_overlay(EHCIQueue *q)
1174 {
1175 EHCIPacket *p = QTAILQ_FIRST(&q->packets);
1176 int i;
1177 int dtoggle;
1178 int ping;
1179 int eps;
1180 int reload;
1181
1182 assert(p != NULL);
1183 assert(p->qtdaddr == q->qtdaddr);
1184
1185 // remember values in fields to preserve in qh after overlay
1186
1187 dtoggle = q->qh.token & QTD_TOKEN_DTOGGLE;
1188 ping = q->qh.token & QTD_TOKEN_PING;
1189
1190 q->qh.current_qtd = p->qtdaddr;
1191 q->qh.next_qtd = p->qtd.next;
1192 q->qh.altnext_qtd = p->qtd.altnext;
1193 q->qh.token = p->qtd.token;
1194
1195
1196 eps = get_field(q->qh.epchar, QH_EPCHAR_EPS);
1197 if (eps == EHCI_QH_EPS_HIGH) {
1198 q->qh.token &= ~QTD_TOKEN_PING;
1199 q->qh.token |= ping;
1200 }
1201
1202 reload = get_field(q->qh.epchar, QH_EPCHAR_RL);
1203 set_field(&q->qh.altnext_qtd, reload, QH_ALTNEXT_NAKCNT);
1204
1205 for (i = 0; i < 5; i++) {
1206 q->qh.bufptr[i] = p->qtd.bufptr[i];
1207 }
1208
1209 if (!(q->qh.epchar & QH_EPCHAR_DTC)) {
1210 // preserve QH DT bit
1211 q->qh.token &= ~QTD_TOKEN_DTOGGLE;
1212 q->qh.token |= dtoggle;
1213 }
1214
1215 q->qh.bufptr[1] &= ~BUFPTR_CPROGMASK_MASK;
1216 q->qh.bufptr[2] &= ~BUFPTR_FRAMETAG_MASK;
1217
1218 BX_EHCI_THIS flush_qh(q);
1219
1220 return 0;
1221 }
1222
1223 // Bochs specific code (no async and scatter/gather support yet)
transfer(EHCIPacket * p)1224 int bx_usb_ehci_c::transfer(EHCIPacket *p)
1225 {
1226 Bit32u cpage, offset, bytes, plen, blen = 0;
1227 Bit64u page;
1228
1229 cpage = get_field(p->qtd.token, QTD_TOKEN_CPAGE);
1230 bytes = get_field(p->qtd.token, QTD_TOKEN_TBYTES);
1231 offset = p->qtd.bufptr[0] & ~QTD_BUFPTR_MASK;
1232
1233 while (bytes > 0) {
1234 if (cpage > 4) {
1235 BX_ERROR(("cpage out of range (%d)", cpage));
1236 return USB_RET_PROCERR;
1237 }
1238
1239 page = p->qtd.bufptr[cpage] & QTD_BUFPTR_MASK;
1240 page += offset;
1241 plen = bytes;
1242 if (plen > 4096 - offset) {
1243 plen = 4096 - offset;
1244 offset = 0;
1245 cpage++;
1246 }
1247
1248 if (p->pid == USB_TOKEN_IN) {
1249 DEV_MEM_WRITE_PHYSICAL_DMA(page, plen, p->packet.data+blen);
1250 } else {
1251 DEV_MEM_READ_PHYSICAL_DMA(page, plen, p->packet.data+blen);
1252 }
1253 blen += plen;
1254 bytes -= plen;
1255 }
1256 return 0;
1257 }
1258
finish_transfer(EHCIQueue * q,int status)1259 void bx_usb_ehci_c::finish_transfer(EHCIQueue *q, int status)
1260 {
1261 Bit32u cpage, offset;
1262
1263 if (status > 0) {
1264 /* update cpage & offset */
1265 cpage = get_field(q->qh.token, QTD_TOKEN_CPAGE);
1266 offset = q->qh.bufptr[0] & ~QTD_BUFPTR_MASK;
1267
1268 offset += status;
1269 cpage += offset >> QTD_BUFPTR_SH;
1270 offset &= ~QTD_BUFPTR_MASK;
1271
1272 set_field(&q->qh.token, cpage, QTD_TOKEN_CPAGE);
1273 q->qh.bufptr[0] &= QTD_BUFPTR_MASK;
1274 q->qh.bufptr[0] |= offset;
1275 }
1276 }
1277
ehci_event_handler(int event,USBPacket * packet,void * dev,int port)1278 void ehci_event_handler(int event, USBPacket *packet, void *dev, int port)
1279 {
1280 ((bx_usb_ehci_c*)dev)->event_handler(event, packet, port);
1281 }
1282
event_handler(int event,USBPacket * packet,int port)1283 void bx_usb_ehci_c::event_handler(int event, USBPacket *packet, int port)
1284 {
1285 EHCIPacket *p;
1286
1287 if (event == USB_EVENT_ASYNC) {
1288 BX_DEBUG(("Experimental async packet completion"));
1289 p = ehci_container_of_usb_packet(packet);
1290 if (p->pid == USB_TOKEN_IN) {
1291 BX_EHCI_THIS transfer(p);
1292 }
1293 BX_ASSERT(p->async == EHCI_ASYNC_INFLIGHT);
1294 p->async = EHCI_ASYNC_FINISHED;
1295 p->usb_status = packet->len;
1296
1297 if (p->queue->async) {
1298 BX_EHCI_THIS advance_async_state();
1299 }
1300 } else if (event == USB_EVENT_WAKEUP) {
1301 if (BX_EHCI_THIS hub.usb_port[port].portsc.sus) {
1302 BX_EHCI_THIS hub.usb_port[port].portsc.fpr = 1;
1303 raise_irq(USBSTS_PCD);
1304 }
1305 } else {
1306 BX_ERROR(("unknown/unsupported event (id=%d) on port #%d", event, port+1));
1307 }
1308 }
1309
execute_complete(EHCIQueue * q)1310 void bx_usb_ehci_c::execute_complete(EHCIQueue *q)
1311 {
1312 EHCIPacket *p = QTAILQ_FIRST(&q->packets);
1313
1314 BX_ASSERT(p != NULL);
1315 BX_ASSERT(p->qtdaddr == q->qtdaddr);
1316 BX_ASSERT(p->async == EHCI_ASYNC_INITIALIZED ||
1317 p->async == EHCI_ASYNC_FINISHED);
1318
1319 BX_DEBUG(("execute_complete: qhaddr 0x%x, next %x, qtdaddr 0x%x, status %d",
1320 q->qhaddr, q->qh.next, q->qtdaddr, p->usb_status));
1321
1322 if (p->usb_status < 0) {
1323 switch (p->usb_status) {
1324 case USB_RET_IOERROR:
1325 case USB_RET_NODEV:
1326 q->qh.token |= (QTD_TOKEN_HALT | QTD_TOKEN_XACTERR);
1327 set_field(&q->qh.token, 0, QTD_TOKEN_CERR);
1328 BX_EHCI_THIS raise_irq(USBSTS_ERRINT);
1329 break;
1330 case USB_RET_STALL:
1331 q->qh.token |= QTD_TOKEN_HALT;
1332 BX_EHCI_THIS raise_irq(USBSTS_ERRINT);
1333 break;
1334 case USB_RET_NAK: /* We're not done yet with this transaction */
1335 set_field(&q->qh.altnext_qtd, 0, QH_ALTNEXT_NAKCNT);
1336 return;
1337 case USB_RET_BABBLE:
1338 q->qh.token |= (QTD_TOKEN_HALT | QTD_TOKEN_BABBLE);
1339 BX_EHCI_THIS raise_irq(USBSTS_ERRINT);
1340 break;
1341 default:
1342 /* should not be triggerable */
1343 BX_PANIC(("USB invalid response %d", p->usb_status));
1344 break;
1345 }
1346 } else {
1347 // TODO check 4.12 for splits
1348 if (p->tbytes && p->pid == USB_TOKEN_IN) {
1349 p->tbytes -= p->usb_status;
1350 } else {
1351 p->tbytes = 0;
1352 }
1353
1354 BX_DEBUG(("updating tbytes to %d", p->tbytes));
1355 set_field(&q->qh.token, p->tbytes, QTD_TOKEN_TBYTES);
1356 }
1357 BX_EHCI_THIS finish_transfer(q, p->usb_status);
1358 p->async = EHCI_ASYNC_NONE;
1359
1360 q->qh.token ^= QTD_TOKEN_DTOGGLE;
1361 q->qh.token &= ~QTD_TOKEN_ACTIVE;
1362
1363 if (q->qh.token & QTD_TOKEN_IOC) {
1364 BX_EHCI_THIS raise_irq(USBSTS_INT);
1365 }
1366 }
1367
execute(EHCIPacket * p)1368 int bx_usb_ehci_c::execute(EHCIPacket *p)
1369 {
1370 int ret;
1371 int endp;
1372
1373 BX_ASSERT(p->async == EHCI_ASYNC_NONE ||
1374 p->async == EHCI_ASYNC_INITIALIZED);
1375
1376 if (!(p->qtd.token & QTD_TOKEN_ACTIVE)) {
1377 BX_ERROR(("Attempting to execute inactive qtd"));
1378 return USB_RET_PROCERR;
1379 }
1380
1381 p->tbytes = (p->qtd.token & QTD_TOKEN_TBYTES_MASK) >> QTD_TOKEN_TBYTES_SH;
1382 if (p->tbytes > BUFF_SIZE) {
1383 BX_ERROR(("guest requested more bytes than allowed"));
1384 return USB_RET_PROCERR;
1385 }
1386
1387 p->pid = (p->qtd.token & QTD_TOKEN_PID_MASK) >> QTD_TOKEN_PID_SH;
1388 switch (p->pid) {
1389 case 0:
1390 p->pid = USB_TOKEN_OUT;
1391 break;
1392 case 1:
1393 p->pid = USB_TOKEN_IN;
1394 break;
1395 case 2:
1396 p->pid = USB_TOKEN_SETUP;
1397 break;
1398 default:
1399 BX_ERROR(("bad token"));
1400 break;
1401 }
1402
1403 endp = get_field(p->queue->qh.epchar, QH_EPCHAR_EP);
1404
1405 if (p->async == EHCI_ASYNC_NONE) {
1406 p->packet.len = p->tbytes;
1407 if (p->pid != USB_TOKEN_IN) {
1408 if (BX_EHCI_THIS transfer(p) != 0) {
1409 return USB_RET_PROCERR;
1410 }
1411 }
1412
1413 // Bochs specific packet setup
1414 p->packet.pid = p->pid;
1415 p->packet.devaddr = p->queue->dev->get_address();
1416 p->packet.devep = endp;
1417 p->packet.complete_cb = ehci_event_handler;
1418 p->packet.complete_dev = BX_EHCI_THIS_PTR;
1419
1420 p->async = EHCI_ASYNC_INITIALIZED;
1421 }
1422
1423 ret = p->queue->dev->handle_packet(&p->packet);
1424 BX_DEBUG(("submit: qh %x next %x qtd %x pid %x len %d (total %d) endp %x ret %d\n",
1425 p->queue->qhaddr, p->queue->qh.next, p->queue->qtdaddr, p->pid,
1426 p->packet.len, p->tbytes, endp, ret));
1427
1428 if (ret > BUFF_SIZE) {
1429 BX_ERROR(("ret from usb_handle_packet > BUFF_SIZE"));
1430 return USB_RET_PROCERR;
1431 }
1432
1433 // Bochs specific code
1434 if (ret > 0) {
1435 if (p->pid == USB_TOKEN_SETUP) {
1436 // TODO: This is a hack. dev->handle_packet() should return the amount of bytes
1437 // it received, not the amount it anticipates on receiving/sending in the next packet.
1438 ret = 8;
1439 } else if (p->pid == USB_TOKEN_IN) {
1440 if (BX_EHCI_THIS transfer(p) != 0) {
1441 return USB_RET_PROCERR;
1442 }
1443 }
1444 }
1445
1446 return ret;
1447 }
1448
process_itd(EHCIitd * itd,Bit32u addr)1449 int bx_usb_ehci_c::process_itd(EHCIitd *itd, Bit32u addr)
1450 {
1451 // TODO
1452 BX_PANIC(("process_itd() not implemented yet"));
1453 return 0;
1454 }
1455
state_waitlisthead(int async)1456 int bx_usb_ehci_c::state_waitlisthead(int async)
1457 {
1458 EHCIqh qh;
1459 int i = 0;
1460 int again = 0;
1461 Bit32u entry = BX_EHCI_THIS hub.op_regs.AsyncListAddr;
1462
1463 /* set reclamation flag at start event (4.8.6) */
1464 if (async) {
1465 BX_EHCI_THIS hub.op_regs.UsbSts.recl = 1;
1466 }
1467
1468 BX_EHCI_THIS queues_rip_unused(async);
1469
1470 /* Find the head of the list (4.9.1.1) */
1471 for (i = 0; i < MAX_QH; i++) {
1472 get_dwords(NLPTR_GET(entry), (Bit32u *) &qh, sizeof(EHCIqh) >> 2);
1473
1474 if (qh.epchar & QH_EPCHAR_H) {
1475 if (async) {
1476 entry |= (NLPTR_TYPE_QH << 1);
1477 }
1478
1479 BX_EHCI_THIS set_fetch_addr(async, entry);
1480 BX_EHCI_THIS set_state(async, EST_FETCHENTRY);
1481 again = 1;
1482 goto out;
1483 }
1484
1485 entry = qh.next;
1486 if (entry == BX_EHCI_THIS hub.op_regs.AsyncListAddr) {
1487 break;
1488 }
1489 }
1490
1491 /* no head found for list. */
1492
1493 BX_EHCI_THIS set_state(async, EST_ACTIVE);
1494
1495 out:
1496 return again;
1497 }
1498
state_fetchentry(int async)1499 int bx_usb_ehci_c::state_fetchentry(int async)
1500 {
1501 int again = 0;
1502 Bit32u entry = BX_EHCI_THIS get_fetch_addr(async);
1503
1504 if (NLPTR_TBIT(entry)) {
1505 BX_EHCI_THIS set_state(async, EST_ACTIVE);
1506 goto out;
1507 }
1508
1509 /* section 4.8, only QH in async schedule */
1510 if (async && (NLPTR_TYPE_GET(entry) != NLPTR_TYPE_QH)) {
1511 BX_ERROR(("non queue head request in async schedule"));
1512 return -1;
1513 }
1514
1515 switch (NLPTR_TYPE_GET(entry)) {
1516 case NLPTR_TYPE_QH:
1517 BX_EHCI_THIS set_state(async, EST_FETCHQH);
1518 again = 1;
1519 break;
1520
1521 case NLPTR_TYPE_ITD:
1522 BX_EHCI_THIS set_state(async, EST_FETCHITD);
1523 again = 1;
1524 break;
1525
1526 case NLPTR_TYPE_STITD:
1527 BX_EHCI_THIS set_state(async, EST_FETCHSITD);
1528 again = 1;
1529 break;
1530
1531 default:
1532 /* TODO: handle FSTN type */
1533 BX_ERROR(("FETCHENTRY: entry at %X is of type %d which is not supported yet",
1534 entry, NLPTR_TYPE_GET(entry)));
1535 return -1;
1536 }
1537
1538 out:
1539 return again;
1540 }
1541
state_fetchqh(int async)1542 EHCIQueue *bx_usb_ehci_c::state_fetchqh(int async)
1543 {
1544 EHCIPacket *p;
1545 Bit32u entry, devaddr, endp;
1546 EHCIQueue *q;
1547 EHCIqh qh;
1548
1549 entry = BX_EHCI_THIS get_fetch_addr(async);
1550 q = BX_EHCI_THIS find_queue_by_qh(entry, async);
1551 if (NULL == q) {
1552 q = BX_EHCI_THIS alloc_queue(entry, async);
1553 }
1554 p = QTAILQ_FIRST(&q->packets);
1555
1556 q->seen++;
1557 if (q->seen > 1) {
1558 /* we are going in circles -- stop processing */
1559 BX_EHCI_THIS set_state(async, EST_ACTIVE);
1560 q = NULL;
1561 goto out;
1562 }
1563
1564 get_dwords(NLPTR_GET(q->qhaddr), (Bit32u*) &qh, sizeof(EHCIqh) >> 2);
1565
1566 /*
1567 * The overlay area of the qh should never be changed by the guest,
1568 * except when idle, in which case the reset is a nop.
1569 */
1570 devaddr = get_field(qh.epchar, QH_EPCHAR_DEVADDR);
1571 endp = get_field(qh.epchar, QH_EPCHAR_EP);
1572 if ((devaddr != get_field(q->qh.epchar, QH_EPCHAR_DEVADDR)) ||
1573 (endp != get_field(q->qh.epchar, QH_EPCHAR_EP)) ||
1574 (memcmp(&qh.current_qtd, &q->qh.current_qtd,
1575 9 * sizeof(Bit32u)) != 0) ||
1576 (q->dev != NULL && q->dev->get_address() != devaddr)) {
1577 if (BX_EHCI_THIS reset_queue(q) > 0) {
1578 BX_ERROR(("guest updated active QH"));
1579 }
1580 p = NULL;
1581 }
1582 q->qh = qh;
1583
1584 if (q->dev == NULL) {
1585 q->dev = BX_EHCI_THIS find_device(devaddr);
1586 }
1587
1588 /* I/O finished -- continue processing queue */
1589 if (p && p->async == EHCI_ASYNC_FINISHED) {
1590 BX_EHCI_THIS set_state(async, EST_EXECUTING);
1591 goto out;
1592 }
1593
1594 if (async && (q->qh.epchar & QH_EPCHAR_H)) {
1595 /* EHCI spec version 1.0 Section 4.8.3 & 4.10.1 */
1596 if (BX_EHCI_THIS hub.op_regs.UsbSts.recl) {
1597 BX_EHCI_THIS hub.op_regs.UsbSts.recl = 0;
1598 } else {
1599 BX_DEBUG(("FETCHQH: QH 0x%08x. H-bit set, reclamation status reset - done processing",
1600 q->qhaddr));
1601 BX_EHCI_THIS set_state(async, EST_ACTIVE);
1602 q = NULL;
1603 goto out;
1604 }
1605 }
1606
1607 #if EHCI_DEBUG
1608 if (q->qhaddr != q->qh.next) {
1609 BX_DEBUG(("FETCHQH: QH 0x%08x (h %x halt %x active %x) next 0x%08x",
1610 q->qhaddr,
1611 q->qh.epchar & QH_EPCHAR_H,
1612 q->qh.token & QTD_TOKEN_HALT,
1613 q->qh.token & QTD_TOKEN_ACTIVE,
1614 q->qh.next));
1615 }
1616 #endif
1617
1618 if (q->qh.token & QTD_TOKEN_HALT) {
1619 BX_EHCI_THIS set_state(async, EST_HORIZONTALQH);
1620 } else if ((q->qh.token & QTD_TOKEN_ACTIVE) &&
1621 (NLPTR_TBIT(q->qh.current_qtd) == 0)) {
1622 q->qtdaddr = q->qh.current_qtd;
1623 BX_EHCI_THIS set_state(async, EST_FETCHQTD);
1624 } else {
1625 /* EHCI spec version 1.0 Section 4.10.2 */
1626 BX_EHCI_THIS set_state(async, EST_ADVANCEQUEUE);
1627 }
1628
1629 out:
1630 return q;
1631 }
1632
state_fetchitd(int async)1633 int bx_usb_ehci_c::state_fetchitd(int async)
1634 {
1635 Bit32u entry;
1636 EHCIitd itd;
1637
1638 BX_ASSERT(!async);
1639 entry = BX_EHCI_THIS get_fetch_addr(async);
1640
1641 get_dwords(NLPTR_GET(entry), (Bit32u*) &itd, sizeof(EHCIitd) >> 2);
1642
1643 if (BX_EHCI_THIS process_itd(&itd, entry) != 0) {
1644 return -1;
1645 }
1646
1647 put_dwords(NLPTR_GET(entry), (Bit32u*) &itd, sizeof(EHCIitd) >> 2);
1648 BX_EHCI_THIS set_fetch_addr(async, itd.next);
1649 BX_EHCI_THIS set_state(async, EST_FETCHENTRY);
1650
1651 return 1;
1652 }
1653
state_fetchsitd(int async)1654 int bx_usb_ehci_c::state_fetchsitd(int async)
1655 {
1656 Bit32u entry;
1657 EHCIsitd sitd;
1658
1659 BX_ASSERT(!async);
1660 entry = BX_EHCI_THIS get_fetch_addr(async);
1661
1662 get_dwords(NLPTR_GET(entry), (Bit32u*)&sitd, sizeof(EHCIsitd) >> 2);
1663
1664 if (!(sitd.results & SITD_RESULTS_ACTIVE)) {
1665 /* siTD is not active, nothing to do */;
1666 } else {
1667 /* TODO: split transfers are not implemented */
1668 BX_ERROR(("WARNING: Skipping active siTD"));
1669 }
1670
1671 BX_EHCI_THIS set_fetch_addr(async, sitd.next);
1672 BX_EHCI_THIS set_state(async, EST_FETCHENTRY);
1673 return 1;
1674 }
1675
state_advqueue(EHCIQueue * q)1676 int bx_usb_ehci_c::state_advqueue(EHCIQueue *q)
1677 {
1678 /*
1679 * want data and alt-next qTD is valid
1680 */
1681 if (((q->qh.token & QTD_TOKEN_TBYTES_MASK) != 0) &&
1682 (NLPTR_TBIT(q->qh.altnext_qtd) == 0)) {
1683 q->qtdaddr = q->qh.altnext_qtd;
1684 BX_EHCI_THIS set_state(q->async, EST_FETCHQTD);
1685
1686
1687 /*
1688 * next qTD is valid
1689 */
1690 } else if (NLPTR_TBIT(q->qh.next_qtd) == 0) {
1691 q->qtdaddr = q->qh.next_qtd;
1692 BX_EHCI_THIS set_state(q->async, EST_FETCHQTD);
1693
1694 /*
1695 * no valid qTD, try next QH
1696 */
1697 } else {
1698 BX_EHCI_THIS set_state(q->async, EST_HORIZONTALQH);
1699 }
1700
1701 return 1;
1702 }
1703
state_fetchqtd(EHCIQueue * q)1704 int bx_usb_ehci_c::state_fetchqtd(EHCIQueue *q)
1705 {
1706 EHCIqtd qtd;
1707 EHCIPacket *p;
1708 int again = 0;
1709
1710 get_dwords(NLPTR_GET(q->qtdaddr), (Bit32u*) &qtd, sizeof(EHCIqtd) >> 2);
1711
1712 p = QTAILQ_FIRST(&q->packets);
1713 if (p != NULL) {
1714 if (p->qtdaddr != q->qtdaddr ||
1715 (!NLPTR_TBIT(p->qtd.next) && (p->qtd.next != qtd.next)) ||
1716 (!NLPTR_TBIT(p->qtd.altnext) && (p->qtd.altnext != qtd.altnext)) ||
1717 p->qtd.bufptr[0] != qtd.bufptr[0]) {
1718 BX_EHCI_THIS cancel_queue(q);
1719 BX_ERROR(("guest updated active QH or qTD"));
1720 p = NULL;
1721 } else {
1722 p->qtd = qtd;
1723 BX_EHCI_THIS qh_do_overlay(q);
1724 }
1725 }
1726
1727 if (!(qtd.token & QTD_TOKEN_ACTIVE)) {
1728 if (p != NULL) {
1729 /* transfer canceled by guest (clear active) */
1730 BX_EHCI_THIS cancel_queue(q);
1731 p = NULL;
1732 }
1733 BX_EHCI_THIS set_state(q->async, EST_HORIZONTALQH);
1734 again = 1;
1735 } else if (p != NULL) {
1736 switch (p->async) {
1737 case EHCI_ASYNC_NONE:
1738 /* Should never happen packet should at least be initialized */
1739 BX_PANIC(("Should never happen"));
1740 break;
1741 case EHCI_ASYNC_INITIALIZED:
1742 /* Previously nacked packet (likely interrupt ep) */
1743 BX_EHCI_THIS set_state(q->async, EST_EXECUTE);
1744 break;
1745 case EHCI_ASYNC_INFLIGHT:
1746 /* Unfinished async handled packet, go horizontal */
1747 BX_EHCI_THIS set_state(q->async, EST_HORIZONTALQH);
1748 break;
1749 case EHCI_ASYNC_FINISHED:
1750 /*
1751 * We get here when advqueue moves to a packet which is already
1752 * finished, which can happen with packets queued up by fill_queue
1753 */
1754 BX_EHCI_THIS set_state(q->async, EST_EXECUTING);
1755 break;
1756 }
1757 again = 1;
1758 } else {
1759 p = BX_EHCI_THIS alloc_packet(q);
1760 p->qtdaddr = q->qtdaddr;
1761 p->qtd = qtd;
1762 BX_EHCI_THIS set_state(q->async, EST_EXECUTE);
1763 again = 1;
1764 }
1765
1766 return again;
1767 }
1768
state_horizqh(EHCIQueue * q)1769 int bx_usb_ehci_c::state_horizqh(EHCIQueue *q)
1770 {
1771 int again = 0;
1772
1773 if (BX_EHCI_THIS get_fetch_addr(q->async) != q->qh.next) {
1774 BX_EHCI_THIS set_fetch_addr(q->async, q->qh.next);
1775 BX_EHCI_THIS set_state(q->async, EST_FETCHENTRY);
1776 again = 1;
1777 } else {
1778 BX_EHCI_THIS set_state(q->async, EST_ACTIVE);
1779 }
1780
1781 return again;
1782 }
1783
fill_queue(EHCIPacket * p)1784 int bx_usb_ehci_c::fill_queue(EHCIPacket *p)
1785 {
1786 EHCIQueue *q = p->queue;
1787 EHCIqtd qtd = p->qtd;
1788 Bit32u qtdaddr;
1789
1790 for (;;) {
1791 if (NLPTR_TBIT(qtd.altnext) == 0) {
1792 break;
1793 }
1794 if (NLPTR_TBIT(qtd.next) != 0) {
1795 break;
1796 }
1797 qtdaddr = qtd.next;
1798 get_dwords(NLPTR_GET(qtdaddr), (Bit32u*) &qtd, sizeof(EHCIqtd) >> 2);
1799 if (!(qtd.token & QTD_TOKEN_ACTIVE)) {
1800 break;
1801 }
1802 p = BX_EHCI_THIS alloc_packet(q);
1803 p->qtdaddr = qtdaddr;
1804 p->qtd = qtd;
1805 p->usb_status = BX_EHCI_THIS execute(p);
1806 if (p->usb_status == USB_RET_PROCERR) {
1807 break;
1808 }
1809 BX_ASSERT(p->usb_status == USB_RET_ASYNC);
1810 p->async = EHCI_ASYNC_INFLIGHT;
1811 }
1812 return p->usb_status;
1813 }
1814
state_execute(EHCIQueue * q)1815 int bx_usb_ehci_c::state_execute(EHCIQueue *q)
1816 {
1817 EHCIPacket *p = QTAILQ_FIRST(&q->packets);
1818 int again = 0;
1819
1820 BX_ASSERT(p != NULL);
1821 BX_ASSERT(p->qtdaddr == q->qtdaddr);
1822
1823 if (BX_EHCI_THIS qh_do_overlay(q) != 0) {
1824 return -1;
1825 }
1826
1827 // TODO verify enough time remains in the uframe as in 4.4.1.1
1828 // TODO write back ptr to async list when done or out of time
1829 // TODO Windows does not seem to ever set the MULT field
1830
1831 if (!q->async) {
1832 int transactCtr = get_field(q->qh.epcap, QH_EPCAP_MULT);
1833 if (!transactCtr) {
1834 BX_EHCI_THIS set_state(q->async, EST_HORIZONTALQH);
1835 again = 1;
1836 goto out;
1837 }
1838 }
1839
1840 if (q->async) {
1841 BX_EHCI_THIS hub.op_regs.UsbSts.recl = 1;
1842 }
1843
1844 p->usb_status = BX_EHCI_THIS execute(p);
1845 if (p->usb_status == USB_RET_PROCERR) {
1846 again = -1;
1847 goto out;
1848 }
1849 if (p->usb_status == USB_RET_ASYNC) {
1850 BX_EHCI_THIS flush_qh(q);
1851 p->async = EHCI_ASYNC_INFLIGHT;
1852 BX_EHCI_THIS set_state(q->async, EST_HORIZONTALQH);
1853 again = (BX_EHCI_THIS fill_queue(p) == USB_RET_PROCERR) ? -1 : 1;
1854 goto out;
1855 }
1856
1857 BX_EHCI_THIS set_state(q->async, EST_EXECUTING);
1858 again = 1;
1859
1860 out:
1861 return again;
1862 }
1863
state_executing(EHCIQueue * q)1864 int bx_usb_ehci_c::state_executing(EHCIQueue *q)
1865 {
1866 EHCIPacket *p = QTAILQ_FIRST(&q->packets);
1867
1868 BX_ASSERT(p != NULL);
1869 BX_ASSERT(p->qtdaddr == q->qtdaddr);
1870
1871 BX_EHCI_THIS execute_complete(q);
1872
1873 // 4.10.3
1874 if (!q->async) {
1875 int transactCtr = get_field(q->qh.epcap, QH_EPCAP_MULT);
1876 transactCtr--;
1877 set_field(&q->qh.epcap, transactCtr, QH_EPCAP_MULT);
1878 // 4.10.3, bottom of page 82, should exit this state when transaction
1879 // counter decrements to 0
1880 }
1881
1882 /* 4.10.5 */
1883 if (p->usb_status == USB_RET_NAK) {
1884 BX_EHCI_THIS set_state(q->async, EST_HORIZONTALQH);
1885 } else {
1886 BX_EHCI_THIS set_state(q->async, EST_WRITEBACK);
1887 }
1888
1889 BX_EHCI_THIS flush_qh(q);
1890 return 1;
1891 }
1892
state_writeback(EHCIQueue * q)1893 int bx_usb_ehci_c::state_writeback(EHCIQueue *q)
1894 {
1895 EHCIPacket *p = QTAILQ_FIRST(&q->packets);
1896 Bit32u *qtd, addr;
1897 int again = 0;
1898
1899 /* Write back the QTD from the QH area */
1900 BX_ASSERT(p != NULL);
1901 BX_ASSERT(p->qtdaddr == q->qtdaddr);
1902
1903 qtd = (Bit32u*) &q->qh.next_qtd;
1904 addr = NLPTR_GET(p->qtdaddr);
1905 put_dwords(addr + 2 * sizeof(Bit32u), qtd + 2, 2);
1906 BX_EHCI_THIS free_packet(p);
1907
1908 /*
1909 * EHCI specs say go horizontal here.
1910 *
1911 * We can also advance the queue here for performance reasons. We
1912 * need to take care to only take that shortcut in case we've
1913 * processed the qtd just written back without errors, i.e. halt
1914 * bit is clear.
1915 */
1916 if (q->qh.token & QTD_TOKEN_HALT) {
1917 /*
1918 * We should not do any further processing on a halted queue!
1919 * This is esp. important for bulk endpoints with pipelining enabled
1920 * (redirection to a real USB device), where we must cancel all the
1921 * transfers after this one so that:
1922 * 1) If they've completed already, they are not processed further
1923 * causing more stalls, originating from the same failed transfer
1924 * 2) If still in flight, they are cancelled before the guest does
1925 * a clear stall, otherwise the guest and device can loose sync!
1926 */
1927 while ((p = QTAILQ_FIRST(&q->packets)) != NULL) {
1928 BX_EHCI_THIS free_packet(p);
1929 }
1930 BX_EHCI_THIS set_state(q->async, EST_HORIZONTALQH);
1931 again = 1;
1932 } else {
1933 BX_EHCI_THIS set_state(q->async, EST_ADVANCEQUEUE);
1934 again = 1;
1935 }
1936 return again;
1937 }
1938
advance_state(int async)1939 void bx_usb_ehci_c::advance_state(int async)
1940 {
1941 EHCIQueue *q = NULL;
1942 int again;
1943
1944 do {
1945 switch (BX_EHCI_THIS get_state(async)) {
1946 case EST_WAITLISTHEAD:
1947 again = BX_EHCI_THIS state_waitlisthead(async);
1948 break;
1949
1950 case EST_FETCHENTRY:
1951 again = BX_EHCI_THIS state_fetchentry(async);
1952 break;
1953
1954 case EST_FETCHQH:
1955 q = BX_EHCI_THIS state_fetchqh(async);
1956 if (q != NULL) {
1957 assert(q->async == async);
1958 again = 1;
1959 } else {
1960 again = 0;
1961 }
1962 break;
1963
1964 case EST_FETCHITD:
1965 again = BX_EHCI_THIS state_fetchitd(async);
1966 break;
1967
1968 case EST_FETCHSITD:
1969 again = BX_EHCI_THIS state_fetchsitd(async);
1970 break;
1971
1972 case EST_ADVANCEQUEUE:
1973 again = BX_EHCI_THIS state_advqueue(q);
1974 break;
1975
1976 case EST_FETCHQTD:
1977 again = BX_EHCI_THIS state_fetchqtd(q);
1978 break;
1979
1980 case EST_HORIZONTALQH:
1981 again = BX_EHCI_THIS state_horizqh(q);
1982 break;
1983
1984 case EST_EXECUTE:
1985 again = BX_EHCI_THIS state_execute(q);
1986 if (async) {
1987 BX_EHCI_THIS hub.async_stepdown = 0;
1988 }
1989 break;
1990
1991 case EST_EXECUTING:
1992 assert(q != NULL);
1993 if (async) {
1994 BX_EHCI_THIS hub.async_stepdown = 0;
1995 }
1996 again = BX_EHCI_THIS state_executing(q);
1997 break;
1998
1999 case EST_WRITEBACK:
2000 assert(q != NULL);
2001 again = BX_EHCI_THIS state_writeback(q);
2002 break;
2003
2004 default:
2005 BX_ERROR(("Bad state!"));
2006 again = -1;
2007 break;
2008 }
2009
2010 if (again < 0) {
2011 BX_ERROR(("processing error - resetting ehci HC"));
2012 BX_EHCI_THIS reset_hc();
2013 again = 0;
2014 }
2015 } while (again);
2016 }
2017
advance_async_state(void)2018 void bx_usb_ehci_c::advance_async_state(void)
2019 {
2020 const int async = 1;
2021
2022 switch (BX_EHCI_THIS get_state(async)) {
2023 case EST_INACTIVE:
2024 if (!BX_EHCI_THIS hub.op_regs.UsbCmd.ase) {
2025 break;
2026 }
2027 BX_EHCI_THIS set_state(async, EST_ACTIVE);
2028 // No break, fall through to ACTIVE
2029
2030 case EST_ACTIVE:
2031 if (!BX_EHCI_THIS hub.op_regs.UsbCmd.ase) {
2032 BX_EHCI_THIS queues_rip_all(async);
2033 BX_EHCI_THIS set_state(async, EST_INACTIVE);
2034 break;
2035 }
2036
2037 /* make sure guest has acknowledged the doorbell interrupt */
2038 /* TO-DO: is this really needed? */
2039 if (BX_EHCI_THIS hub.op_regs.UsbSts.inti & USBSTS_IAA) {
2040 BX_DEBUG(("IAA status bit still set."));
2041 break;
2042 }
2043
2044 /* check that address register has been set */
2045 if (BX_EHCI_THIS hub.op_regs.AsyncListAddr == 0) {
2046 break;
2047 }
2048
2049 BX_EHCI_THIS set_state(async, EST_WAITLISTHEAD);
2050 BX_EHCI_THIS advance_state(async);
2051
2052 /* If the doorbell is set, the guest wants to make a change to the
2053 * schedule. The host controller needs to release cached data.
2054 * (section 4.8.2)
2055 */
2056 if (BX_EHCI_THIS hub.op_regs.UsbCmd.iaad) {
2057 /* Remove all unseen qhs from the async qhs queue */
2058 BX_EHCI_THIS queues_rip_unseen(async);
2059 BX_EHCI_THIS hub.op_regs.UsbCmd.iaad = 0;
2060 BX_EHCI_THIS raise_irq(USBSTS_IAA);
2061 }
2062 break;
2063
2064 default:
2065 /* this should only be due to a developer mistake */
2066 BX_PANIC(("Bad asynchronous state %d. Resetting to active", BX_EHCI_THIS hub.astate));
2067 BX_EHCI_THIS set_state(async, EST_ACTIVE);
2068 }
2069 }
2070
advance_periodic_state(void)2071 void bx_usb_ehci_c::advance_periodic_state(void)
2072 {
2073 Bit32u entry;
2074 Bit32u list;
2075 const int async = 0;
2076
2077 // 4.6
2078
2079 switch (BX_EHCI_THIS get_state(async)) {
2080 case EST_INACTIVE:
2081 if (!(BX_EHCI_THIS hub.op_regs.FrIndex & 7) && BX_EHCI_THIS hub.op_regs.UsbCmd.pse) {
2082 BX_EHCI_THIS set_state(async, EST_ACTIVE);
2083 // No break, fall through to ACTIVE
2084 } else
2085 break;
2086
2087 case EST_ACTIVE:
2088 if (!(BX_EHCI_THIS hub.op_regs.FrIndex & 7) && !BX_EHCI_THIS hub.op_regs.UsbCmd.pse) {
2089 BX_EHCI_THIS queues_rip_all(async);
2090 BX_EHCI_THIS set_state(async, EST_INACTIVE);
2091 break;
2092 }
2093
2094 list = BX_EHCI_THIS hub.op_regs.PeriodicListBase & 0xfffff000;
2095 /* check that register has been set */
2096 if (list == 0) {
2097 break;
2098 }
2099 list |= ((BX_EHCI_THIS hub.op_regs.FrIndex & 0x1ff8) >> 1);
2100
2101 DEV_MEM_READ_PHYSICAL(list, 4, (Bit8u*)&entry);
2102
2103 BX_DEBUG(("PERIODIC state adv fr=%d. [%08X] -> %08X",
2104 BX_EHCI_THIS hub.op_regs.FrIndex / 8, list, entry));
2105 BX_EHCI_THIS set_fetch_addr(async, entry);
2106 BX_EHCI_THIS set_state(async, EST_FETCHENTRY);
2107 BX_EHCI_THIS advance_state(async);
2108 BX_EHCI_THIS queues_rip_unused(async);
2109 break;
2110
2111 default:
2112 /* this should only be due to a developer mistake */
2113 BX_PANIC(("Bad periodic state %d. Resetting to active", BX_EHCI_THIS hub.pstate));
2114 }
2115 }
2116
update_frindex(int frames)2117 void bx_usb_ehci_c::update_frindex(int frames)
2118 {
2119 int i;
2120
2121 if (!BX_EHCI_THIS hub.op_regs.UsbCmd.rs) {
2122 return;
2123 }
2124
2125 for (i = 0; i < frames; i++) {
2126 BX_EHCI_THIS hub.op_regs.FrIndex += 8;
2127
2128 if (BX_EHCI_THIS hub.op_regs.FrIndex == 0x00002000) {
2129 BX_EHCI_THIS raise_irq(USBSTS_FLR);
2130 }
2131
2132 if (BX_EHCI_THIS hub.op_regs.FrIndex == 0x00004000) {
2133 BX_EHCI_THIS raise_irq(USBSTS_FLR);
2134 BX_EHCI_THIS hub.op_regs.FrIndex = 0;
2135 if (BX_EHCI_THIS hub.usbsts_frindex >= 0x00004000) {
2136 BX_EHCI_THIS hub.usbsts_frindex -= 0x00004000;
2137 } else {
2138 BX_EHCI_THIS hub.usbsts_frindex = 0;
2139 }
2140 }
2141 }
2142 }
2143
ehci_frame_handler(void * this_ptr)2144 void bx_usb_ehci_c::ehci_frame_handler(void *this_ptr)
2145 {
2146 bx_usb_ehci_c *class_ptr = (bx_usb_ehci_c *) this_ptr;
2147 class_ptr->ehci_frame_timer();
2148 }
2149
2150 // Frame timer called once every 1.000 msec
ehci_frame_timer(void)2151 void bx_usb_ehci_c::ehci_frame_timer(void)
2152 {
2153 int need_timer = 0;
2154 Bit64u t_now;
2155 Bit64u usec_elapsed;
2156 int frames, skipped_frames;
2157 int i;
2158
2159 t_now = bx_pc_system.time_usec();
2160 usec_elapsed = t_now - BX_EHCI_THIS hub.last_run_usec;
2161 frames = (int)(usec_elapsed / FRAME_TIMER_USEC);
2162
2163 if (BX_EHCI_THIS periodic_enabled() || (BX_EHCI_THIS hub.pstate != EST_INACTIVE)) {
2164 need_timer++;
2165 BX_EHCI_THIS hub.async_stepdown = 0;
2166
2167 if (frames > (int)BX_EHCI_THIS maxframes) {
2168 skipped_frames = frames - BX_EHCI_THIS maxframes;
2169 BX_EHCI_THIS update_frindex(skipped_frames);
2170 BX_EHCI_THIS hub.last_run_usec += FRAME_TIMER_USEC * skipped_frames;
2171 frames -= skipped_frames;
2172 BX_DEBUG(("WARNING - EHCI skipped %d frames", skipped_frames));
2173 }
2174
2175 for (i = 0; i < frames; i++) {
2176 /*
2177 * If we're running behind schedule, we should not catch up
2178 * too fast, as that will make some guests unhappy:
2179 * 1) We must process a minimum of MIN_FR_PER_TICK frames,
2180 * otherwise we will never catch up
2181 * 2) Process frames until the guest has requested an irq (IOC)
2182 */
2183 if (i >= MIN_FR_PER_TICK) {
2184 BX_EHCI_THIS commit_irq();
2185 if ((BX_EHCI_THIS hub.op_regs.UsbSts.inti & BX_EHCI_THIS hub.op_regs.UsbIntr) > 0){
2186 break;
2187 }
2188 }
2189 BX_EHCI_THIS update_frindex(1);
2190 BX_EHCI_THIS advance_periodic_state();
2191 BX_EHCI_THIS hub.last_run_usec += FRAME_TIMER_USEC;
2192 }
2193 } else {
2194 if (BX_EHCI_THIS hub.async_stepdown < BX_EHCI_THIS maxframes / 2) {
2195 BX_EHCI_THIS hub.async_stepdown++;
2196 }
2197 BX_EHCI_THIS update_frindex(frames);
2198 BX_EHCI_THIS hub.last_run_usec += FRAME_TIMER_USEC * frames;
2199 }
2200
2201 /* Async is not inside loop since it executes everything it can once
2202 * called
2203 */
2204 if (BX_EHCI_THIS async_enabled() || (BX_EHCI_THIS hub.astate != EST_INACTIVE)) {
2205 need_timer++;
2206 BX_EHCI_THIS advance_async_state();
2207 }
2208
2209 BX_EHCI_THIS commit_irq();
2210 if (BX_EHCI_THIS hub.usbsts_pending) {
2211 need_timer++;
2212 BX_EHCI_THIS hub.async_stepdown = 0;
2213 }
2214 if (need_timer) {
2215 // TODO: modify timer not implemented
2216 }
2217 }
2218
2219 // runtime configuration handler (called when continuing simulation)
runtime_config_handler(void * this_ptr)2220 void bx_usb_ehci_c::runtime_config_handler(void *this_ptr)
2221 {
2222 bx_usb_ehci_c *class_ptr = (bx_usb_ehci_c *) this_ptr;
2223 class_ptr->runtime_config();
2224 }
2225
runtime_config(void)2226 void bx_usb_ehci_c::runtime_config(void)
2227 {
2228 int i;
2229 char pname[6];
2230
2231 for (i = 0; i < USB_EHCI_PORTS; i++) {
2232 // device change support
2233 if ((BX_EHCI_THIS device_change & (1 << i)) != 0) {
2234 if (BX_EHCI_THIS hub.usb_port[i].device == NULL) {
2235 sprintf(pname, "port%d", i + 1);
2236 init_device(i, (bx_list_c*)SIM->get_param(pname, SIM->get_param(BXPN_USB_EHCI)));
2237 } else {
2238 set_connect_status(i, 0);
2239 }
2240 BX_EHCI_THIS device_change &= ~(1 << i);
2241 }
2242 // forward to connected device
2243 if (BX_EHCI_THIS hub.usb_port[i].device != NULL) {
2244 BX_EHCI_THIS hub.usb_port[i].device->runtime_config();
2245 }
2246 }
2247 }
2248
2249 // pci configuration space write callback handler
pci_write_handler(Bit8u address,Bit32u value,unsigned io_len)2250 void bx_usb_ehci_c::pci_write_handler(Bit8u address, Bit32u value, unsigned io_len)
2251 {
2252 if (((address >= 0x14) && (address <= 0x3b)) || (address > 0x80))
2253 return;
2254
2255 BX_DEBUG_PCI_WRITE(address, value, io_len);
2256 for (unsigned i=0; i<io_len; i++) {
2257 Bit8u value8 = (value >> (i*8)) & 0xFF;
2258 // Bit8u oldval = BX_EHCI_THIS pci_conf[address+i];
2259 switch (address+i) {
2260 case 0x04:
2261 value8 &= 0x06; // (bit 0 is read only for this card) (we don't allow port IO)
2262 BX_EHCI_THIS pci_conf[address+i] = value8;
2263 break;
2264 case 0x05: // disallowing write to command hi-byte
2265 case 0x06: // disallowing write to status lo-byte (is that expected?)
2266 case 0x0d: //
2267 case 0x3d: //
2268 case 0x3e: //
2269 case 0x3f: //
2270 case 0x60: //
2271 break;
2272 case 0x2c:
2273 case 0x2d:
2274 case 0x2e:
2275 case 0x2f:
2276 if (BX_EHCI_THIS pci_conf[0x80] & 1) {
2277 BX_EHCI_THIS pci_conf[address+i] = value8;
2278 }
2279 break;
2280 case 0x61:
2281 value8 &= 0x3f;
2282 default:
2283 BX_EHCI_THIS pci_conf[address+i] = value8;
2284 }
2285 }
2286 }
2287
2288 // USB runtime parameter handler
usb_param_handler(bx_param_c * param,bool set,Bit64s val)2289 Bit64s bx_usb_ehci_c::usb_param_handler(bx_param_c *param, bool set, Bit64s val)
2290 {
2291 int portnum;
2292
2293 if (set) {
2294 portnum = atoi((param->get_parent())->get_name()+4) - 1;
2295 bool empty = (val == 0);
2296 if ((portnum >= 0) && (portnum < USB_EHCI_PORTS)) {
2297 if (empty && (BX_EHCI_THIS hub.usb_port[portnum].device != NULL)) {
2298 BX_EHCI_THIS device_change |= (1 << portnum);
2299 } else if (!empty && (BX_EHCI_THIS hub.usb_port[portnum].device == NULL)) {
2300 BX_EHCI_THIS device_change |= (1 << portnum);
2301 } else if (val != ((bx_param_enum_c*)param)->get()) {
2302 BX_ERROR(("usb_param_handler(): port #%d already in use", portnum+1));
2303 val = ((bx_param_enum_c*)param)->get();
2304 }
2305 } else {
2306 BX_PANIC(("usb_param_handler called with unexpected parameter '%s'", param->get_name()));
2307 }
2308 }
2309 return val;
2310 }
2311
2312 // USB runtime parameter enable handler
usb_param_enable_handler(bx_param_c * param,bool en)2313 bool bx_usb_ehci_c::usb_param_enable_handler(bx_param_c *param, bool en)
2314 {
2315 int portnum = atoi((param->get_parent())->get_name()+4) - 1;
2316 if (en && (BX_EHCI_THIS hub.usb_port[portnum].device != NULL)) {
2317 en = 0;
2318 }
2319 return en;
2320 }
2321
2322 #endif // BX_SUPPORT_PCI && BX_SUPPORT_USB_EHCI
2323