Add over-current signaling
This adds over-current signaling to the USBs four host controllers. To signal an OC, use the runtime configuration and set the checkbox (GUI) or text config's parameter to 1. This pull request also adds USB documentation to user.dbk.
This commit is contained in:
parent
d01e0f6cf8
commit
dacc965593
@ -166,7 +166,7 @@ void bx_uhci_core_c::reset_uhci(unsigned type)
|
||||
hub.usb_port[j].resume = 0;
|
||||
hub.usb_port[j].suspend = 0;
|
||||
hub.usb_port[j].over_current_change = 0;
|
||||
hub.usb_port[j].over_current = 1;
|
||||
hub.usb_port[j].over_current = 0;
|
||||
hub.usb_port[j].enabled = 0;
|
||||
hub.usb_port[j].enable_changed = 0;
|
||||
hub.usb_port[j].status = 0;
|
||||
@ -564,7 +564,7 @@ void bx_uhci_core_c::write(Bit32u address, Bit32u value, unsigned io_len)
|
||||
if (hub.usb_port[port].reset) {
|
||||
hub.usb_port[port].suspend = 0;
|
||||
hub.usb_port[port].over_current_change = 0;
|
||||
hub.usb_port[port].over_current = 1;
|
||||
hub.usb_port[port].over_current = 0;
|
||||
hub.usb_port[port].resume = 0;
|
||||
hub.usb_port[port].enabled = 0;
|
||||
// are we are currently connected/disconnected
|
||||
@ -645,7 +645,7 @@ void bx_uhci_core_c::uhci_timer(void)
|
||||
hub.usb_port[i].reset = 0;
|
||||
hub.usb_port[i].resume = 0;
|
||||
hub.usb_port[i].status = 0;
|
||||
hub.usb_port[i].over_current = 1;
|
||||
hub.usb_port[i].over_current = 0;
|
||||
hub.usb_port[i].over_current_change = 0;
|
||||
hub.usb_port[i].suspend = 0;
|
||||
}
|
||||
@ -734,10 +734,14 @@ void bx_uhci_core_c::uhci_timer(void)
|
||||
const int r_actlen = (((td.dword1 & 0x7FF) + 1) & 0x7FF);
|
||||
const int r_maxlen = (((td.dword2 >> 21) + 1) & 0x7FF);
|
||||
BX_DEBUG((" r_actlen = %d r_maxlen = %d", r_actlen, r_maxlen));
|
||||
if (((td.dword2 & 0xFF) == USB_TOKEN_IN) && spd && (queue_addr != 0) && (r_actlen < r_maxlen) && ((td.dword1 & 0x00FF0000) == 0)) {
|
||||
BX_DEBUG(("Short Packet Detected"));
|
||||
shortpacket = was_short = 1;
|
||||
td.dword1 |= (1<<29);
|
||||
if (((td.dword2 & 0xFF) == USB_TOKEN_IN) && (queue_addr != 0) && (r_actlen < r_maxlen) && ((td.dword1 & 0x00FF0000) == 0)) {
|
||||
if (spd) {
|
||||
BX_DEBUG(("Short Packet Detected"));
|
||||
shortpacket = was_short = 1;
|
||||
td.dword1 |= (1<<29);
|
||||
} else {
|
||||
BX_DEBUG(("A Short Packet was detected, but the SPD bit in DWORD1 was clear"));
|
||||
}
|
||||
}
|
||||
if (td.dword1 & (1<<22)) stalled = was_stall = 1;
|
||||
|
||||
|
@ -168,7 +168,7 @@ typedef struct {
|
||||
bool status;
|
||||
} usb_port[USB_UHCI_PORTS];
|
||||
|
||||
int max_bandwidth; // standard USB 1.1 is 1280 bytes (VTxxxxx models allowed a few more)
|
||||
int max_bandwidth; // standard USB 1.1 is 1280 bytes (VTxxxxx models allowed a few less (1023))
|
||||
int loop_reached; // did we reach our bandwidth loop limit
|
||||
Bit8u devfunc;
|
||||
} bx_uhci_core_t;
|
||||
|
@ -194,7 +194,7 @@ bx_usb_ehci_c::bx_usb_ehci_c()
|
||||
|
||||
bx_usb_ehci_c::~bx_usb_ehci_c()
|
||||
{
|
||||
char pname[16];
|
||||
char pname[32];
|
||||
int i;
|
||||
|
||||
SIM->unregister_runtime_config_handler(rt_conf_id);
|
||||
@ -209,6 +209,8 @@ bx_usb_ehci_c::~bx_usb_ehci_c()
|
||||
SIM->get_param_enum(pname, SIM->get_param(BXPN_USB_EHCI))->set_handler(NULL);
|
||||
sprintf(pname, "port%d.options", i+1);
|
||||
SIM->get_param_string(pname, SIM->get_param(BXPN_USB_EHCI))->set_enable_handler(NULL);
|
||||
sprintf(pname, "port%d.over_current", i+1);
|
||||
SIM->get_param_bool(pname, SIM->get_param(BXPN_USB_EHCI))->set_handler(NULL);
|
||||
remove_device(i);
|
||||
}
|
||||
|
||||
@ -225,7 +227,14 @@ void bx_usb_ehci_c::init(void)
|
||||
bx_list_c *ehci, *port;
|
||||
bx_param_enum_c *device;
|
||||
bx_param_string_c *options;
|
||||
bx_param_bool_c *over_current;
|
||||
Bit8u devfunc;
|
||||
|
||||
/* If you wish to set DEBUG=report in the code, instead of
|
||||
* in the configuration, simply uncomment this line. I use
|
||||
* it when I am working on this emulation.
|
||||
*/
|
||||
//LOG_THIS setonoff(LOGLEV_DEBUG, ACT_REPORT);
|
||||
|
||||
// Read in values from config interface
|
||||
ehci = (bx_list_c*) SIM->get_param(BXPN_USB_EHCI);
|
||||
@ -283,6 +292,8 @@ void bx_usb_ehci_c::init(void)
|
||||
device->set_handler(usb_param_handler);
|
||||
options = (bx_param_string_c*)port->get_by_name("options");
|
||||
options->set_enable_handler(usb_param_enable_handler);
|
||||
over_current = (bx_param_bool_c*)port->get_by_name("over_current");
|
||||
over_current->set_handler(usb_param_oc_handler);
|
||||
BX_EHCI_THIS hub.usb_port[i].device = NULL;
|
||||
BX_EHCI_THIS hub.usb_port[i].owner_change = 0;
|
||||
BX_EHCI_THIS hub.usb_port[i].portsc.ccs = 0;
|
||||
@ -530,6 +541,7 @@ void bx_usb_ehci_c::init_device(Bit8u port, bx_list_c *portconf)
|
||||
} else {
|
||||
((bx_param_enum_c*)portconf->get_by_name("device"))->set_by_name("none");
|
||||
((bx_param_string_c*)portconf->get_by_name("options"))->set("none");
|
||||
((bx_param_bool_c*)portconf->get_by_name("over_current"))->set(0);
|
||||
set_connect_status(port, 0);
|
||||
}
|
||||
}
|
||||
@ -1370,6 +1382,15 @@ int bx_usb_ehci_c::execute(EHCIPacket *p)
|
||||
int ret;
|
||||
int endp;
|
||||
|
||||
// if we remove the device, or signal an over-current, there is a possibility
|
||||
// that 'dev' is NULL. simply return that we transfered zero bytes.
|
||||
// ( we can't return USB_RET_PROCERR, since this code will then reset the HC.
|
||||
// On an over-current, we don't want the HC to reset... )
|
||||
if (p->queue->dev == NULL) {
|
||||
BX_DEBUG(("Attempting to execute a packet with no device attached."));
|
||||
return 0;
|
||||
}
|
||||
|
||||
BX_ASSERT(p->async == EHCI_ASYNC_NONE ||
|
||||
p->async == EHCI_ASYNC_INITIALIZED);
|
||||
|
||||
@ -2329,6 +2350,32 @@ Bit64s bx_usb_ehci_c::usb_param_handler(bx_param_c *param, bool set, Bit64s val)
|
||||
return val;
|
||||
}
|
||||
|
||||
// USB runtime parameter handler: over-current
|
||||
Bit64s bx_usb_ehci_c::usb_param_oc_handler(bx_param_c *param, bool set, Bit64s val)
|
||||
{
|
||||
int portnum;
|
||||
|
||||
if (set && val) {
|
||||
portnum = atoi((param->get_parent())->get_name()+4) - 1;
|
||||
if ((portnum >= 0) && (portnum < USB_EHCI_PORTS)) {
|
||||
if (BX_EHCI_THIS hub.usb_port[portnum].portsc.ccs) {
|
||||
// EHCI, section 4.2.5, page 58
|
||||
BX_EHCI_THIS hub.usb_port[portnum].portsc.occ = 1;
|
||||
BX_EHCI_THIS hub.usb_port[portnum].portsc.oca = 1;
|
||||
BX_EHCI_THIS hub.usb_port[portnum].portsc.pec = 1;
|
||||
BX_EHCI_THIS hub.usb_port[portnum].portsc.ped = 0;
|
||||
BX_EHCI_THIS hub.usb_port[portnum].portsc.pp = 0; // optional (the HC may leave power on, limiting the current)
|
||||
BX_DEBUG(("Over-current signaled on port #%d.", portnum + 1));
|
||||
BX_EHCI_THIS raise_irq(USBSTS_PCD);
|
||||
}
|
||||
} else {
|
||||
BX_ERROR(("Over-current: Bad portnum given: %d", portnum + 1));
|
||||
}
|
||||
}
|
||||
|
||||
return 0; // clear the indicator for next time
|
||||
}
|
||||
|
||||
// USB runtime parameter enable handler
|
||||
bool bx_usb_ehci_c::usb_param_enable_handler(bx_param_c *param, bool en)
|
||||
{
|
||||
|
@ -419,6 +419,7 @@ private:
|
||||
void runtime_config(void);
|
||||
|
||||
static Bit64s usb_param_handler(bx_param_c *param, bool set, Bit64s val);
|
||||
static Bit64s usb_param_oc_handler(bx_param_c *param, bool set, Bit64s val);
|
||||
static bool usb_param_enable_handler(bx_param_c *param, bool en);
|
||||
};
|
||||
|
||||
|
@ -254,6 +254,7 @@ bool usb_hub_device_c::init()
|
||||
bx_list_c *port, *deplist;
|
||||
bx_param_enum_c *device;
|
||||
bx_param_string_c *options;
|
||||
bx_param_bool_c *overcurrent;
|
||||
|
||||
// set up config descriptor, status and runtime config for hub.n_ports
|
||||
bx_hub_config_descriptor[22] = (hub.n_ports + 1 + 7) / 8;
|
||||
@ -272,8 +273,14 @@ bool usb_hub_device_c::init()
|
||||
options = new bx_param_string_c(port, "options", "Options", "", "",
|
||||
BX_PATHNAME_LEN);
|
||||
options->set_enable_handler(hub_param_enable_handler);
|
||||
overcurrent = new bx_param_bool_c(port,
|
||||
"over_current",
|
||||
"signal over-current",
|
||||
"signal over-current", 0);
|
||||
overcurrent->set_handler(hub_param_oc_handler);
|
||||
deplist = new bx_list_c(NULL);
|
||||
deplist->add(options);
|
||||
deplist->add(overcurrent);
|
||||
device->set_dependent_list(deplist, 1);
|
||||
device->set_dependent_bitmap(0, 0);
|
||||
}
|
||||
@ -601,12 +608,8 @@ void usb_hub_device_c::init_device(Bit8u port, bx_list_c *portconf)
|
||||
|
||||
void usb_hub_device_c::remove_device(Bit8u port)
|
||||
{
|
||||
// TODO: there is something wrong with 'delete'ing hub.usb_port[port].device
|
||||
// Bochs crashes and doesn't delete the .lock file when we close Bochs
|
||||
if (hub.usb_port[port].device != NULL) {
|
||||
|
||||
delete hub.usb_port[port].device; // this is the culprit. Somewhere in the destruction of usb_device_c, something happens.
|
||||
// simply freeing (free(hub.usb_port[port].device)) it, doesn't crash, so it is one of the destructors...
|
||||
delete hub.usb_port[port].device;
|
||||
hub.usb_port[port].device = NULL;
|
||||
}
|
||||
}
|
||||
@ -764,6 +767,28 @@ bool usb_hub_device_c::hub_param_enable_handler(bx_param_c *param, bool en)
|
||||
return en;
|
||||
}
|
||||
|
||||
// USB runtime parameter handler: over-current
|
||||
Bit64s usb_hub_device_c::hub_param_oc_handler(bx_param_c *param, bool set, Bit64s val)
|
||||
{
|
||||
int portnum;
|
||||
usb_hub_device_c *hub;
|
||||
bx_list_c *port;
|
||||
|
||||
if (set && val) {
|
||||
port = (bx_list_c *) param->get_parent();
|
||||
hub = (usb_hub_device_c *) (port->get_parent()->get_device_param());
|
||||
if (hub != NULL) {
|
||||
portnum = atoi(port->get_name()+4) - 1;
|
||||
hub->hub.usb_port[portnum].PortStatus &= ~PORT_STAT_POWER;
|
||||
hub->hub.usb_port[portnum].PortStatus |= PORT_STAT_OVERCURRENT;
|
||||
hub->hub.usb_port[portnum].PortChange |= PORT_STAT_C_OVERCURRENT;
|
||||
BX_DEBUG(("Over-current signaled on port #%d.", portnum + 1));
|
||||
}
|
||||
}
|
||||
|
||||
return 0; // clear the indicator for next time
|
||||
}
|
||||
|
||||
void usb_hub_restore_handler(void *dev, bx_list_c *conf)
|
||||
{
|
||||
if (dev != NULL) {
|
||||
|
@ -77,6 +77,7 @@ private:
|
||||
|
||||
static Bit64s hub_param_handler(bx_param_c *param, bool set, Bit64s val);
|
||||
static bool hub_param_enable_handler(bx_param_c *param, bool en);
|
||||
static Bit64s hub_param_oc_handler(bx_param_c *param, bool set, Bit64s val);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@ -137,7 +137,7 @@ bx_usb_ohci_c::bx_usb_ohci_c()
|
||||
|
||||
bx_usb_ohci_c::~bx_usb_ohci_c()
|
||||
{
|
||||
char pname[16];
|
||||
char pname[32];
|
||||
|
||||
SIM->unregister_runtime_config_handler(hub.rt_conf_id);
|
||||
|
||||
@ -146,6 +146,8 @@ bx_usb_ohci_c::~bx_usb_ohci_c()
|
||||
SIM->get_param_enum(pname, SIM->get_param(BXPN_USB_OHCI))->set_handler(NULL);
|
||||
sprintf(pname, "port%d.options", i+1);
|
||||
SIM->get_param_string(pname, SIM->get_param(BXPN_USB_OHCI))->set_enable_handler(NULL);
|
||||
sprintf(pname, "port%d.over_current", i+1);
|
||||
SIM->get_param_bool(pname, SIM->get_param(BXPN_USB_OHCI))->set_handler(NULL);
|
||||
remove_device(i);
|
||||
}
|
||||
|
||||
@ -162,6 +164,7 @@ void bx_usb_ohci_c::init(void)
|
||||
bx_list_c *ohci, *port;
|
||||
bx_param_enum_c *device;
|
||||
bx_param_string_c *options;
|
||||
bx_param_bool_c *over_current;
|
||||
|
||||
/* If you wish to set DEBUG=report in the code, instead of
|
||||
* in the configuration, simply uncomment this line. I use
|
||||
@ -208,6 +211,8 @@ void bx_usb_ohci_c::init(void)
|
||||
device->set_handler(usb_param_handler);
|
||||
options = (bx_param_string_c*)port->get_by_name("options");
|
||||
options->set_enable_handler(usb_param_enable_handler);
|
||||
over_current = (bx_param_bool_c*)port->get_by_name("over_current");
|
||||
over_current->set_handler(usb_param_oc_handler);
|
||||
BX_OHCI_THIS hub.usb_port[i].device = NULL;
|
||||
BX_OHCI_THIS hub.usb_port[i].HcRhPortStatus.ccs = 0;
|
||||
BX_OHCI_THIS hub.usb_port[i].HcRhPortStatus.csc = 0;
|
||||
@ -373,7 +378,7 @@ void bx_usb_ohci_c::reset_hc()
|
||||
sprintf(pname, "port%d", i+1);
|
||||
init_device(i, (bx_list_c*)SIM->get_param(pname, SIM->get_param(BXPN_USB_OHCI)));
|
||||
} else {
|
||||
usb_set_connect_status(i, 1);
|
||||
set_connect_status(i, 1);
|
||||
}
|
||||
}
|
||||
|
||||
@ -498,7 +503,7 @@ void bx_usb_ohci_c::init_device(Bit8u port, bx_list_c *portconf)
|
||||
char pname[BX_PATHNAME_LEN];
|
||||
|
||||
if (DEV_usb_init_device(portconf, BX_OHCI_THIS_PTR, &BX_OHCI_THIS hub.usb_port[port].device)) {
|
||||
if (usb_set_connect_status(port, 1)) {
|
||||
if (set_connect_status(port, 1)) {
|
||||
portconf->get_by_name("options")->set_enabled(0);
|
||||
sprintf(pname, "usb_ohci.hub.port%d.device", port+1);
|
||||
bx_list_c *sr_list = (bx_list_c*)SIM->get_param(pname, SIM->get_bochs_root());
|
||||
@ -506,7 +511,8 @@ void bx_usb_ohci_c::init_device(Bit8u port, bx_list_c *portconf)
|
||||
} else {
|
||||
((bx_param_enum_c*)portconf->get_by_name("device"))->set_by_name("none");
|
||||
((bx_param_string_c*)portconf->get_by_name("options"))->set("none");
|
||||
usb_set_connect_status(port, 0);
|
||||
((bx_param_bool_c*)portconf->get_by_name("over_current"))->set(0);
|
||||
set_connect_status(port, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -684,24 +690,21 @@ bool bx_usb_ohci_c::read_handler(bx_phy_address addr, unsigned len, void *data,
|
||||
#endif
|
||||
case 0x54: // HcRhPortStatus[0]
|
||||
p = (offset - 0x54) >> 2;
|
||||
if (BX_OHCI_THIS hub.usb_port[p].HcRhPortStatus.pps == 1) {
|
||||
val = (BX_OHCI_THIS hub.usb_port[p].HcRhPortStatus.reserved0 << 21)
|
||||
| (BX_OHCI_THIS hub.usb_port[p].HcRhPortStatus.prsc ? (1 << 20) : 0)
|
||||
| (BX_OHCI_THIS hub.usb_port[p].HcRhPortStatus.ocic ? (1 << 19) : 0)
|
||||
| (BX_OHCI_THIS hub.usb_port[p].HcRhPortStatus.pssc ? (1 << 18) : 0)
|
||||
| (BX_OHCI_THIS hub.usb_port[p].HcRhPortStatus.pesc ? (1 << 17) : 0)
|
||||
| (BX_OHCI_THIS hub.usb_port[p].HcRhPortStatus.csc ? (1 << 16) : 0)
|
||||
| (BX_OHCI_THIS hub.usb_port[p].HcRhPortStatus.reserved1 << 10)
|
||||
| (BX_OHCI_THIS hub.usb_port[p].HcRhPortStatus.lsda ? (1 << 9) : 0)
|
||||
| (BX_OHCI_THIS hub.usb_port[p].HcRhPortStatus.pps ? (1 << 8) : 0)
|
||||
| (BX_OHCI_THIS hub.usb_port[p].HcRhPortStatus.reserved2 << 5)
|
||||
| (BX_OHCI_THIS hub.usb_port[p].HcRhPortStatus.prs ? (1 << 4) : 0)
|
||||
| (BX_OHCI_THIS hub.usb_port[p].HcRhPortStatus.poci ? (1 << 3) : 0)
|
||||
| (BX_OHCI_THIS hub.usb_port[p].HcRhPortStatus.pss ? (1 << 2) : 0)
|
||||
| (BX_OHCI_THIS hub.usb_port[p].HcRhPortStatus.pes ? (1 << 1) : 0)
|
||||
| (BX_OHCI_THIS hub.usb_port[p].HcRhPortStatus.ccs ? (1 << 0) : 0);
|
||||
} else
|
||||
val = 0;
|
||||
val = (BX_OHCI_THIS hub.usb_port[p].HcRhPortStatus.reserved0 << 21)
|
||||
| (BX_OHCI_THIS hub.usb_port[p].HcRhPortStatus.prsc ? (1 << 20) : 0)
|
||||
| (BX_OHCI_THIS hub.usb_port[p].HcRhPortStatus.ocic ? (1 << 19) : 0)
|
||||
| (BX_OHCI_THIS hub.usb_port[p].HcRhPortStatus.pssc ? (1 << 18) : 0)
|
||||
| (BX_OHCI_THIS hub.usb_port[p].HcRhPortStatus.pesc ? (1 << 17) : 0)
|
||||
| (BX_OHCI_THIS hub.usb_port[p].HcRhPortStatus.csc ? (1 << 16) : 0)
|
||||
| (BX_OHCI_THIS hub.usb_port[p].HcRhPortStatus.reserved1 << 10)
|
||||
| (BX_OHCI_THIS hub.usb_port[p].HcRhPortStatus.lsda ? (1 << 9) : 0)
|
||||
| (BX_OHCI_THIS hub.usb_port[p].HcRhPortStatus.pps ? (1 << 8) : 0)
|
||||
| (BX_OHCI_THIS hub.usb_port[p].HcRhPortStatus.reserved2 << 5)
|
||||
| (BX_OHCI_THIS hub.usb_port[p].HcRhPortStatus.prs ? (1 << 4) : 0)
|
||||
| (BX_OHCI_THIS hub.usb_port[p].HcRhPortStatus.poci ? (1 << 3) : 0)
|
||||
| (BX_OHCI_THIS hub.usb_port[p].HcRhPortStatus.pss ? (1 << 2) : 0)
|
||||
| (BX_OHCI_THIS hub.usb_port[p].HcRhPortStatus.pes ? (1 << 1) : 0)
|
||||
| (BX_OHCI_THIS hub.usb_port[p].HcRhPortStatus.ccs ? (1 << 0) : 0);
|
||||
break;
|
||||
|
||||
default:
|
||||
@ -979,7 +982,7 @@ bool bx_usb_ohci_c::write_handler(bx_phy_address addr, unsigned len, void *data,
|
||||
if (BX_OHCI_THIS hub.usb_port[p].device != NULL) {
|
||||
BX_OHCI_THIS hub.usb_port[p].HcRhPortStatus.lsda =
|
||||
(BX_OHCI_THIS hub.usb_port[p].device->get_speed() == USB_SPEED_LOW);
|
||||
usb_set_connect_status(p, 1);
|
||||
set_connect_status(p, 1);
|
||||
BX_OHCI_THIS hub.usb_port[p].device->usb_send_msg(USB_MSG_RESET);
|
||||
}
|
||||
set_interrupt(OHCI_INTR_RHSC);
|
||||
@ -1433,7 +1436,7 @@ void bx_usb_ohci_c::runtime_config(void)
|
||||
sprintf(pname, "port%d", i + 1);
|
||||
init_device(i, (bx_list_c*)SIM->get_param(pname, SIM->get_param(BXPN_USB_OHCI)));
|
||||
} else {
|
||||
usb_set_connect_status(i, 0);
|
||||
set_connect_status(i, 0);
|
||||
}
|
||||
BX_OHCI_THIS hub.device_change &= ~(1 << i);
|
||||
}
|
||||
@ -1473,7 +1476,7 @@ void bx_usb_ohci_c::pci_write_handler(Bit8u address, Bit32u value, unsigned io_l
|
||||
}
|
||||
}
|
||||
|
||||
bool bx_usb_ohci_c::usb_set_connect_status(Bit8u port, bool connected)
|
||||
bool bx_usb_ohci_c::set_connect_status(Bit8u port, bool connected)
|
||||
{
|
||||
const bool ccs_org = BX_OHCI_THIS hub.usb_port[port].HcRhPortStatus.ccs;
|
||||
const bool pes_org = BX_OHCI_THIS hub.usb_port[port].HcRhPortStatus.pes;
|
||||
@ -1544,6 +1547,42 @@ Bit64s bx_usb_ohci_c::usb_param_handler(bx_param_c *param, bool set, Bit64s val)
|
||||
return val;
|
||||
}
|
||||
|
||||
// USB runtime parameter handler: over-current
|
||||
Bit64s bx_usb_ohci_c::usb_param_oc_handler(bx_param_c *param, bool set, Bit64s val)
|
||||
{
|
||||
int portnum;
|
||||
|
||||
if (set && val) {
|
||||
if (BX_OHCI_THIS hub.op_regs.HcRhDescriptorA.nocp == 0) {
|
||||
portnum = atoi((param->get_parent())->get_name()+4) - 1;
|
||||
if ((portnum >= 0) && (portnum < USB_OHCI_PORTS)) {
|
||||
if (BX_OHCI_THIS hub.usb_port[portnum].HcRhPortStatus.ccs) {
|
||||
// is over current reported on a per-port basis?
|
||||
if (BX_OHCI_THIS hub.op_regs.HcRhDescriptorA.ocpm == 1) {
|
||||
BX_OHCI_THIS hub.usb_port[portnum].HcRhPortStatus.ocic = 1;
|
||||
BX_OHCI_THIS hub.usb_port[portnum].HcRhPortStatus.poci = 1;
|
||||
BX_OHCI_THIS hub.usb_port[portnum].HcRhPortStatus.pes = 0;
|
||||
BX_OHCI_THIS hub.usb_port[portnum].HcRhPortStatus.pesc = 1;
|
||||
BX_OHCI_THIS hub.usb_port[portnum].HcRhPortStatus.pps = 0;
|
||||
BX_DEBUG(("Over-current signaled on port #%d.", portnum + 1));
|
||||
// else over current is reported globally
|
||||
} else {
|
||||
BX_OHCI_THIS hub.op_regs.HcRhStatus.oci = 1;
|
||||
BX_DEBUG(("Global over-current signaled."));
|
||||
}
|
||||
set_interrupt(OHCI_INTR_RHSC);
|
||||
}
|
||||
} else {
|
||||
BX_ERROR(("Over-current: Bad portnum given: %d", portnum + 1));
|
||||
}
|
||||
} else {
|
||||
BX_DEBUG(("Over-current signaled with NOCP set."));
|
||||
}
|
||||
}
|
||||
|
||||
return 0; // clear the indicator for next time
|
||||
}
|
||||
|
||||
// USB runtime parameter enable handler
|
||||
bool bx_usb_ohci_c::usb_param_enable_handler(bx_param_c *param, bool en)
|
||||
{
|
||||
|
@ -275,7 +275,7 @@ private:
|
||||
static void init_device(Bit8u port, bx_list_c *portconf);
|
||||
static void remove_device(Bit8u port);
|
||||
static int broadcast_packet(USBPacket *p);
|
||||
static bool usb_set_connect_status(Bit8u port, bool connected);
|
||||
static bool set_connect_status(Bit8u port, bool connected);
|
||||
|
||||
static void usb_frame_handler(void *);
|
||||
void usb_frame_timer(void);
|
||||
@ -298,6 +298,7 @@ private:
|
||||
void runtime_config(void);
|
||||
|
||||
static Bit64s usb_param_handler(bx_param_c *param, bool set, Bit64s val);
|
||||
static Bit64s usb_param_oc_handler(bx_param_c *param, bool set, Bit64s val);
|
||||
static bool usb_param_enable_handler(bx_param_c *param, bool en);
|
||||
};
|
||||
|
||||
|
@ -401,7 +401,8 @@ int usb_msd_device_c::uasp_do_data(UASPRequest *req, USBPacket *p)
|
||||
req->usb_len = 0;
|
||||
}
|
||||
|
||||
usb_dump_packet(p->data, len, 0, p->devaddr, ((UASP_GET_DIR(req->mode) == USB_TOKEN_IN) ? USB_DIR_IN : USB_DIR_OUT) | p->devep, USB_TRANS_TYPE_BULK, false, true);
|
||||
// This fills the log.txt file extremely fast, so I comment it out.
|
||||
//usb_dump_packet(p->data, len, 0, p->devaddr, ((UASP_GET_DIR(req->mode) == USB_TOKEN_IN) ? USB_DIR_IN : USB_DIR_OUT) | p->devep, USB_TRANS_TYPE_BULK, false, true);
|
||||
|
||||
return len;
|
||||
}
|
||||
|
@ -102,26 +102,30 @@ PLUGIN_ENTRY_FOR_MODULE(usb_uhci)
|
||||
bx_usb_uhci_c::bx_usb_uhci_c()
|
||||
{
|
||||
put("usb_uhci", "UHCI");
|
||||
device_change = 0;
|
||||
rt_conf_id = -1;
|
||||
}
|
||||
|
||||
bx_usb_uhci_c::~bx_usb_uhci_c()
|
||||
{
|
||||
char pname[16];
|
||||
char pname[32];
|
||||
|
||||
SIM->unregister_runtime_config_handler(rt_conf_id);
|
||||
|
||||
|
||||
for (int i=0; i<USB_UHCI_PORTS; i++) {
|
||||
sprintf(pname, "port%d.device", i+1);
|
||||
SIM->get_param_enum(pname, SIM->get_param(BXPN_USB_UHCI))->set_handler(NULL);
|
||||
sprintf(pname, "port%d.options", i+1);
|
||||
SIM->get_param_string(pname, SIM->get_param(BXPN_USB_UHCI))->set_enable_handler(NULL);
|
||||
sprintf(pname, "port%d.over_current", i+1);
|
||||
SIM->get_param_bool(pname, SIM->get_param(BXPN_USB_UHCI))->set_handler(NULL);
|
||||
remove_device(i);
|
||||
}
|
||||
|
||||
|
||||
SIM->get_bochs_root()->remove("usb_uhci");
|
||||
bx_list_c *usb_rt = (bx_list_c *) SIM->get_param(BXPN_MENU_RUNTIME_USB);
|
||||
usb_rt->remove("uhci");
|
||||
|
||||
BX_DEBUG(("Exit"));
|
||||
}
|
||||
|
||||
@ -132,6 +136,7 @@ void bx_usb_uhci_c::init(void)
|
||||
bx_list_c *uhci, *port;
|
||||
bx_param_enum_c *device;
|
||||
bx_param_string_c *options;
|
||||
bx_param_bool_c *over_current;
|
||||
Bit8u devfunc;
|
||||
Bit16u devid;
|
||||
|
||||
@ -174,6 +179,8 @@ void bx_usb_uhci_c::init(void)
|
||||
device->set_handler(usb_param_handler);
|
||||
options = (bx_param_string_c *) port->get_by_name("options");
|
||||
options->set_enable_handler(usb_param_enable_handler);
|
||||
over_current = (bx_param_bool_c *) port->get_by_name("over_current");
|
||||
over_current->set_handler(usb_param_oc_handler);
|
||||
}
|
||||
|
||||
// register handler for correct device connect handling after runtime config
|
||||
@ -220,6 +227,7 @@ void bx_usb_uhci_c::init_device(Bit8u port, bx_list_c *portconf)
|
||||
} else {
|
||||
((bx_param_enum_c *) portconf->get_by_name("device"))->set_by_name("none");
|
||||
((bx_param_string_c *) portconf->get_by_name("options"))->set("none");
|
||||
((bx_param_bool_c *) portconf->get_by_name("over_current"))->set(0);
|
||||
set_connect_status(port, 0);
|
||||
}
|
||||
}
|
||||
@ -287,6 +295,31 @@ Bit64s bx_usb_uhci_c::usb_param_handler(bx_param_c *param, bool set, Bit64s val)
|
||||
return val;
|
||||
}
|
||||
|
||||
// USB runtime parameter handler: over-current
|
||||
Bit64s bx_usb_uhci_c::usb_param_oc_handler(bx_param_c *param, bool set, Bit64s val)
|
||||
{
|
||||
int portnum;
|
||||
|
||||
if (set && val) {
|
||||
portnum = atoi((param->get_parent())->get_name()+4) - 1;
|
||||
if ((portnum >= 0) && (portnum < USB_UHCI_PORTS)) {
|
||||
if (BX_UHCI_THIS hub.usb_port[portnum].status) {
|
||||
// The UHCI specification does not specify what happens when an over-current
|
||||
// condition exists. Therefore, we will set the condition and then envoke
|
||||
// an interrupt. Hopefully the guest will check the port change.
|
||||
BX_UHCI_THIS hub.usb_port[portnum].over_current_change = 1;
|
||||
BX_UHCI_THIS hub.usb_port[portnum].over_current = 1;
|
||||
BX_DEBUG(("Over-current signaled on port #%d.", portnum + 1));
|
||||
BX_UHCI_THIS update_irq();
|
||||
}
|
||||
} else {
|
||||
BX_ERROR(("Over-current: Bad portnum given: %d", portnum + 1));
|
||||
}
|
||||
}
|
||||
|
||||
return 0; // clear the indicator for next time
|
||||
}
|
||||
|
||||
// USB runtime parameter enable handler
|
||||
bool bx_usb_uhci_c::usb_param_enable_handler(bx_param_c *param, bool en)
|
||||
{
|
||||
|
@ -50,6 +50,7 @@ private:
|
||||
void runtime_config(void);
|
||||
|
||||
static Bit64s usb_param_handler(bx_param_c *param, bool set, Bit64s val);
|
||||
static Bit64s usb_param_oc_handler(bx_param_c *param, bool set, Bit64s val);
|
||||
static bool usb_param_enable_handler(bx_param_c *param, bool en);
|
||||
};
|
||||
|
||||
|
@ -148,8 +148,6 @@ static Bit8u ext_caps[EXT_CAPS_SIZE] = {
|
||||
// builtin configuration handling functions
|
||||
Bit32s usb_xhci_options_parser(const char *context, int num_params, char *params[])
|
||||
{
|
||||
int max_ports;
|
||||
|
||||
if (!strcmp(params[0], "usb_xhci")) {
|
||||
bx_list_c *base = (bx_list_c*) SIM->get_param(BXPN_USB_XHCI);
|
||||
for (int i = 1; i < num_params; i++) {
|
||||
@ -163,7 +161,7 @@ Bit32s usb_xhci_options_parser(const char *context, int num_params, char *params
|
||||
else
|
||||
BX_PANIC(("%s: unknown parameter '%s' for usb_xhci: model=", context, ¶ms[i][6]));
|
||||
} else if (!strncmp(params[i], "n_ports=", 8)) {
|
||||
max_ports = (int) strtol(¶ms[i][8], NULL, 10);
|
||||
int max_ports = (int) strtol(¶ms[i][8], NULL, 10);
|
||||
if ((max_ports >= 2) && (max_ports <= USB_XHCI_PORTS_MAX) && !(max_ports & 1))
|
||||
SIM->get_param_num(BXPN_XHCI_N_PORTS)->set(max_ports);
|
||||
else
|
||||
@ -225,7 +223,7 @@ bx_usb_xhci_c::bx_usb_xhci_c()
|
||||
|
||||
bx_usb_xhci_c::~bx_usb_xhci_c()
|
||||
{
|
||||
char pname[16];
|
||||
char pname[32];
|
||||
|
||||
SIM->unregister_runtime_config_handler(rt_conf_id);
|
||||
|
||||
@ -234,6 +232,8 @@ bx_usb_xhci_c::~bx_usb_xhci_c()
|
||||
SIM->get_param_enum(pname, SIM->get_param(BXPN_USB_XHCI))->set_handler(NULL);
|
||||
sprintf(pname, "port%d.options", i+1);
|
||||
SIM->get_param_string(pname, SIM->get_param(BXPN_USB_XHCI))->set_enable_handler(NULL);
|
||||
sprintf(pname, "port%d.over_current", i+1);
|
||||
SIM->get_param_bool(pname, SIM->get_param(BXPN_USB_XHCI))->set_handler(NULL);
|
||||
remove_device(i);
|
||||
}
|
||||
|
||||
@ -251,6 +251,7 @@ void bx_usb_xhci_c::init(void)
|
||||
bx_list_c *xhci, *port;
|
||||
bx_param_enum_c *device;
|
||||
bx_param_string_c *options;
|
||||
bx_param_bool_c *over_current;
|
||||
struct XHCI_PROTOCOL *protocol;
|
||||
|
||||
/* If you wish to set DEBUG=report in the code, instead of
|
||||
@ -303,7 +304,7 @@ void bx_usb_xhci_c::init(void)
|
||||
Bit32s n_ports = SIM->get_param_num(BXPN_XHCI_N_PORTS)->get();
|
||||
if (n_ports > -1) BX_XHCI_THIS hub.n_ports = n_ports;
|
||||
if ((BX_XHCI_THIS hub.n_ports < 2) || (BX_XHCI_THIS hub.n_ports > USB_XHCI_PORTS_MAX) || (BX_XHCI_THIS hub.n_ports & 1)) {
|
||||
BX_PANIC(("n_ports (%d) must be at least 2, not more than 10, and must be an even number.", BX_XHCI_THIS hub.n_ports));
|
||||
BX_PANIC(("n_ports (%d) must be at least 2, not more than %d, and must be an even number.", BX_XHCI_THIS hub.n_ports, USB_XHCI_PORTS_MAX));
|
||||
return;
|
||||
}
|
||||
|
||||
@ -342,6 +343,8 @@ void bx_usb_xhci_c::init(void)
|
||||
device->set_handler(usb_param_handler);
|
||||
options = (bx_param_string_c*)port->get_by_name("options");
|
||||
options->set_enable_handler(usb_param_enable_handler);
|
||||
over_current = (bx_param_bool_c*)port->get_by_name("over_current");
|
||||
over_current->set_handler(usb_param_oc_handler);
|
||||
BX_XHCI_THIS hub.usb_port[i].device = NULL;
|
||||
BX_XHCI_THIS hub.usb_port[i].portsc.ccs = 0;
|
||||
BX_XHCI_THIS hub.usb_port[i].portsc.csc = 0;
|
||||
@ -648,7 +651,7 @@ void bx_usb_xhci_c::reset_hc()
|
||||
sprintf(pname, "port%d", i+1);
|
||||
init_device(i, (bx_list_c *) SIM->get_param(pname, SIM->get_param(BXPN_USB_XHCI)));
|
||||
} else {
|
||||
usb_set_connect_status(i, 1);
|
||||
set_connect_status(i, 1);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1091,7 +1094,7 @@ void bx_usb_xhci_c::init_device(Bit8u port, bx_list_c *portconf)
|
||||
char pname[BX_PATHNAME_LEN];
|
||||
|
||||
if (DEV_usb_init_device(portconf, BX_XHCI_THIS_PTR, &BX_XHCI_THIS hub.usb_port[port].device)) {
|
||||
if (usb_set_connect_status(port, 1)) {
|
||||
if (set_connect_status(port, 1)) {
|
||||
portconf->get_by_name("options")->set_enabled(0);
|
||||
sprintf(pname, "usb_xhci.hub.port%d.device", port+1);
|
||||
bx_list_c *sr_list = (bx_list_c *) SIM->get_param(pname, SIM->get_bochs_root());
|
||||
@ -1099,7 +1102,8 @@ void bx_usb_xhci_c::init_device(Bit8u port, bx_list_c *portconf)
|
||||
} else {
|
||||
((bx_param_enum_c*)portconf->get_by_name("device"))->set_by_name("none");
|
||||
((bx_param_string_c*)portconf->get_by_name("options"))->set("none");
|
||||
usb_set_connect_status(port, 0);
|
||||
((bx_param_bool_c*)portconf->get_by_name("over_current"))->set(0);
|
||||
set_connect_status(port, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1611,7 +1615,6 @@ bool bx_usb_xhci_c::write_handler(bx_phy_address addr, unsigned len, void *data,
|
||||
BX_XHCI_THIS hub.op_regs.HcStatus.pcd = (value & (1 << 4)) ? 0 : BX_XHCI_THIS hub.op_regs.HcStatus.pcd;
|
||||
BX_XHCI_THIS hub.op_regs.HcStatus.eint = (value & (1 << 3)) ? 0 : BX_XHCI_THIS hub.op_regs.HcStatus.eint;
|
||||
BX_XHCI_THIS hub.op_regs.HcStatus.hse = (value & (1 << 2)) ? 0 : BX_XHCI_THIS hub.op_regs.HcStatus.hse;
|
||||
//FIXME: should this line go where system software clears the IP bit, or here when it clears the status:eint bit?
|
||||
if (value & (1 << 3)) // acknowledging the interrupt
|
||||
DEV_pci_set_irq(BX_XHCI_THIS devfunc, BX_XHCI_THIS pci_conf[0x3d], 0);
|
||||
break;
|
||||
@ -3487,6 +3490,12 @@ void bx_usb_xhci_c::xhci_timer(void)
|
||||
*/
|
||||
for (port=0; port<BX_XHCI_THIS hub.n_ports; port++) {
|
||||
new_psceg = get_psceg(port);
|
||||
// if any bit has transitioned from 0 to 1 (in any port),
|
||||
// set the pcd bit in the host status register.
|
||||
if ((new_psceg & BX_XHCI_THIS hub.usb_port[port].psceg) > 0)
|
||||
BX_XHCI_THIS hub.op_regs.HcStatus.pcd = 1;
|
||||
// clear any bits that have been cleared by the guest,
|
||||
// if we are now zero *and* there are any new bits set, send a Change Event.
|
||||
BX_XHCI_THIS hub.usb_port[port].psceg &= new_psceg;
|
||||
if ((BX_XHCI_THIS hub.usb_port[port].psceg == 0) && (new_psceg != 0)) {
|
||||
BX_DEBUG(("Port #%d Status Change Event: (%2Xh)", port + 1, new_psceg));
|
||||
@ -3536,7 +3545,7 @@ void bx_usb_xhci_c::runtime_config(void)
|
||||
sprintf(pname, "port%d", i + 1);
|
||||
init_device(i, (bx_list_c *) SIM->get_param(pname, SIM->get_param(BXPN_USB_XHCI)));
|
||||
} else {
|
||||
usb_set_connect_status(i, 0);
|
||||
set_connect_status(i, 0);
|
||||
}
|
||||
BX_XHCI_THIS device_change &= ~(1 << i);
|
||||
}
|
||||
@ -3585,7 +3594,7 @@ void bx_usb_xhci_c::pci_write_handler(Bit8u address, Bit32u value, unsigned io_l
|
||||
}
|
||||
}
|
||||
|
||||
bool bx_usb_xhci_c::usb_set_connect_status(Bit8u port, bool connected)
|
||||
bool bx_usb_xhci_c::set_connect_status(Bit8u port, bool connected)
|
||||
{
|
||||
const bool ccs_org = BX_XHCI_THIS hub.usb_port[port].portsc.ccs;
|
||||
const bool ped_org = BX_XHCI_THIS hub.usb_port[port].portsc.ped;
|
||||
@ -3683,6 +3692,28 @@ Bit64s bx_usb_xhci_c::usb_param_handler(bx_param_c *param, bool set, Bit64s val)
|
||||
return val;
|
||||
}
|
||||
|
||||
// USB runtime parameter handler: over-current
|
||||
Bit64s bx_usb_xhci_c::usb_param_oc_handler(bx_param_c *param, bool set, Bit64s val)
|
||||
{
|
||||
int portnum;
|
||||
|
||||
if (set) {
|
||||
portnum = atoi((param->get_parent())->get_name()+4) - 1;
|
||||
if ((portnum >= 0) && (portnum < (int) BX_XHCI_THIS hub.n_ports)) {
|
||||
if (val) {
|
||||
if (BX_XHCI_THIS hub.usb_port[portnum].portsc.ccs) {
|
||||
BX_XHCI_THIS hub.usb_port[portnum].portsc.occ = 1;
|
||||
BX_XHCI_THIS hub.usb_port[portnum].portsc.oca = 1;
|
||||
BX_DEBUG(("Over-current signaled on port #%d.", portnum + 1));
|
||||
write_event_TRB(0, ((portnum + 1) << 24), TRB_SET_COMP_CODE(1), TRB_SET_TYPE(PORT_STATUS_CHANGE), 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0; // clear the indicator for next time
|
||||
}
|
||||
|
||||
// USB runtime parameter enable handler
|
||||
bool bx_usb_xhci_c::usb_param_enable_handler(bx_param_c *param, bool en)
|
||||
{
|
||||
|
@ -620,7 +620,7 @@ private:
|
||||
|
||||
static void init_device(Bit8u port, bx_list_c *portconf);
|
||||
static void remove_device(Bit8u port);
|
||||
static bool usb_set_connect_status(Bit8u port, bool connected);
|
||||
static bool set_connect_status(Bit8u port, bool connected);
|
||||
|
||||
static int broadcast_speed(const int slot);
|
||||
static int broadcast_packet(USBPacket *p, const int port);
|
||||
@ -668,6 +668,7 @@ private:
|
||||
void runtime_config(void);
|
||||
|
||||
static Bit64s usb_param_handler(bx_param_c *param, bool set, Bit64s val);
|
||||
static Bit64s usb_param_oc_handler(bx_param_c *param, bool set, Bit64s val);
|
||||
static bool usb_param_enable_handler(bx_param_c *param, bool en);
|
||||
};
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user