Some fixes and cleanups in the USB code.

- USB hub: disable device "options" parameter if device is set to "none".
- USB hub: handle device disconnect in runtime_config().
- Removed handling of USB device type in host controllers and external hub.
This commit is contained in:
Volker Ruppert 2021-02-16 17:04:04 +00:00
parent 368c83127e
commit 16d79cbf0b
14 changed files with 305 additions and 327 deletions

View File

@ -159,7 +159,7 @@ void bx_uhci_core_c::reset_uhci(unsigned type)
hub.usb_port[j].able_changed = 0;
hub.usb_port[j].status = 0;
if (hub.usb_port[j].device != NULL) {
set_connect_status(j, hub.usb_port[j].device->get_type(), 1);
set_connect_status(j, 1);
}
}
while (packets != NULL) {
@ -541,7 +541,7 @@ void bx_uhci_core_c::write(Bit32u address, Bit32u value, unsigned io_len)
if (hub.usb_port[port].device != NULL) {
hub.usb_port[port].low_speed =
(hub.usb_port[port].device->get_speed() == USB_SPEED_LOW);
set_connect_status(port, hub.usb_port[port].device->get_type(), 1);
set_connect_status(port, 1);
hub.usb_port[port].device->usb_send_msg(USB_MSG_RESET);
}
}
@ -935,72 +935,71 @@ const char *usb_speed[4] = {
"super"
};
void bx_uhci_core_c::set_connect_status(Bit8u port, int type, bool connected)
bool bx_uhci_core_c::set_connect_status(Bit8u port, bool connected)
{
usb_device_c *device = hub.usb_port[port].device;
if (device != NULL) {
if (device->get_type() == type) {
if (connected) {
BX_DEBUG(("port #%d: speed = %s", port+1, usb_speed[device->get_speed()]));
switch (device->get_speed()) {
case USB_SPEED_LOW:
hub.usb_port[port].low_speed = 1;
break;
case USB_SPEED_FULL:
hub.usb_port[port].low_speed = 0;
break;
case USB_SPEED_HIGH:
case USB_SPEED_SUPER:
BX_ERROR(("HC ignores device with unsupported speed"));
return;
default:
BX_PANIC(("USB device returned invalid speed value"));
set_connect_status(port, type, 0);
return;
}
if (hub.usb_port[port].low_speed) {
hub.usb_port[port].line_dminus = 1; // dminus=1 & dplus=0 = low speed (at idle time)
hub.usb_port[port].line_dplus = 0; // dminus=0 & dplus=1 = high speed (at idle time)
} else {
hub.usb_port[port].line_dminus = 0;
hub.usb_port[port].line_dplus = 1;
}
hub.usb_port[port].status = 1;
hub.usb_port[port].connect_changed = 1;
// if in suspend state, signal resume
if (hub.usb_command.suspend) {
hub.usb_port[port].resume = 1;
hub.usb_status.resume = 1;
if (hub.usb_enable.resume) {
hub.usb_status.interrupt = 1;
}
update_irq();
}
if (!device->get_connected()) {
if (!device->init()) {
set_connect_status(port, type, 0);
BX_ERROR(("port #%d: connect failed", port+1));
return;
} else {
BX_INFO(("port #%d: connect: %s", port+1, device->get_info()));
}
}
device->set_event_handler(this, uhci_event_handler, port);
} else {
hub.usb_port[port].status = 0;
hub.usb_port[port].connect_changed = 1;
if (hub.usb_port[port].enabled) {
hub.usb_port[port].able_changed = 1;
hub.usb_port[port].enabled = 0;
}
hub.usb_port[port].low_speed = 0;
hub.usb_port[port].line_dminus = 0;
hub.usb_port[port].line_dplus = 0;
if (connected) {
BX_DEBUG(("port #%d: speed = %s", port+1, usb_speed[device->get_speed()]));
switch (device->get_speed()) {
case USB_SPEED_LOW:
hub.usb_port[port].low_speed = 1;
break;
case USB_SPEED_FULL:
hub.usb_port[port].low_speed = 0;
break;
case USB_SPEED_HIGH:
case USB_SPEED_SUPER:
BX_ERROR(("HC ignores device with unsupported speed"));
return 0;
default:
BX_PANIC(("USB device returned invalid speed value"));
set_connect_status(port, 0);
return 0;
}
if (hub.usb_port[port].low_speed) {
hub.usb_port[port].line_dminus = 1; // dminus=1 & dplus=0 = low speed (at idle time)
hub.usb_port[port].line_dplus = 0; // dminus=0 & dplus=1 = high speed (at idle time)
} else {
hub.usb_port[port].line_dminus = 0;
hub.usb_port[port].line_dplus = 1;
}
hub.usb_port[port].status = 1;
hub.usb_port[port].connect_changed = 1;
// if in suspend state, signal resume
if (hub.usb_command.suspend) {
hub.usb_port[port].resume = 1;
hub.usb_status.resume = 1;
if (hub.usb_enable.resume) {
hub.usb_status.interrupt = 1;
}
update_irq();
}
if (!device->get_connected()) {
if (!device->init()) {
set_connect_status(port, 0);
BX_ERROR(("port #%d: connect failed", port+1));
return 0;
} else {
BX_INFO(("port #%d: connect: %s", port+1, device->get_info()));
}
}
device->set_event_handler(this, uhci_event_handler, port);
} else {
hub.usb_port[port].status = 0;
hub.usb_port[port].connect_changed = 1;
if (hub.usb_port[port].enabled) {
hub.usb_port[port].able_changed = 1;
hub.usb_port[port].enabled = 0;
}
hub.usb_port[port].low_speed = 0;
hub.usb_port[port].line_dminus = 0;
hub.usb_port[port].line_dplus = 0;
}
}
return connected;
}
void bx_uhci_core_c::set_port_device(int port, usb_device_c *dev)
@ -1008,9 +1007,9 @@ void bx_uhci_core_c::set_port_device(int port, usb_device_c *dev)
usb_device_c *olddev = hub.usb_port[port].device;
if ((dev != NULL) && (olddev == NULL)) {
hub.usb_port[port].device = dev;
set_connect_status(port, dev->get_type(), 1);
set_connect_status(port, 1);
} else if ((dev == NULL) && (olddev != NULL)) {
set_connect_status(port, olddev->get_type(), 0);
set_connect_status(port, 0);
hub.usb_port[port].device = dev;
}
}

View File

@ -193,7 +193,7 @@ protected:
void update_irq(void);
int broadcast_packet(USBPacket *p);
void set_connect_status(Bit8u port, int type, bool connected);
bool set_connect_status(Bit8u port, bool connected);
static void uhci_timer_handler(void *);
void uhci_timer(void);

View File

@ -108,7 +108,7 @@ void bx_usbdev_ctl_c::list_devices(void)
}
}
int bx_usbdev_ctl_c::init_device(bx_list_c *portconf, logfunctions *hub, void **dev)
bool bx_usbdev_ctl_c::init_device(bx_list_c *portconf, logfunctions *hub, void **dev)
{
usbmod_type modtype = USB_MOD_TYPE_NONE;
usbdev_type devtype = USB_DEV_TYPE_NONE;
@ -174,7 +174,7 @@ int bx_usbdev_ctl_c::init_device(bx_list_c *portconf, logfunctions *hub, void **
if (*device != NULL) {
parse_port_options(*device, portconf);
}
return devtype;
return (*device != NULL);
}
void bx_usbdev_ctl_c::parse_port_options(usb_device_c *device, bx_list_c *portconf)

View File

@ -176,7 +176,7 @@ public:
void exit(void);
const char **get_device_names(void);
void list_devices(void);
virtual int init_device(bx_list_c *portconf, logfunctions *hub, void **dev);
virtual bool init_device(bx_list_c *portconf, logfunctions *hub, void **dev);
private:
void parse_port_options(usb_device_c *dev, bx_list_c *portconf);
};

