Usb compliance (#91)
Made all devices pass USB 2.0 Compliance on WinXP (old version of the compliance test). USB Hub still needs a little work to be in complete compliance. Fixed potential bug in EHCI to UHCI hand-off. Fixed compilation error with Floppy CB/CBI emulation. Minor syntax fixes (tabulation, old irrelevant comments) MSD serial numbers must be 12 chars. Added to CHANGES file
This commit is contained in:
parent
ffa64461ab
commit
bcbe5da030
@ -15,6 +15,50 @@ We welcome every new contributor !
|
||||
- Apply standard CPPFLAGS from environment in all makefiles
|
||||
- Fixed and improved PCI slot config error handling
|
||||
- Updated Bochs instrumentation examples for new disassembler introduced in Bochs 2.7 release
|
||||
- USB: SCSI: added the Event Status command (0x4a).
|
||||
- USB: SCSI: added BX_DEBUG checks to the command sent by the Guest.
|
||||
- USB: SCSI: added the block_size in the Read Capacity command (0x25).
|
||||
- USB: SCSI: added some 0x9E/xx commands. ReadCapacity(16).
|
||||
- USB: UHCI: re-wrote the uhci stack to better support control/bulk reclamation.
|
||||
- USB: UHCI: check that a reset doesn't clear the CSC bit during a reset, but should after the reset is complete.
|
||||
- USB: added the ability to change interfaces (ex: BBB to UASP).
|
||||
- USB: added the Toggle bit check to all controllers/devices. (optional with a #define)
|
||||
- USB: added the ability to trigger an over-current to all controllers.
|
||||
- USB: added numberous BX_DEBUG checks to the USB_COMMON emulation to help show bugs in a Guest's device driver.
|
||||
- USB: added BX_DEBUG if the first requested packet after a reset is not 8 bytes.
|
||||
- USB: added a BX_DEBUG check to make sure the speed indicator is correct within TDs.
|
||||
- USB: added BX_DEBUG checks to all request lengths, max packet size, and other length checks.
|
||||
- USB: return default speed of device/controller combination.
|
||||
- USB: check that the bochsrc file doesn't specify two different devices for the same port.
|
||||
- USB: check that the bochsrc file has a super-speed device defined on a correct port number.
|
||||
- USB: re-wrote how the USB_COMMON passed on packets to allow for zero-length packets to be accepted.
|
||||
- USB: HID: added multiple mouse modes to have different HID Reports, including a physical report, and an irregular report.
|
||||
- USB: HID: added the Boot Protocol function.
|
||||
- USB: HUB: fixed/Added a more accurate DeviceRemovable emulation.
|
||||
- USB: HUB: Allow USB 1.0 or USB 1.1 emulation (there is a difference).
|
||||
- USB: HUB: Add bit 0 function to the returned report (change status bit).
|
||||
- USB: HUB: Some Guests think a NAK on the Interrupt EP is an error. (option to ignore this)
|
||||
- USB: Floppy: Fixed the CBI/CB configuration descriptor.
|
||||
- USB: fixed/added USB 2.0 Compliance to all devices. Hub still needs a few additions.
|
||||
- Floppies (using the CB/CBI protocol) can only be full-speed.
|
||||
- Fixed the Endpoint Clear Feature request (halted, etc.).
|
||||
- Added the Endpoint Get Status request to each device.
|
||||
- Hub power switching emulation.
|
||||
- Fixed the return/request error on Device Qualifier requests.
|
||||
- Fixed Device Qualifier and Other Speed requests.
|
||||
- USB: MSD: fixed USB 2.0 only descriptor emulation. (Device Qualifier, etc.)
|
||||
- USB: OHCI: fixed the toggle emulation.
|
||||
- USB: added the ability to catch 0xEE descriptors (Microsoft specific).
|
||||
- USB: xHCI: added the ability to have more than one model of xHCI hardware. Currently there are two.
|
||||
- USB: xHCI: added the ability to indicate the port count.
|
||||
- USB: xHCI: check the USB2 and USB3 port assignments.
|
||||
- USB: xHCI: added experimental Stream emulation.
|
||||
- USB: added experimental MSD UASP emulation.
|
||||
- USB: xHCI: added the (vendor) Dump Controller command (Specific to Bochs).
|
||||
- USB: xHCI: added checks to the Evaluate Context and Address Device commands.
|
||||
- USB: xHCI: fixed/updated the Port Status Change Event emulation.
|
||||
- USB: xHCI: fixed/updated the port bandwidth emulation.
|
||||
- USB: Many documentation additions.
|
||||
- Documentation fixes
|
||||
|
||||
-------------------------------------------------------------------------
|
||||
|
@ -550,9 +550,9 @@ void bx_uhci_core_c::write(Bit32u address, Bit32u value, unsigned io_len)
|
||||
if (value & (1<<11)) hub.usb_port[port].over_current_change = 0;
|
||||
hub.usb_port[port].reset = (value & (1<<9)) ? 1 : 0;
|
||||
hub.usb_port[port].resume = (value & (1<<6)) ? 1 : 0;
|
||||
if (!hub.usb_port[port].enabled && (value & (1<<2)))
|
||||
if (!hub.usb_port[port].enabled && (value & (1<<2))) {
|
||||
hub.usb_port[port].enable_changed = 0;
|
||||
else
|
||||
} else
|
||||
if (value & (1<<3)) hub.usb_port[port].enable_changed = 0;
|
||||
hub.usb_port[port].enabled = (value & (1<<2)) ? 1 : 0;
|
||||
if (value & (1<<1)) hub.usb_port[port].connect_changed = 0;
|
||||
@ -908,7 +908,7 @@ bool bx_uhci_core_c::DoTransfer(Bit32u address, struct TD *td) {
|
||||
}
|
||||
|
||||
BX_DEBUG(("TD found at address 0x%08X: 0x%08X 0x%08X 0x%08X 0x%08X", address, td->dword0, td->dword1, td->dword2, td->dword3));
|
||||
|
||||
|
||||
// check TD to make sure it is valid
|
||||
// A max length 0x500 to 0x77E is illegal
|
||||
if ((maxlen >= 0x500) && (maxlen != 0x7FF)) {
|
||||
@ -1141,6 +1141,8 @@ 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)) {
|
||||
// make sure we are calling the correct handler for the device
|
||||
dev->set_event_handler(this, uhci_event_handler, port);
|
||||
hub.usb_port[port].device = dev;
|
||||
set_connect_status(port, 1);
|
||||
} else if ((dev == NULL) && (olddev != NULL)) {
|
||||
|
@ -477,7 +477,7 @@ int usb_device_c::handle_packet(USBPacket *p)
|
||||
break;
|
||||
|
||||
default:
|
||||
BX_ERROR(("Unknown Data state while finding Control In Packet."));
|
||||
BX_ERROR(("Unknown Data state while finding Control In Packet. (state = %i)", d.setup_state));
|
||||
goto fail;
|
||||
}
|
||||
break;
|
||||
@ -550,7 +550,7 @@ int usb_device_c::handle_packet(USBPacket *p)
|
||||
break;
|
||||
|
||||
default:
|
||||
BX_ERROR(("Unknown Data state while finding Control Out Packet."));
|
||||
BX_ERROR(("Unknown Data state while finding Control Out Packet. (state = %i)", d.setup_state));
|
||||
goto fail;
|
||||
}
|
||||
break;
|
||||
@ -695,6 +695,11 @@ int usb_device_c::handle_control_common(int request, int value, int index, int l
|
||||
}
|
||||
d.config = value;
|
||||
d.state = USB_STATE_CONFIGURED;
|
||||
#if HANDLE_TOGGLE_CONTROL
|
||||
// we must also clear all of the EP toggle bits
|
||||
for (int i=0; i<USB_MAX_ENDPOINTS; i++)
|
||||
set_toggle(i, 0);
|
||||
#endif
|
||||
ret = 0;
|
||||
break;
|
||||
case DeviceOutRequest | USB_REQ_CLEAR_FEATURE:
|
||||
@ -752,13 +757,36 @@ int usb_device_c::handle_control_common(int request, int value, int index, int l
|
||||
}
|
||||
break;
|
||||
case EndpointOutRequest | USB_REQ_CLEAR_FEATURE:
|
||||
BX_DEBUG(("EndpointOutRequest | USB_REQ_CLEAR_FEATURE:"));
|
||||
BX_DEBUG(("EndpointOutRequest | USB_REQ_CLEAR_FEATURE: ep = %d", index & 0x7F));
|
||||
// Value == 0 == Endpoint Halt (the Guest wants to reset the endpoint)
|
||||
if (value == 0) { /* clear ep halt */
|
||||
if (value == USB_ENDPOINT_HALT) {
|
||||
if ((index & 0x7F) < USB_MAX_ENDPOINTS) {
|
||||
#if HANDLE_TOGGLE_CONTROL
|
||||
set_toggle(index & 0x7F, 0);
|
||||
set_toggle(index, 0);
|
||||
#endif
|
||||
ret = 0;
|
||||
set_halted(index, 0);
|
||||
ret = 0;
|
||||
} else {
|
||||
BX_ERROR(("EndpointOutRequest | USB_REQ_CLEAR_FEATURE: index > ep count: %d", index));
|
||||
}
|
||||
} else {
|
||||
BX_ERROR(("EndpointOutRequest | USB_REQ_CLEAR_FEATURE: Unknown Clear Feature Request found: %d", value));
|
||||
}
|
||||
break;
|
||||
case EndpointOutRequest | USB_REQ_SET_FEATURE:
|
||||
// with EndpointRequest, The wLength field must be zero
|
||||
if (length != 0) {
|
||||
BX_ERROR(("USB_REQ_SET_FEATURE: This type of request requires the wLength field to be zero."));
|
||||
}
|
||||
if (value == USB_ENDPOINT_HALT) {
|
||||
if ((index & 0x7F) < USB_MAX_ENDPOINTS) {
|
||||
set_halted(index, 1);
|
||||
ret = 0;
|
||||
} else {
|
||||
BX_ERROR(("EndpointOutRequest | USB_REQ_SET_FEATURE: index > ep count: %d", index));
|
||||
}
|
||||
} else {
|
||||
BX_ERROR(("EndpointOutRequest | USB_REQ_SET_FEATURE: Unknown Set Feature Request found: %d", value));
|
||||
}
|
||||
break;
|
||||
// should not have a default: here, so allowing the device's handle_control() to try to execute the request
|
||||
|
@ -118,6 +118,7 @@
|
||||
#define USB_REQ_SET_SEL 0x30
|
||||
#define USB_REQ_SET_ISO_DELAY 0x31
|
||||
|
||||
#define USB_ENDPOINT_HALT 0
|
||||
#define USB_DEVICE_SELF_POWERED 0
|
||||
#define USB_DEVICE_REMOTE_WAKEUP 1
|
||||
#define USB_DEVICE_U1_ENABLE 48
|
||||
@ -188,6 +189,7 @@ typedef struct USBEndPoint {
|
||||
#if HANDLE_TOGGLE_CONTROL
|
||||
int toggle; // the current toggle for the endpoint (0, 1, or -1 for xHCI)
|
||||
#endif
|
||||
bool halted; // is the current ep halted?
|
||||
} USBEndPoint;
|
||||
|
||||
class BOCHSAPI bx_usbdev_ctl_c : public logfunctions {
|
||||
@ -258,13 +260,20 @@ public:
|
||||
|
||||
#if HANDLE_TOGGLE_CONTROL
|
||||
int get_toggle(const int ep) {
|
||||
return (ep < USB_MAX_ENDPOINTS) ? d.endpoint_info[ep].toggle : 0;
|
||||
return ((ep & 0x7F) < USB_MAX_ENDPOINTS) ? d.endpoint_info[(ep & 0x7F)].toggle : 0;
|
||||
}
|
||||
void set_toggle(const int ep, const int toggle) {
|
||||
if (ep < USB_MAX_ENDPOINTS)
|
||||
d.endpoint_info[ep].toggle = toggle;
|
||||
if ((ep & 0x7F) < USB_MAX_ENDPOINTS)
|
||||
d.endpoint_info[(ep & 0x7F)].toggle = toggle;
|
||||
}
|
||||
#endif
|
||||
bool get_halted(const int ep) {
|
||||
return ((ep & 0x7F) < USB_MAX_ENDPOINTS) ? d.endpoint_info[(ep & 0x7F)].halted : 0;
|
||||
}
|
||||
void set_halted(const int ep, const bool halted) {
|
||||
if ((ep & 0x7F) < USB_MAX_ENDPOINTS)
|
||||
d.endpoint_info[(ep & 0x7F)].halted = halted;
|
||||
}
|
||||
|
||||
Bit8u get_type() {
|
||||
return d.type;
|
||||
|
@ -123,8 +123,6 @@ static inline struct EHCIPacket *ehci_container_of_usb_packet(void *ptr)
|
||||
reinterpret_cast<size_t>(&(static_cast<struct EHCIPacket*>(0)->packet)));
|
||||
}
|
||||
|
||||
int ehci_event_handler(int event, void *ptr, void *dev, int port);
|
||||
|
||||
// builtin configuration handling functions
|
||||
|
||||
Bit32s usb_ehci_options_parser(const char *context, int num_params, char *params[])
|
||||
@ -525,6 +523,8 @@ void bx_usb_ehci_c::reset_port(int p)
|
||||
BX_EHCI_THIS hub.usb_port[p].portsc.csc = 0;
|
||||
}
|
||||
|
||||
int ehci_event_handler(int event, void *ptr, void *dev, int port);
|
||||
|
||||
void bx_usb_ehci_c::init_device(Bit8u port, bx_list_c *portconf)
|
||||
{
|
||||
char pname[BX_PATHNAME_LEN];
|
||||
@ -603,18 +603,18 @@ bool bx_usb_ehci_c::set_connect_status(Bit8u port, bool connected)
|
||||
} else { // not connected
|
||||
BX_INFO(("port #%d: device disconnect", port+1));
|
||||
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;
|
||||
}
|
||||
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 {
|
||||
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);
|
||||
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);
|
||||
@ -652,6 +652,11 @@ void bx_usb_ehci_c::change_port_owner(int port)
|
||||
set_connect_status(port, 1);
|
||||
}
|
||||
}
|
||||
// make sure we are calling the correct handler for the device
|
||||
if (device != NULL) {
|
||||
if (BX_EHCI_THIS hub.usb_port[port].portsc.po == 0)
|
||||
device->set_event_handler(BX_EHCI_THIS_PTR, ehci_event_handler, port);
|
||||
}
|
||||
BX_EHCI_THIS hub.usb_port[port].owner_change = 0;
|
||||
}
|
||||
}
|
||||
@ -888,6 +893,7 @@ bool bx_usb_ehci_c::write_handler(bx_phy_address addr, unsigned len, void *data,
|
||||
if (oldfpr && !BX_EHCI_THIS hub.usb_port[port].portsc.fpr) {
|
||||
BX_EHCI_THIS hub.usb_port[port].portsc.sus = 0;
|
||||
}
|
||||
} else if (port == USB_EHCI_PORTS) {
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@ -2224,7 +2230,7 @@ void bx_usb_ehci_c::ehci_frame_timer(void)
|
||||
t_now = bx_pc_system.time_usec();
|
||||
usec_elapsed = t_now - BX_EHCI_THIS hub.last_run_usec;
|
||||
frames = (int)(usec_elapsed / FRAME_TIMER_USEC);
|
||||
|
||||
|
||||
if (BX_EHCI_THIS periodic_enabled() || (BX_EHCI_THIS hub.pstate != EST_INACTIVE)) {
|
||||
need_timer++;
|
||||
BX_EHCI_THIS hub.async_stepdown = 0;
|
||||
|
@ -93,20 +93,22 @@ protected:
|
||||
// to match your changes.
|
||||
|
||||
// Full-speed only
|
||||
// * USB Mass Storage Class Specification, p4, section 3, states that
|
||||
// * that a Mass Storage Class device using CB/CBI must be full-speed only.
|
||||
static Bit8u bx_floppy_dev_descriptor[] = {
|
||||
0x12, /* u8 bLength; */
|
||||
0x01, /* u8 bDescriptorType; Device */
|
||||
0x00, 0x02, /* u16 bcdUSB; v2.0 */
|
||||
0x01, 0x01, /* u16 bcdUSB; v1.1 */
|
||||
|
||||
0x00, /* u8 bDeviceClass; */
|
||||
0x00, /* u8 bDeviceSubClass; */
|
||||
0x00, /* u8 bDeviceProtocol; [ low/full speeds only ] */
|
||||
0x00, /* u8 bDeviceProtocol; */
|
||||
0x40, /* u8 bMaxPacketSize; 64 Bytes */
|
||||
|
||||
/* Vendor and product id are arbitrary. */
|
||||
0x00, 0x00, /* u16 idVendor; */
|
||||
0x00, 0x00, /* u16 idProduct; */
|
||||
0x00, 0x00, /* u16 bcdDevice */
|
||||
0x00, 0x00, /* u16 bcdDevice; */
|
||||
|
||||
0x01, /* u8 iManufacturer; */
|
||||
0x02, /* u8 iProduct; */
|
||||
@ -120,7 +122,11 @@ static const Bit8u bx_floppy_config_descriptor[] = {
|
||||
/* one configuration */
|
||||
0x09, /* u8 bLength; */
|
||||
0x02, /* u8 bDescriptorType; Configuration */
|
||||
#if USB_FLOPPY_USE_INTERRUPT
|
||||
0x27, 0x00, /* u16 wTotalLength; */
|
||||
#else
|
||||
0x20, 0x00, /* u16 wTotalLength; */
|
||||
#endif
|
||||
0x01, /* u8 bNumInterfaces; (1) */
|
||||
0x01, /* u8 bConfigurationValue; */
|
||||
0x00, /* u8 iConfiguration; */
|
||||
@ -324,6 +330,7 @@ usb_floppy_device_c::usb_floppy_device_c()
|
||||
bx_param_bool_c *readonly;
|
||||
bx_param_enum_c *status, *mode;
|
||||
|
||||
// MSC Compliance states that a CB(I) device must be full-speed only
|
||||
d.speed = d.minspeed = d.maxspeed = USB_SPEED_FULL;
|
||||
memset((void *) &s, 0, sizeof(s));
|
||||
strcpy(d.devname, "BOCHS UFI/CBI FLOPPY");
|
||||
@ -456,13 +463,13 @@ bool usb_floppy_device_c::init()
|
||||
bx_floppy_dev_descriptor[9] = 0x06;
|
||||
d.vendor_desc = "TEAC ";
|
||||
d.product_desc = "TEAC FD-05PUW ";
|
||||
d.serial_num = "3000";
|
||||
d.serial_num = "3000 ";
|
||||
} else {
|
||||
bx_floppy_dev_descriptor[8] = 0x00;
|
||||
bx_floppy_dev_descriptor[9] = 0x00;
|
||||
d.vendor_desc = "BOCHS ";
|
||||
d.product_desc = d.devname;
|
||||
d.serial_num = "00.10";
|
||||
d.serial_num = "00.10 ";
|
||||
}
|
||||
if (set_inserted(1)) {
|
||||
sprintf(s.info_txt, "USB floppy: path='%s', mode='%s'", s.fname, s.image_mode);
|
||||
@ -552,6 +559,29 @@ int usb_floppy_device_c::handle_control(int request, int value, int index, int l
|
||||
}
|
||||
ret = 0;
|
||||
break;
|
||||
case EndpointRequest | USB_REQ_GET_STATUS:
|
||||
BX_DEBUG(("USB_REQ_GET_STATUS: Endpoint."));
|
||||
// if the endpoint is currently halted, return bit 0 = 1
|
||||
if (value == USB_ENDPOINT_HALT) {
|
||||
int indx = (index & 0x7F);
|
||||
#if USB_FLOPPY_USE_INTERRUPT
|
||||
int limit = 3;
|
||||
#else
|
||||
int limit = 2;
|
||||
#endif
|
||||
if ((indx > 0) && (indx <= limit)) {
|
||||
data[0] = 0x00 | (get_halted(indx) ? 1 : 0);
|
||||
data[1] = 0x00;
|
||||
ret = 2;
|
||||
} else {
|
||||
BX_ERROR(("EndpointRequest | USB_REQ_GET_STATUS: index > ep count: %d", index));
|
||||
goto fail;
|
||||
}
|
||||
} else {
|
||||
BX_ERROR(("EndpointRequest | USB_REQ_SET_FEATURE: Unknown Get Status Request found: %d", value));
|
||||
goto fail;
|
||||
}
|
||||
break;
|
||||
case DeviceRequest | USB_REQ_GET_DESCRIPTOR:
|
||||
switch (value >> 8) {
|
||||
case USB_DT_STRING:
|
||||
@ -579,17 +609,6 @@ int usb_floppy_device_c::handle_control(int request, int value, int index, int l
|
||||
goto fail;
|
||||
}
|
||||
break;
|
||||
case EndpointOutRequest | USB_REQ_CLEAR_FEATURE:
|
||||
BX_DEBUG(("USB_REQ_CLEAR_FEATURE:"));
|
||||
// Value == 0 == Endpoint Halt (the Guest wants to reset the endpoint)
|
||||
if (value == 0) { /* clear ep halt */
|
||||
#if HANDLE_TOGGLE_CONTROL
|
||||
set_toggle(index, 0);
|
||||
#endif
|
||||
ret = 0;
|
||||
} else
|
||||
goto fail;
|
||||
break;
|
||||
case DeviceOutRequest | USB_REQ_SET_SEL:
|
||||
// Set U1 and U2 System Exit Latency
|
||||
BX_DEBUG(("SET_SEL (U1 and U2):"));
|
||||
@ -646,13 +665,13 @@ bool usb_floppy_device_c::handle_command(Bit8u *command)
|
||||
}
|
||||
|
||||
#if UFI_DO_INQUIRY_HACK
|
||||
// to be consistant with real hardware, we need to fail with
|
||||
// to be consistent with real hardware, we need to fail with
|
||||
// a STALL twice for any command after the first Inquiry except
|
||||
// for the inquiry and request_sense commands.
|
||||
// (I don't know why, and will document further when I know more)
|
||||
if ((s.fail_count > 0) &&
|
||||
(s.cur_command != UFI_INQUIRY) && (s.cur_command != UFI_REQUEST_SENSE)) {
|
||||
BX_DEBUG(("Consistant stall of %d of 2.", 2 - s.fail_count + 1));
|
||||
BX_INFO(("Consistent stall of %d of 2.", 2 - s.fail_count + 1));
|
||||
s.fail_count--;
|
||||
return 0;
|
||||
}
|
||||
|
@ -96,11 +96,11 @@ protected:
|
||||
static const Bit8u bx_mouse_dev_descriptor[] = {
|
||||
0x12, /* u8 bLength; */
|
||||
0x01, /* u8 bDescriptorType; Device */
|
||||
0x00, 0x01, /* u16 bcdUSB; v1.0 */
|
||||
0x01, 0x01, /* u16 bcdUSB; v1.1 */
|
||||
|
||||
0x00, /* u8 bDeviceClass; */
|
||||
0x00, /* u8 bDeviceSubClass; */
|
||||
0x00, /* u8 bDeviceProtocol; [ low/full speeds only ] */
|
||||
0x00, /* u8 bDeviceProtocol; */
|
||||
0x08, /* u8 bMaxPacketSize; 8 Bytes */
|
||||
|
||||
0x27, 0x06, /* u16 idVendor; */
|
||||
@ -120,7 +120,7 @@ static const Bit8u bx_mouse_dev_descriptor2[] = {
|
||||
|
||||
0x00, /* u8 bDeviceClass; */
|
||||
0x00, /* u8 bDeviceSubClass; */
|
||||
0x00, /* u8 bDeviceProtocol; [ low/full speeds only ] */
|
||||
0x00, /* u8 bDeviceProtocol; */
|
||||
0x40, /* u8 bMaxPacketSize; 64 Bytes */
|
||||
|
||||
0x27, 0x06, /* u16 idVendor; */
|
||||
@ -461,7 +461,8 @@ static Bit8u bx_mouse_config_descriptor0[] = {
|
||||
0x81, /* u8 ep_bEndpointAddress; IN Endpoint 1 */
|
||||
0x03, /* u8 ep_bmAttributes; Interrupt */
|
||||
0x08, 0x00, /* u16 ep_wMaxPacketSize; */
|
||||
0x0a, /* u8 ep_bInterval; (0 - 255ms -- usb 2.0 spec) */
|
||||
0x0A, /* u8 ep_bInterval; (10 - 255ms -- usb 2.0 spec, 5.7.4) */
|
||||
/* however: (11 - 255ms -- usb 2.0 compliance 1.2.84, pg 11 */
|
||||
};
|
||||
|
||||
#define HID_PHYS_DESC_SET_LEN 7
|
||||
@ -797,11 +798,11 @@ static const Bit8u bx_keypad_hid_report_descriptor[] = {
|
||||
static const Bit8u bx_keypad_dev_descriptor[] = {
|
||||
0x12, /* u8 bLength; */
|
||||
0x01, /* u8 bDescriptorType; Device */
|
||||
0x10, 0x01, /* u16 bcdUSB; v1.1 */
|
||||
0x01, 0x01, /* u16 bcdUSB; v1.1 */
|
||||
|
||||
0x00, /* u8 bDeviceClass; */
|
||||
0x00, /* u8 bDeviceSubClass; */
|
||||
0x00, /* u8 bDeviceProtocol; [ low/full speeds only ] */
|
||||
0x00, /* u8 bDeviceProtocol; */
|
||||
0x08, /* u8 bMaxPacketSize; 8 Bytes */
|
||||
|
||||
0xB4, 0x04, /* u16 idVendor; */
|
||||
@ -821,7 +822,7 @@ static const Bit8u bx_keypad_dev_descriptor2[] = {
|
||||
|
||||
0x00, /* u8 bDeviceClass; */
|
||||
0x00, /* u8 bDeviceSubClass; */
|
||||
0x00, /* u8 bDeviceProtocol; [ low/full speeds only ] */
|
||||
0x00, /* u8 bDeviceProtocol; */
|
||||
0x40, /* u8 bMaxPacketSize; 64 Bytes */
|
||||
|
||||
0xB4, 0x04, /* u16 idVendor; */
|
||||
@ -1346,6 +1347,23 @@ int usb_hid_device_c::handle_control(int request, int value, int index, int leng
|
||||
BX_DEBUG(("HID: DeviceRequest | SET_FEATURE:"));
|
||||
goto fail;
|
||||
break;
|
||||
case EndpointRequest | USB_REQ_GET_STATUS:
|
||||
BX_DEBUG(("USB_REQ_GET_STATUS: Endpoint."));
|
||||
// if the endpoint is currently halted, return bit 0 = 1
|
||||
if (value == USB_ENDPOINT_HALT) {
|
||||
if (index == 0x81) {
|
||||
data[0] = 0x00 | (get_halted(index) ? 1 : 0);
|
||||
data[1] = 0x00;
|
||||
ret = 2;
|
||||
} else {
|
||||
BX_ERROR(("EndpointRequest | USB_REQ_GET_STATUS: index > ep count: %d", index));
|
||||
goto fail;
|
||||
}
|
||||
} else {
|
||||
BX_ERROR(("EndpointRequest | USB_REQ_SET_FEATURE: Unknown Get Status Request found: %d", value));
|
||||
goto fail;
|
||||
}
|
||||
break;
|
||||
case DeviceRequest | USB_REQ_GET_DESCRIPTOR:
|
||||
BX_DEBUG(("HID: DeviceRequest | USB_REQ_GET_DESCRIPTOR:"));
|
||||
switch(value >> 8) {
|
||||
@ -1439,12 +1457,6 @@ int usb_hid_device_c::handle_control(int request, int value, int index, int leng
|
||||
goto fail;
|
||||
}
|
||||
break;
|
||||
case EndpointOutRequest | USB_REQ_CLEAR_FEATURE:
|
||||
BX_DEBUG(("HID: CLEAR_FEATURE:"));
|
||||
if ((value == 0) && (index != 0x81)) { /* clear EP halt */
|
||||
goto fail;
|
||||
}
|
||||
break;
|
||||
case InterfaceInClassRequest | GET_REPORT:
|
||||
BX_DEBUG(("HID: GET_REPORT:"));
|
||||
if ((value >> 8) == 1) { // Input report
|
||||
|
@ -97,6 +97,31 @@ protected:
|
||||
|
||||
static Bit32u serial_number = 1234;
|
||||
|
||||
// Set this to a version of the USB you wish to emulate.
|
||||
// 0x0100 = v1.0 or 0x0101 = v1.1
|
||||
#define USB_HUB_VERSION 0x0100
|
||||
|
||||
// Set USB_HUB_POWER_SWITCHING to 1 if power switching is supported
|
||||
// (If not supported power is always on)
|
||||
// (It must be set if USB_HUB_VERSION == 1.1+)
|
||||
#define USB_HUB_POWER_SWITCHING 1
|
||||
#if (USB_HUB_VERSION > 0x100) && (USB_HUB_POWER_SWITCHING == 0)
|
||||
#error USB_HUB_POWER_SWITCHING must be set for USB_HUB_VERSION 1.1+
|
||||
#endif
|
||||
|
||||
// Set USB_HUB_POWER_PER_PORT to 1 if per-port power switching is on,
|
||||
// else set to 0 for ganged power switching (all ports powered at same time)
|
||||
// (is ignored if USB_HUB_POWER_SWITCHING == 0)
|
||||
#define USB_HUB_POWER_PER_PORT 1
|
||||
|
||||
// The USB specification (usb1.0 11.8, usb1.1 11.13.1, usb2.0 11.12.1)
|
||||
// states that if there is nothing to report from the IN interrupt
|
||||
// that the device should respond with a USB_RET_NAK. However, Win95
|
||||
// considers that an error and stops the IN pipe, finding no further
|
||||
// connection status. Set this to 1 if you are emulating Win95 or
|
||||
// a similar Guest.
|
||||
#define USB_HUB_ALWAYS_REPORT 1
|
||||
|
||||
// If you change any of the Max Packet Size, or other fields within these
|
||||
// descriptors, you must also change the d.endpoint_info[] array
|
||||
// to match your changes.
|
||||
@ -104,11 +129,16 @@ static Bit32u serial_number = 1234;
|
||||
static const Bit8u bx_hub_dev_descriptor[] = {
|
||||
0x12, /* u8 bLength; */
|
||||
0x01, /* u8 bDescriptorType; Device */
|
||||
0x10, 0x01, /* u16 bcdUSB; v1.1 */
|
||||
|
||||
#if USB_HUB_VERSION == 0x0100
|
||||
0x00, 0x01, /* u16 bcdUSB; v1.0 */
|
||||
#elif USB_HUB_VERSION == 0x0101
|
||||
0x01, 0x01, /* u16 bcdUSB; v1.1 */
|
||||
#else
|
||||
#error Unknown USB_HUB_VERSION value found
|
||||
#endif
|
||||
0x09, /* u8 bDeviceClass; HUB_CLASSCODE */
|
||||
0x00, /* u8 bDeviceSubClass; */
|
||||
0x00, /* u8 bDeviceProtocol; [ low/full speeds only ] */
|
||||
0x00, /* u8 bDeviceProtocol; */
|
||||
0x40, /* u8 bMaxPacketSize; 64 Bytes */
|
||||
|
||||
0x09, 0x04, /* u16 idVendor; */
|
||||
@ -122,6 +152,7 @@ static const Bit8u bx_hub_dev_descriptor[] = {
|
||||
};
|
||||
|
||||
/* XXX: patch interrupt size */
|
||||
#define BX_Hub_Config_Descriptor_pos 22
|
||||
static Bit8u bx_hub_config_descriptor[] = {
|
||||
|
||||
/* one configuration */
|
||||
@ -174,10 +205,17 @@ static const Bit8u bx_hub_hub_descriptor[] =
|
||||
0x00, /* u8 bLength; patched in later */
|
||||
0x29, /* u8 bDescriptorType; Hub-descriptor */
|
||||
0x00, /* u8 bNbrPorts; (patched later) */
|
||||
0x0a, /* u16 wHubCharacteristics; */
|
||||
0x00, /* (per-port OC, no power switching) */
|
||||
#if USB_HUB_POWER_SWITCHING
|
||||
#if USB_HUB_POWER_PER_PORT
|
||||
0x09, 0x00, /* u16 wHubCharacteristics; (per-port OC, per-port power switching) */
|
||||
#else
|
||||
0x08, 0x00, /* u16 wHubCharacteristics; (per-port OC, ganged power switching) */
|
||||
#endif
|
||||
#else
|
||||
0x0a, 0x00, /* u16 wHubCharacteristics; (per-port OC, no power switching) */
|
||||
#endif
|
||||
0x01, /* u8 bPwrOn2pwrGood; 2ms */
|
||||
0x00 /* u8 bHubContrCurrent; 0 mA */
|
||||
0x40 /* u8 bHubContrCurrent; 64 mA */
|
||||
|
||||
/* DeviceRemovable and PortPwrCtrlMask patched in later */
|
||||
};
|
||||
@ -197,9 +235,9 @@ usb_hub_device_c::usb_hub_device_c()
|
||||
d.device_desc_size = sizeof(bx_hub_dev_descriptor);
|
||||
d.config_descriptor = bx_hub_config_descriptor;
|
||||
d.config_desc_size = sizeof(bx_hub_config_descriptor);
|
||||
d.endpoint_info[USB_CONTROL_EP].max_packet_size = 8; // Control ep0
|
||||
d.endpoint_info[USB_CONTROL_EP].max_packet_size = 64; // Control ep0
|
||||
d.endpoint_info[USB_CONTROL_EP].max_burst_size = 0;
|
||||
d.endpoint_info[1].max_packet_size = 2; // In ep1
|
||||
d.endpoint_info[1].max_packet_size = (USB_HUB_MAX_PORTS + 1 + 7) / 8; // In ep1
|
||||
d.endpoint_info[1].max_burst_size = 0;
|
||||
d.vendor_desc = "BOCHS";
|
||||
d.product_desc = "BOCHS USB HUB";
|
||||
@ -257,11 +295,12 @@ bool usb_hub_device_c::init()
|
||||
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;
|
||||
bx_hub_config_descriptor[BX_Hub_Config_Descriptor_pos] = (hub.n_ports + 1 + 7) / 8;
|
||||
for(i = 0; i < hub.n_ports; i++) {
|
||||
hub.usb_port[i].PortStatus = PORT_STAT_POWER;
|
||||
hub.usb_port[i].PortChange = 0;
|
||||
}
|
||||
hub.PortStatusC = 0;
|
||||
for(i = 0; i < hub.n_ports; i++) {
|
||||
sprintf(pname, "port%d", i+1);
|
||||
sprintf(label, "Port #%d Configuration", i+1);
|
||||
@ -319,6 +358,7 @@ void usb_hub_device_c::register_state_specific(bx_list_c *parent)
|
||||
// empty list for USB device state
|
||||
new bx_list_c(port, "device");
|
||||
}
|
||||
BXRS_HEX_PARAM_FIELD(hub.state, PortStatusC, hub.PortStatusC);
|
||||
}
|
||||
|
||||
void usb_hub_device_c::after_restore_state()
|
||||
@ -363,15 +403,26 @@ int usb_hub_device_c::handle_control(int request, int value, int index, int leng
|
||||
case DeviceOutRequest | USB_REQ_CLEAR_FEATURE:
|
||||
goto fail;
|
||||
break;
|
||||
case EndpointOutRequest | USB_REQ_CLEAR_FEATURE:
|
||||
if (value == 0 && index != 0x81) { /* clear ep halt */
|
||||
goto fail;
|
||||
}
|
||||
ret = 0;
|
||||
break;
|
||||
case DeviceOutRequest | USB_REQ_SET_FEATURE:
|
||||
goto fail;
|
||||
break;
|
||||
case EndpointRequest | USB_REQ_GET_STATUS:
|
||||
BX_DEBUG(("USB_REQ_GET_STATUS: Endpoint."));
|
||||
// if the endpoint is currently halted, return bit 0 = 1
|
||||
if (value == USB_ENDPOINT_HALT) {
|
||||
if (index == 0x81) {
|
||||
data[0] = 0x00 | (get_halted(index) ? 1 : 0);
|
||||
data[1] = 0x00;
|
||||
ret = 2;
|
||||
} else {
|
||||
BX_ERROR(("EndpointRequest | USB_REQ_GET_STATUS: index > ep count: %d", index));
|
||||
goto fail;
|
||||
}
|
||||
} else {
|
||||
BX_ERROR(("EndpointRequest | USB_REQ_SET_FEATURE: Unknown Get Status Request found: %d", value));
|
||||
goto fail;
|
||||
}
|
||||
break;
|
||||
case DeviceRequest | USB_REQ_GET_DESCRIPTOR:
|
||||
switch(value >> 8) {
|
||||
case USB_DT_STRING:
|
||||
@ -437,9 +488,23 @@ int usb_hub_device_c::handle_control(int request, int value, int index, int leng
|
||||
hub.usb_port[n].PortChange |= PORT_STAT_C_RESET;
|
||||
/* set enable bit */
|
||||
hub.usb_port[n].PortStatus |= PORT_STAT_ENABLE;
|
||||
hub.usb_port[n].PortStatus &= ~PORT_STAT_SUSPEND;
|
||||
}
|
||||
break;
|
||||
case PORT_POWER:
|
||||
#if USB_HUB_POWER_SWITCHING
|
||||
#if USB_HUB_POWER_PER_PORT == 0
|
||||
for (n = 0; n < hub.n_ports; n++) {
|
||||
#endif
|
||||
if ((hub.usb_port[n].PortStatus & PORT_STAT_POWER) == 0) {
|
||||
hub.usb_port[n].PortStatus = PORT_STAT_POWER;
|
||||
hub.device_change |= (1 << n);
|
||||
runtime_config();
|
||||
}
|
||||
#if USB_HUB_POWER_PER_PORT == 0
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
break;
|
||||
default:
|
||||
BX_ERROR(("Unknown SetPortFeature: %d", value));
|
||||
@ -452,6 +517,23 @@ int usb_hub_device_c::handle_control(int request, int value, int index, int leng
|
||||
if (n >= hub.n_ports)
|
||||
goto fail;
|
||||
switch(value) {
|
||||
case PORT_POWER:
|
||||
#if USB_HUB_POWER_SWITCHING
|
||||
#if USB_HUB_POWER_PER_PORT == 0
|
||||
for (n = 0; n < hub.n_ports; n++) {
|
||||
#endif
|
||||
if (hub.usb_port[n].PortStatus & PORT_STAT_POWER) {
|
||||
hub.usb_port[n].PortStatus &= ~PORT_STAT_POWER;
|
||||
hub.device_change |= (1 << n);
|
||||
runtime_config();
|
||||
hub.usb_port[n].PortStatus = 0;
|
||||
hub.usb_port[n].PortChange = 0;
|
||||
}
|
||||
#if USB_HUB_POWER_PER_PORT == 0
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
break;
|
||||
case PORT_ENABLE:
|
||||
hub.usb_port[n].PortStatus &= ~PORT_STAT_ENABLE;
|
||||
break;
|
||||
@ -480,30 +562,63 @@ int usb_hub_device_c::handle_control(int request, int value, int index, int leng
|
||||
ret = 0;
|
||||
break;
|
||||
case DeviceClassInRequest | USB_REQ_GET_DESCRIPTOR:
|
||||
{
|
||||
unsigned int limit, var_hub_size = 0;
|
||||
if (
|
||||
#if USB_HUB_VERSION == 0x0100
|
||||
((value >> 8) == 0x00) || // USB 1.0 defines it as type = zero
|
||||
#endif
|
||||
((value >> 8) == 0x29)) { // USB 1.1+ defines it as type = 0x29
|
||||
unsigned int var_hub_size = 0, indx = 7;
|
||||
memcpy(data, bx_hub_hub_descriptor,
|
||||
sizeof(bx_hub_hub_descriptor));
|
||||
data[2] = hub.n_ports;
|
||||
|
||||
|
||||
/* fill DeviceRemovable bits */
|
||||
limit = ((hub.n_ports + 1 + 7) / 8) + 7;
|
||||
for (n = 7; n < limit; n++) {
|
||||
data[n] = 0x00;
|
||||
unsigned int byte_count = ((hub.n_ports + 1 + 7) / 8);
|
||||
for (n = 0; n < byte_count; n++) {
|
||||
data[indx + n] = 0x00;
|
||||
var_hub_size++;
|
||||
}
|
||||
|
||||
#if USB_HUB_VERSION == 0x0100
|
||||
/* Build a bitmap of all present ports starting with:
|
||||
bit 1 = port 0, bit 2 = port 1, etc.
|
||||
We can assume there will be less than 16 ports (USB_HUB_MAX_PORTS < 16) */
|
||||
unsigned int status = 0;
|
||||
for (n = 0; n < hub.n_ports; n++) {
|
||||
status |= (1 << (n + 1));
|
||||
}
|
||||
#endif
|
||||
/* fill PortPwrCtrlMask bits */
|
||||
limit = limit + ((hub.n_ports + 7) / 8);
|
||||
for (;n < limit; n++) {
|
||||
data[n] = 0xff;
|
||||
/* USB 1.0: has this field set each bit indicating if a port is present
|
||||
starting with bit 1. */
|
||||
/* USB 1.1+: states that this field should be all 1's */
|
||||
indx += var_hub_size;
|
||||
for (n = 0; n < byte_count; n++) {
|
||||
#if USB_HUB_VERSION == 0x0100
|
||||
#if USB_HUB_POWER_SWITCHING && USB_HUB_POWER_PER_PORT
|
||||
data[indx + n] = (Bit8u) (status & 0xFF);
|
||||
status >>= 8;
|
||||
#else
|
||||
data[indx + n] = 0x00;
|
||||
#endif
|
||||
#else
|
||||
data[indx + n] = 0xFF;
|
||||
#endif
|
||||
var_hub_size++;
|
||||
}
|
||||
|
||||
ret = sizeof(bx_hub_hub_descriptor) + var_hub_size;
|
||||
data[0] = ret;
|
||||
break;
|
||||
#if USB_HUB_VERSION != 0x0100
|
||||
} else if ((value >> 8) == 0x00) { // USB 1.0 defines it as type = zero
|
||||
BX_INFO(("handle_control: Hub Class: A request of zero is a USB 1.0 request. USB 1.1+ use 0x29."));
|
||||
goto fail;
|
||||
#endif
|
||||
} else {
|
||||
BX_ERROR(("handle_control: Hub Class: unknown type requested: 0x%02x", value >> 8));
|
||||
goto fail;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
BX_ERROR(("handle_control: unknown request: 0x%04x", request));
|
||||
fail:
|
||||
@ -526,7 +641,6 @@ int usb_hub_device_c::handle_data(USBPacket *p)
|
||||
switch(p->pid) {
|
||||
case USB_TOKEN_IN:
|
||||
if (p->devep == 1) {
|
||||
unsigned int status;
|
||||
int i, n;
|
||||
n = (hub.n_ports + 1 + 7) / 8;
|
||||
if (p->len == 1) { /* FreeBSD workaround */
|
||||
@ -534,19 +648,27 @@ int usb_hub_device_c::handle_data(USBPacket *p)
|
||||
} else if (n > p->len) {
|
||||
return USB_RET_BABBLE;
|
||||
}
|
||||
status = 0;
|
||||
Bit16u status = 0;
|
||||
for(i = 0; i < hub.n_ports; i++) {
|
||||
if (hub.usb_port[i].PortChange)
|
||||
status |= (1 << (i + 1));
|
||||
}
|
||||
if (status != hub.PortStatusC) {
|
||||
hub.PortStatusC = status;
|
||||
status |= 1; // bit 0 = hub change detected
|
||||
}
|
||||
#if USB_HUB_ALWAYS_REPORT != 1
|
||||
if (status != 0) {
|
||||
#endif
|
||||
for(i = 0; i < n; i++) {
|
||||
p->data[i] = status >> (8 * i);
|
||||
}
|
||||
ret = n;
|
||||
#if USB_HUB_ALWAYS_REPORT != 1
|
||||
} else {
|
||||
ret = USB_RET_NAK; /* usb11 11.13.1 */
|
||||
ret = USB_RET_NAK;
|
||||
}
|
||||
#endif
|
||||
} else {
|
||||
goto fail;
|
||||
}
|
||||
@ -639,7 +761,11 @@ int usb_hub_device_c::event_handler(int event, void *ptr, int port)
|
||||
}
|
||||
break;
|
||||
|
||||
// host controller events start here
|
||||
// "host controller" events start here
|
||||
case USB_EVENT_DEFAULT_SPEED:
|
||||
// return default speed for specified port
|
||||
return USB_SPEED_FULL;
|
||||
|
||||
case USB_EVENT_CHECK_SPEED:
|
||||
if (ptr != NULL) {
|
||||
usb_device_c *usb_device = (usb_device_c *) ptr;
|
||||
@ -706,6 +832,7 @@ bool usb_hub_device_c::usb_set_connect_status(Bit8u port, bool connected)
|
||||
hub.usb_port[port].PortStatus &= ~PORT_STAT_ENABLE;
|
||||
hub.usb_port[port].PortChange |= PORT_STAT_C_ENABLE;
|
||||
}
|
||||
hub.usb_port[port].PortStatus &= ~PORT_STAT_SUSPEND;
|
||||
remove_device(port);
|
||||
}
|
||||
}
|
||||
@ -720,13 +847,17 @@ void usb_hub_device_c::runtime_config()
|
||||
for (i = 0; i < hub.n_ports; i++) {
|
||||
// device change support
|
||||
if ((hub.device_change & (1 << i)) != 0) {
|
||||
if ((hub.usb_port[i].PortStatus & PORT_STAT_CONNECTION) == 0) {
|
||||
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_POWER) {
|
||||
if ((hub.usb_port[i].PortStatus & PORT_STAT_CONNECTION) == 0) {
|
||||
sprintf(pname, "port%d", i + 1);
|
||||
init_device(i, (bx_list_c *) SIM->get_param(pname, hub.config));
|
||||
} else {
|
||||
usb_set_connect_status(i, 0);
|
||||
}
|
||||
hub.device_change &= ~(1 << i);
|
||||
} else {
|
||||
usb_set_connect_status(i, 0);
|
||||
}
|
||||
hub.device_change &= ~(1 << i);
|
||||
}
|
||||
// forward to connected device
|
||||
if (hub.usb_port[i].device != NULL) {
|
||||
@ -798,7 +929,9 @@ Bit64s usb_hub_device_c::hub_param_oc_handler(bx_param_c *param, bool set, Bit64
|
||||
hub = (usb_hub_device_c *) (port->get_parent()->get_device_param());
|
||||
if (hub != NULL) {
|
||||
portnum = atoi(port->get_name()+4) - 1;
|
||||
#if USB_HUB_POWER_SWITCHING
|
||||
hub->hub.usb_port[portnum].PortStatus &= ~PORT_STAT_POWER;
|
||||
#endif
|
||||
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));
|
||||
|
@ -30,7 +30,7 @@
|
||||
#define BX_IODEV_USB_HUB_H
|
||||
|
||||
|
||||
#define USB_HUB_MAX_PORTS 8
|
||||
#define USB_HUB_MAX_PORTS 8 // must be at least 2 and less than 16
|
||||
#define USB_HUB_DEF_PORTS 4
|
||||
|
||||
class usb_hub_device_c : public usb_device_c {
|
||||
@ -67,6 +67,7 @@ private:
|
||||
Bit16u PortStatus;
|
||||
Bit16u PortChange;
|
||||
} usb_port[USB_HUB_MAX_PORTS];
|
||||
Bit16u PortStatusC;
|
||||
Bit16u device_change;
|
||||
} hub;
|
||||
|
||||
|
@ -98,14 +98,17 @@ struct usb_msd_csw {
|
||||
// to match your changes.
|
||||
|
||||
// Full-speed
|
||||
// For full-speed devices, we set the bcdUSB to 1.1 so that an emulated host
|
||||
// won't try to send the USB_DT_DEVICE_QUALIFIER or USB_DT_OTHER_SPEED_CONFIG
|
||||
// requests.
|
||||
static const Bit8u bx_msd_dev_descriptor[] = {
|
||||
0x12, /* u8 bLength; */
|
||||
0x01, /* u8 bDescriptorType; Device */
|
||||
0x00, 0x02, /* u16 bcdUSB; v2.0 */
|
||||
0x01, 0x01, /* u16 bcdUSB; v1.1 */
|
||||
|
||||
0x00, /* u8 bDeviceClass; */
|
||||
0x00, /* u8 bDeviceSubClass; */
|
||||
0x00, /* u8 bDeviceProtocol; [ low/full speeds only ] */
|
||||
0x00, /* u8 bDeviceProtocol; */
|
||||
0x40, /* u8 bMaxPacketSize; 64 Bytes */
|
||||
|
||||
/* Vendor and product id are arbitrary. */
|
||||
@ -172,7 +175,7 @@ static const Bit8u bx_msd_dev_descriptor2[] = {
|
||||
|
||||
0x00, /* u8 bDeviceClass; */
|
||||
0x00, /* u8 bDeviceSubClass; */
|
||||
0x00, /* u8 bDeviceProtocol; [ low/full speeds only ] */
|
||||
0x00, /* u8 bDeviceProtocol; */
|
||||
0x40, /* u8 bMaxPacketSize; 64 Bytes */
|
||||
|
||||
/* Vendor and product id are arbitrary. */
|
||||
@ -841,6 +844,25 @@ int usb_msd_device_c::handle_control(int request, int value, int index, int leng
|
||||
}
|
||||
ret = 0;
|
||||
break;
|
||||
case EndpointRequest | USB_REQ_GET_STATUS:
|
||||
BX_DEBUG(("USB_REQ_GET_STATUS: Endpoint."));
|
||||
// if the endpoint is currently halted, return bit 0 = 1
|
||||
if (value == USB_ENDPOINT_HALT) {
|
||||
int indx = (index & 0x7F);
|
||||
int limit = (get_aIface() == MSD_PROTO_BBB) ? MSD_BBB_DATAOUT_EP : MSD_UASP_DATAOUT;
|
||||
if ((indx > 0) && (indx <= limit)) {
|
||||
data[0] = 0x00 | (get_halted(index) ? 1 : 0);
|
||||
data[1] = 0x00;
|
||||
ret = 2;
|
||||
} else {
|
||||
BX_ERROR(("EndpointRequest | USB_REQ_GET_STATUS: index > ep count: %d", index));
|
||||
goto fail;
|
||||
}
|
||||
} else {
|
||||
BX_ERROR(("EndpointRequest | USB_REQ_SET_FEATURE: Unknown Get Status Request found: %d", value));
|
||||
goto fail;
|
||||
}
|
||||
break;
|
||||
case DeviceRequest | USB_REQ_GET_DESCRIPTOR:
|
||||
switch (value >> 8) {
|
||||
case USB_DT_STRING:
|
||||
@ -868,8 +890,13 @@ int usb_msd_device_c::handle_control(int request, int value, int index, int leng
|
||||
if (d.speed == USB_SPEED_HIGH) {
|
||||
data[0] = 10; // 10 bytes long
|
||||
data[1] = USB_DT_DEVICE_QUALIFIER;
|
||||
memcpy(data + 2, bx_msd_dev_descriptor + 2, 6);
|
||||
data[8] = 1; // bNumConfigurations
|
||||
data[2] = 0x00; // version 2.00
|
||||
data[3] = 0x02; //
|
||||
data[4] = bx_msd_dev_descriptor[4]; // class code
|
||||
data[5] = bx_msd_dev_descriptor[5]; // subclass code
|
||||
data[6] = bx_msd_dev_descriptor[6]; // protocol
|
||||
data[7] = bx_msd_dev_descriptor[7]; // max packed size
|
||||
data[8] = 1; // bNumConfigurations (number of other-speed configurations)
|
||||
data[9] = 0; // reserved
|
||||
ret = 10; // return a 10-byte descriptor
|
||||
} else if (d.speed == USB_SPEED_FULL) {
|
||||
@ -890,6 +917,21 @@ int usb_msd_device_c::handle_control(int request, int value, int index, int leng
|
||||
goto fail;
|
||||
}
|
||||
break;
|
||||
case USB_DT_OTHER_SPEED_CONFIG:
|
||||
BX_DEBUG(("USB_REQ_GET_DESCRIPTOR: Other Speed Configuration"));
|
||||
if (get_speed() == USB_SPEED_HIGH) {
|
||||
ret = * (Bit16u *) &bx_msd_config_descriptor[2];
|
||||
memcpy(data, bx_msd_config_descriptor, ret);
|
||||
data[1] = USB_DT_OTHER_SPEED_CONFIG;
|
||||
} else if (get_speed() == USB_SPEED_FULL) {
|
||||
ret = * (Bit16u *) &bx_msd_config_descriptor2[2];
|
||||
memcpy(data, bx_msd_config_descriptor2, ret);
|
||||
data[1] = USB_DT_OTHER_SPEED_CONFIG;
|
||||
} else {
|
||||
BX_ERROR(("USB_REQ_GET_DESCRIPTOR: Other Speed Configuration: Valid on high- or full-speed only."));
|
||||
goto fail;
|
||||
}
|
||||
break;
|
||||
case USB_DT_BIN_DEV_OBJ_STORE:
|
||||
BX_DEBUG(("USB_REQ_GET_DESCRIPTOR: BOS"));
|
||||
// only devices with a version of 0x0210 or higher are allowed to request this descriptor.
|
||||
@ -909,19 +951,6 @@ int usb_msd_device_c::handle_control(int request, int value, int index, int leng
|
||||
goto fail;
|
||||
}
|
||||
break;
|
||||
case EndpointOutRequest | USB_REQ_CLEAR_FEATURE:
|
||||
BX_DEBUG(("USB_REQ_CLEAR_FEATURE:"));
|
||||
// Value == 0 == Endpoint Halt (the Guest wants to reset the endpoint)
|
||||
if (value == 0) { /* clear ep halt */
|
||||
#if HANDLE_TOGGLE_CONTROL
|
||||
set_toggle(index, 0);
|
||||
#endif
|
||||
ret = 0;
|
||||
} else {
|
||||
BX_ERROR(("Bad value for clear feature: %d", value));
|
||||
goto fail;
|
||||
}
|
||||
break;
|
||||
case DeviceOutRequest | USB_REQ_SET_SEL:
|
||||
// Set U1 and U2 System Exit Latency
|
||||
BX_DEBUG(("SET_SEL (U1 and U2):"));
|
||||
@ -986,7 +1015,6 @@ void usb_msd_device_c::handle_iface_change(int iface)
|
||||
} else {
|
||||
BX_ERROR(("Unknown interface number: %d", iface));
|
||||
}
|
||||
// ben
|
||||
} else if (d.speed == USB_SPEED_HIGH) {
|
||||
d.endpoint_info[USB_CONTROL_EP].max_packet_size = 64; // Control ep0
|
||||
d.endpoint_info[USB_CONTROL_EP].max_burst_size = 0;
|
||||
|
@ -68,7 +68,7 @@ static const Bit8u bx_printer_dev_descriptor[] = {
|
||||
|
||||
0x00, /* u8 bDeviceClass; */
|
||||
0x00, /* u8 bDeviceSubClass; */
|
||||
0x00, /* u8 bDeviceProtocol; [ low/full speeds only ] */
|
||||
0x00, /* u8 bDeviceProtocol; */
|
||||
0x40, /* u8 bMaxPacketSize; 64 Bytes */
|
||||
|
||||
0xF0, 0x03, /* u16 idVendor; */
|
||||
@ -255,6 +255,24 @@ int usb_printer_device_c::handle_control(int request, int value, int index, int
|
||||
case DeviceOutRequest | USB_REQ_SET_FEATURE:
|
||||
goto fail;
|
||||
break;
|
||||
case EndpointRequest | USB_REQ_GET_STATUS:
|
||||
BX_DEBUG(("USB_REQ_GET_STATUS: Endpoint."));
|
||||
// if the endpoint is currently halted, return bit 0 = 1
|
||||
if (value == USB_ENDPOINT_HALT) {
|
||||
int indx = (index & 0x7F);
|
||||
if ((indx >= 1) && (indx <= 2)) {
|
||||
data[0] = 0x00 | (get_halted(indx) ? 1 : 0);
|
||||
data[1] = 0x00;
|
||||
ret = 2;
|
||||
} else {
|
||||
BX_ERROR(("EndpointRequest | USB_REQ_GET_STATUS: index > ep count: %d", index));
|
||||
goto fail;
|
||||
}
|
||||
} else {
|
||||
BX_ERROR(("EndpointRequest | USB_REQ_SET_FEATURE: Unknown Get Status Request found: %d", value));
|
||||
goto fail;
|
||||
}
|
||||
break;
|
||||
case DeviceRequest | USB_REQ_GET_DESCRIPTOR:
|
||||
switch(value >> 8) {
|
||||
case USB_DT_STRING:
|
||||
|
Loading…
x
Reference in New Issue
Block a user