mirror of
https://github.com/holub/mame
synced 2025-10-05 08:41:31 +03:00
xbox.cpp: more usb, interrupt transfers (nw)
This commit is contained in:
parent
6bb33aa52c
commit
070fa52fdc
@ -314,6 +314,8 @@ protected:
|
|||||||
virtual int handle_synch_frame_request(int endpoint, USBSetupPacket *setup) { return 0; };
|
virtual int handle_synch_frame_request(int endpoint, USBSetupPacket *setup) { return 0; };
|
||||||
virtual void handle_status_stage(int endpoint) { return; };
|
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_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_device_descriptor(const USBStandardDeviceDescriptor &descriptor);
|
||||||
void add_configuration_descriptor(const USBStandardConfigurationDescriptor &descriptor);
|
void add_configuration_descriptor(const USBStandardConfigurationDescriptor &descriptor);
|
||||||
@ -357,6 +359,7 @@ class ohci_game_controller_device : public ohci_function_device
|
|||||||
public:
|
public:
|
||||||
ohci_game_controller_device(running_machine &machine, xbox_base_state *usb_bus_manager);
|
ohci_game_controller_device(running_machine &machine, xbox_base_state *usb_bus_manager);
|
||||||
int handle_nonstandard_request(int endpoint, USBSetupPacket *setup) override;
|
int handle_nonstandard_request(int endpoint, USBSetupPacket *setup) override;
|
||||||
|
int handle_interrupt_pid(int endpoint, int pid, UINT8 *buffer, int size) override;
|
||||||
private:
|
private:
|
||||||
static const USBStandardDeviceDescriptor devdesc;
|
static const USBStandardDeviceDescriptor devdesc;
|
||||||
static const USBStandardConfigurationDescriptor condesc;
|
static const USBStandardConfigurationDescriptor condesc;
|
||||||
|
@ -677,6 +677,7 @@ WRITE32_MEMBER(xbox_base_state::usbctrl_w)
|
|||||||
TIMER_CALLBACK_MEMBER(xbox_base_state::usb_ohci_timer)
|
TIMER_CALLBACK_MEMBER(xbox_base_state::usb_ohci_timer)
|
||||||
{
|
{
|
||||||
UINT32 hcca;
|
UINT32 hcca;
|
||||||
|
UINT32 plh;
|
||||||
int changed = 0;
|
int changed = 0;
|
||||||
int list = 1;
|
int list = 1;
|
||||||
bool cont = false;
|
bool cont = false;
|
||||||
@ -709,8 +710,163 @@ TIMER_CALLBACK_MEMBER(xbox_base_state::usb_ohci_timer)
|
|||||||
if (list == 0) {
|
if (list == 0) {
|
||||||
if (ohcist.hc_regs[HcControl] & PLE) {
|
if (ohcist.hc_regs[HcControl] & PLE) {
|
||||||
// periodic list
|
// periodic list
|
||||||
if (ohcist.hc_regs[HcControl] & IE) {
|
plh=ohcist.space->read_dword(hcca + (ohcist.framenumber & 0x1f) * 4);
|
||||||
// isochronous list
|
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;
|
list = -1;
|
||||||
@ -789,7 +945,7 @@ TIMER_CALLBACK_MEMBER(xbox_base_state::usb_ohci_timer)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// should check for time available
|
// 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);
|
done = ohcist.address[ohcist.endpoint_descriptor.fa].function->execute_transfer(ohcist.endpoint_descriptor.en, pid, ohcist.buffer, mps);
|
||||||
// if receiving ...
|
// if receiving ...
|
||||||
if (pid == InPid) {
|
if (pid == InPid) {
|
||||||
@ -905,10 +1061,6 @@ TIMER_CALLBACK_MEMBER(xbox_base_state::usb_ohci_timer)
|
|||||||
mps = ohcist.endpoint_descriptor.mps;
|
mps = ohcist.endpoint_descriptor.mps;
|
||||||
if (remain < mps)
|
if (remain < mps)
|
||||||
mps = remain;
|
mps = remain;
|
||||||
if (ohcist.transfer_descriptor.cbp == 0) {
|
|
||||||
remain = 0;
|
|
||||||
mps = 0;
|
|
||||||
}
|
|
||||||
b = ohcist.transfer_descriptor.cbp;
|
b = ohcist.transfer_descriptor.cbp;
|
||||||
// if sending ...
|
// if sending ...
|
||||||
if (pid != InPid) {
|
if (pid != InPid) {
|
||||||
@ -921,7 +1073,7 @@ TIMER_CALLBACK_MEMBER(xbox_base_state::usb_ohci_timer)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// should check for time available
|
// 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);
|
done = ohcist.address[ohcist.endpoint_descriptor.fa].function->execute_transfer(ohcist.endpoint_descriptor.en, pid, ohcist.buffer, mps);
|
||||||
// if receiving ...
|
// if receiving ...
|
||||||
if (pid == InPid) {
|
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))
|
if ((ohcist.hc_regs[HcCommandStatus] & (1 << 1)) && (ohcist.hc_regs[HcControl] & CLE))
|
||||||
list = 1; // go to control list if enabled and filled
|
list = 1; // go to control list if enabled and filled
|
||||||
else if ((ohcist.hc_regs[HcCommandStatus] & (1 << 2)) && (ohcist.hc_regs[HcControl] & BLE))
|
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
|
else
|
||||||
list = 0; // if no control or bulk lists, go to periodic list
|
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)
|
else if (endpoints[endpoint].type == BulkEndpoint)
|
||||||
return handle_bulk_pid(endpoint, pid, buffer, size);
|
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
|
else
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
else if (pid == OutPid) {
|
else if (pid == OutPid) {
|
||||||
if (endpoints[endpoint].type == ControlEndpoint) { //if (endpoint == 0) {
|
if (endpoints[endpoint].type == ControlEndpoint) {
|
||||||
// case ==1, nothing
|
// case ==1, nothing
|
||||||
// case ==0, give data
|
// case ==0, give data
|
||||||
// if host->device, since OutPid then this is data stage
|
// 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)
|
else if (endpoints[endpoint].type == BulkEndpoint)
|
||||||
return handle_bulk_pid(endpoint, pid, buffer, size);
|
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
|
else
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@ -1495,21 +1655,62 @@ ohci_game_controller_device::ohci_game_controller_device(running_machine &machin
|
|||||||
int ohci_game_controller_device::handle_nonstandard_request(int endpoint, USBSetupPacket *setup)
|
int ohci_game_controller_device::handle_nonstandard_request(int endpoint, USBSetupPacket *setup)
|
||||||
{
|
{
|
||||||
// >=8 ==42 !=0 !=0 1,3 2<20 <=20
|
// >=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 };
|
static const UINT8 mytestdata1[16] = { 0x10,0x42 ,0x32,0x43,1 ,0x65,0x18,0x20,0x98,0xa9,0xba,0xcb,0xdc,0xed,0xfe };
|
||||||
|
|
||||||
if (endpoint != 0)
|
if (endpoint != 0)
|
||||||
return -1;
|
return -1;
|
||||||
if ((endpoints[endpoint].controltype == VendorType) && (endpoints[endpoint].controlrecipient == InterfaceRecipient))
|
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 *)mytestdata1;
|
||||||
{
|
|
||||||
endpoints[endpoint].position = (UINT8 *)mytestdata;
|
|
||||||
endpoints[endpoint].remain = 16;
|
endpoints[endpoint].remain = 16;
|
||||||
return 0;
|
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;
|
return -1;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user