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(&params[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