xbox.cpp: more usb, interrupt transfers (nw)

This commit is contained in:
yz70s 2016-04-16 11:18:09 +02:00
parent 6bb33aa52c
commit 070fa52fdc
2 changed files with 223 additions and 19 deletions

View File

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

View File

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