From 070fa52fdc18fe20b494ddde65e4d31f9a2894d0 Mon Sep 17 00:00:00 2001 From: yz70s Date: Sat, 16 Apr 2016 11:18:09 +0200 Subject: [PATCH] xbox.cpp: more usb, interrupt transfers (nw) --- src/mame/includes/xbox.h | 3 + src/mame/machine/xbox.cpp | 239 +++++++++++++++++++++++++++++++++++--- 2 files changed, 223 insertions(+), 19 deletions(-) diff --git a/src/mame/includes/xbox.h b/src/mame/includes/xbox.h index 5d11a86043d..94f6ced7eb9 100644 --- a/src/mame/includes/xbox.h +++ b/src/mame/includes/xbox.h @@ -314,6 +314,8 @@ protected: virtual int handle_synch_frame_request(int endpoint, USBSetupPacket *setup) { return 0; }; virtual void handle_status_stage(int endpoint) { return; }; virtual int handle_bulk_pid(int endpoint, int pid, UINT8 *buffer, int size) { return 0; }; + virtual int handle_interrupt_pid(int endpoint, int pid, UINT8 *buffer, int size) { return 0; }; + virtual int handle_isochronous_pid(int endpoint, int pid, UINT8 *buffer, int size) { return 0; }; void add_device_descriptor(const USBStandardDeviceDescriptor &descriptor); void add_configuration_descriptor(const USBStandardConfigurationDescriptor &descriptor); @@ -357,6 +359,7 @@ class ohci_game_controller_device : public ohci_function_device public: ohci_game_controller_device(running_machine &machine, xbox_base_state *usb_bus_manager); int handle_nonstandard_request(int endpoint, USBSetupPacket *setup) override; + int handle_interrupt_pid(int endpoint, int pid, UINT8 *buffer, int size) override; private: static const USBStandardDeviceDescriptor devdesc; static const USBStandardConfigurationDescriptor condesc; diff --git a/src/mame/machine/xbox.cpp b/src/mame/machine/xbox.cpp index 96d2a688326..cd4ce8abba1 100644 --- a/src/mame/machine/xbox.cpp +++ b/src/mame/machine/xbox.cpp @@ -677,6 +677,7 @@ WRITE32_MEMBER(xbox_base_state::usbctrl_w) TIMER_CALLBACK_MEMBER(xbox_base_state::usb_ohci_timer) { UINT32 hcca; + UINT32 plh; int changed = 0; int list = 1; bool cont = false; @@ -709,8 +710,163 @@ TIMER_CALLBACK_MEMBER(xbox_base_state::usb_ohci_timer) if (list == 0) { if (ohcist.hc_regs[HcControl] & PLE) { // periodic list - if (ohcist.hc_regs[HcControl] & IE) { - // isochronous list + plh=ohcist.space->read_dword(hcca + (ohcist.framenumber & 0x1f) * 4); + cont = true; + while (cont == true) { + if (plh != 0) { + usb_ohci_read_endpoint_descriptor(plh); + // if this an isochronous endpoint and isochronous list not enabled, stop list processing + if (((ohcist.hc_regs[HcControl] & IE) == 0) && (ohcist.endpoint_descriptor.f == 1)) + cont = false; + } + else + cont = false; + if (cont == false) + break; + // service endpoint descriptor + // only if it is not halted and not to be skipped + if (!(ohcist.endpoint_descriptor.h | ohcist.endpoint_descriptor.k)) { + // compare the Endpoint Descriptor TailPointer and NextTransferDescriptor fields. + if (ohcist.endpoint_descriptor.headp != ohcist.endpoint_descriptor.tailp) { + UINT32 a, b; + int R = 0; + + // service transfer descriptor + if (ohcist.endpoint_descriptor.f != 1) { + usb_ohci_read_transfer_descriptor(ohcist.endpoint_descriptor.headp); + // get pid + if (ohcist.endpoint_descriptor.d == 1) + pid = OutPid; // out + else if (ohcist.endpoint_descriptor.d == 2) + pid = InPid; // in + else { + pid = ohcist.transfer_descriptor.dp; // 0 setup 1 out 2 in + } + a = ohcist.transfer_descriptor.be; + b = ohcist.transfer_descriptor.cbp; + } + else { + usb_ohci_read_isochronous_transfer_descriptor(ohcist.endpoint_descriptor.headp); + // get pid + if (ohcist.endpoint_descriptor.d == 1) + pid = OutPid; // out + else if (ohcist.endpoint_descriptor.d == 2) + pid = InPid; // in + else + pid = InPid; // in + R = (int)ohcist.framenumber - (int)ohcist.isochronous_transfer_descriptor.sf; + //if ((R < 0) || (R > (int)ohcist.isochronous_transfer_descriptor.fc)) + // ; // greater than fc should be an error + if (R == (int)ohcist.isochronous_transfer_descriptor.fc) + a = ohcist.isochronous_transfer_descriptor.be; + else { + a = ohcist.isochronous_transfer_descriptor.offset[R + 1] - 1; + if (a & (1 << 12)) + a = (ohcist.isochronous_transfer_descriptor.be & 0xfffff000) | (a & 0xfff); + else + a = ohcist.isochronous_transfer_descriptor.bp0 | (a & 0xfff); + } + b=ohcist.isochronous_transfer_descriptor.offset[R]; + if (b & (1 << 12)) + b = (ohcist.isochronous_transfer_descriptor.be & 0xfffff000) | (b & 0xfff); + else + b = ohcist.isochronous_transfer_descriptor.bp0 | (b & 0xfff); + } + if ((a ^ b) & 0xfffff000) + remain = ((a | 0x1000) & 0x1fff) - (b & 0xfff) + 1; + else + remain = a - b + 1; + mps = ohcist.endpoint_descriptor.mps; + if (remain < mps) + mps = remain; + // if sending ... + if (pid != InPid) { + // ... get mps bytes + for (int c = 0; c < remain; c++) { + ohcist.buffer[c] = ohcist.space->read_byte(b); + b++; + if ((b & 0xfff) == 0) + b = ohcist.transfer_descriptor.be & 0xfffff000; + } + } + // should check for time available + // execute transaction + done = ohcist.address[ohcist.endpoint_descriptor.fa].function->execute_transfer(ohcist.endpoint_descriptor.en, pid, ohcist.buffer, mps); + // if receiving ... + if (pid == InPid) { + // ... store done bytes + for (int c = 0; c < done; c++) { + ohcist.space->write_byte(b, ohcist.buffer[c]); + b++; + if ((b & 0xfff) == 0) + b = a & 0xfffff000; + } + } + if (ohcist.endpoint_descriptor.f != 1) { + // status writeback (CompletionCode field, DataToggleControl field, CurrentBufferPointer field, ErrorCount field) + ohcist.transfer_descriptor.cc = NoError; + ohcist.transfer_descriptor.t = (ohcist.transfer_descriptor.t ^ 1) | 2; + // if all data is transferred (or there was no data to transfer) cbp must be 0, otherwise it must be updated + if (done == remain) + b = 0; + ohcist.transfer_descriptor.cbp = b; + ohcist.transfer_descriptor.ec = 0; + retire = false; + if ((done == mps) && (done == remain)) { + retire = true; + } + if ((done != mps) && (done <= remain)) + retire = true; + if (done == 0) + retire = true; + if (retire == true) { + // retire transfer descriptor + a = ohcist.endpoint_descriptor.headp; + ohcist.endpoint_descriptor.headp = ohcist.transfer_descriptor.nexttd; + ohcist.transfer_descriptor.nexttd = ohcist.hc_regs[HcDoneHead]; + ohcist.hc_regs[HcDoneHead] = a; + ohcist.endpoint_descriptor.c = ohcist.transfer_descriptor.t & 1; + if (ohcist.transfer_descriptor.di != 7) { + if (ohcist.transfer_descriptor.di < ohcist.writebackdonehadcounter) + ohcist.writebackdonehadcounter = ohcist.transfer_descriptor.di; + } + usb_ohci_writeback_transfer_descriptor(a); + usb_ohci_writeback_endpoint_descriptor(plh); + } + else { + usb_ohci_writeback_transfer_descriptor(ohcist.endpoint_descriptor.headp); + } + } else + { + // status writeback + ohcist.isochronous_transfer_descriptor.cc = NoError; + if (done == remain) + b = 0; + ohcist.isochronous_transfer_descriptor.offset[R] = b; + retire = false; + if ((done == mps) && (done == remain)) { + retire = true; + } + if ((done != mps) && (done <= remain)) + retire = true; + if (done == 0) + retire = true; + if (retire == true) { + // retire transfer descriptor + } + else { + usb_ohci_writeback_isochronous_transfer_descriptor(ohcist.endpoint_descriptor.headp); + } + } + } + } + // go to next endpoint + if (ohcist.endpoint_descriptor.nexted != 0) + { + plh = ohcist.endpoint_descriptor.nexted; + } + else + cont = false; } } list = -1; @@ -789,7 +945,7 @@ TIMER_CALLBACK_MEMBER(xbox_base_state::usb_ohci_timer) } } // should check for time available - // execute transaction ohcist.endpoint_descriptor.fa + // execute transaction done = ohcist.address[ohcist.endpoint_descriptor.fa].function->execute_transfer(ohcist.endpoint_descriptor.en, pid, ohcist.buffer, mps); // if receiving ... if (pid == InPid) { @@ -905,10 +1061,6 @@ TIMER_CALLBACK_MEMBER(xbox_base_state::usb_ohci_timer) mps = ohcist.endpoint_descriptor.mps; if (remain < mps) mps = remain; - if (ohcist.transfer_descriptor.cbp == 0) { - remain = 0; - mps = 0; - } b = ohcist.transfer_descriptor.cbp; // if sending ... if (pid != InPid) { @@ -921,7 +1073,7 @@ TIMER_CALLBACK_MEMBER(xbox_base_state::usb_ohci_timer) } } // should check for time available - // execute transaction ohcist.endpoint_descriptor.fa + // execute transaction done = ohcist.address[ohcist.endpoint_descriptor.fa].function->execute_transfer(ohcist.endpoint_descriptor.en, pid, ohcist.buffer, mps); // if receiving ... if (pid == InPid) { @@ -981,7 +1133,7 @@ TIMER_CALLBACK_MEMBER(xbox_base_state::usb_ohci_timer) if ((ohcist.hc_regs[HcCommandStatus] & (1 << 1)) && (ohcist.hc_regs[HcControl] & CLE)) list = 1; // go to control list if enabled and filled else if ((ohcist.hc_regs[HcCommandStatus] & (1 << 2)) && (ohcist.hc_regs[HcControl] & BLE)) - list = 2; // otherwise stai in bulk list if enabled and filled + list = 2; // otherwise stay in bulk list if enabled and filled else list = 0; // if no control or bulk lists, go to periodic list } @@ -1445,11 +1597,15 @@ int ohci_function_device::execute_transfer(int endpoint, int pid, UINT8 *buffer, } else if (endpoints[endpoint].type == BulkEndpoint) return handle_bulk_pid(endpoint, pid, buffer, size); + else if (endpoints[endpoint].type == InterruptEndpoint) + return handle_interrupt_pid(endpoint, pid, buffer, size); + else if (endpoints[endpoint].type == IsochronousEndpoint) + return handle_isochronous_pid(endpoint, pid, buffer, size); else return -1; } else if (pid == OutPid) { - if (endpoints[endpoint].type == ControlEndpoint) { //if (endpoint == 0) { + if (endpoints[endpoint].type == ControlEndpoint) { // case ==1, nothing // case ==0, give data // if host->device, since OutPid then this is data stage @@ -1470,6 +1626,10 @@ int ohci_function_device::execute_transfer(int endpoint, int pid, UINT8 *buffer, } else if (endpoints[endpoint].type == BulkEndpoint) return handle_bulk_pid(endpoint, pid, buffer, size); + else if (endpoints[endpoint].type == InterruptEndpoint) + return handle_interrupt_pid(endpoint, pid, buffer, size); + else if (endpoints[endpoint].type == IsochronousEndpoint) + return handle_isochronous_pid(endpoint, pid, buffer, size); else return -1; } @@ -1494,23 +1654,64 @@ ohci_game_controller_device::ohci_game_controller_device(running_machine &machin int ohci_game_controller_device::handle_nonstandard_request(int endpoint, USBSetupPacket *setup) { - // >=8 ==42 !=0 !=0 1,3 2<20 <=20 - static const UINT8 mytestdata[16] = { 0x10,0x42 ,0x32,0x43,1 ,0x65,0x18,0x20,0x98,0xa9,0xba,0xcb,0xdc,0xed,0xfe }; + // >=8 ==42 !=0 !=0 1,3 2<20 <=20 + static const UINT8 mytestdata1[16] = { 0x10,0x42 ,0x32,0x43,1 ,0x65,0x18,0x20,0x98,0xa9,0xba,0xcb,0xdc,0xed,0xfe }; if (endpoint != 0) return -1; if ((endpoints[endpoint].controltype == VendorType) && (endpoints[endpoint].controlrecipient == InterfaceRecipient)) { - if (setup->bRequest == GET_DESCRIPTOR) + if ((setup->bRequest == GET_DESCRIPTOR) && (setup->wValue == 0x4200)) { - if (setup->wValue == 0x4200) - { - endpoints[endpoint].position = (UINT8 *)mytestdata; - endpoints[endpoint].remain = 16; - return 0; - } + endpoints[endpoint].position = (UINT8 *)mytestdata1; + endpoints[endpoint].remain = 16; + return 0; } } + if ((endpoints[endpoint].controltype == ClassType) && (endpoints[endpoint].controlrecipient == InterfaceRecipient)) + { + if ((setup->bRequest == 1) && (setup->wValue == 0x0100)) + { + endpoints[endpoint].position = endpoints[endpoint].buffer; + endpoints[endpoint].remain = setup->wLength; + for (int n = 0; n < setup->wLength; n++) + endpoints[endpoint].buffer[n] = 0x10 ^ n; + endpoints[endpoint].buffer[2] = 0; + return 0; + } + } + if ((endpoints[endpoint].controltype == VendorType) && (endpoints[endpoint].controlrecipient == InterfaceRecipient)) + { + if ((setup->bRequest == 1) && (setup->wValue == 0x0200)) + { + endpoints[endpoint].position = endpoints[endpoint].buffer; + endpoints[endpoint].remain = setup->wLength; + for (int n = 0; n < setup->wLength; n++) + endpoints[endpoint].buffer[n] = 0x20 ^ n; + return 0; + } + } + if ((endpoints[endpoint].controltype == VendorType) && (endpoints[endpoint].controlrecipient == InterfaceRecipient)) + { + if ((setup->bRequest == 1) && (setup->wValue == 0x0100)) + { + endpoints[endpoint].position = endpoints[endpoint].buffer; + endpoints[endpoint].remain = setup->wLength; + for (int n = 0; n < setup->wLength; n++) + endpoints[endpoint].buffer[n] = 0x30 ^ n; + return 0; + } + } + return -1; +} + +int ohci_game_controller_device::handle_interrupt_pid(int endpoint, int pid, UINT8 *buffer, int size) +{ + if ((endpoint == 2) && (pid == InPid)) { + for (int n = 0; n < size; n++) + buffer[n] = n; + return size; + } return -1; }