Merge pull request #39 from fysnet/master

Add over-current signaling
This commit is contained in:
Stanislav Shwartsman 2023-03-23 07:22:46 +02:00 committed by GitHub
commit 8eee519f4e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 11374 additions and 10942 deletions

View File

@ -267,9 +267,14 @@ void bx_init_usb_options(const char *usb_name, const char *pname, int maxports)
"Options",
descr,
"", BX_PATHNAME_LEN);
bx_param_bool_c *overcurrent = new bx_param_bool_c(port,
"over_current",
"signal over-current",
"signal over-current", 0);
port->set_group(group);
deplist->add(port);
deplist->add(device);
deplist->add(overcurrent);
deplist2 = new bx_list_c(NULL);
deplist2->add(options);
device->set_dependent_list(deplist2, 1);

File diff suppressed because it is too large Load Diff

View File

@ -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;

View File

@ -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;

View File

@ -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)
{

View File

@ -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);
};

View File

@ -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) {

View File

@ -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

View File

@ -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)
{

View File

@ -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);
};

View File

@ -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;
}

View File

@ -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)
{

View File

@ -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);
};

View File

@ -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, &params[i][6]));
} else if (!strncmp(params[i], "n_ports=", 8)) {
max_ports = (int) strtol(&params[i][8], NULL, 10);
int max_ports = (int) strtol(&params[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)
{

View File

@ -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);
};