View File

@ -468,7 +468,7 @@ void bx_usb_ehci_c::reset_hc()
sprintf(pname, "port%d", i+1);
init_device(i, (bx_list_c*)SIM->get_param(pname, SIM->get_param(BXPN_USB_EHCI)));
} else {
set_connect_status(i, BX_EHCI_THIS hub.usb_port[i].device->get_type(), 1);
set_connect_status(i, 1);
}
}
@ -506,7 +506,6 @@ void bx_usb_ehci_c::reset_port(int p)
void bx_usb_ehci_c::init_device(Bit8u port, bx_list_c *portconf)
{
int type;
char pname[BX_PATHNAME_LEN];
const char *devname = NULL;
@ -518,12 +517,12 @@ void bx_usb_ehci_c::init_device(Bit8u port, bx_list_c *portconf)
BX_ERROR(("init_device(): port%d already in use", port+1));
return;
}
sprintf(pname, "usb_ehci.hub.port%d.device", port+1);
bx_list_c *sr_list = (bx_list_c*)SIM->get_param(pname, SIM->get_bochs_root());
type = DEV_usb_init_device(portconf, BX_EHCI_THIS_PTR, &BX_EHCI_THIS hub.usb_port[port].device);
if (BX_EHCI_THIS hub.usb_port[port].device != NULL) {
set_connect_status(port, type, 1);
BX_EHCI_THIS hub.usb_port[port].device->register_state(sr_list);
if (DEV_usb_init_device(portconf, BX_EHCI_THIS_PTR, &BX_EHCI_THIS hub.usb_port[port].device)) {
if (set_connect_status(port, 1)) {
sprintf(pname, "usb_ehci.hub.port%d.device", port+1);
bx_list_c *sr_list = (bx_list_c*)SIM->get_param(pname, SIM->get_bochs_root());
BX_EHCI_THIS hub.usb_port[port].device->register_state(sr_list);
}
}
}
@ -535,75 +534,73 @@ void bx_usb_ehci_c::remove_device(Bit8u port)
}
}
void bx_usb_ehci_c::set_connect_status(Bit8u port, int type, bool connected)
bool bx_usb_ehci_c::set_connect_status(Bit8u port, bool connected)
{
const bool ccs_org = BX_EHCI_THIS hub.usb_port[port].portsc.ccs;
const bool ped_org = BX_EHCI_THIS hub.usb_port[port].portsc.ped;
usb_device_c *device = BX_EHCI_THIS hub.usb_port[port].device;
if (device != NULL) {
if (device->get_type() == type) {
if (connected) {
if (BX_EHCI_THIS hub.usb_port[port].portsc.po) {
BX_EHCI_THIS uhci[port >> 1]->set_port_device(port & 1, device);
return;
if (connected) {
if (BX_EHCI_THIS hub.usb_port[port].portsc.po) {
BX_EHCI_THIS uhci[port >> 1]->set_port_device(port & 1, device);
return 1;
}
if (device->get_speed() == USB_SPEED_SUPER) {
BX_PANIC(("Super-speed device not supported on USB2 port."));
set_connect_status(port, 0);
return 0;
}
switch (device->get_speed()) {
case USB_SPEED_LOW:
BX_INFO(("Low speed device connected to port #%d", port+1));
BX_EHCI_THIS hub.usb_port[port].portsc.ls = 0x1;
BX_EHCI_THIS hub.usb_port[port].portsc.ped = 0;
break;
case USB_SPEED_FULL:
BX_INFO(("Full speed device connected to port #%d", port+1));
BX_EHCI_THIS hub.usb_port[port].portsc.ls = 0x2;
BX_EHCI_THIS hub.usb_port[port].portsc.ped = 0;
break;
case USB_SPEED_HIGH:
BX_INFO(("High speed device connected to port #%d", port+1));
BX_EHCI_THIS hub.usb_port[port].portsc.ls = 0x0;
BX_EHCI_THIS hub.usb_port[port].portsc.ped = 1;
break;
default:
BX_ERROR(("device->get_speed() returned invalid speed value"));
}
BX_EHCI_THIS hub.usb_port[port].portsc.ccs = 1;
if (!device->get_connected()) {
if (!device->init()) {
set_connect_status(port, 0);
BX_ERROR(("port #%d: connect failed", port+1));
return 0;
} else {
BX_INFO(("port #%d: connect: %s", port+1, device->get_info()));
}
if (device->get_speed() == USB_SPEED_SUPER) {
BX_PANIC(("Super-speed device not supported on USB2 port."));
set_connect_status(port, type, 0);
return;
}
switch (device->get_speed()) {
case USB_SPEED_LOW:
BX_INFO(("Low speed device connected to port #%d", port+1));
BX_EHCI_THIS hub.usb_port[port].portsc.ls = 0x1;
BX_EHCI_THIS hub.usb_port[port].portsc.ped = 0;
break;
case USB_SPEED_FULL:
BX_INFO(("Full speed device connected to port #%d", port+1));
BX_EHCI_THIS hub.usb_port[port].portsc.ls = 0x2;
BX_EHCI_THIS hub.usb_port[port].portsc.ped = 0;
break;
case USB_SPEED_HIGH:
BX_INFO(("High speed device connected to port #%d", port+1));
BX_EHCI_THIS hub.usb_port[port].portsc.ls = 0x0;
BX_EHCI_THIS hub.usb_port[port].portsc.ped = 1;
break;
default:
BX_ERROR(("device->get_speed() returned invalid speed value"));
}
BX_EHCI_THIS hub.usb_port[port].portsc.ccs = 1;
if (!device->get_connected()) {
if (!device->init()) {
set_connect_status(port, type, 0);
BX_ERROR(("port #%d: connect failed", port+1));
return;
} else {
BX_INFO(("port #%d: connect: %s", port+1, device->get_info()));
}
}
device->set_event_handler(BX_EHCI_THIS_PTR, ehci_event_handler, port);
} else { // not connected
if (BX_EHCI_THIS hub.usb_port[port].portsc.po) {
}
device->set_event_handler(BX_EHCI_THIS_PTR, ehci_event_handler, port);
} else { // not connected
if (BX_EHCI_THIS hub.usb_port[port].portsc.po) {
BX_EHCI_THIS uhci[port >> 1]->set_port_device(port & 1, NULL);
if ((!BX_EHCI_THIS hub.usb_port[port].owner_change) &&
(BX_EHCI_THIS hub.op_regs.ConfigFlag & 1)) {
BX_EHCI_THIS hub.usb_port[port].portsc.po = 0;
BX_EHCI_THIS hub.usb_port[port].portsc.csc = 1;
}
} else {
} else {
BX_EHCI_THIS hub.usb_port[port].portsc.ccs = 0;
BX_EHCI_THIS hub.usb_port[port].portsc.ped = 0;
BX_EHCI_THIS queues_rip_device(device, 0);
BX_EHCI_THIS queues_rip_device(device, 1);
device->set_async_mode(0);
}
if (!BX_EHCI_THIS hub.usb_port[port].owner_change) {
remove_device(port);
}
if (BX_EHCI_THIS hub.usb_port[port].portsc.po)
return;
}
if (!BX_EHCI_THIS hub.usb_port[port].owner_change) {
remove_device(port);
}
if (BX_EHCI_THIS hub.usb_port[port].portsc.po)
return 0;
}
if (ccs_org != BX_EHCI_THIS hub.usb_port[port].portsc.ccs)
BX_EHCI_THIS hub.usb_port[port].portsc.csc = 1;
@ -613,6 +610,7 @@ void bx_usb_ehci_c::set_connect_status(Bit8u port, int type, bool connected)
BX_EHCI_THIS hub.op_regs.UsbSts.inti |= USBSTS_PCD;
BX_EHCI_THIS update_irq();
}
return connected;
}
void bx_usb_ehci_c::change_port_owner(int port)
@ -627,11 +625,11 @@ void bx_usb_ehci_c::change_port_owner(int port)
BX_INFO(("port #%d: owner change to %s", port+1,
BX_EHCI_THIS hub.usb_port[port].portsc.po ? "EHCI":"UHCI"));
if (device != NULL) {
set_connect_status(port, device->get_type(), 0);
set_connect_status(port, 0);
}
BX_EHCI_THIS hub.usb_port[port].portsc.po ^= 1;
if (device != NULL) {
set_connect_status(port, device->get_type(), 1);
set_connect_status(port, 1);
}
}
BX_EHCI_THIS hub.usb_port[port].owner_change = 0;
@ -2220,7 +2218,6 @@ void bx_usb_ehci_c::runtime_config(void)
{
int i;
char pname[6];
int type = -1;
for (i = 0; i < USB_EHCI_PORTS; i++) {
// device change support
@ -2231,10 +2228,7 @@ void bx_usb_ehci_c::runtime_config(void)
init_device(i, (bx_list_c*)SIM->get_param(pname, SIM->get_param(BXPN_USB_EHCI)));
} else {
BX_INFO(("USB port #%d: device disconnect", i+1));
if (BX_EHCI_THIS hub.usb_port[i].device != NULL) {
type = BX_EHCI_THIS hub.usb_port[i].device->get_type();
}
set_connect_status(i, type, 0);
set_connect_status(i, 0);
}
BX_EHCI_THIS device_change &= ~(1 << i);
}

View File

@ -349,7 +349,7 @@ private:
static void init_device(Bit8u port, bx_list_c *portconf);
static void remove_device(Bit8u port);
static void set_connect_status(Bit8u port, int type, bool connected);
static bool set_connect_status(Bit8u port, bool connected);
static void change_port_owner(int port);
// EHCI core methods ported from QEMU 1.2.2

View File

@ -254,8 +254,9 @@ bool usb_hub_device_c::init()
int i;
char pname[10];
char label[32];
bx_list_c *port;
bx_list_c *port, *deplist;
bx_param_enum_c *device;
bx_param_string_c *options;
// set up config descriptor, status and runtime config for hub.n_ports
bx_hub_config_descriptor[22] = (hub.n_ports + 1 + 7) / 8;
@ -270,7 +271,11 @@ bool usb_hub_device_c::init()
port->set_options(port->SERIES_ASK | port->USE_BOX_TITLE);
device = new bx_param_enum_c(port, "device", "Device", "", usb_device_names, 0, 0);
device->set_handler(hub_param_handler);
new bx_param_string_c(port, "options", "Options", "", "", BX_PATHNAME_LEN);
options = new bx_param_string_c(port, "options", "Options", "", "", BX_PATHNAME_LEN);
deplist = new bx_list_c(NULL);
deplist->add(options);
device->set_dependent_list(deplist, 1);
device->set_dependent_bitmap(0, 0);
}
if (SIM->is_wx_selected()) {
bx_list_c *usb = (bx_list_c*)SIM->get_param("ports.usb");
@ -565,7 +570,6 @@ int usb_hub_device_c::handle_packet(USBPacket *p)
void usb_hub_device_c::init_device(Bit8u port, bx_list_c *portconf)
{
int type;
char pname[BX_PATHNAME_LEN];
const char *devname = NULL;
@ -577,12 +581,12 @@ void usb_hub_device_c::init_device(Bit8u port, bx_list_c *portconf)
BX_ERROR(("init_device(): port%d already in use", port+1));
return;
}
sprintf(pname, "port%d.device", port+1);
bx_list_c *sr_list = (bx_list_c*)SIM->get_param(pname, hub.state);
type = DEV_usb_init_device(portconf, this, &hub.usb_port[port].device);
if (hub.usb_port[port].device != NULL) {
usb_set_connect_status(port, type, 1);
hub.usb_port[port].device->register_state(sr_list);
if (DEV_usb_init_device(portconf, this, &hub.usb_port[port].device)) {
if (usb_set_connect_status(port, 1)) {
sprintf(pname, "port%d.device", port+1);
bx_list_c *sr_list = (bx_list_c*)SIM->get_param(pname, hub.state);
hub.usb_port[port].device->register_state(sr_list);
}
}
}
@ -613,61 +617,60 @@ void usb_hub_device_c::event_handler(int event, USBPacket *packet, int port)
}
}
void usb_hub_device_c::usb_set_connect_status(Bit8u port, int type, bool connected)
bool usb_hub_device_c::usb_set_connect_status(Bit8u port, bool connected)
{
usb_device_c *device = hub.usb_port[port].device;
if (device != NULL) {
if (device->get_type() == type) {
if (connected) {
switch (device->get_speed()) {
case USB_SPEED_LOW:
hub.usb_port[port].PortStatus |= PORT_STAT_LOW_SPEED;
break;
case USB_SPEED_FULL:
hub.usb_port[port].PortStatus &= ~PORT_STAT_LOW_SPEED;
break;
case USB_SPEED_HIGH:
case USB_SPEED_SUPER:
BX_PANIC(("Hub supports 'low' or 'full' speed devices only."));
usb_set_connect_status(port, type, 0);
return;
default:
BX_PANIC(("USB device returned invalid speed value"));
usb_set_connect_status(port, type, 0);
return;
}
hub.usb_port[port].PortStatus |= PORT_STAT_CONNECTION;
hub.usb_port[port].PortChange |= PORT_STAT_C_CONNECTION;
if (hub.usb_port[port].PortStatus & PORT_STAT_SUSPEND) {
hub.usb_port[port].PortChange |= PORT_STAT_C_SUSPEND;
}
if (d.event.dev != NULL) {
d.event.cb(USB_EVENT_WAKEUP, NULL, d.event.dev, d.event.port);
}
if (!device->get_connected()) {
if (!device->init()) {
usb_set_connect_status(port, type, 0);
BX_ERROR(("port #%d: connect failed", port+1));
return;
} else {
BX_INFO(("port #%d: connect: %s", port+1, device->get_info()));
}
}
device->set_event_handler(this, hub_event_handler, port);
} else {
if (d.event.dev != NULL) {
d.event.cb(USB_EVENT_WAKEUP, NULL, d.event.dev, d.event.port);
}
hub.usb_port[port].PortStatus &= ~PORT_STAT_CONNECTION;
hub.usb_port[port].PortChange |= PORT_STAT_C_CONNECTION;
if (hub.usb_port[port].PortStatus & PORT_STAT_ENABLE) {
hub.usb_port[port].PortStatus &= ~PORT_STAT_ENABLE;
hub.usb_port[port].PortChange |= PORT_STAT_C_ENABLE;
}
remove_device(port);
if (connected) {
switch (device->get_speed()) {
case USB_SPEED_LOW:
hub.usb_port[port].PortStatus |= PORT_STAT_LOW_SPEED;
break;
case USB_SPEED_FULL:
hub.usb_port[port].PortStatus &= ~PORT_STAT_LOW_SPEED;
break;
case USB_SPEED_HIGH:
case USB_SPEED_SUPER:
BX_PANIC(("Hub supports 'low' or 'full' speed devices only."));
usb_set_connect_status(port, 0);
return 0;
default:
BX_PANIC(("USB device returned invalid speed value"));
usb_set_connect_status(port, 0);
return 0;
}
hub.usb_port[port].PortStatus |= PORT_STAT_CONNECTION;
hub.usb_port[port].PortChange |= PORT_STAT_C_CONNECTION;
if (hub.usb_port[port].PortStatus & PORT_STAT_SUSPEND) {
hub.usb_port[port].PortChange |= PORT_STAT_C_SUSPEND;
}
if (d.event.dev != NULL) {
d.event.cb(USB_EVENT_WAKEUP, NULL, d.event.dev, d.event.port);
}
if (!device->get_connected()) {
if (!device->init()) {
usb_set_connect_status(port, 0);
BX_ERROR(("port #%d: connect failed", port+1));
return 0;
} else {
BX_INFO(("port #%d: connect: %s", port+1, device->get_info()));
}
}
device->set_event_handler(this, hub_event_handler, port);
} else {
if (d.event.dev != NULL) {
d.event.cb(USB_EVENT_WAKEUP, NULL, d.event.dev, d.event.port);
}
hub.usb_port[port].PortStatus &= ~PORT_STAT_CONNECTION;
hub.usb_port[port].PortChange |= PORT_STAT_C_CONNECTION;
if (hub.usb_port[port].PortStatus & PORT_STAT_ENABLE) {
hub.usb_port[port].PortStatus &= ~PORT_STAT_ENABLE;
hub.usb_port[port].PortChange |= PORT_STAT_C_ENABLE;
}
remove_device(port);
}
}
return connected;
}
void usb_hub_device_c::runtime_config()
@ -679,9 +682,14 @@ void usb_hub_device_c::runtime_config()
// device change support
if ((hub.device_change & (1 << i)) != 0) {
hubnum = atoi(hub.config->get_name()+6);
BX_INFO(("USB hub #%d, port #%d: device connect", hubnum, i+1));
sprintf(pname, "port%d", i + 1);
init_device(i, (bx_list_c*)SIM->get_param(pname, hub.config));
if ((hub.usb_port[i].PortStatus & PORT_STAT_CONNECTION) == 0) {
BX_INFO(("USB hub #%d, port #%d: device connect", hubnum, i+1));
sprintf(pname, "port%d", i + 1);
init_device(i, (bx_list_c*)SIM->get_param(pname, hub.config));
} else {
BX_INFO(("USB hub #%d, port #%d: device disconnect", hubnum, i+1));
usb_set_connect_status(i, 0);
}
hub.device_change &= ~(1 << i);
}
// forward to connected device
@ -697,8 +705,7 @@ void usb_hub_device_c::runtime_config()
// USB hub runtime parameter handler
Bit64s usb_hub_device_c::hub_param_handler(bx_param_c *param, int set, Bit64s val)
{
int type = -1;
int hubnum, portnum;
int portnum;
usb_hub_device_c *hub;
bx_list_c *port;
@ -706,16 +713,11 @@ Bit64s usb_hub_device_c::hub_param_handler(bx_param_c *param, int set, Bit64s va
port = (bx_list_c*)param->get_parent();
hub = (usb_hub_device_c*)(port->get_parent()->get_device_param());
if (hub != NULL) {
hubnum = atoi(port->get_parent()->get_name()+6);
portnum = atoi(port->get_name()+4) - 1;
bool empty = (val == 0);
if ((portnum >= 0) && (portnum < hub->hub.n_ports)) {
if (empty && (hub->hub.usb_port[portnum].PortStatus & PORT_STAT_CONNECTION)) {
BX_INFO(("USB hub #%d, port #%d: device disconnect", hubnum, portnum+1));
if (hub->hub.usb_port[portnum].device != NULL) {
type = hub->hub.usb_port[portnum].device->get_type();
}
hub->usb_set_connect_status(portnum, type, 0);
hub->hub.device_change |= (1 << portnum);
} else if (!empty && !(hub->hub.usb_port[portnum].PortStatus & PORT_STAT_CONNECTION)) {
hub->hub.device_change |= (1 << portnum);
} else {

View File

@ -73,7 +73,7 @@ private:
int broadcast_packet(USBPacket *p);
void init_device(Bit8u port, bx_list_c *portconf);
void remove_device(Bit8u port);
void usb_set_connect_status(Bit8u port, int type, bool connected);
bool usb_set_connect_status(Bit8u port, bool connected);
static Bit64s hub_param_handler(bx_param_c *param, int set, Bit64s val);
};

View File

@ -360,7 +360,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, BX_OHCI_THIS hub.usb_port[i].device->get_type(), 1);
usb_set_connect_status(i, 1);
}
}
@ -482,7 +482,6 @@ void bx_usb_ohci_c::after_restore_state(void)
void bx_usb_ohci_c::init_device(Bit8u port, bx_list_c *portconf)
{
int type;
char pname[BX_PATHNAME_LEN];
const char *devname = NULL;
@ -494,12 +493,12 @@ void bx_usb_ohci_c::init_device(Bit8u port, bx_list_c *portconf)
BX_ERROR(("init_device(): port%d already in use", port+1));
return;
}
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());
type = DEV_usb_init_device(portconf, BX_OHCI_THIS_PTR, &BX_OHCI_THIS hub.usb_port[port].device);
if (BX_OHCI_THIS hub.usb_port[port].device != NULL) {
usb_set_connect_status(port, type, 1);
BX_OHCI_THIS hub.usb_port[port].device->register_state(sr_list);
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)) {
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());
BX_OHCI_THIS hub.usb_port[port].device->register_state(sr_list);
}
}
}
@ -971,7 +970,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, BX_OHCI_THIS hub.usb_port[p].device->get_type(), 1);
usb_set_connect_status(p, 1);
BX_OHCI_THIS hub.usb_port[p].device->usb_send_msg(USB_MSG_RESET);
}
set_interrupt(OHCI_INTR_RHSC);
@ -1403,7 +1402,6 @@ void bx_usb_ohci_c::runtime_config(void)
{
int i;
char pname[6];
int type = -1;
for (i = 0; i < USB_OHCI_PORTS; i++) {
// device change support
@ -1414,10 +1412,7 @@ void bx_usb_ohci_c::runtime_config(void)
init_device(i, (bx_list_c*)SIM->get_param(pname, SIM->get_param(BXPN_USB_OHCI)));
} else {
BX_INFO(("USB port #%d: device disconnect", i+1));
if (BX_OHCI_THIS hub.usb_port[i].device != NULL) {
type = BX_OHCI_THIS hub.usb_port[i].device->get_type();
}
usb_set_connect_status(i, type, 0);
usb_set_connect_status(i, 0);
}
BX_OHCI_THIS hub.device_change &= ~(1 << i);
}
@ -1458,49 +1453,47 @@ void bx_usb_ohci_c::pci_write_handler(Bit8u address, Bit32u value, unsigned io_l
}
}
void bx_usb_ohci_c::usb_set_connect_status(Bit8u port, int type, bool connected)
bool bx_usb_ohci_c::usb_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;
usb_device_c *device = BX_OHCI_THIS hub.usb_port[port].device;
if (device != NULL) {
if (device->get_type() == type) {
if (connected) {
switch (device->get_speed()) {
case USB_SPEED_LOW:
BX_OHCI_THIS hub.usb_port[port].HcRhPortStatus.lsda = 1;
break;
case USB_SPEED_FULL:
BX_OHCI_THIS hub.usb_port[port].HcRhPortStatus.lsda = 0;
break;
case USB_SPEED_HIGH:
case USB_SPEED_SUPER:
BX_PANIC(("HC supports 'low' or 'full' speed devices only."));
usb_set_connect_status(port, type, 0);
return;
default:
BX_PANIC(("USB device returned invalid speed value"));
usb_set_connect_status(port, type, 0);
return;
}
BX_OHCI_THIS hub.usb_port[port].HcRhPortStatus.ccs = 1;
if (!device->get_connected()) {
if (!device->init()) {
usb_set_connect_status(port, type, 0);
BX_ERROR(("port #%d: connect failed", port+1));
return;
} else {
BX_INFO(("port #%d: connect: %s", port+1, device->get_info()));
}
}
device->set_event_handler(BX_OHCI_THIS_PTR, ohci_event_handler, port);
} else { // not connected
BX_OHCI_THIS hub.usb_port[port].HcRhPortStatus.ccs = 0;
BX_OHCI_THIS hub.usb_port[port].HcRhPortStatus.pes = 0;
BX_OHCI_THIS hub.usb_port[port].HcRhPortStatus.lsda = 0;
remove_device(port);
if (connected) {
switch (device->get_speed()) {
case USB_SPEED_LOW:
BX_OHCI_THIS hub.usb_port[port].HcRhPortStatus.lsda = 1;
break;
case USB_SPEED_FULL:
BX_OHCI_THIS hub.usb_port[port].HcRhPortStatus.lsda = 0;
break;
case USB_SPEED_HIGH:
case USB_SPEED_SUPER:
BX_PANIC(("HC supports 'low' or 'full' speed devices only."));
usb_set_connect_status(port, 0);
return 0;
default:
BX_PANIC(("USB device returned invalid speed value"));
usb_set_connect_status(port, 0);
return 0;
}
BX_OHCI_THIS hub.usb_port[port].HcRhPortStatus.ccs = 1;
if (!device->get_connected()) {
if (!device->init()) {
usb_set_connect_status(port, 0);
BX_ERROR(("port #%d: connect failed", port+1));
return 0;
} else {
BX_INFO(("port #%d: connect: %s", port+1, device->get_info()));
}
}
device->set_event_handler(BX_OHCI_THIS_PTR, ohci_event_handler, port);
} else { // not connected
BX_OHCI_THIS hub.usb_port[port].HcRhPortStatus.ccs = 0;
BX_OHCI_THIS hub.usb_port[port].HcRhPortStatus.pes = 0;
BX_OHCI_THIS hub.usb_port[port].HcRhPortStatus.lsda = 0;
remove_device(port);
}
BX_OHCI_THIS hub.usb_port[port].HcRhPortStatus.csc |= (ccs_org != BX_OHCI_THIS hub.usb_port[port].HcRhPortStatus.ccs);
BX_OHCI_THIS hub.usb_port[port].HcRhPortStatus.pesc |= (pes_org != BX_OHCI_THIS hub.usb_port[port].HcRhPortStatus.pes);
@ -1508,6 +1501,7 @@ void bx_usb_ohci_c::usb_set_connect_status(Bit8u port, int type, bool connected)
// we changed the value of the port, so show it
set_interrupt(OHCI_INTR_RHSC);
}
return connected;
}
// USB runtime parameter handler

View File

@ -277,7 +277,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 void usb_set_connect_status(Bit8u port, int type, bool connected);
static bool usb_set_connect_status(Bit8u port, bool connected);
static void usb_frame_handler(void *);
void usb_frame_timer(void);

View File

@ -196,7 +196,6 @@ void bx_usb_uhci_c::after_restore_state()
void bx_usb_uhci_c::init_device(Bit8u port, bx_list_c *portconf)
{
int type;
char pname[BX_PATHNAME_LEN];
const char *devname = NULL;
@ -208,12 +207,12 @@ void bx_usb_uhci_c::init_device(Bit8u port, bx_list_c *portconf)
BX_ERROR(("init_device(): port%d already in use", port+1));
return;
}
sprintf(pname, "usb_uhci.hub.port%d.device", port+1);
bx_list_c *sr_list = (bx_list_c*)SIM->get_param(pname, SIM->get_bochs_root());
type = DEV_usb_init_device(portconf, BX_UHCI_THIS_PTR, &BX_UHCI_THIS hub.usb_port[port].device);
if (BX_UHCI_THIS hub.usb_port[port].device != NULL) {
set_connect_status(port, type, 1);
BX_UHCI_THIS hub.usb_port[port].device->register_state(sr_list);
if (DEV_usb_init_device(portconf, BX_UHCI_THIS_PTR, &BX_UHCI_THIS hub.usb_port[port].device)) {
if (set_connect_status(port, 1)) {
sprintf(pname, "usb_uhci.hub.port%d.device", port+1);
bx_list_c *sr_list = (bx_list_c*)SIM->get_param(pname, SIM->get_bochs_root());
BX_UHCI_THIS hub.usb_port[port].device->register_state(sr_list);
}
}
}
@ -235,7 +234,6 @@ void bx_usb_uhci_c::runtime_config(void)
{
int i;
char pname[6];
int type = -1;
for (i = 0; i < USB_UHCI_PORTS; i++) {
// device change support
@ -246,10 +244,7 @@ void bx_usb_uhci_c::runtime_config(void)
init_device(i, (bx_list_c*)SIM->get_param(pname, SIM->get_param(BXPN_USB_UHCI)));
} else {
BX_INFO(("USB port #%d: device disconnect", i+1));
if (BX_UHCI_THIS hub.usb_port[i].device != NULL) {
type = BX_UHCI_THIS hub.usb_port[i].device->get_type();
}
set_connect_status(i, type, 0);
set_connect_status(i, 0);
remove_device(i);
}
BX_UHCI_THIS device_change &= ~(1 << i);

View File

@ -3,7 +3,7 @@
/////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2009-2016 Benjamin D Lunt (fys [at] fysnet [dot] net)
// 2009-2016 The Bochs Project
// 2009-2021 The Bochs Project
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public

View File

@ -542,7 +542,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, BX_XHCI_THIS hub.usb_port[i].device->get_type(), 1);
usb_set_connect_status(i, 1);
}
}
@ -975,7 +975,6 @@ void bx_usb_xhci_c::after_restore_state(void)
void bx_usb_xhci_c::init_device(Bit8u port, bx_list_c *portconf)
{
int type;
char pname[BX_PATHNAME_LEN];
const char *devname = NULL;
@ -987,12 +986,12 @@ void bx_usb_xhci_c::init_device(Bit8u port, bx_list_c *portconf)
BX_ERROR(("init_device(): port%d already in use", port+1));
return;
}
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());
type = DEV_usb_init_device(portconf, BX_XHCI_THIS_PTR, &BX_XHCI_THIS hub.usb_port[port].device);
if (BX_XHCI_THIS hub.usb_port[port].device != NULL) {
usb_set_connect_status(port, type, 1);
BX_XHCI_THIS hub.usb_port[port].device->register_state(sr_list);
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)) {
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());
BX_XHCI_THIS hub.usb_port[port].device->register_state(sr_list);
}
}
}
@ -3076,7 +3075,6 @@ void bx_usb_xhci_c::runtime_config(void)
{
int i;
char pname[6];
int type = -1;
for (i = 0; i < BX_N_USB_XHCI_PORTS; i++) {
// device change support
@ -3087,10 +3085,7 @@ void bx_usb_xhci_c::runtime_config(void)
init_device(i, (bx_list_c*)SIM->get_param(pname, SIM->get_param(BXPN_USB_XHCI)));
} else {
BX_INFO(("USB port #%d: device disconnect", i+1));
if (BX_XHCI_THIS hub.usb_port[i].device != NULL) {
type = BX_XHCI_THIS hub.usb_port[i].device->get_type();
}
usb_set_connect_status(i, type, 0);
usb_set_connect_status(i, 0);
}
BX_XHCI_THIS device_change &= ~(1 << i);
}
@ -3139,63 +3134,61 @@ void bx_usb_xhci_c::pci_write_handler(Bit8u address, Bit32u value, unsigned io_l
}
}
void bx_usb_xhci_c::usb_set_connect_status(Bit8u port, int type, bool connected)
bool bx_usb_xhci_c::usb_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;
usb_device_c *device = BX_XHCI_THIS hub.usb_port[port].device;
if (device != NULL) {
if (device->get_type() == type) {
if (connected) {
if ((device->get_speed() == USB_SPEED_SUPER) &&
!BX_XHCI_THIS hub.usb_port[port].is_usb3) {
BX_PANIC(("Super-speed device not supported on USB2 port."));
usb_set_connect_status(port, type, 0);
return;
if (connected) {
if ((device->get_speed() == USB_SPEED_SUPER) &&
!BX_XHCI_THIS hub.usb_port[port].is_usb3) {
BX_PANIC(("Super-speed device not supported on USB2 port."));
usb_set_connect_status(port, 0);
return 0;
}
if (BX_XHCI_THIS hub.usb_port[port].is_usb3) {
if (!device->set_speed(USB_SPEED_SUPER)) {
BX_PANIC(("Only super-speed devices supported on USB3 port."));
usb_set_connect_status(port, 0);
return 0;
}
if (BX_XHCI_THIS hub.usb_port[port].is_usb3) {
if (!device->set_speed(USB_SPEED_SUPER)) {
BX_PANIC(("Only super-speed devices supported on USB3 port."));
usb_set_connect_status(port, type, 0);
return;
}
}
switch (device->get_speed()) {
case USB_SPEED_LOW:
BX_XHCI_THIS hub.usb_port[port].portsc.speed = 2;
break;
case USB_SPEED_FULL:
BX_XHCI_THIS hub.usb_port[port].portsc.speed = 1;
break;
case USB_SPEED_HIGH:
BX_XHCI_THIS hub.usb_port[port].portsc.speed = 3;
break;
case USB_SPEED_SUPER:
BX_XHCI_THIS hub.usb_port[port].portsc.speed = 4;
break;
default:
BX_PANIC(("USB device returned invalid speed value"));
usb_set_connect_status(port, 0);
return 0;
}
BX_XHCI_THIS hub.usb_port[port].portsc.ccs = 1;
if (!device->get_connected()) {
if (!device->init()) {
usb_set_connect_status(port, 0);
BX_ERROR(("port #%d: connect failed", port+1));
return 0;
} else {
BX_INFO(("port #%d: connect: %s", port+1, device->get_info()));
}
switch (device->get_speed()) {
case USB_SPEED_LOW:
BX_XHCI_THIS hub.usb_port[port].portsc.speed = 2;
break;
case USB_SPEED_FULL:
BX_XHCI_THIS hub.usb_port[port].portsc.speed = 1;
break;
case USB_SPEED_HIGH:
BX_XHCI_THIS hub.usb_port[port].portsc.speed = 3;
break;
case USB_SPEED_SUPER:
BX_XHCI_THIS hub.usb_port[port].portsc.speed = 4;
break;
default:
BX_PANIC(("USB device returned invalid speed value"));
usb_set_connect_status(port, type, 0);
return;
}
BX_XHCI_THIS hub.usb_port[port].portsc.ccs = 1;
if (!device->get_connected()) {
if (!device->init()) {
usb_set_connect_status(port, type, 0);
BX_ERROR(("port #%d: connect failed", port+1));
return;
} else {
BX_INFO(("port #%d: connect: %s", port+1, device->get_info()));
}
}
device->set_event_handler(BX_XHCI_THIS_PTR, xhci_event_handler, port);
} else { // not connected
}
device->set_event_handler(BX_XHCI_THIS_PTR, xhci_event_handler, port);
} else { // not connected
BX_XHCI_THIS hub.usb_port[port].portsc.ccs = 0;
BX_XHCI_THIS hub.usb_port[port].portsc.ped = 0;
BX_XHCI_THIS hub.usb_port[port].portsc.speed = 0;
remove_device(port);
}
}
if (ccs_org != BX_XHCI_THIS hub.usb_port[port].portsc.ccs)
BX_XHCI_THIS hub.usb_port[port].portsc.csc = 1;
@ -3208,6 +3201,7 @@ void bx_usb_xhci_c::usb_set_connect_status(Bit8u port, int type, bool connected)
write_event_TRB(0, ((port + 1) << 24), TRB_SET_COMP_CODE(1), TRB_SET_TYPE(PORT_STATUS_CHANGE), 1);
}
}
return connected;
}
// USB runtime parameter handler

View File

@ -565,7 +565,7 @@ private:
static void init_device(Bit8u port, bx_list_c *portconf);
static void remove_device(Bit8u port);
static void usb_set_connect_status(Bit8u port, int type, bool connected);
static bool usb_set_connect_status(Bit8u port, bool connected);
static int broadcast_packet(USBPacket *p, const int port);
static void xhci_timer_handler(void *);