diff options
author | yz70s <yz70s@users.noreply.github.com> | 2016-02-27 09:59:40 +0100 |
---|---|---|
committer | yz70s <yz70s@users.noreply.github.com> | 2016-03-07 22:17:58 +0100 |
commit | d9a00119f4df57e7845524dfcbd3408ab58d9173 (patch) | |
tree | 827a5a5f847be3e99dafa576e07469e63adbfb25 | |
parent | b61b025eab66d07488f10ba3b932d92d1476ba37 (diff) |
xbox.cpp: more usb (nw)
-rw-r--r-- | src/mame/includes/xbox.h | 68 | ||||
-rw-r--r-- | src/mame/machine/xbox.cpp | 313 |
2 files changed, 310 insertions, 71 deletions
diff --git a/src/mame/includes/xbox.h b/src/mame/includes/xbox.h index 8094ac33100..045d7504700 100644 --- a/src/mame/includes/xbox.h +++ b/src/mame/includes/xbox.h @@ -1,6 +1,8 @@ // license:BSD-3-Clause // copyright-holders:Samuele Zannoli +#include <forward_list> + struct OHCIEndpointDescriptor { int mps; // MaximumPacketSize int f; // Format @@ -211,29 +213,79 @@ enum USBDeviceState ConfiguredState }; +enum USBControlDirection +{ + HostToDevice=0, + DeviceToHost=1 +}; + +enum USBEndpointType +{ + ControlEndpoint=0, + IsochronousEndpoint, + BulkEndpoint, + InterruptEndpoint +}; + +struct usb_device_interface_alternate +{ + USBStandardInterfaceDescriptor interface_descriptor; + std::forward_list<USBStandardEndpointDescriptor> endpoint_descriptors; +}; + +struct usb_device_interface +{ + std::forward_list<usb_device_interface_alternate> alternate_settings; + int selected_alternate; +}; + +struct usb_device_configuration +{ + USBStandardConfigurationDescriptor configuration_descriptor; + std::forward_list<usb_device_interface> interfaces; +}; + class ohci_function_device { public: ohci_function_device(running_machine &machine); void execute_reset(); int execute_transfer(int address, int endpoint, int pid, UINT8 *buffer, int size); +protected: + int handle_nonstandard_request(int endpoint, USBSetupPacket *setup); + virtual int handle_get_status_request(int endpoint, USBSetupPacket *setup) = 0; + virtual int handle_clear_feature_request(int endpoint, USBSetupPacket *setup) = 0; + virtual int handle_set_feature_request(int endpoint, USBSetupPacket *setup) = 0; + virtual int handle_set_descriptor_request(int endpoint, USBSetupPacket *setup) = 0; + virtual int handle_synch_frame_request(int endpoint, USBSetupPacket *setup) = 0; private: void add_device_descriptor(USBStandardDeviceDescriptor &descriptor); void add_configuration_descriptor(USBStandardConfigurationDescriptor &descriptor); void add_interface_descriptor(USBStandardInterfaceDescriptor &descriptor); void add_endpoint_descriptor(USBStandardEndpointDescriptor &descriptor); - int handle_nonstandard_request(USBSetupPacket *setup); + void select_configuration(int index); + void select_alternate(int interfacei, int index); + int find_alternate(int interfacei); + struct { + int type; + int controldirection; + int controltype; + int controlrecipient; + int remain; + UINT8 *position; + UINT8 buffer[4]; + } endpoints[256]; int state; - int address; + bool settingaddress; int newaddress; - int controldirection; - int controltype; - int controlrecipient; + int address; int configurationvalue; - bool settingaddress; - int remain; - UINT8 *position; UINT8 *descriptors; int descriptors_pos; + USBStandardDeviceDescriptor device_descriptor; + std::forward_list<usb_device_configuration> configurations; + usb_device_configuration *latest_configuration; + usb_device_interface_alternate *latest_alternate; + usb_device_configuration *selected_configuration; }; class xbox_base_state : public driver_device diff --git a/src/mame/machine/xbox.cpp b/src/mame/machine/xbox.cpp index 5748e09d469..2f8de78b4b4 100644 --- a/src/mame/machine/xbox.cpp +++ b/src/mame/machine/xbox.cpp @@ -846,13 +846,19 @@ ohci_function_device::ohci_function_device(running_machine &machine) descriptors_pos = 0; address = 0; newaddress = 0; - controldirection = 0; - controltype = 0; - controlrecipient = 0; - configurationvalue = 0; - remain = 0; - position = nullptr; + for (int e = 0; e < 256;e++) { + endpoints[e].type = -1; + endpoints[e].controldirection = 0; + endpoints[e].controltype = 0; + endpoints[e].controlrecipient = 0; + endpoints[e].remain = 0; + endpoints[e].position = nullptr; + } + endpoints[0].type = ControlEndpoint; settingaddress = false; + configurationvalue = 0; + latest_configuration = nullptr; + latest_alternate = nullptr; add_device_descriptor(devdesc); add_configuration_descriptor(condesc); add_interface_descriptor(intdesc); @@ -862,26 +868,175 @@ ohci_function_device::ohci_function_device(running_machine &machine) void ohci_function_device::add_device_descriptor(USBStandardDeviceDescriptor &descriptor) { - memcpy(descriptors + descriptors_pos, &descriptor, sizeof(descriptor)); + UINT8 *p = descriptors + descriptors_pos; + + p[0] = descriptor.bLength; + p[1] = descriptor.bDescriptorType; + p[2] = descriptor.bcdUSB & 255; + p[3] = descriptor.bcdUSB >> 8; + p[4] = descriptor.bDeviceClass; + p[5] = descriptor.bDeviceSubClass; + p[6] = descriptor.bDeviceProtocol; + p[7] = descriptor.bMaxPacketSize0; + p[8] = descriptor.idVendor & 255; + p[9] = descriptor.idVendor >> 8; + p[10] = descriptor.idProduct & 255; + p[11] = descriptor.idProduct >> 8; + p[12] = descriptor.bcdDevice & 255; + p[13] = descriptor.bcdDevice >> 8; + p[14] = descriptor.iManufacturer; + p[15] = descriptor.iProduct; + p[16] = descriptor.iSerialNumber; + p[17] = descriptor.bNumConfigurations; descriptors_pos += descriptor.bLength; + memcpy(&device_descriptor, &descriptor, sizeof(USBStandardDeviceDescriptor)); } void ohci_function_device::add_configuration_descriptor(USBStandardConfigurationDescriptor &descriptor) { - memcpy(descriptors + descriptors_pos, &descriptor, sizeof(descriptor)); + usb_device_configuration *c = new usb_device_configuration; + UINT8 *p = descriptors + descriptors_pos; + + p[0] = descriptor.bLength; + p[1] = descriptor.bDescriptorType; + p[2] = descriptor.wTotalLength & 255; + p[3] = descriptor.wTotalLength >> 8; + p[4] = descriptor.bNumInterfaces; + p[5] = descriptor.bConfigurationValue; + p[6] = descriptor.iConfiguration; + p[7] = descriptor.bmAttributes; + p[8] = descriptor.MaxPower; descriptors_pos += descriptor.bLength; + memcpy(&c->configuration_descriptor, &descriptor, sizeof(USBStandardConfigurationDescriptor)); + configurations.push_front(*c); + latest_configuration = c; + latest_alternate = nullptr; } void ohci_function_device::add_interface_descriptor(USBStandardInterfaceDescriptor &descriptor) { - memcpy(descriptors + descriptors_pos, &descriptor, sizeof(descriptor)); + usb_device_interface *ii; + usb_device_interface_alternate *aa; + UINT8 *p = descriptors + descriptors_pos; + + if (latest_configuration == nullptr) + return; + p[0] = descriptor.bLength; + p[1] = descriptor.bDescriptorType; + p[2] = descriptor.bInterfaceNumber; + p[3] = descriptor.bAlternateSetting; + p[4] = descriptor.bNumEndpoints; + p[5] = descriptor.bInterfaceClass; + p[6] = descriptor.bInterfaceSubClass; + p[7] = descriptor.bInterfaceProtocol; + p[8] = descriptor.iInterface; descriptors_pos += descriptor.bLength; + for (auto i = latest_configuration->interfaces.begin(); i != latest_configuration->interfaces.end(); ++i) + { + if (i->alternate_settings.front().interface_descriptor.bInterfaceNumber == descriptor.bInterfaceNumber) + { + aa = new usb_device_interface_alternate; + memcpy(&aa->interface_descriptor, &descriptor, sizeof(USBStandardInterfaceDescriptor)); + i->alternate_settings.push_front(*aa); + latest_alternate = aa; + return; + } + } + ii = new usb_device_interface; + aa = new usb_device_interface_alternate; + memcpy(&aa->interface_descriptor, &descriptor, sizeof(USBStandardInterfaceDescriptor)); + ii->selected_alternate = -1; + ii->alternate_settings.push_front(*aa); + latest_alternate = aa; + latest_configuration->interfaces.push_front(*ii); } void ohci_function_device::add_endpoint_descriptor(USBStandardEndpointDescriptor &descriptor) { - memcpy(descriptors + descriptors_pos, &descriptor, sizeof(descriptor)); + UINT8 *p = descriptors + descriptors_pos; + + if (latest_alternate == nullptr) + return; + p[0] = descriptor.bLength; + p[1] = descriptor.bDescriptorType; + p[2] = descriptor.bEndpointAddress; + p[3] = descriptor.bmAttributes; + p[4] = descriptor.wMaxPacketSize & 255; + p[5] = descriptor.wMaxPacketSize >> 8; + p[6] = descriptor.bInterval; descriptors_pos += descriptor.bLength; + latest_alternate->endpoint_descriptors.push_front(descriptor); +} + +void ohci_function_device::select_configuration(int index) +{ + configurationvalue = index; + for (auto c = configurations.begin(); c != configurations.end(); ++c) + { + if (c->configuration_descriptor.bConfigurationValue == index) + { + selected_configuration = &(*c); + for (auto i = c->interfaces.begin(); i != c->interfaces.end(); ++i) + { + i->selected_alternate = 0; + for (auto a = i->alternate_settings.begin(); a != i->alternate_settings.end(); ++a) + { + if (a->interface_descriptor.bAlternateSetting == 0) + { + for (auto e = a->endpoint_descriptors.begin(); e != a->endpoint_descriptors.end(); ++e) + { + endpoints[e->bEndpointAddress].type = e->bmAttributes & 3; + endpoints[e->bEndpointAddress].remain = 0; + } + } + } + } + } + } +} + +void ohci_function_device::select_alternate(int interfacei, int index) +{ + for (auto i = selected_configuration->interfaces.begin(); i != selected_configuration->interfaces.end(); ++i) + { + for (auto a = i->alternate_settings.begin(); a != i->alternate_settings.end(); ++a) + { + if ((a->interface_descriptor.bInterfaceNumber == interfacei) && (a->interface_descriptor.bAlternateSetting == i->selected_alternate)) + { + for (auto e = a->endpoint_descriptors.begin(); e != a->endpoint_descriptors.end(); ++e) + { + endpoints[e->bEndpointAddress].type = -1; + } + } + } + for (auto a = i->alternate_settings.begin(); a != i->alternate_settings.end(); ++a) + { + if ((a->interface_descriptor.bInterfaceNumber == interfacei) && (a->interface_descriptor.bAlternateSetting == index)) + { + i->selected_alternate = index; + for (auto e = a->endpoint_descriptors.begin(); e != a->endpoint_descriptors.end(); ++e) + { + endpoints[e->bEndpointAddress].type = e->bmAttributes & 3; + endpoints[e->bEndpointAddress].remain = 0; + } + } + } + } +} + +int ohci_function_device::find_alternate(int interfacei) +{ + for (auto i = selected_configuration->interfaces.begin(); i != selected_configuration->interfaces.end(); ++i) + { + for (auto a = i->alternate_settings.begin(); a != i->alternate_settings.end(); ++a) + { + if (a->interface_descriptor.bInterfaceNumber == interfacei) + { + return i->selected_alternate; + } + } + } + return 0; } void ohci_function_device::execute_reset() @@ -894,25 +1049,30 @@ int ohci_function_device::execute_transfer(int address, int endpoint, int pid, U { int descriptortype;// descriptorindex; - if (endpoint == 0) { - if (pid == SetupPid) { - USBSetupPacket *p=(USBSetupPacket *)buffer; - // define direction 0:host->device 1:device->host - controldirection = (p->bmRequestType & 128) >> 7; - // case ==1, IN data stage and OUT status stage - // case ==0, OUT data stage and IN status stage - // data stage is optional, IN status stage - controltype = (p->bmRequestType & 0x60) >> 5; - controlrecipient = p->bmRequestType & 0x1f; - position = nullptr; + if (pid == SetupPid) { + USBSetupPacket *p=(USBSetupPacket *)buffer; + // define direction 0:host->device 1:device->host + // case == 1, IN data stage and OUT status stage + // case == 0, OUT data stage and IN status stage + // data stage is optional, IN status stage + endpoints[endpoint].controldirection = (p->bmRequestType & 128) >> 7; + endpoints[endpoint].controltype = (p->bmRequestType & 0x60) >> 5; + endpoints[endpoint].controlrecipient = p->bmRequestType & 0x1f; + if (endpoint == 0) { + endpoints[endpoint].position = nullptr; // number of byte to transfer in data stage (0 no data stage) - remain = p->wLength; + endpoints[endpoint].remain = p->wLength; // if standard device request - if ((controltype == StandardType) && (controlrecipient == DeviceRecipient)) { + if ((endpoints[endpoint].controltype == StandardType) && (endpoints[endpoint].controlrecipient == DeviceRecipient)) { switch (p->bRequest) { case GET_STATUS: + return handle_get_status_request(endpoint, p); + break; case CLEAR_FEATURE: + return handle_clear_feature_request(endpoint, p); + break; case SET_FEATURE: + return handle_set_feature_request(endpoint, p); break; case SET_ADDRESS: newaddress = p->wValue; @@ -922,52 +1082,74 @@ int ohci_function_device::execute_transfer(int address, int endpoint, int pid, U descriptortype = p->wValue >> 8; //descriptorindex = p->wValue & 255; if (descriptortype == DEVICE) { // device descriptor - position = descriptors; - remain = descriptors[0]; + endpoints[endpoint].position = descriptors; + endpoints[endpoint].remain = descriptors[0]; } else if (descriptortype == CONFIGURATION) { // configuration descriptor - position = descriptors + 18; - remain = descriptors[18+2]; + endpoints[endpoint].position = descriptors + 18; + endpoints[endpoint].remain = descriptors[18 + 2]; } else if (descriptortype == INTERFACE) { // interface descriptor - position = descriptors + 18 + 9; - remain = descriptors[18 + 9]; + endpoints[endpoint].position = descriptors + 18 + 9; + endpoints[endpoint].remain = descriptors[18 + 9]; } else if (descriptortype == ENDPOINT) { // endpoint descriptor - position = descriptors + 18 + 9 + 9; - remain = descriptors[18 + 9 + 9]; + endpoints[endpoint].position = descriptors + 18 + 9 + 9; + endpoints[endpoint].remain = descriptors[18 + 9 + 9]; } else - remain = 0; - if (remain > p->wLength) - remain = p->wLength; + endpoints[endpoint].remain = 0; + if (endpoints[endpoint].remain > p->wLength) + endpoints[endpoint].remain = p->wLength; break; case SET_CONFIGURATION: if (p->wValue == 0) state = AddressState; else { - configurationvalue = p->wValue; + select_configuration(p->wValue); state = ConfiguredState; } break; + case SET_INTERFACE: + select_alternate(p->wIndex, p->wValue); + break; case SET_DESCRIPTOR: + return handle_set_descriptor_request(endpoint, p); + break; case GET_CONFIGURATION: + endpoints[endpoint].buffer[0] = (UINT8)configurationvalue; + endpoints[endpoint].position = endpoints[endpoint].buffer; + endpoints[endpoint].remain = 1; + if (p->wLength == 0) + endpoints[endpoint].remain = 0; + break; case GET_INTERFACE: - case SET_INTERFACE: + endpoints[endpoint].buffer[0] = (UINT8)find_alternate(p->wIndex); + endpoints[endpoint].position = endpoints[endpoint].buffer; + endpoints[endpoint].remain = 1; + if (p->wLength == 0) + endpoints[endpoint].remain = 0; + break; case SYNCH_FRAME: + return handle_synch_frame_request(endpoint, p); default: + return handle_nonstandard_request(endpoint, p); break; } } else - return handle_nonstandard_request(p); + return handle_nonstandard_request(endpoint, p); size = 0; } - else if (pid == InPid) { + else + return handle_nonstandard_request(endpoint, p); + } + else if (pid == InPid) { + if (endpoint == 0) { // if no data has been transferred (except for the setup stage) // and the lenght of this IN transaction is 0 // assume this is the status stage - if ((size == 0) && (remain == 0)) { + if ((size == 0) && (endpoints[endpoint].remain == 0)) { if (settingaddress == true) { // set of address is active at end of status stage @@ -980,53 +1162,58 @@ int ohci_function_device::execute_transfer(int address, int endpoint, int pid, U // case ==1, give data // case ==0, nothing // if device->host - if (controldirection == 1) { + if (endpoints[endpoint].controldirection == DeviceToHost) { // data stage - if (size > remain) - size = remain; - if (position != nullptr) - memcpy(buffer, position, size); - position = position + size; - remain = remain - size; + if (size > endpoints[endpoint].remain) + size = endpoints[endpoint].remain; + if (endpoints[endpoint].position != nullptr) + memcpy(buffer, endpoints[endpoint].position, size); + endpoints[endpoint].position = endpoints[endpoint].position + size; + endpoints[endpoint].remain = endpoints[endpoint].remain - size; } } - else if (pid == OutPid) { + else + return -1; + } + else if (pid == OutPid) { + if (endpoint == 0) { // case ==1, nothing // case ==0, give data // if host->device - if (controldirection == 0) { + if (endpoints[endpoint].controldirection == HostToDevice) { // data stage - if (size > remain) - size = remain; - if (position != nullptr) - memcpy(position, buffer, size); - position = position + size; - remain = remain - size; + if (size > endpoints[endpoint].remain) + size = endpoints[endpoint].remain; + if (endpoints[endpoint].position != nullptr) + memcpy(endpoints[endpoint].position, buffer, size); + endpoints[endpoint].position = endpoints[endpoint].position + size; + endpoints[endpoint].remain = endpoints[endpoint].remain - size; } } + else + return -1; } - else - return -1; return size; } -int ohci_function_device::handle_nonstandard_request(USBSetupPacket *setup) +int ohci_function_device::handle_nonstandard_request(int endpoint, USBSetupPacket *setup) { // >=8 ==42 !=0 !=0 1,3 2<20 <=20 static UINT8 mytestdata[16] = { 0x10,0x42 ,0x32,0x43,1 ,0x65,0x18,0x20,0x98,0xa9,0xba,0xcb,0xdc,0xed,0xfe }; - if ((controltype == VendorType) && (controlrecipient == InterfaceRecipient)) + if ((endpoints[endpoint].controltype == VendorType) && (endpoints[endpoint].controlrecipient == InterfaceRecipient)) { if (setup->bRequest == GET_DESCRIPTOR) { if (setup->wValue == 0x4200) { - position = mytestdata; - remain = 16; + endpoints[endpoint].position = mytestdata; + endpoints[endpoint].remain = 16; + return 0; } } } - return 0; + return -1; } void xbox_base_state::usb_ohci_interrupts() @@ -1232,8 +1419,8 @@ WRITE32_MEMBER(xbox_base_state::audio_apu_w) return; } if (offset == 0x2037c / 4) { // value related to sample rate - INT16 v = (INT16)(data >> 16); // upper 16 bits as a signed 16 bit value - float vv = ((float)v) / 4096.0f; // divide by 4096 + INT16 v0 = (INT16)(data >> 16); // upper 16 bits as a signed 16 bit value + float vv = ((float)v0) / 4096.0f; // divide by 4096 float vvv = powf(2, vv); // two to the vv int f = vvv*48000.0f; // sample rate apust.voices_frequency[apust.voice_number] = f; |