From 6f29697a3861e96659265f2c66c77989dee9a666 Mon Sep 17 00:00:00 2001 From: yz70s Date: Wed, 29 Jun 2016 23:11:52 +0200 Subject: [PATCH] xbox.cpp: move usb part into new file xbox_usb.cpp and .h (nw) --- scripts/target/mame/arcade.lua | 1 + scripts/target/mame/mess.lua | 2 + src/mame/drivers/chihiro.cpp | 1 + src/mame/drivers/xbox.cpp | 1 + src/mame/includes/xbox.h | 453 +--------- src/mame/includes/xbox_usb.h | 457 ++++++++++ src/mame/machine/xbox.cpp | 1520 +------------------------------ src/mame/machine/xbox_usb.cpp | 1540 ++++++++++++++++++++++++++++++++ 8 files changed, 2005 insertions(+), 1970 deletions(-) create mode 100644 src/mame/includes/xbox_usb.h create mode 100644 src/mame/machine/xbox_usb.cpp diff --git a/scripts/target/mame/arcade.lua b/scripts/target/mame/arcade.lua index df58452777d..e83cc986b28 100644 --- a/scripts/target/mame/arcade.lua +++ b/scripts/target/mame/arcade.lua @@ -3227,6 +3227,7 @@ files { MAME_DIR .. "src/mame/machine/gdrom.cpp", MAME_DIR .. "src/mame/machine/gdrom.h", MAME_DIR .. "src/mame/machine/xbox.cpp", + MAME_DIR .. "src/mame/machine/xbox_usb.cpp", } createMAMEProjects(_target, _subtarget, "seibu") diff --git a/scripts/target/mame/mess.lua b/scripts/target/mame/mess.lua index 1063bd71a93..7c050bd06a5 100644 --- a/scripts/target/mame/mess.lua +++ b/scripts/target/mame/mess.lua @@ -1070,6 +1070,7 @@ files { MAME_DIR .. "src/mame/video/cps1.cpp", MAME_DIR .. "src/mame/video/chihiro.cpp", MAME_DIR .. "src/mame/machine/xbox.cpp", + MAME_DIR .. "src/mame/machine/xbox_usb.cpp", MAME_DIR .. "src/mame/includes/saturn.h", MAME_DIR .. "src/mame/drivers/saturn.cpp", MAME_DIR .. "src/mame/machine/saturn.cpp", @@ -2018,6 +2019,7 @@ createMESSProjects(_target, _subtarget, "microsoft") files { MAME_DIR .. "src/mame/drivers/xbox.cpp", MAME_DIR .. "src/mame/includes/xbox.h", + MAME_DIR .. "src/mame/includes/xbox_usb.h", } createMESSProjects(_target, _subtarget, "mit") diff --git a/src/mame/drivers/chihiro.cpp b/src/mame/drivers/chihiro.cpp index 25650bac37d..b4af01645a2 100644 --- a/src/mame/drivers/chihiro.cpp +++ b/src/mame/drivers/chihiro.cpp @@ -381,6 +381,7 @@ Thanks to Alex, Mr Mudkips, and Philip Burke for this info. #include "debugger.h" #include "includes/chihiro.h" #include "includes/xbox.h" +#include "includes/xbox_usb.h" #define LOG_PCI //#define LOG_BASEBOARD diff --git a/src/mame/drivers/xbox.cpp b/src/mame/drivers/xbox.cpp index c49dde71548..375ecaf869b 100644 --- a/src/mame/drivers/xbox.cpp +++ b/src/mame/drivers/xbox.cpp @@ -25,6 +25,7 @@ #include "debugger.h" #include "includes/chihiro.h" #include "includes/xbox.h" +#include "includes/xbox_usb.h" #define CPU_DIV 64 diff --git a/src/mame/includes/xbox.h b/src/mame/includes/xbox.h index 1a7988b4511..55659b296e4 100644 --- a/src/mame/includes/xbox.h +++ b/src/mame/includes/xbox.h @@ -1,458 +1,9 @@ // license:BSD-3-Clause // copyright-holders:Samuele Zannoli -#include +#pragma once -struct OHCIEndpointDescriptor { - int mps; // MaximumPacketSize - int f; // Format - int k; // sKip - int s; // Speed - int d; // Direction - int en; // EndpointNumber - int fa; // FunctionAddress - UINT32 tailp; // TDQueueTailPointer - UINT32 headp; // TDQueueHeadPointer - UINT32 nexted; // NextED - int c; // toggleCarry - int h; // Halted - UINT32 word0; -}; - -struct OHCITransferDescriptor { - int cc; // ConditionCode - int ec; // ErrorCount - int t; // DataToggle - int di; // DelayInterrupt - int dp; // Direction/PID - int r; // bufferRounding - UINT32 cbp; // CurrentBufferPointer - UINT32 nexttd; // NextTD - UINT32 be; // BufferEnd - UINT32 word0; -}; - -struct OHCIIsochronousTransferDescriptor { - int cc; // ConditionCode - int fc; // FrameCount - int di; // DelayInterrupt - int sf; // StartingFrame - UINT32 bp0; // BufferPage0 - UINT32 nexttd; // NextTD - UINT32 be; // BufferEnd - UINT32 offset[8]; // Offset/PacketStatusWord - UINT32 word0; - UINT32 word1; -}; - -enum OHCIRegisters { - HcRevision=0, - HcControl, - HcCommandStatus, - HcInterruptStatus, - HcInterruptEnable, - HcInterruptDisable, - HcHCCA, - HcPeriodCurrentED, - HcControlHeadED, - HcControlCurrentED, - HcBulkHeadED, - HcBulkCurrentED, - HcDoneHead, - HcFmInterval, - HcFmRemaining, - HcFmNumber, - HcPeriodicStart, - HcLSThreshold, - HcRhDescriptorA, - HcRhDescriptorB, - HcRhStatus, - HcRhPortStatus1 -}; - -enum HcControlBits -{ - CBSR = 1 << 0, // ControlBulkServiceRatio - PLE = 1 << 2, // PeriodicListEnable - IE = 1 << 3, // IsochronousEnable - CLE = 1 << 4, // ControlListEnable - BLE = 1 << 5, // BulkListEnable - HCFS = 1 << 6, // HostControllerFunctionalState - IR = 1 << 8, // InterruptRouting - RWC = 1 << 9, // RemoteWakeupConnected - RWE = 1 << 10 // RemoteWakeupEnable -}; - -enum HcRhStatusBits -{ - LPS = 1 << 0, // LocalPowerStatus - OCI = 1 << 1, // OverCurrentIndicator - DRWE = 1 << 15, // DeviceRemoteWakeupEnable - LPSC = 1 << 16, // LocalPowerStatusChange - OCIC = 1 << 17, // OverCurrentIndicatorChange - CRWE = 1 << 31, // ClearRemoteWakeupEnable -}; - -enum HcRhPortStatusBits -{ - CCS = 1 << 0, // CurrentConnectStatus - PES = 1 << 1, // PortEnableStatus - PSS = 1 << 2, // PortSuspendStatus - POCI = 1 << 3, // PortOverCurrentIndicator - PRS = 1 << 4, // PortResetStatus - PPS = 1 << 8, // PortPowerStatus - LSDA = 1 << 9, // LowSpeedDeviceAttached - CSC = 1 << 16, // ConnectStatusChange - PESC = 1 << 17, // PortEnableStatusChange - PSSC = 1 << 18, // PortSuspendStatusChange - POCIC = 1 << 19, // PortOverCurrentIndicatorChange - PRSC = 1 << 20 // PortResetStatusChange -}; - -enum OHCIHostControllerFunctionalState { - UsbReset=0, - UsbResume, - UsbOperational, - UsbSuspend -}; - -enum OHCIInterrupt { - SchedulingOverrun=1, - WritebackDoneHead=2, - StartofFrame=4, - ResumeDetected=8, - UnrecoverableError=16, - FrameNumberOverflow=32, - RootHubStatusChange=64, - OwnershipChange=0x40000000, - MasterInterruptEnable=0x80000000 -}; - -enum OHCICompletionCode { - NoError=0, - CRC, - BitStuffing, - DataToggleMismatch, - Stall, - DeviceNotResponding, - PIDCheckFailure, - UnexpectedPID, - DataOverrun, - DataUnderrun, - BufferOverrun=12, - BufferUnderrun, - NotAccessed=14 -}; - -struct USBSetupPacket { - UINT8 bmRequestType; - UINT8 bRequest; - UINT16 wValue; - UINT16 wIndex; - UINT16 wLength; -}; - -struct USBStandardDeviceDescriptor { - UINT8 bLength; - UINT8 bDescriptorType; - UINT16 bcdUSB; - UINT8 bDeviceClass; - UINT8 bDeviceSubClass; - UINT8 bDeviceProtocol; - UINT8 bMaxPacketSize0; - UINT16 idVendor; - UINT16 idProduct; - UINT16 bcdDevice; - UINT8 iManufacturer; - UINT8 iProduct; - UINT8 iSerialNumber; - UINT8 bNumConfigurations; -}; - -struct USBStandardConfigurationDescriptor { - UINT8 bLength; - UINT8 bDescriptorType; - UINT16 wTotalLength; - UINT8 bNumInterfaces; - UINT8 bConfigurationValue; - UINT8 iConfiguration; - UINT8 bmAttributes; - UINT8 MaxPower; -}; - -struct USBStandardInterfaceDescriptor { - UINT8 bLength; - UINT8 bDescriptorType; - UINT8 bInterfaceNumber; - UINT8 bAlternateSetting; - UINT8 bNumEndpoints; - UINT8 bInterfaceClass; - UINT8 bInterfaceSubClass; - UINT8 bInterfaceProtocol; - UINT8 iInterface; -}; - -struct USBStandardEndpointDescriptor { - UINT8 bLength; - UINT8 bDescriptorType; - UINT8 bEndpointAddress; - UINT8 bmAttributes; - UINT16 wMaxPacketSize; - UINT8 bInterval; -}; - -enum USBPid { - SetupPid=0, - OutPid, - InPid -}; - -enum USBRequestCode { - GET_STATUS=0, - CLEAR_FEATURE=1, - SET_FEATURE=3, - SET_ADDRESS=5, - GET_DESCRIPTOR=6, - SET_DESCRIPTOR=7, - GET_CONFIGURATION=8, - SET_CONFIGURATION=9, - GET_INTERFACE=10, - SET_INTERFACE=11, - SYNCH_FRAME=12 -}; - -enum USBDescriptorType { - DEVICE=1, - CONFIGURATION=2, - STRING=3, - INTERFACE=4, - ENDPOINT=5 -}; - -enum USBRequestType -{ - StandardType=0, - ClassType, - VendorType, - ReservedType -}; - -enum USBRequestRecipient -{ - DeviceRecipient=0, - InterfaceRecipient, - EndpointRecipient, - OtherRecipient -}; - -enum USBDeviceState -{ - DefaultState, - AddressState, - ConfiguredState -}; - -enum USBControlDirection -{ - HostToDevice=0, - DeviceToHost=1 -}; - -enum USBEndpointType -{ - ControlEndpoint=0, - IsochronousEndpoint, - BulkEndpoint, - InterruptEndpoint -}; - -struct usb_device_string -{ - UINT8 *position; - int size; -}; - -struct usb_device_interface_alternate -{ - UINT8 *position; - int size; - USBStandardInterfaceDescriptor interface_descriptor; - std::forward_list endpoint_descriptors; -}; - -struct usb_device_interface -{ - UINT8 *position; - int size; - std::forward_list alternate_settings; - int selected_alternate; -}; - -struct usb_device_configuration -{ - USBStandardConfigurationDescriptor configuration_descriptor; - UINT8 *position; - int size; - std::forward_list interfaces; -}; - -class ohci_function_device; // forward declaration - -class ohci_usb_controller : public device_t -{ -public: - ohci_usb_controller(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); - ~ohci_usb_controller() {} - void usb_ohci_plug(int port, ohci_function_device *function); - void usb_ohci_device_address_changed(int old_address, int new_address); - - template static devcb_base &set_interrupt_handler(device_t &device, _Object object) { return downcast(device).m_interrupt_handler.set_callback(object); } - - DECLARE_READ32_MEMBER(read); - DECLARE_WRITE32_MEMBER(write); - -protected: - // device-level overrides - virtual void device_start() override; - virtual void device_reset() override; - virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override; - -private: - void usb_ohci_interrupts(); - void usb_ohci_read_endpoint_descriptor(UINT32 address); - void usb_ohci_writeback_endpoint_descriptor(UINT32 address); - void usb_ohci_read_transfer_descriptor(UINT32 address); - void usb_ohci_writeback_transfer_descriptor(UINT32 address); - void usb_ohci_read_isochronous_transfer_descriptor(UINT32 address); - void usb_ohci_writeback_isochronous_transfer_descriptor(UINT32 address); - cpu_device *m_maincpu; - //required_device pic8259_1; - struct { - UINT32 hc_regs[256]; - struct { - ohci_function_device *function; - int address; - int delay; - } ports[4 + 1]; - struct - { - ohci_function_device *function; - int port; - } address[256]; - emu_timer *timer; - int state; - UINT32 framenumber; - UINT32 nextinterupted; - UINT32 nextbulked; - int interruptbulkratio; - int writebackdonehadcounter; - address_space *space; - UINT8 buffer[1024]; - OHCIEndpointDescriptor endpoint_descriptor; - OHCITransferDescriptor transfer_descriptor; - OHCIIsochronousTransferDescriptor isochronous_transfer_descriptor; - } ohcist; - devcb_write_line m_interrupt_handler; -}; - -extern const device_type OHCI_USB_CONTROLLER; - -#define MCFG_OHCI_USB_CONTROLLER_ADD(_tag) \ - MCFG_DEVICE_ADD(_tag, OHCI_USB_CONTROLLER, 0) -#define MCFG_OHCI_USB_CONTROLLER_INTERRUPT_HANDLER(_devcb) \ - devcb = &ohci_usb_controller::set_interrupt_handler(*device, DEVCB_##_devcb); - -class ohci_function_device { -public: - ohci_function_device(); - virtual void initialize(running_machine &machine, ohci_usb_controller *usb_bus_manager); - virtual void execute_reset(); - virtual void execute_connect() {}; - virtual void execute_disconnect() {}; - int execute_transfer(int endpoint, int pid, UINT8 *buffer, int size); -protected: - virtual int handle_nonstandard_request(int endpoint, USBSetupPacket *setup) { return -1; }; - virtual int handle_get_status_request(int endpoint, USBSetupPacket *setup) { return 0; }; - virtual int handle_clear_feature_request(int endpoint, USBSetupPacket *setup) { return 0; }; - virtual int handle_set_feature_request(int endpoint, USBSetupPacket *setup) { return 0; }; - virtual int handle_set_descriptor_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 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); - void add_interface_descriptor(const USBStandardInterfaceDescriptor &descriptor); - void add_endpoint_descriptor(const USBStandardEndpointDescriptor &descriptor); - void add_string_descriptor(const UINT8 *descriptor); - void select_configuration(int index); - void select_alternate(int interfacei, int index); - int find_alternate(int interfacei); - UINT8 *position_device_descriptor(int &size); - UINT8 *position_configuration_descriptor(int index, int &size); - UINT8 *position_string_descriptor(int index, int &size); - ohci_usb_controller *busmanager; - struct { - int type; - int controldirection; - int controltype; - int controlrecipient; - int remain; - UINT8 *position; - UINT8 buffer[128]; - } endpoints[256]; - int state; - bool settingaddress; - int newaddress; - int address; - int configurationvalue; - UINT8 *descriptors; - int descriptors_pos; - bool wantstatuscallback; - USBStandardDeviceDescriptor device_descriptor; - std::forward_list configurations; - std::forward_list device_strings; - usb_device_configuration *latest_configuration; - usb_device_interface_alternate *latest_alternate; - usb_device_configuration *selected_configuration; -}; - -extern const device_type OHCI_GAME_CONTROLLER; - -class ohci_game_controller_device : public device_t, public ohci_function_device -{ -public: - ohci_game_controller_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); - void initialize(running_machine &machine, ohci_usb_controller *usb_bus_manager) override; - int handle_nonstandard_request(int endpoint, USBSetupPacket *setup) override; - int handle_interrupt_pid(int endpoint, int pid, UINT8 *buffer, int size) override; - -protected: - virtual void device_start() override; - virtual ioport_constructor device_input_ports() const override; -private: - static const USBStandardDeviceDescriptor devdesc; - static const USBStandardConfigurationDescriptor condesc; - static const USBStandardInterfaceDescriptor intdesc; - static const USBStandardEndpointDescriptor enddesc82; - static const USBStandardEndpointDescriptor enddesc02; - required_ioport m_ThumbstickLh; // left analog thumbstick horizontal movement - required_ioport m_ThumbstickLv; // left analog thumbstick vertical movement - required_ioport m_ThumbstickRh; // right analog thumbstick horizontal movement - required_ioport m_ThumbstickRv; // right analog thumbstick vertical movement - required_ioport m_DPad; // pressure sensitive directional pad - required_ioport m_TriggerL; // analog trigger - required_ioport m_TriggerR; // analog trigger - required_ioport m_Buttons; // digital buttons - required_ioport m_AGreen; // analog button - required_ioport m_BRed; // analog button - required_ioport m_XBlue; // analog button - required_ioport m_YYellow; // analog button - required_ioport m_Black; // analog button - required_ioport m_White; // analog button -}; +#include "xbox_usb.h" class xbox_base_state : public driver_device { diff --git a/src/mame/includes/xbox_usb.h b/src/mame/includes/xbox_usb.h new file mode 100644 index 00000000000..5e9505d3723 --- /dev/null +++ b/src/mame/includes/xbox_usb.h @@ -0,0 +1,457 @@ +// license:BSD-3-Clause +// copyright-holders:Samuele Zannoli + +#pragma once + +#include + +struct OHCIEndpointDescriptor { + int mps; // MaximumPacketSize + int f; // Format + int k; // sKip + int s; // Speed + int d; // Direction + int en; // EndpointNumber + int fa; // FunctionAddress + UINT32 tailp; // TDQueueTailPointer + UINT32 headp; // TDQueueHeadPointer + UINT32 nexted; // NextED + int c; // toggleCarry + int h; // Halted + UINT32 word0; +}; + +struct OHCITransferDescriptor { + int cc; // ConditionCode + int ec; // ErrorCount + int t; // DataToggle + int di; // DelayInterrupt + int dp; // Direction/PID + int r; // bufferRounding + UINT32 cbp; // CurrentBufferPointer + UINT32 nexttd; // NextTD + UINT32 be; // BufferEnd + UINT32 word0; +}; + +struct OHCIIsochronousTransferDescriptor { + int cc; // ConditionCode + int fc; // FrameCount + int di; // DelayInterrupt + int sf; // StartingFrame + UINT32 bp0; // BufferPage0 + UINT32 nexttd; // NextTD + UINT32 be; // BufferEnd + UINT32 offset[8]; // Offset/PacketStatusWord + UINT32 word0; + UINT32 word1; +}; + +enum OHCIRegisters { + HcRevision=0, + HcControl, + HcCommandStatus, + HcInterruptStatus, + HcInterruptEnable, + HcInterruptDisable, + HcHCCA, + HcPeriodCurrentED, + HcControlHeadED, + HcControlCurrentED, + HcBulkHeadED, + HcBulkCurrentED, + HcDoneHead, + HcFmInterval, + HcFmRemaining, + HcFmNumber, + HcPeriodicStart, + HcLSThreshold, + HcRhDescriptorA, + HcRhDescriptorB, + HcRhStatus, + HcRhPortStatus1 +}; + +enum HcControlBits +{ + CBSR = 1 << 0, // ControlBulkServiceRatio + PLE = 1 << 2, // PeriodicListEnable + IE = 1 << 3, // IsochronousEnable + CLE = 1 << 4, // ControlListEnable + BLE = 1 << 5, // BulkListEnable + HCFS = 1 << 6, // HostControllerFunctionalState + IR = 1 << 8, // InterruptRouting + RWC = 1 << 9, // RemoteWakeupConnected + RWE = 1 << 10 // RemoteWakeupEnable +}; + +enum HcRhStatusBits +{ + LPS = 1 << 0, // LocalPowerStatus + OCI = 1 << 1, // OverCurrentIndicator + DRWE = 1 << 15, // DeviceRemoteWakeupEnable + LPSC = 1 << 16, // LocalPowerStatusChange + OCIC = 1 << 17, // OverCurrentIndicatorChange + CRWE = 1 << 31, // ClearRemoteWakeupEnable +}; + +enum HcRhPortStatusBits +{ + CCS = 1 << 0, // CurrentConnectStatus + PES = 1 << 1, // PortEnableStatus + PSS = 1 << 2, // PortSuspendStatus + POCI = 1 << 3, // PortOverCurrentIndicator + PRS = 1 << 4, // PortResetStatus + PPS = 1 << 8, // PortPowerStatus + LSDA = 1 << 9, // LowSpeedDeviceAttached + CSC = 1 << 16, // ConnectStatusChange + PESC = 1 << 17, // PortEnableStatusChange + PSSC = 1 << 18, // PortSuspendStatusChange + POCIC = 1 << 19, // PortOverCurrentIndicatorChange + PRSC = 1 << 20 // PortResetStatusChange +}; + +enum OHCIHostControllerFunctionalState { + UsbReset=0, + UsbResume, + UsbOperational, + UsbSuspend +}; + +enum OHCIInterrupt { + SchedulingOverrun=1, + WritebackDoneHead=2, + StartofFrame=4, + ResumeDetected=8, + UnrecoverableError=16, + FrameNumberOverflow=32, + RootHubStatusChange=64, + OwnershipChange=0x40000000, + MasterInterruptEnable=0x80000000 +}; + +enum OHCICompletionCode { + NoError=0, + CRC, + BitStuffing, + DataToggleMismatch, + Stall, + DeviceNotResponding, + PIDCheckFailure, + UnexpectedPID, + DataOverrun, + DataUnderrun, + BufferOverrun=12, + BufferUnderrun, + NotAccessed=14 +}; + +struct USBSetupPacket { + UINT8 bmRequestType; + UINT8 bRequest; + UINT16 wValue; + UINT16 wIndex; + UINT16 wLength; +}; + +struct USBStandardDeviceDescriptor { + UINT8 bLength; + UINT8 bDescriptorType; + UINT16 bcdUSB; + UINT8 bDeviceClass; + UINT8 bDeviceSubClass; + UINT8 bDeviceProtocol; + UINT8 bMaxPacketSize0; + UINT16 idVendor; + UINT16 idProduct; + UINT16 bcdDevice; + UINT8 iManufacturer; + UINT8 iProduct; + UINT8 iSerialNumber; + UINT8 bNumConfigurations; +}; + +struct USBStandardConfigurationDescriptor { + UINT8 bLength; + UINT8 bDescriptorType; + UINT16 wTotalLength; + UINT8 bNumInterfaces; + UINT8 bConfigurationValue; + UINT8 iConfiguration; + UINT8 bmAttributes; + UINT8 MaxPower; +}; + +struct USBStandardInterfaceDescriptor { + UINT8 bLength; + UINT8 bDescriptorType; + UINT8 bInterfaceNumber; + UINT8 bAlternateSetting; + UINT8 bNumEndpoints; + UINT8 bInterfaceClass; + UINT8 bInterfaceSubClass; + UINT8 bInterfaceProtocol; + UINT8 iInterface; +}; + +struct USBStandardEndpointDescriptor { + UINT8 bLength; + UINT8 bDescriptorType; + UINT8 bEndpointAddress; + UINT8 bmAttributes; + UINT16 wMaxPacketSize; + UINT8 bInterval; +}; + +enum USBPid { + SetupPid=0, + OutPid, + InPid +}; + +enum USBRequestCode { + GET_STATUS=0, + CLEAR_FEATURE=1, + SET_FEATURE=3, + SET_ADDRESS=5, + GET_DESCRIPTOR=6, + SET_DESCRIPTOR=7, + GET_CONFIGURATION=8, + SET_CONFIGURATION=9, + GET_INTERFACE=10, + SET_INTERFACE=11, + SYNCH_FRAME=12 +}; + +enum USBDescriptorType { + DEVICE=1, + CONFIGURATION=2, + STRING=3, + INTERFACE=4, + ENDPOINT=5 +}; + +enum USBRequestType +{ + StandardType=0, + ClassType, + VendorType, + ReservedType +}; + +enum USBRequestRecipient +{ + DeviceRecipient=0, + InterfaceRecipient, + EndpointRecipient, + OtherRecipient +}; + +enum USBDeviceState +{ + DefaultState, + AddressState, + ConfiguredState +}; + +enum USBControlDirection +{ + HostToDevice=0, + DeviceToHost=1 +}; + +enum USBEndpointType +{ + ControlEndpoint=0, + IsochronousEndpoint, + BulkEndpoint, + InterruptEndpoint +}; + +struct usb_device_string +{ + UINT8 *position; + int size; +}; + +struct usb_device_interface_alternate +{ + UINT8 *position; + int size; + USBStandardInterfaceDescriptor interface_descriptor; + std::forward_list endpoint_descriptors; +}; + +struct usb_device_interface +{ + UINT8 *position; + int size; + std::forward_list alternate_settings; + int selected_alternate; +}; + +struct usb_device_configuration +{ + USBStandardConfigurationDescriptor configuration_descriptor; + UINT8 *position; + int size; + std::forward_list interfaces; +}; + +class ohci_function_device; // forward declaration + +class ohci_usb_controller : public device_t +{ +public: + ohci_usb_controller(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + ~ohci_usb_controller() {} + void usb_ohci_plug(int port, ohci_function_device *function); + void usb_ohci_device_address_changed(int old_address, int new_address); + + template static devcb_base &set_interrupt_handler(device_t &device, _Object object) { return downcast(device).m_interrupt_handler.set_callback(object); } + + DECLARE_READ32_MEMBER(read); + DECLARE_WRITE32_MEMBER(write); + +protected: + // device-level overrides + virtual void device_start() override; + virtual void device_reset() override; + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override; + +private: + void usb_ohci_interrupts(); + void usb_ohci_read_endpoint_descriptor(UINT32 address); + void usb_ohci_writeback_endpoint_descriptor(UINT32 address); + void usb_ohci_read_transfer_descriptor(UINT32 address); + void usb_ohci_writeback_transfer_descriptor(UINT32 address); + void usb_ohci_read_isochronous_transfer_descriptor(UINT32 address); + void usb_ohci_writeback_isochronous_transfer_descriptor(UINT32 address); + cpu_device *m_maincpu; + //required_device pic8259_1; + struct { + UINT32 hc_regs[256]; + struct { + ohci_function_device *function; + int address; + int delay; + } ports[4 + 1]; + struct + { + ohci_function_device *function; + int port; + } address[256]; + emu_timer *timer; + int state; + UINT32 framenumber; + UINT32 nextinterupted; + UINT32 nextbulked; + int interruptbulkratio; + int writebackdonehadcounter; + address_space *space; + UINT8 buffer[1024]; + OHCIEndpointDescriptor endpoint_descriptor; + OHCITransferDescriptor transfer_descriptor; + OHCIIsochronousTransferDescriptor isochronous_transfer_descriptor; + } ohcist; + devcb_write_line m_interrupt_handler; +}; + +extern const device_type OHCI_USB_CONTROLLER; + +#define MCFG_OHCI_USB_CONTROLLER_ADD(_tag) \ + MCFG_DEVICE_ADD(_tag, OHCI_USB_CONTROLLER, 0) +#define MCFG_OHCI_USB_CONTROLLER_INTERRUPT_HANDLER(_devcb) \ + devcb = &ohci_usb_controller::set_interrupt_handler(*device, DEVCB_##_devcb); + +class ohci_function_device { +public: + ohci_function_device(); + virtual void initialize(running_machine &machine, ohci_usb_controller *usb_bus_manager); + virtual void execute_reset(); + virtual void execute_connect() {}; + virtual void execute_disconnect() {}; + int execute_transfer(int endpoint, int pid, UINT8 *buffer, int size); +protected: + virtual int handle_nonstandard_request(int endpoint, USBSetupPacket *setup) { return -1; }; + virtual int handle_get_status_request(int endpoint, USBSetupPacket *setup) { return 0; }; + virtual int handle_clear_feature_request(int endpoint, USBSetupPacket *setup) { return 0; }; + virtual int handle_set_feature_request(int endpoint, USBSetupPacket *setup) { return 0; }; + virtual int handle_set_descriptor_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 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); + void add_interface_descriptor(const USBStandardInterfaceDescriptor &descriptor); + void add_endpoint_descriptor(const USBStandardEndpointDescriptor &descriptor); + void add_string_descriptor(const UINT8 *descriptor); + void select_configuration(int index); + void select_alternate(int interfacei, int index); + int find_alternate(int interfacei); + UINT8 *position_device_descriptor(int &size); + UINT8 *position_configuration_descriptor(int index, int &size); + UINT8 *position_string_descriptor(int index, int &size); + ohci_usb_controller *busmanager; + struct { + int type; + int controldirection; + int controltype; + int controlrecipient; + int remain; + UINT8 *position; + UINT8 buffer[128]; + } endpoints[256]; + int state; + bool settingaddress; + int newaddress; + int address; + int configurationvalue; + UINT8 *descriptors; + int descriptors_pos; + bool wantstatuscallback; + USBStandardDeviceDescriptor device_descriptor; + std::forward_list configurations; + std::forward_list device_strings; + usb_device_configuration *latest_configuration; + usb_device_interface_alternate *latest_alternate; + usb_device_configuration *selected_configuration; +}; + +extern const device_type OHCI_GAME_CONTROLLER; + +class ohci_game_controller_device : public device_t, public ohci_function_device +{ +public: + ohci_game_controller_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + void initialize(running_machine &machine, ohci_usb_controller *usb_bus_manager) override; + int handle_nonstandard_request(int endpoint, USBSetupPacket *setup) override; + int handle_interrupt_pid(int endpoint, int pid, UINT8 *buffer, int size) override; + +protected: + virtual void device_start() override; + virtual ioport_constructor device_input_ports() const override; +private: + static const USBStandardDeviceDescriptor devdesc; + static const USBStandardConfigurationDescriptor condesc; + static const USBStandardInterfaceDescriptor intdesc; + static const USBStandardEndpointDescriptor enddesc82; + static const USBStandardEndpointDescriptor enddesc02; + required_ioport m_ThumbstickLh; // left analog thumbstick horizontal movement + required_ioport m_ThumbstickLv; // left analog thumbstick vertical movement + required_ioport m_ThumbstickRh; // right analog thumbstick horizontal movement + required_ioport m_ThumbstickRv; // right analog thumbstick vertical movement + required_ioport m_DPad; // pressure sensitive directional pad + required_ioport m_TriggerL; // analog trigger + required_ioport m_TriggerR; // analog trigger + required_ioport m_Buttons; // digital buttons + required_ioport m_AGreen; // analog button + required_ioport m_BRed; // analog button + required_ioport m_XBlue; // analog button + required_ioport m_YYellow; // analog button + required_ioport m_Black; // analog button + required_ioport m_White; // analog button +}; diff --git a/src/mame/machine/xbox.cpp b/src/mame/machine/xbox.cpp index 35654e90b42..13db44bea65 100644 --- a/src/mame/machine/xbox.cpp +++ b/src/mame/machine/xbox.cpp @@ -17,10 +17,10 @@ #include "debug/debugcpu.h" #include "includes/chihiro.h" #include "includes/xbox.h" +#include "includes/xbox_usb.h" #define LOG_PCI //#define LOG_AUDIO -//#define LOG_OHCI #define USB_HACK_ENABLED void xbox_base_state::dump_string_command(int ref, int params, const char **param) @@ -500,1524 +500,6 @@ static void geforce_pci_w(device_t *busdevice, device_t *device, int function, i #endif } -/* - * ohci usb controller - */ - -#ifdef LOG_OHCI -static const char *const usbregnames[] = { - "HcRevision", - "HcControl", - "HcCommandStatus", - "HcInterruptStatus", - "HcInterruptEnable", - "HcInterruptDisable", - "HcHCCA", - "HcPeriodCurrentED", - "HcControlHeadED", - "HcControlCurrentED", - "HcBulkHeadED", - "HcBulkCurrentED", - "HcDoneHead", - "HcFmInterval", - "HcFmRemaining", - "HcFmNumber", - "HcPeriodicStart", - "HcLSThreshold", - "HcRhDescriptorA", - "HcRhDescriptorB", - "HcRhStatus", - "HcRhPortStatus[1]" -}; -#endif - -const device_type OHCI_USB_CONTROLLER = &device_creator; - -ohci_usb_controller::ohci_usb_controller(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : - device_t(mconfig, OHCI_USB_CONTROLLER, "OHCI USB CONTROLLER", tag, owner, clock, "ohciusb", __FILE__), - m_interrupt_handler(*this) -{ - memset(&ohcist, 0, sizeof(ohcist)); -} - -void ohci_usb_controller::device_start() -{ - m_maincpu = machine().device("maincpu"); - m_interrupt_handler.resolve_safe(); - ohcist.hc_regs[HcRevision] = 0x10; - ohcist.hc_regs[HcFmInterval] = 0x2edf; - ohcist.hc_regs[HcLSThreshold] = 0x628; - ohcist.hc_regs[HcRhDescriptorA] = 4; - ohcist.hc_regs[HcControl] = UsbReset << 6; - ohcist.state = UsbReset; - ohcist.interruptbulkratio = 1; - ohcist.writebackdonehadcounter = 7; - for (int n = 0; n <= 4; n++) - ohcist.ports[n].address = -1; - for (int n = 0; n < 256; n++) - ohcist.address[n].port = -1; - ohcist.space = &(m_maincpu->space()); - ohcist.timer = timer_alloc(0); - ohcist.timer->enable(false); -} - -void ohci_usb_controller::device_reset() -{ -} - -READ32_MEMBER(ohci_usb_controller::read) -{ - UINT32 ret; - -#ifdef LOG_OHCI - if (offset >= 0x54 / 4) - logerror("usb controller 0 register HcRhPortStatus[%d] read\n", (offset - 0x54 / 4) + 1); - else - logerror("usb controller 0 register %s read\n", usbregnames[offset]); -#endif - ret = ohcist.hc_regs[offset]; - return ret; -} - -WRITE32_MEMBER(ohci_usb_controller::write) -{ - UINT32 old = ohcist.hc_regs[offset]; - -#ifdef LOG_OHCI - if (offset >= 0x54 / 4) - logerror("usb controller 0 register HcRhPortStatus[%d] write %08X\n", (offset - 0x54 / 4) + 1, data); - else - logerror("usb controller 0 register %s write %08X\n", usbregnames[offset], data); -#endif - if (offset == HcRhStatus) { - if (data & CRWE) - ohcist.hc_regs[HcRhStatus] &= ~DRWE; - if (data & OCIC) - ohcist.hc_regs[HcRhStatus] &= ~OCI; - if (data & LPSC) - ohcist.hc_regs[HcRhStatus] &= ~LPS; - return; - } - if (offset == HcControl) { - int hcfs; - - hcfs = (data >> 6) & 3; // HostControllerFunctionalState - if (hcfs == UsbOperational) { - ohcist.timer->enable(); - ohcist.timer->adjust(attotime::from_msec(1), 0, attotime::from_msec(1)); - ohcist.writebackdonehadcounter = 7; - // need to load the FrameRemaining field of HcFmRemaining with the value of the FrameInterval field in HcFmInterval - } - else - ohcist.timer->enable(false); - ohcist.interruptbulkratio = (data & 3) + 1; - if ((hcfs != UsbReset) && (ohcist.state == UsbReset)) - { - ohcist.hc_regs[HcInterruptStatus] |= RootHubStatusChange; - usb_ohci_interrupts(); - } - ohcist.state = hcfs; - } - if (offset == HcCommandStatus) { - if (data & 1) // HostControllerReset - ohcist.hc_regs[HcControl] |= 3 << 6; - ohcist.hc_regs[HcCommandStatus] |= data; - return; - } - if (offset == HcInterruptStatus) { - ohcist.hc_regs[HcInterruptStatus] &= ~data; - usb_ohci_interrupts(); - return; - } - if (offset == HcInterruptEnable) { - ohcist.hc_regs[HcInterruptEnable] |= data; - usb_ohci_interrupts(); - return; - } - if (offset == HcInterruptDisable) { - ohcist.hc_regs[HcInterruptEnable] &= ~data; - usb_ohci_interrupts(); - return; - } - if (offset >= HcRhPortStatus1) { - int port = offset - HcRhPortStatus1 + 1; // port 0 not used - // bit 0 R:CurrentConnectStatus W:ClearPortEnable: 1 clears PortEnableStatus - if (data & CCS) { - ohcist.hc_regs[offset] &= ~PES; - ohcist.address[ohcist.ports[port].address].port = -1; - } - // bit 1 R:PortEnableStatus W:SetPortEnable: 1 sets PortEnableStatus - if (data & PES) { - ohcist.hc_regs[offset] |= PES; - // the port is enabled, so the device connected to it can communicate on the bus - ohcist.address[ohcist.ports[port].address].function = ohcist.ports[port].function; - ohcist.address[ohcist.ports[port].address].port = port; - } - // bit 2 R:PortSuspendStatus W:SetPortSuspend: 1 sets PortSuspendStatus - if (data & PSS) { - ohcist.hc_regs[offset] |= PSS; - } - // bit 3 R:PortOverCurrentIndicator W:ClearSuspendStatus: 1 clears PortSuspendStatus - if (data & POCI) { - ohcist.hc_regs[offset] &= ~PSS; - } - // bit 4 R: PortResetStatus W:SetPortReset: 1 sets PortResetStatus - if (data & PRS) { - ohcist.hc_regs[offset] |= PRS; - if (ohcist.ports[port].address >= 0) - ohcist.address[ohcist.ports[port].address].port = -1; - ohcist.ports[port].address = 0; - if (ohcist.hc_regs[offset] & PES) - { - ohcist.address[0].function = ohcist.ports[port].function; - ohcist.address[0].port = port; - } - ohcist.ports[port].function->execute_reset(); - // after 10ms set PortResetStatusChange and clear PortResetStatus and set PortEnableStatus - ohcist.ports[port].delay = 10; - } - // bit 8 R:PortPowerStatus W:SetPortPower: 1 sets PortPowerStatus - if (data & PPS) { - ohcist.hc_regs[offset] |= PPS; - } - // bit 9 R:LowSpeedDeviceAttached W:ClearPortPower: 1 clears PortPowerStatus - if (data & LSDA) { - ohcist.hc_regs[offset] &= ~PPS; - } - // bit 16 R:ConnectStatusChange W: 1 clears ConnectStatusChange - if (data & CSC) { - ohcist.hc_regs[offset] &= ~CSC; - } - // bit 17 R:PortEnableStatusChange W: 1 clears PortEnableStatusChange - if (data & PESC) { - ohcist.hc_regs[offset] &= ~PESC; - } - // bit 18 R:PortSuspendStatusChange W: 1 clears PortSuspendStatusChange - if (data & PSSC) { - ohcist.hc_regs[offset] &= ~PSSC; - } - // bit 19 R:PortOverCurrentIndicatorChange W: 1 clears PortOverCurrentIndicatorChange - if (data & POCIC) { - ohcist.hc_regs[offset] &= ~POCIC; - } - // bit 20 R:PortResetStatusChange W: 1 clears PortResetStatusChange - if (data & PRSC) { - ohcist.hc_regs[offset] &= ~PRSC; - } - if (ohcist.hc_regs[offset] != old) - ohcist.hc_regs[HcInterruptStatus] |= RootHubStatusChange; - usb_ohci_interrupts(); - return; - } - ohcist.hc_regs[offset] = data; -} - -void ohci_usb_controller::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) -{ - UINT32 hcca; - UINT32 plh; - int changed = 0; - int list = 1; - bool cont = false; - bool retire = false; - int pid, remain, mps, done; - - hcca = ohcist.hc_regs[HcHCCA]; - if (ohcist.state == UsbOperational) { - // increment frame number - ohcist.framenumber = (ohcist.framenumber + 1) & 0xffff; - ohcist.space->write_dword(hcca + 0x80, ohcist.framenumber); - ohcist.hc_regs[HcFmNumber] = ohcist.framenumber; - } - // port reset delay - for (int p = 1; p <= 4; p++) { - if (ohcist.ports[p].delay > 0) { - ohcist.ports[p].delay--; - if (ohcist.ports[p].delay == 0) { - ohcist.hc_regs[HcRhPortStatus1 + p - 1] = (ohcist.hc_regs[HcRhPortStatus1 + p - 1] & ~PRS) | PRSC | PES; - ohcist.address[ohcist.ports[p].address].function = ohcist.ports[p].function; - ohcist.address[ohcist.ports[p].address].port = p; - changed = 1; - } - } - } - if (ohcist.state == UsbOperational) { - while (list >= 0) - { - // select list, do transfer - if (list == 0) { - if (ohcist.hc_regs[HcControl] & PLE) { - // periodic 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; - } - if (list == 1) { - // control list - // check if control list active - if (ohcist.hc_regs[HcControl] & CLE) { - cont = true; - while (cont == true) { - // if current endpoint descriptor is not 0 use it, otherwise ... - if (ohcist.hc_regs[HcControlCurrentED] == 0) { - // ... check the filled bit ... - if (ohcist.hc_regs[HcCommandStatus] & (1 << 1)) { - // ... if 1 start processing from the head of the list - ohcist.hc_regs[HcControlCurrentED] = ohcist.hc_regs[HcControlHeadED]; - // clear CLF (ControlListFilled) - ohcist.hc_regs[HcCommandStatus] &= ~(1 << 1); - // but if the list is empty, go to the next list - if (ohcist.hc_regs[HcControlCurrentED] == 0) - cont = false; - else - cont = true; - } - else - cont = false; - } - else - cont = true; - if (cont == false) - break; - // service endpoint descriptor - usb_ohci_read_endpoint_descriptor(ohcist.hc_regs[HcControlCurrentED]); - // 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; - // set CLF (ControlListFilled) - ohcist.hc_regs[HcCommandStatus] |= (1 << 1); - // service transfer descriptor - 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 - } - // determine how much data to transfer - // setup pid must be 8 bytes - a = ohcist.transfer_descriptor.be & 0xfff; - b = ohcist.transfer_descriptor.cbp & 0xfff; - if ((ohcist.transfer_descriptor.be ^ ohcist.transfer_descriptor.cbp) & 0xfffff000) - a |= 0x1000; - remain = a - b + 1; - mps = ohcist.endpoint_descriptor.mps; - if ((pid == InPid) || (pid == OutPid)) { - 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) { - // ... 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 = ohcist.transfer_descriptor.be & 0xfffff000; - } - } - // 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) || (pid == SetupPid)) - 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(ohcist.hc_regs[HcControlCurrentED]); - } - else { - usb_ohci_writeback_transfer_descriptor(ohcist.endpoint_descriptor.headp); - } - } - else { - // no transfer descriptors for this endpoint, so go to next endpoint - ohcist.hc_regs[HcControlCurrentED] = ohcist.endpoint_descriptor.nexted; - } - } - else { - // not enabled, so go to next endpoint - ohcist.hc_regs[HcControlCurrentED] = ohcist.endpoint_descriptor.nexted; - } - // one bulk every n control transfers - ohcist.interruptbulkratio--; - if (ohcist.interruptbulkratio <= 0) { - ohcist.interruptbulkratio = (ohcist.hc_regs[HcControl] & 3) + 1; // ControlBulkServiceRatio - cont = false; - } - } - } - list = 2; - } - if (list == 2) { - // bulk list - // check if bulk list active - if (ohcist.hc_regs[HcControl] & BLE) { - // if current endpoint descriptor is not 0 use it, otherwise ... - if (ohcist.hc_regs[HcBulkCurrentED] == 0) { - // ... check the filled bit ... - if (ohcist.hc_regs[HcCommandStatus] & (1 << 2)) { - // ... if 1 start processing from the head of the list - ohcist.hc_regs[HcBulkCurrentED] = ohcist.hc_regs[HcBulkHeadED]; - // clear BLF (BulkListFilled) - ohcist.hc_regs[HcCommandStatus] &= ~(1 << 2); - // but if the list is empty, go to the next list - if (ohcist.hc_regs[HcBulkCurrentED] == 0) - cont = false; - else - cont = true; - } - else - cont = false; - } - else - cont = true; - if (cont == true) { - // service endpoint descriptor - usb_ohci_read_endpoint_descriptor(ohcist.hc_regs[HcBulkCurrentED]); - // 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; - // set BLF (BulkListFilled) - ohcist.hc_regs[HcCommandStatus] |= (1 << 2); - // service transfer descriptor - 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 - } - // determine how much data to transfer - a = ohcist.transfer_descriptor.be & 0xfff; - b = ohcist.transfer_descriptor.cbp & 0xfff; - if ((ohcist.transfer_descriptor.be ^ ohcist.transfer_descriptor.cbp) & 0xfffff000) - a |= 0x1000; - remain = a - b + 1; - mps = ohcist.endpoint_descriptor.mps; - if (remain < mps) - mps = remain; - b = ohcist.transfer_descriptor.cbp; - // 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 = ohcist.transfer_descriptor.be & 0xfffff000; - } - } - // 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(ohcist.hc_regs[HcBulkCurrentED]); - } - else { - usb_ohci_writeback_transfer_descriptor(ohcist.endpoint_descriptor.headp); - } - } - else { - // no transfer descriptors for this endpoint, so go to next endpoint - ohcist.hc_regs[HcBulkCurrentED] = ohcist.endpoint_descriptor.nexted; - } - } - else { - // not enabled, so go to next endpoint - ohcist.hc_regs[HcBulkCurrentED] = ohcist.endpoint_descriptor.nexted; - } - } - // go to the next list - 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 stay in bulk list if enabled and filled - else - list = 0; // if no control or bulk lists, go to periodic list - } - } - } - if (ohcist.framenumber == 0) - ohcist.hc_regs[HcInterruptStatus] |= FrameNumberOverflow; - ohcist.hc_regs[HcInterruptStatus] |= StartofFrame; - if ((ohcist.writebackdonehadcounter != 0) && (ohcist.writebackdonehadcounter != 7)) - ohcist.writebackdonehadcounter--; - if ((ohcist.writebackdonehadcounter == 0) && ((ohcist.hc_regs[HcInterruptStatus] & WritebackDoneHead) == 0)) { - UINT32 b = 0; - - if ((ohcist.hc_regs[HcInterruptStatus] & ohcist.hc_regs[HcInterruptEnable]) != WritebackDoneHead) - b = 1; - ohcist.hc_regs[HcInterruptStatus] |= WritebackDoneHead; - ohcist.space->write_dword(hcca + 0x84, ohcist.hc_regs[HcDoneHead] | b); - ohcist.hc_regs[HcDoneHead] = 0; - ohcist.writebackdonehadcounter = 7; - } - } - if (changed != 0) { - ohcist.hc_regs[HcInterruptStatus] |= RootHubStatusChange; - } - usb_ohci_interrupts(); -} - -void ohci_usb_controller::usb_ohci_plug(int port, ohci_function_device *function) -{ - if ((port > 0) && (port <= 4)) { - ohcist.ports[port].function = function; - ohcist.ports[port].address = -1; - ohcist.hc_regs[HcRhPortStatus1 + port - 1] = CCS | CSC; - if (ohcist.state != UsbReset) - { - ohcist.hc_regs[HcInterruptStatus] |= RootHubStatusChange; - usb_ohci_interrupts(); - } - } -} - -void ohci_usb_controller::usb_ohci_interrupts() -{ - if (((ohcist.hc_regs[HcInterruptStatus] & ohcist.hc_regs[HcInterruptEnable]) != 0) && ((ohcist.hc_regs[HcInterruptEnable] & MasterInterruptEnable) != 0)) - { - //pic8259_1->ir1_w(1); - m_interrupt_handler(1); - } else - { - //pic8259_1->ir1_w(0); - m_interrupt_handler(0); - } -} - -void ohci_usb_controller::usb_ohci_read_endpoint_descriptor(UINT32 address) -{ - UINT32 w; - - w = ohcist.space->read_dword(address); - ohcist.endpoint_descriptor.word0 = w; - ohcist.endpoint_descriptor.fa = w & 0x7f; - ohcist.endpoint_descriptor.en = (w >> 7) & 15; - ohcist.endpoint_descriptor.d = (w >> 11) & 3; - ohcist.endpoint_descriptor.s = (w >> 13) & 1; - ohcist.endpoint_descriptor.k = (w >> 14) & 1; - ohcist.endpoint_descriptor.f = (w >> 15) & 1; - ohcist.endpoint_descriptor.mps = (w >> 16) & 0x7ff; - ohcist.endpoint_descriptor.tailp = ohcist.space->read_dword(address + 4); - w = ohcist.space->read_dword(address + 8); - ohcist.endpoint_descriptor.headp = w & 0xfffffffc; - ohcist.endpoint_descriptor.h = w & 1; - ohcist.endpoint_descriptor.c = (w >> 1) & 1; - ohcist.endpoint_descriptor.nexted = ohcist.space->read_dword(address + 12); -} - -void ohci_usb_controller::usb_ohci_writeback_endpoint_descriptor(UINT32 address) -{ - UINT32 w; - - w = ohcist.endpoint_descriptor.word0 & 0xf8000000; - w = w | (ohcist.endpoint_descriptor.mps << 16) | (ohcist.endpoint_descriptor.f << 15) | (ohcist.endpoint_descriptor.k << 14) | (ohcist.endpoint_descriptor.s << 13) | (ohcist.endpoint_descriptor.d << 11) | (ohcist.endpoint_descriptor.en << 7) | ohcist.endpoint_descriptor.fa; - ohcist.space->write_dword(address, w); - w = ohcist.endpoint_descriptor.headp | (ohcist.endpoint_descriptor.c << 1) | ohcist.endpoint_descriptor.h; - ohcist.space->write_dword(address + 8, w); -} - -void ohci_usb_controller::usb_ohci_read_transfer_descriptor(UINT32 address) -{ - UINT32 w; - - w = ohcist.space->read_dword(address); - ohcist.transfer_descriptor.word0 = w; - ohcist.transfer_descriptor.cc = (w >> 28) & 15; - ohcist.transfer_descriptor.ec = (w >> 26) & 3; - ohcist.transfer_descriptor.t = (w >> 24) & 3; - ohcist.transfer_descriptor.di = (w >> 21) & 7; - ohcist.transfer_descriptor.dp = (w >> 19) & 3; - ohcist.transfer_descriptor.r = (w >> 18) & 1; - ohcist.transfer_descriptor.cbp = ohcist.space->read_dword(address + 4); - ohcist.transfer_descriptor.nexttd = ohcist.space->read_dword(address + 8); - ohcist.transfer_descriptor.be = ohcist.space->read_dword(address + 12); -} - -void ohci_usb_controller::usb_ohci_writeback_transfer_descriptor(UINT32 address) -{ - UINT32 w; - - w = ohcist.transfer_descriptor.word0 & 0x0003ffff; - w = w | (ohcist.transfer_descriptor.cc << 28) | (ohcist.transfer_descriptor.ec << 26) | (ohcist.transfer_descriptor.t << 24) | (ohcist.transfer_descriptor.di << 21) | (ohcist.transfer_descriptor.dp << 19) | (ohcist.transfer_descriptor.r << 18); - ohcist.space->write_dword(address, w); - ohcist.space->write_dword(address + 4, ohcist.transfer_descriptor.cbp); - ohcist.space->write_dword(address + 8, ohcist.transfer_descriptor.nexttd); -} - -void ohci_usb_controller::usb_ohci_read_isochronous_transfer_descriptor(UINT32 address) -{ - UINT32 w; - - w = ohcist.space->read_dword(address); - ohcist.isochronous_transfer_descriptor.word0 = w; - ohcist.isochronous_transfer_descriptor.cc = (w >> 28) & 15; - ohcist.isochronous_transfer_descriptor.fc = (w >> 24) & 7; - ohcist.isochronous_transfer_descriptor.di = (w >> 21) & 7; - ohcist.isochronous_transfer_descriptor.sf = w & 0xffff; - w = ohcist.space->read_dword(address + 4); - ohcist.isochronous_transfer_descriptor.word1 = w; - ohcist.isochronous_transfer_descriptor.bp0 = w & 0xfffff000; - ohcist.isochronous_transfer_descriptor.nexttd = ohcist.space->read_dword(address + 8); - ohcist.isochronous_transfer_descriptor.be = ohcist.space->read_dword(address + 12); - w = ohcist.space->read_dword(address + 16); - ohcist.isochronous_transfer_descriptor.offset[0] = w & 0xffff; - ohcist.isochronous_transfer_descriptor.offset[1] = (w >> 16) & 0xffff; - w = ohcist.space->read_dword(address + 20); - ohcist.isochronous_transfer_descriptor.offset[2] = w & 0xffff; - ohcist.isochronous_transfer_descriptor.offset[3] = (w >> 16) & 0xffff; - w = ohcist.space->read_dword(address + 24); - ohcist.isochronous_transfer_descriptor.offset[4] = w & 0xffff; - ohcist.isochronous_transfer_descriptor.offset[5] = (w >> 16) & 0xffff; - w = ohcist.space->read_dword(address + 28); - ohcist.isochronous_transfer_descriptor.offset[6] = w & 0xffff; - ohcist.isochronous_transfer_descriptor.offset[7] = (w >> 16) & 0xffff; -} - -void ohci_usb_controller::usb_ohci_writeback_isochronous_transfer_descriptor(UINT32 address) -{ - UINT32 w; - - w = ohcist.isochronous_transfer_descriptor.word0 & 0x1f0000; - w = w | (ohcist.isochronous_transfer_descriptor.cc << 28) | (ohcist.isochronous_transfer_descriptor.fc << 24) | (ohcist.isochronous_transfer_descriptor.di << 21) | ohcist.isochronous_transfer_descriptor.sf; - ohcist.space->write_dword(address, w); - w = ohcist.isochronous_transfer_descriptor.word1 & 0xfff; - w = w | ohcist.isochronous_transfer_descriptor.bp0; - ohcist.space->write_dword(address + 4, w); - ohcist.space->write_dword(address + 8, ohcist.isochronous_transfer_descriptor.nexttd); - ohcist.space->write_dword(address + 12, ohcist.isochronous_transfer_descriptor.be); - w = (ohcist.isochronous_transfer_descriptor.offset[1] << 16) | ohcist.isochronous_transfer_descriptor.offset[0]; - ohcist.space->write_dword(address + 16, w); - w = (ohcist.isochronous_transfer_descriptor.offset[3] << 16) | ohcist.isochronous_transfer_descriptor.offset[2]; - ohcist.space->write_dword(address + 20, w); - w = (ohcist.isochronous_transfer_descriptor.offset[5] << 16) | ohcist.isochronous_transfer_descriptor.offset[4]; - ohcist.space->write_dword(address + 24, w); - w = (ohcist.isochronous_transfer_descriptor.offset[7] << 16) | ohcist.isochronous_transfer_descriptor.offset[6]; - ohcist.space->write_dword(address + 28, w); -} - -void ohci_usb_controller::usb_ohci_device_address_changed(int old_address, int new_address) -{ - ohcist.address[new_address].function = ohcist.address[old_address].function; - ohcist.address[new_address].port = ohcist.address[old_address].port; - ohcist.address[old_address].port = -1; -} - -/* -* ohci device base class -*/ - -ohci_function_device::ohci_function_device() -{ -} - -void ohci_function_device::initialize(running_machine &machine, ohci_usb_controller *usb_bus_manager) -{ - busmanager = usb_bus_manager; - state = DefaultState; - descriptors = auto_alloc_array(machine, UINT8, 1024); - descriptors_pos = 0; - address = 0; - newaddress = 0; - 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; - wantstatuscallback = false; - settingaddress = false; - configurationvalue = 0; - selected_configuration = nullptr; - latest_configuration = nullptr; - latest_alternate = nullptr; -} - -void ohci_function_device::add_device_descriptor(const USBStandardDeviceDescriptor &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(const USBStandardConfigurationDescriptor &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; - c->position = p; - c->size = descriptor.bLength; - 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(const USBStandardInterfaceDescriptor &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; - latest_configuration->size += 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) - { - (*i)->size += descriptor.bLength; - latest_configuration->interfaces.front()->size += descriptor.bLength; - aa = new usb_device_interface_alternate; - memcpy(&aa->interface_descriptor, &descriptor, sizeof(USBStandardInterfaceDescriptor)); - aa->position = p; - aa->size = descriptor.bLength; - (*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)); - aa->position = p; - aa->size = descriptor.bLength; - ii->position = p; - ii->size = descriptor.bLength; - 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(const USBStandardEndpointDescriptor &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); - latest_alternate->size += descriptor.bLength; - latest_configuration->interfaces.front()->size += descriptor.bLength; - latest_configuration->size += descriptor.bLength; -} - -void ohci_function_device::add_string_descriptor(const UINT8 *descriptor) -{ - usb_device_string *ss; - int len = descriptor[0]; - UINT8 *p = descriptors + descriptors_pos; - - - ss = new usb_device_string; - memcpy(p, descriptor, len); - descriptors_pos += len; - ss->size = len; - ss->position = p; - device_strings.push_front(ss); - //latest_configuration->size += len; -} - -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; - // by default, activate alternate setting 0 in each interface - 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) - { - // activate the endpoints in interface i alternate setting 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; - } - break; - } - } - } - break; - } - } -} - -void ohci_function_device::select_alternate(int interfacei, int index) -{ - // among all the interfaces in the currently selected configuration, consider interface interfacei - for (auto i = selected_configuration->interfaces.begin(); i != selected_configuration->interfaces.end(); ++i) - { - // deactivate the endpoints in the currently selected alternate setting for interface interfacei - 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; - } - break; - } - } - // activate the endpoints in the newly selected alternate setting - 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; - } - break; - } - } - } -} - -int ohci_function_device::find_alternate(int interfacei) -{ - // find the active alternate setting for interface inteerfacei - 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; -} - -UINT8 *ohci_function_device::position_device_descriptor(int &size) -{ - size = descriptors_pos; // descriptors[0]; - return descriptors; -} - -UINT8 *ohci_function_device::position_configuration_descriptor(int index, int &size) -{ - for (auto c = configurations.begin(); c != configurations.end(); ++c) - { - if ((*c)->configuration_descriptor.bConfigurationValue == (index + 1)) - { - size = (*c)->size; - return (*c)->position; - } - } - size = 0; - return nullptr; -} - -UINT8 *ohci_function_device::position_string_descriptor(int index, int &size) -{ - int i = 0; - - for (auto s = device_strings.begin(); s != device_strings.end(); ++s) - { - if (index == i) - { - size = (*s)->size; - return (*s)->position; - } - i++; - } - size = 0; - return nullptr; -} - -void ohci_function_device::execute_reset() -{ - address = 0; - newaddress = 0; -} - -int ohci_function_device::execute_transfer(int endpoint, int pid, UINT8 *buffer, int size) -{ - int descriptortype, descriptorindex; - - if (pid == SetupPid) { - USBSetupPacket *p=(USBSetupPacket *)buffer; - // control transfers are done in 3 stages: first the setup stage, then an optional data stage, then a status stage - // so there are 3 cases: - // 1- control transfer with a data stage where the host sends data to the device - // in this case the sequence of pids transferred is control pid, data out pid, data in pid - // 2- control transfer with a data stage where the host receives data from the device - // in this case the sequence of pids transferred is control pid, data in pid, data out pid - // 3- control transfer without a data stage - // in this case the sequence of pids transferred is control pid, data in pid - // define direction 0:host->device 1:device->host - // direction == 1 -> IN data stage and OUT status stage - // direction == 0 -> OUT data stage and IN status stage - // data stage not present -> IN status stage - endpoints[endpoint].controldirection = (p->bmRequestType & 128) >> 7; - endpoints[endpoint].controltype = (p->bmRequestType & 0x60) >> 5; - endpoints[endpoint].controlrecipient = p->bmRequestType & 0x1f; - wantstatuscallback = false; - if (endpoint == 0) { - endpoints[endpoint].position = nullptr; - // number of byte to transfer in data stage (0 no data stage) - endpoints[endpoint].remain = p->wLength; - // if standard device request - 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; - settingaddress = true; - break; - case GET_DESCRIPTOR: - descriptortype = p->wValue >> 8; - descriptorindex = p->wValue & 255; - if (descriptortype == DEVICE) { // device descriptor - endpoints[endpoint].position = position_device_descriptor(endpoints[endpoint].remain); - } - else if (descriptortype == CONFIGURATION) { // configuration descriptor - endpoints[endpoint].position = position_configuration_descriptor(descriptorindex, endpoints[endpoint].remain); - } - else if (descriptortype == STRING) { // string descriptor - //p->wIndex; language id - endpoints[endpoint].position = position_string_descriptor(descriptorindex, endpoints[endpoint].remain); - } - else - 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 { - 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: - 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(endpoint, p); - size = 0; - } - else - return handle_nonstandard_request(endpoint, p); - } - else if (pid == InPid) { - if (endpoints[endpoint].type == ControlEndpoint) { //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 ((endpoints[endpoint].remain == 0) && (size == 0)) { - if ((endpoint == 0) && (settingaddress == true)) - { - // set of address is active at end of status stage - busmanager->usb_ohci_device_address_changed(address, newaddress); - address = newaddress; - settingaddress = false; - state = AddressState; - } - if (wantstatuscallback == true) - handle_status_stage(endpoint); - wantstatuscallback = false; - return 0; - } - // case ==1, give data - // case ==0, nothing - // if device->host, since InPid then this is data stage - if (endpoints[endpoint].controldirection == DeviceToHost) { - // data stage - 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 (wantstatuscallback == true) - handle_status_stage(endpoint); - wantstatuscallback = false; - } - } - 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) { - // case ==1, nothing - // case ==0, give data - // if host->device, since OutPid then this is data stage - if (endpoints[endpoint].controldirection == HostToDevice) { - // data stage - 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 { - if (wantstatuscallback == true) - handle_status_stage(endpoint); - wantstatuscallback = false; - } - } - 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; - } - return size; -} - -INPUT_PORTS_START(xbox_controller) - PORT_START("ThumbstickLh") // left analog thumbstick horizontal movement - PORT_BIT(0xff, 0x80, IPT_AD_STICK_X) PORT_NAME("ThumbstickLh") PORT_SENSITIVITY(100) PORT_KEYDELTA(1) PORT_MINMAX(0, 0xff) - PORT_CODE_DEC(KEYCODE_J) PORT_CODE_INC(KEYCODE_L) - PORT_START("ThumbstickLv") // left analog thumbstick vertical movement - PORT_BIT(0xff, 0x80, IPT_AD_STICK_Y) PORT_NAME("ThumbstickLv") PORT_SENSITIVITY(100) PORT_KEYDELTA(1) PORT_MINMAX(0, 0xff) - PORT_CODE_DEC(KEYCODE_K) PORT_CODE_INC(KEYCODE_I) - - PORT_START("ThumbstickRh") // right analog thumbstick horizontal movement - PORT_BIT(0xff, 0x80, IPT_AD_STICK_X) PORT_NAME("ThumbstickRh") PORT_SENSITIVITY(100) PORT_KEYDELTA(1) PORT_MINMAX(0, 0xff) - PORT_CODE_DEC(KEYCODE_4_PAD) PORT_CODE_INC(KEYCODE_6_PAD) - PORT_START("ThumbstickRv") // right analog thumbstick vertical movement - PORT_BIT(0xff, 0x80, IPT_AD_STICK_Y) PORT_NAME("ThumbstickRv") PORT_SENSITIVITY(100) PORT_KEYDELTA(1) PORT_MINMAX(0, 0xff) - PORT_CODE_DEC(KEYCODE_2_PAD) PORT_CODE_INC(KEYCODE_8_PAD) - - PORT_START("DPad") // pressure sensitive directional pad - PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_JOYSTICK_UP) PORT_NAME("DPad Up") - PORT_BIT(0x02, IP_ACTIVE_HIGH, IPT_JOYSTICK_DOWN) PORT_NAME("DPad Down") - PORT_BIT(0x04, IP_ACTIVE_HIGH, IPT_JOYSTICK_LEFT) PORT_NAME("DPad Left") - PORT_BIT(0x08, IP_ACTIVE_HIGH, IPT_JOYSTICK_RIGHT) PORT_NAME("DPad Right") - - PORT_START("TriggerL") // analog trigger - PORT_BIT(0xff, 0x00, IPT_PEDAL) PORT_NAME("TriggerL") PORT_SENSITIVITY(100) PORT_KEYDELTA(1) PORT_MINMAX(0, 0xff) - PORT_CODE_DEC(KEYCODE_1_PAD) PORT_CODE_INC(KEYCODE_7_PAD) - - PORT_START("TriggerR") // analog trigger - PORT_BIT(0xff, 0x00, IPT_PEDAL) PORT_NAME("TriggerR") PORT_SENSITIVITY(100) PORT_KEYDELTA(1) PORT_MINMAX(0, 0xff) - PORT_CODE_DEC(KEYCODE_3_PAD) PORT_CODE_INC(KEYCODE_9_PAD) - - PORT_START("Buttons") // digital buttons - PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_BUTTON2) PORT_NAME("Start") // Start button - PORT_BIT(0x02, IP_ACTIVE_HIGH, IPT_BUTTON1) PORT_NAME("Back") // Back button - - PORT_START("AGreen") // analog button - PORT_BIT(0xff, 0x00, IPT_PEDAL) PORT_NAME("A-Green") PORT_SENSITIVITY(100) PORT_KEYDELTA(32) PORT_MINMAX(0, 0xff) - PORT_CODE_DEC(KEYCODE_A) PORT_CODE_INC(KEYCODE_Q) - - PORT_START("BRed") // analog button - PORT_BIT(0xff, 0x00, IPT_PEDAL) PORT_NAME("B-Red") PORT_SENSITIVITY(100) PORT_KEYDELTA(32) PORT_MINMAX(0, 0xff) - PORT_CODE_DEC(KEYCODE_S) PORT_CODE_INC(KEYCODE_W) - - PORT_START("XBlue") // analog button - PORT_BIT(0xff, 0x00, IPT_PEDAL) PORT_NAME("X-Blue") PORT_SENSITIVITY(100) PORT_KEYDELTA(32) PORT_MINMAX(0, 0xff) - PORT_CODE_DEC(KEYCODE_D) PORT_CODE_INC(KEYCODE_E) - - PORT_START("YYellow") // analog button - PORT_BIT(0xff, 0x00, IPT_PEDAL) PORT_NAME("Y-Yellow") PORT_SENSITIVITY(100) PORT_KEYDELTA(32) PORT_MINMAX(0, 0xff) - PORT_CODE_DEC(KEYCODE_F) PORT_CODE_INC(KEYCODE_R) - - PORT_START("Black") // analog button - PORT_BIT(0xff, 0x00, IPT_PEDAL) PORT_NAME("Black") PORT_SENSITIVITY(100) PORT_KEYDELTA(32) PORT_MINMAX(0, 0xff) - PORT_CODE_DEC(KEYCODE_G) PORT_CODE_INC(KEYCODE_T) - - PORT_START("White") // analog button - PORT_BIT(0xff, 0x00, IPT_PEDAL) PORT_NAME("White") PORT_SENSITIVITY(100) PORT_KEYDELTA(32) PORT_MINMAX(0, 0xff) - PORT_CODE_DEC(KEYCODE_H) PORT_CODE_INC(KEYCODE_Y) -INPUT_PORTS_END - -const USBStandardDeviceDescriptor ohci_game_controller_device::devdesc = { 18,1,0x110,0x00,0x00,0x00,64,0x45e,0x202,0x100,0,0,0,1 }; -const USBStandardConfigurationDescriptor ohci_game_controller_device::condesc = { 9,2,0x20,1,1,0,0x80,50 }; -const USBStandardInterfaceDescriptor ohci_game_controller_device::intdesc = { 9,4,0,0,2,0x58,0x42,0,0 }; -const USBStandardEndpointDescriptor ohci_game_controller_device::enddesc82 = { 7,5,0x82,3,0x20,4 }; -const USBStandardEndpointDescriptor ohci_game_controller_device::enddesc02 = { 7,5,0x02,3,0x20,4 }; - -const device_type OHCI_GAME_CONTROLLER = &device_creator; - -ohci_game_controller_device::ohci_game_controller_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : - device_t(mconfig, OHCI_GAME_CONTROLLER, "OHCI Game Controller", tag, owner, clock, "ohci_gc", __FILE__), - ohci_function_device(), - m_ThumbstickLh(*this, "ThumbstickLh"), - m_ThumbstickLv(*this, "ThumbstickLv"), - m_ThumbstickRh(*this, "ThumbstickRh"), - m_ThumbstickRv(*this, "ThumbstickRv"), - m_DPad(*this, "DPad"), - m_TriggerL(*this, "TriggerL"), - m_TriggerR(*this, "TriggerR"), - m_Buttons(*this, "Buttons"), - m_AGreen(*this, "AGreen"), - m_BRed(*this, "BRed"), - m_XBlue(*this, "XBlue"), - m_YYellow(*this, "YYellow"), - m_Black(*this, "Black"), - m_White(*this, "White") -{ -} - -void ohci_game_controller_device::initialize(running_machine &machine, ohci_usb_controller *usb_bus_manager) -{ - ohci_function_device::initialize(machine, usb_bus_manager); - add_device_descriptor(devdesc); - add_configuration_descriptor(condesc); - add_interface_descriptor(intdesc); - add_endpoint_descriptor(enddesc82); - add_endpoint_descriptor(enddesc02); -} - -int ohci_game_controller_device::handle_nonstandard_request(int endpoint, USBSetupPacket *setup) -{ - // >=8 ==42 !=0 !=0 1,3 2<20 <=20 - static const UINT8 reportinfo[16] = { 0x10,0x42 ,0x32,0x43,1 ,0x65,0x14,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) && (setup->wValue == 0x4200)) - { - endpoints[endpoint].position = (UINT8 *)reportinfo; - 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)) { - int v; - - buffer[0] = 0; - buffer[1] = 20; - v = m_DPad->read(); - v = v | (m_Buttons->read() << 4); - buffer[2] = (UINT8)v; - buffer[3] = 0; - buffer[4] = m_AGreen->read(); - buffer[5] = m_BRed->read(); - buffer[6] = m_XBlue->read(); - buffer[7] = m_YYellow->read(); - buffer[8] = m_Black->read(); - buffer[9] = m_White->read(); - buffer[10] = m_TriggerL->read(); - buffer[11] = m_TriggerR->read(); - v = m_ThumbstickLh->read(); - v = (v - 128) * 256; - buffer[12] = (UINT16)v & 255; - buffer[13] = (UINT16)v >> 8; - v = m_ThumbstickLv->read(); - v = (v - 128) * 256; - buffer[14] = (UINT16)v & 255; - buffer[15] = (UINT16)v >> 8; - v = m_ThumbstickRh->read(); - v = (v - 128) * 256; - buffer[16] = (UINT16)v & 255; - buffer[17] = (UINT16)v >> 8; - v = m_ThumbstickRv->read(); - v = (v - 128) * 256; - buffer[18] = (UINT16)v & 255; - buffer[19] = (UINT16)v >> 8; - return size; - } - return -1; -} - -void ohci_game_controller_device::device_start() -{ -} - -ioport_constructor ohci_game_controller_device::device_input_ports() const -{ - return INPUT_PORTS_NAME(xbox_controller); -} - -WRITE_LINE_MEMBER(xbox_base_state::xbox_ohci_usb_interrupt_changed) -{ - xbox_base_devs.pic8259_1->ir1_w(state); -} - /* * Audio */ diff --git a/src/mame/machine/xbox_usb.cpp b/src/mame/machine/xbox_usb.cpp new file mode 100644 index 00000000000..38efc96c984 --- /dev/null +++ b/src/mame/machine/xbox_usb.cpp @@ -0,0 +1,1540 @@ +// license:BSD-3-Clause +// copyright-holders:Samuele Zannoli + +#include + +#include "emu.h" +#include "cpu/i386/i386.h" +#include "machine/lpci.h" +#include "machine/pic8259.h" +#include "machine/pit8253.h" +#include "machine/idectrl.h" +#include "video/poly.h" +#include "bitmap.h" +#include "debugger.h" +#include "debug/debugcon.h" +#include "debug/debugcmd.h" +#include "debug/debugcpu.h" +#include "includes/chihiro.h" +#include "includes/xbox.h" +#include "includes/xbox_usb.h" + +//#define LOG_OHCI + +/* + * ohci usb controller + */ + +#ifdef LOG_OHCI +static const char *const usbregnames[] = { + "HcRevision", + "HcControl", + "HcCommandStatus", + "HcInterruptStatus", + "HcInterruptEnable", + "HcInterruptDisable", + "HcHCCA", + "HcPeriodCurrentED", + "HcControlHeadED", + "HcControlCurrentED", + "HcBulkHeadED", + "HcBulkCurrentED", + "HcDoneHead", + "HcFmInterval", + "HcFmRemaining", + "HcFmNumber", + "HcPeriodicStart", + "HcLSThreshold", + "HcRhDescriptorA", + "HcRhDescriptorB", + "HcRhStatus", + "HcRhPortStatus[1]" +}; +#endif + +const device_type OHCI_USB_CONTROLLER = &device_creator; + +ohci_usb_controller::ohci_usb_controller(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, OHCI_USB_CONTROLLER, "OHCI USB CONTROLLER", tag, owner, clock, "ohciusb", __FILE__), + m_interrupt_handler(*this) +{ + memset(&ohcist, 0, sizeof(ohcist)); +} + +void ohci_usb_controller::device_start() +{ + m_maincpu = machine().device("maincpu"); + m_interrupt_handler.resolve_safe(); + ohcist.hc_regs[HcRevision] = 0x10; + ohcist.hc_regs[HcFmInterval] = 0x2edf; + ohcist.hc_regs[HcLSThreshold] = 0x628; + ohcist.hc_regs[HcRhDescriptorA] = 4; + ohcist.hc_regs[HcControl] = UsbReset << 6; + ohcist.state = UsbReset; + ohcist.interruptbulkratio = 1; + ohcist.writebackdonehadcounter = 7; + for (int n = 0; n <= 4; n++) + ohcist.ports[n].address = -1; + for (int n = 0; n < 256; n++) + ohcist.address[n].port = -1; + ohcist.space = &(m_maincpu->space()); + ohcist.timer = timer_alloc(0); + ohcist.timer->enable(false); +} + +void ohci_usb_controller::device_reset() +{ +} + +READ32_MEMBER(ohci_usb_controller::read) +{ + UINT32 ret; + +#ifdef LOG_OHCI + if (offset >= 0x54 / 4) + logerror("usb controller 0 register HcRhPortStatus[%d] read\n", (offset - 0x54 / 4) + 1); + else + logerror("usb controller 0 register %s read\n", usbregnames[offset]); +#endif + ret = ohcist.hc_regs[offset]; + return ret; +} + +WRITE32_MEMBER(ohci_usb_controller::write) +{ + UINT32 old = ohcist.hc_regs[offset]; + +#ifdef LOG_OHCI + if (offset >= 0x54 / 4) + logerror("usb controller 0 register HcRhPortStatus[%d] write %08X\n", (offset - 0x54 / 4) + 1, data); + else + logerror("usb controller 0 register %s write %08X\n", usbregnames[offset], data); +#endif + if (offset == HcRhStatus) { + if (data & CRWE) + ohcist.hc_regs[HcRhStatus] &= ~DRWE; + if (data & OCIC) + ohcist.hc_regs[HcRhStatus] &= ~OCI; + if (data & LPSC) + ohcist.hc_regs[HcRhStatus] &= ~LPS; + return; + } + if (offset == HcControl) { + int hcfs; + + hcfs = (data >> 6) & 3; // HostControllerFunctionalState + if (hcfs == UsbOperational) { + ohcist.timer->enable(); + ohcist.timer->adjust(attotime::from_msec(1), 0, attotime::from_msec(1)); + ohcist.writebackdonehadcounter = 7; + // need to load the FrameRemaining field of HcFmRemaining with the value of the FrameInterval field in HcFmInterval + } + else + ohcist.timer->enable(false); + ohcist.interruptbulkratio = (data & 3) + 1; + if ((hcfs != UsbReset) && (ohcist.state == UsbReset)) + { + ohcist.hc_regs[HcInterruptStatus] |= RootHubStatusChange; + usb_ohci_interrupts(); + } + ohcist.state = hcfs; + } + if (offset == HcCommandStatus) { + if (data & 1) // HostControllerReset + ohcist.hc_regs[HcControl] |= 3 << 6; + ohcist.hc_regs[HcCommandStatus] |= data; + return; + } + if (offset == HcInterruptStatus) { + ohcist.hc_regs[HcInterruptStatus] &= ~data; + usb_ohci_interrupts(); + return; + } + if (offset == HcInterruptEnable) { + ohcist.hc_regs[HcInterruptEnable] |= data; + usb_ohci_interrupts(); + return; + } + if (offset == HcInterruptDisable) { + ohcist.hc_regs[HcInterruptEnable] &= ~data; + usb_ohci_interrupts(); + return; + } + if (offset >= HcRhPortStatus1) { + int port = offset - HcRhPortStatus1 + 1; // port 0 not used + // bit 0 R:CurrentConnectStatus W:ClearPortEnable: 1 clears PortEnableStatus + if (data & CCS) { + ohcist.hc_regs[offset] &= ~PES; + ohcist.address[ohcist.ports[port].address].port = -1; + } + // bit 1 R:PortEnableStatus W:SetPortEnable: 1 sets PortEnableStatus + if (data & PES) { + ohcist.hc_regs[offset] |= PES; + // the port is enabled, so the device connected to it can communicate on the bus + ohcist.address[ohcist.ports[port].address].function = ohcist.ports[port].function; + ohcist.address[ohcist.ports[port].address].port = port; + } + // bit 2 R:PortSuspendStatus W:SetPortSuspend: 1 sets PortSuspendStatus + if (data & PSS) { + ohcist.hc_regs[offset] |= PSS; + } + // bit 3 R:PortOverCurrentIndicator W:ClearSuspendStatus: 1 clears PortSuspendStatus + if (data & POCI) { + ohcist.hc_regs[offset] &= ~PSS; + } + // bit 4 R: PortResetStatus W:SetPortReset: 1 sets PortResetStatus + if (data & PRS) { + ohcist.hc_regs[offset] |= PRS; + if (ohcist.ports[port].address >= 0) + ohcist.address[ohcist.ports[port].address].port = -1; + ohcist.ports[port].address = 0; + if (ohcist.hc_regs[offset] & PES) + { + ohcist.address[0].function = ohcist.ports[port].function; + ohcist.address[0].port = port; + } + ohcist.ports[port].function->execute_reset(); + // after 10ms set PortResetStatusChange and clear PortResetStatus and set PortEnableStatus + ohcist.ports[port].delay = 10; + } + // bit 8 R:PortPowerStatus W:SetPortPower: 1 sets PortPowerStatus + if (data & PPS) { + ohcist.hc_regs[offset] |= PPS; + } + // bit 9 R:LowSpeedDeviceAttached W:ClearPortPower: 1 clears PortPowerStatus + if (data & LSDA) { + ohcist.hc_regs[offset] &= ~PPS; + } + // bit 16 R:ConnectStatusChange W: 1 clears ConnectStatusChange + if (data & CSC) { + ohcist.hc_regs[offset] &= ~CSC; + } + // bit 17 R:PortEnableStatusChange W: 1 clears PortEnableStatusChange + if (data & PESC) { + ohcist.hc_regs[offset] &= ~PESC; + } + // bit 18 R:PortSuspendStatusChange W: 1 clears PortSuspendStatusChange + if (data & PSSC) { + ohcist.hc_regs[offset] &= ~PSSC; + } + // bit 19 R:PortOverCurrentIndicatorChange W: 1 clears PortOverCurrentIndicatorChange + if (data & POCIC) { + ohcist.hc_regs[offset] &= ~POCIC; + } + // bit 20 R:PortResetStatusChange W: 1 clears PortResetStatusChange + if (data & PRSC) { + ohcist.hc_regs[offset] &= ~PRSC; + } + if (ohcist.hc_regs[offset] != old) + ohcist.hc_regs[HcInterruptStatus] |= RootHubStatusChange; + usb_ohci_interrupts(); + return; + } + ohcist.hc_regs[offset] = data; +} + +void ohci_usb_controller::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + UINT32 hcca; + UINT32 plh; + int changed = 0; + int list = 1; + bool cont = false; + bool retire = false; + int pid, remain, mps, done; + + hcca = ohcist.hc_regs[HcHCCA]; + if (ohcist.state == UsbOperational) { + // increment frame number + ohcist.framenumber = (ohcist.framenumber + 1) & 0xffff; + ohcist.space->write_dword(hcca + 0x80, ohcist.framenumber); + ohcist.hc_regs[HcFmNumber] = ohcist.framenumber; + } + // port reset delay + for (int p = 1; p <= 4; p++) { + if (ohcist.ports[p].delay > 0) { + ohcist.ports[p].delay--; + if (ohcist.ports[p].delay == 0) { + ohcist.hc_regs[HcRhPortStatus1 + p - 1] = (ohcist.hc_regs[HcRhPortStatus1 + p - 1] & ~PRS) | PRSC | PES; + ohcist.address[ohcist.ports[p].address].function = ohcist.ports[p].function; + ohcist.address[ohcist.ports[p].address].port = p; + changed = 1; + } + } + } + if (ohcist.state == UsbOperational) { + while (list >= 0) + { + // select list, do transfer + if (list == 0) { + if (ohcist.hc_regs[HcControl] & PLE) { + // periodic 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; + } + if (list == 1) { + // control list + // check if control list active + if (ohcist.hc_regs[HcControl] & CLE) { + cont = true; + while (cont == true) { + // if current endpoint descriptor is not 0 use it, otherwise ... + if (ohcist.hc_regs[HcControlCurrentED] == 0) { + // ... check the filled bit ... + if (ohcist.hc_regs[HcCommandStatus] & (1 << 1)) { + // ... if 1 start processing from the head of the list + ohcist.hc_regs[HcControlCurrentED] = ohcist.hc_regs[HcControlHeadED]; + // clear CLF (ControlListFilled) + ohcist.hc_regs[HcCommandStatus] &= ~(1 << 1); + // but if the list is empty, go to the next list + if (ohcist.hc_regs[HcControlCurrentED] == 0) + cont = false; + else + cont = true; + } + else + cont = false; + } + else + cont = true; + if (cont == false) + break; + // service endpoint descriptor + usb_ohci_read_endpoint_descriptor(ohcist.hc_regs[HcControlCurrentED]); + // 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; + // set CLF (ControlListFilled) + ohcist.hc_regs[HcCommandStatus] |= (1 << 1); + // service transfer descriptor + 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 + } + // determine how much data to transfer + // setup pid must be 8 bytes + a = ohcist.transfer_descriptor.be & 0xfff; + b = ohcist.transfer_descriptor.cbp & 0xfff; + if ((ohcist.transfer_descriptor.be ^ ohcist.transfer_descriptor.cbp) & 0xfffff000) + a |= 0x1000; + remain = a - b + 1; + mps = ohcist.endpoint_descriptor.mps; + if ((pid == InPid) || (pid == OutPid)) { + 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) { + // ... 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 = ohcist.transfer_descriptor.be & 0xfffff000; + } + } + // 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) || (pid == SetupPid)) + 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(ohcist.hc_regs[HcControlCurrentED]); + } + else { + usb_ohci_writeback_transfer_descriptor(ohcist.endpoint_descriptor.headp); + } + } + else { + // no transfer descriptors for this endpoint, so go to next endpoint + ohcist.hc_regs[HcControlCurrentED] = ohcist.endpoint_descriptor.nexted; + } + } + else { + // not enabled, so go to next endpoint + ohcist.hc_regs[HcControlCurrentED] = ohcist.endpoint_descriptor.nexted; + } + // one bulk every n control transfers + ohcist.interruptbulkratio--; + if (ohcist.interruptbulkratio <= 0) { + ohcist.interruptbulkratio = (ohcist.hc_regs[HcControl] & 3) + 1; // ControlBulkServiceRatio + cont = false; + } + } + } + list = 2; + } + if (list == 2) { + // bulk list + // check if bulk list active + if (ohcist.hc_regs[HcControl] & BLE) { + // if current endpoint descriptor is not 0 use it, otherwise ... + if (ohcist.hc_regs[HcBulkCurrentED] == 0) { + // ... check the filled bit ... + if (ohcist.hc_regs[HcCommandStatus] & (1 << 2)) { + // ... if 1 start processing from the head of the list + ohcist.hc_regs[HcBulkCurrentED] = ohcist.hc_regs[HcBulkHeadED]; + // clear BLF (BulkListFilled) + ohcist.hc_regs[HcCommandStatus] &= ~(1 << 2); + // but if the list is empty, go to the next list + if (ohcist.hc_regs[HcBulkCurrentED] == 0) + cont = false; + else + cont = true; + } + else + cont = false; + } + else + cont = true; + if (cont == true) { + // service endpoint descriptor + usb_ohci_read_endpoint_descriptor(ohcist.hc_regs[HcBulkCurrentED]); + // 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; + // set BLF (BulkListFilled) + ohcist.hc_regs[HcCommandStatus] |= (1 << 2); + // service transfer descriptor + 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 + } + // determine how much data to transfer + a = ohcist.transfer_descriptor.be & 0xfff; + b = ohcist.transfer_descriptor.cbp & 0xfff; + if ((ohcist.transfer_descriptor.be ^ ohcist.transfer_descriptor.cbp) & 0xfffff000) + a |= 0x1000; + remain = a - b + 1; + mps = ohcist.endpoint_descriptor.mps; + if (remain < mps) + mps = remain; + b = ohcist.transfer_descriptor.cbp; + // 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 = ohcist.transfer_descriptor.be & 0xfffff000; + } + } + // 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(ohcist.hc_regs[HcBulkCurrentED]); + } + else { + usb_ohci_writeback_transfer_descriptor(ohcist.endpoint_descriptor.headp); + } + } + else { + // no transfer descriptors for this endpoint, so go to next endpoint + ohcist.hc_regs[HcBulkCurrentED] = ohcist.endpoint_descriptor.nexted; + } + } + else { + // not enabled, so go to next endpoint + ohcist.hc_regs[HcBulkCurrentED] = ohcist.endpoint_descriptor.nexted; + } + } + // go to the next list + 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 stay in bulk list if enabled and filled + else + list = 0; // if no control or bulk lists, go to periodic list + } + } + } + if (ohcist.framenumber == 0) + ohcist.hc_regs[HcInterruptStatus] |= FrameNumberOverflow; + ohcist.hc_regs[HcInterruptStatus] |= StartofFrame; + if ((ohcist.writebackdonehadcounter != 0) && (ohcist.writebackdonehadcounter != 7)) + ohcist.writebackdonehadcounter--; + if ((ohcist.writebackdonehadcounter == 0) && ((ohcist.hc_regs[HcInterruptStatus] & WritebackDoneHead) == 0)) { + UINT32 b = 0; + + if ((ohcist.hc_regs[HcInterruptStatus] & ohcist.hc_regs[HcInterruptEnable]) != WritebackDoneHead) + b = 1; + ohcist.hc_regs[HcInterruptStatus] |= WritebackDoneHead; + ohcist.space->write_dword(hcca + 0x84, ohcist.hc_regs[HcDoneHead] | b); + ohcist.hc_regs[HcDoneHead] = 0; + ohcist.writebackdonehadcounter = 7; + } + } + if (changed != 0) { + ohcist.hc_regs[HcInterruptStatus] |= RootHubStatusChange; + } + usb_ohci_interrupts(); +} + +void ohci_usb_controller::usb_ohci_plug(int port, ohci_function_device *function) +{ + if ((port > 0) && (port <= 4)) { + ohcist.ports[port].function = function; + ohcist.ports[port].address = -1; + ohcist.hc_regs[HcRhPortStatus1 + port - 1] = CCS | CSC; + if (ohcist.state != UsbReset) + { + ohcist.hc_regs[HcInterruptStatus] |= RootHubStatusChange; + usb_ohci_interrupts(); + } + } +} + +void ohci_usb_controller::usb_ohci_interrupts() +{ + if (((ohcist.hc_regs[HcInterruptStatus] & ohcist.hc_regs[HcInterruptEnable]) != 0) && ((ohcist.hc_regs[HcInterruptEnable] & MasterInterruptEnable) != 0)) + { + //pic8259_1->ir1_w(1); + m_interrupt_handler(1); + } else + { + //pic8259_1->ir1_w(0); + m_interrupt_handler(0); + } +} + +void ohci_usb_controller::usb_ohci_read_endpoint_descriptor(UINT32 address) +{ + UINT32 w; + + w = ohcist.space->read_dword(address); + ohcist.endpoint_descriptor.word0 = w; + ohcist.endpoint_descriptor.fa = w & 0x7f; + ohcist.endpoint_descriptor.en = (w >> 7) & 15; + ohcist.endpoint_descriptor.d = (w >> 11) & 3; + ohcist.endpoint_descriptor.s = (w >> 13) & 1; + ohcist.endpoint_descriptor.k = (w >> 14) & 1; + ohcist.endpoint_descriptor.f = (w >> 15) & 1; + ohcist.endpoint_descriptor.mps = (w >> 16) & 0x7ff; + ohcist.endpoint_descriptor.tailp = ohcist.space->read_dword(address + 4); + w = ohcist.space->read_dword(address + 8); + ohcist.endpoint_descriptor.headp = w & 0xfffffffc; + ohcist.endpoint_descriptor.h = w & 1; + ohcist.endpoint_descriptor.c = (w >> 1) & 1; + ohcist.endpoint_descriptor.nexted = ohcist.space->read_dword(address + 12); +} + +void ohci_usb_controller::usb_ohci_writeback_endpoint_descriptor(UINT32 address) +{ + UINT32 w; + + w = ohcist.endpoint_descriptor.word0 & 0xf8000000; + w = w | (ohcist.endpoint_descriptor.mps << 16) | (ohcist.endpoint_descriptor.f << 15) | (ohcist.endpoint_descriptor.k << 14) | (ohcist.endpoint_descriptor.s << 13) | (ohcist.endpoint_descriptor.d << 11) | (ohcist.endpoint_descriptor.en << 7) | ohcist.endpoint_descriptor.fa; + ohcist.space->write_dword(address, w); + w = ohcist.endpoint_descriptor.headp | (ohcist.endpoint_descriptor.c << 1) | ohcist.endpoint_descriptor.h; + ohcist.space->write_dword(address + 8, w); +} + +void ohci_usb_controller::usb_ohci_read_transfer_descriptor(UINT32 address) +{ + UINT32 w; + + w = ohcist.space->read_dword(address); + ohcist.transfer_descriptor.word0 = w; + ohcist.transfer_descriptor.cc = (w >> 28) & 15; + ohcist.transfer_descriptor.ec = (w >> 26) & 3; + ohcist.transfer_descriptor.t = (w >> 24) & 3; + ohcist.transfer_descriptor.di = (w >> 21) & 7; + ohcist.transfer_descriptor.dp = (w >> 19) & 3; + ohcist.transfer_descriptor.r = (w >> 18) & 1; + ohcist.transfer_descriptor.cbp = ohcist.space->read_dword(address + 4); + ohcist.transfer_descriptor.nexttd = ohcist.space->read_dword(address + 8); + ohcist.transfer_descriptor.be = ohcist.space->read_dword(address + 12); +} + +void ohci_usb_controller::usb_ohci_writeback_transfer_descriptor(UINT32 address) +{ + UINT32 w; + + w = ohcist.transfer_descriptor.word0 & 0x0003ffff; + w = w | (ohcist.transfer_descriptor.cc << 28) | (ohcist.transfer_descriptor.ec << 26) | (ohcist.transfer_descriptor.t << 24) | (ohcist.transfer_descriptor.di << 21) | (ohcist.transfer_descriptor.dp << 19) | (ohcist.transfer_descriptor.r << 18); + ohcist.space->write_dword(address, w); + ohcist.space->write_dword(address + 4, ohcist.transfer_descriptor.cbp); + ohcist.space->write_dword(address + 8, ohcist.transfer_descriptor.nexttd); +} + +void ohci_usb_controller::usb_ohci_read_isochronous_transfer_descriptor(UINT32 address) +{ + UINT32 w; + + w = ohcist.space->read_dword(address); + ohcist.isochronous_transfer_descriptor.word0 = w; + ohcist.isochronous_transfer_descriptor.cc = (w >> 28) & 15; + ohcist.isochronous_transfer_descriptor.fc = (w >> 24) & 7; + ohcist.isochronous_transfer_descriptor.di = (w >> 21) & 7; + ohcist.isochronous_transfer_descriptor.sf = w & 0xffff; + w = ohcist.space->read_dword(address + 4); + ohcist.isochronous_transfer_descriptor.word1 = w; + ohcist.isochronous_transfer_descriptor.bp0 = w & 0xfffff000; + ohcist.isochronous_transfer_descriptor.nexttd = ohcist.space->read_dword(address + 8); + ohcist.isochronous_transfer_descriptor.be = ohcist.space->read_dword(address + 12); + w = ohcist.space->read_dword(address + 16); + ohcist.isochronous_transfer_descriptor.offset[0] = w & 0xffff; + ohcist.isochronous_transfer_descriptor.offset[1] = (w >> 16) & 0xffff; + w = ohcist.space->read_dword(address + 20); + ohcist.isochronous_transfer_descriptor.offset[2] = w & 0xffff; + ohcist.isochronous_transfer_descriptor.offset[3] = (w >> 16) & 0xffff; + w = ohcist.space->read_dword(address + 24); + ohcist.isochronous_transfer_descriptor.offset[4] = w & 0xffff; + ohcist.isochronous_transfer_descriptor.offset[5] = (w >> 16) & 0xffff; + w = ohcist.space->read_dword(address + 28); + ohcist.isochronous_transfer_descriptor.offset[6] = w & 0xffff; + ohcist.isochronous_transfer_descriptor.offset[7] = (w >> 16) & 0xffff; +} + +void ohci_usb_controller::usb_ohci_writeback_isochronous_transfer_descriptor(UINT32 address) +{ + UINT32 w; + + w = ohcist.isochronous_transfer_descriptor.word0 & 0x1f0000; + w = w | (ohcist.isochronous_transfer_descriptor.cc << 28) | (ohcist.isochronous_transfer_descriptor.fc << 24) | (ohcist.isochronous_transfer_descriptor.di << 21) | ohcist.isochronous_transfer_descriptor.sf; + ohcist.space->write_dword(address, w); + w = ohcist.isochronous_transfer_descriptor.word1 & 0xfff; + w = w | ohcist.isochronous_transfer_descriptor.bp0; + ohcist.space->write_dword(address + 4, w); + ohcist.space->write_dword(address + 8, ohcist.isochronous_transfer_descriptor.nexttd); + ohcist.space->write_dword(address + 12, ohcist.isochronous_transfer_descriptor.be); + w = (ohcist.isochronous_transfer_descriptor.offset[1] << 16) | ohcist.isochronous_transfer_descriptor.offset[0]; + ohcist.space->write_dword(address + 16, w); + w = (ohcist.isochronous_transfer_descriptor.offset[3] << 16) | ohcist.isochronous_transfer_descriptor.offset[2]; + ohcist.space->write_dword(address + 20, w); + w = (ohcist.isochronous_transfer_descriptor.offset[5] << 16) | ohcist.isochronous_transfer_descriptor.offset[4]; + ohcist.space->write_dword(address + 24, w); + w = (ohcist.isochronous_transfer_descriptor.offset[7] << 16) | ohcist.isochronous_transfer_descriptor.offset[6]; + ohcist.space->write_dword(address + 28, w); +} + +void ohci_usb_controller::usb_ohci_device_address_changed(int old_address, int new_address) +{ + ohcist.address[new_address].function = ohcist.address[old_address].function; + ohcist.address[new_address].port = ohcist.address[old_address].port; + ohcist.address[old_address].port = -1; +} + +/* +* ohci device base class +*/ + +ohci_function_device::ohci_function_device() +{ +} + +void ohci_function_device::initialize(running_machine &machine, ohci_usb_controller *usb_bus_manager) +{ + busmanager = usb_bus_manager; + state = DefaultState; + descriptors = auto_alloc_array(machine, UINT8, 1024); + descriptors_pos = 0; + address = 0; + newaddress = 0; + 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; + wantstatuscallback = false; + settingaddress = false; + configurationvalue = 0; + selected_configuration = nullptr; + latest_configuration = nullptr; + latest_alternate = nullptr; +} + +void ohci_function_device::add_device_descriptor(const USBStandardDeviceDescriptor &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(const USBStandardConfigurationDescriptor &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; + c->position = p; + c->size = descriptor.bLength; + 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(const USBStandardInterfaceDescriptor &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; + latest_configuration->size += 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) + { + (*i)->size += descriptor.bLength; + latest_configuration->interfaces.front()->size += descriptor.bLength; + aa = new usb_device_interface_alternate; + memcpy(&aa->interface_descriptor, &descriptor, sizeof(USBStandardInterfaceDescriptor)); + aa->position = p; + aa->size = descriptor.bLength; + (*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)); + aa->position = p; + aa->size = descriptor.bLength; + ii->position = p; + ii->size = descriptor.bLength; + 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(const USBStandardEndpointDescriptor &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); + latest_alternate->size += descriptor.bLength; + latest_configuration->interfaces.front()->size += descriptor.bLength; + latest_configuration->size += descriptor.bLength; +} + +void ohci_function_device::add_string_descriptor(const UINT8 *descriptor) +{ + usb_device_string *ss; + int len = descriptor[0]; + UINT8 *p = descriptors + descriptors_pos; + + + ss = new usb_device_string; + memcpy(p, descriptor, len); + descriptors_pos += len; + ss->size = len; + ss->position = p; + device_strings.push_front(ss); + //latest_configuration->size += len; +} + +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; + // by default, activate alternate setting 0 in each interface + 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) + { + // activate the endpoints in interface i alternate setting 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; + } + break; + } + } + } + break; + } + } +} + +void ohci_function_device::select_alternate(int interfacei, int index) +{ + // among all the interfaces in the currently selected configuration, consider interface interfacei + for (auto i = selected_configuration->interfaces.begin(); i != selected_configuration->interfaces.end(); ++i) + { + // deactivate the endpoints in the currently selected alternate setting for interface interfacei + 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; + } + break; + } + } + // activate the endpoints in the newly selected alternate setting + 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; + } + break; + } + } + } +} + +int ohci_function_device::find_alternate(int interfacei) +{ + // find the active alternate setting for interface inteerfacei + 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; +} + +UINT8 *ohci_function_device::position_device_descriptor(int &size) +{ + size = descriptors_pos; // descriptors[0]; + return descriptors; +} + +UINT8 *ohci_function_device::position_configuration_descriptor(int index, int &size) +{ + for (auto c = configurations.begin(); c != configurations.end(); ++c) + { + if ((*c)->configuration_descriptor.bConfigurationValue == (index + 1)) + { + size = (*c)->size; + return (*c)->position; + } + } + size = 0; + return nullptr; +} + +UINT8 *ohci_function_device::position_string_descriptor(int index, int &size) +{ + int i = 0; + + for (auto s = device_strings.begin(); s != device_strings.end(); ++s) + { + if (index == i) + { + size = (*s)->size; + return (*s)->position; + } + i++; + } + size = 0; + return nullptr; +} + +void ohci_function_device::execute_reset() +{ + address = 0; + newaddress = 0; +} + +int ohci_function_device::execute_transfer(int endpoint, int pid, UINT8 *buffer, int size) +{ + int descriptortype, descriptorindex; + + if (pid == SetupPid) { + USBSetupPacket *p=(USBSetupPacket *)buffer; + // control transfers are done in 3 stages: first the setup stage, then an optional data stage, then a status stage + // so there are 3 cases: + // 1- control transfer with a data stage where the host sends data to the device + // in this case the sequence of pids transferred is control pid, data out pid, data in pid + // 2- control transfer with a data stage where the host receives data from the device + // in this case the sequence of pids transferred is control pid, data in pid, data out pid + // 3- control transfer without a data stage + // in this case the sequence of pids transferred is control pid, data in pid + // define direction 0:host->device 1:device->host + // direction == 1 -> IN data stage and OUT status stage + // direction == 0 -> OUT data stage and IN status stage + // data stage not present -> IN status stage + endpoints[endpoint].controldirection = (p->bmRequestType & 128) >> 7; + endpoints[endpoint].controltype = (p->bmRequestType & 0x60) >> 5; + endpoints[endpoint].controlrecipient = p->bmRequestType & 0x1f; + wantstatuscallback = false; + if (endpoint == 0) { + endpoints[endpoint].position = nullptr; + // number of byte to transfer in data stage (0 no data stage) + endpoints[endpoint].remain = p->wLength; + // if standard device request + 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; + settingaddress = true; + break; + case GET_DESCRIPTOR: + descriptortype = p->wValue >> 8; + descriptorindex = p->wValue & 255; + if (descriptortype == DEVICE) { // device descriptor + endpoints[endpoint].position = position_device_descriptor(endpoints[endpoint].remain); + } + else if (descriptortype == CONFIGURATION) { // configuration descriptor + endpoints[endpoint].position = position_configuration_descriptor(descriptorindex, endpoints[endpoint].remain); + } + else if (descriptortype == STRING) { // string descriptor + //p->wIndex; language id + endpoints[endpoint].position = position_string_descriptor(descriptorindex, endpoints[endpoint].remain); + } + else + 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 { + 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: + 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(endpoint, p); + size = 0; + } + else + return handle_nonstandard_request(endpoint, p); + } + else if (pid == InPid) { + if (endpoints[endpoint].type == ControlEndpoint) { //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 ((endpoints[endpoint].remain == 0) && (size == 0)) { + if ((endpoint == 0) && (settingaddress == true)) + { + // set of address is active at end of status stage + busmanager->usb_ohci_device_address_changed(address, newaddress); + address = newaddress; + settingaddress = false; + state = AddressState; + } + if (wantstatuscallback == true) + handle_status_stage(endpoint); + wantstatuscallback = false; + return 0; + } + // case ==1, give data + // case ==0, nothing + // if device->host, since InPid then this is data stage + if (endpoints[endpoint].controldirection == DeviceToHost) { + // data stage + 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 (wantstatuscallback == true) + handle_status_stage(endpoint); + wantstatuscallback = false; + } + } + 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) { + // case ==1, nothing + // case ==0, give data + // if host->device, since OutPid then this is data stage + if (endpoints[endpoint].controldirection == HostToDevice) { + // data stage + 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 { + if (wantstatuscallback == true) + handle_status_stage(endpoint); + wantstatuscallback = false; + } + } + 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; + } + return size; +} + +INPUT_PORTS_START(xbox_controller) + PORT_START("ThumbstickLh") // left analog thumbstick horizontal movement + PORT_BIT(0xff, 0x80, IPT_AD_STICK_X) PORT_NAME("ThumbstickLh") PORT_SENSITIVITY(100) PORT_KEYDELTA(1) PORT_MINMAX(0, 0xff) + PORT_CODE_DEC(KEYCODE_J) PORT_CODE_INC(KEYCODE_L) + PORT_START("ThumbstickLv") // left analog thumbstick vertical movement + PORT_BIT(0xff, 0x80, IPT_AD_STICK_Y) PORT_NAME("ThumbstickLv") PORT_SENSITIVITY(100) PORT_KEYDELTA(1) PORT_MINMAX(0, 0xff) + PORT_CODE_DEC(KEYCODE_K) PORT_CODE_INC(KEYCODE_I) + + PORT_START("ThumbstickRh") // right analog thumbstick horizontal movement + PORT_BIT(0xff, 0x80, IPT_AD_STICK_X) PORT_NAME("ThumbstickRh") PORT_SENSITIVITY(100) PORT_KEYDELTA(1) PORT_MINMAX(0, 0xff) + PORT_CODE_DEC(KEYCODE_4_PAD) PORT_CODE_INC(KEYCODE_6_PAD) + PORT_START("ThumbstickRv") // right analog thumbstick vertical movement + PORT_BIT(0xff, 0x80, IPT_AD_STICK_Y) PORT_NAME("ThumbstickRv") PORT_SENSITIVITY(100) PORT_KEYDELTA(1) PORT_MINMAX(0, 0xff) + PORT_CODE_DEC(KEYCODE_2_PAD) PORT_CODE_INC(KEYCODE_8_PAD) + + PORT_START("DPad") // pressure sensitive directional pad + PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_JOYSTICK_UP) PORT_NAME("DPad Up") + PORT_BIT(0x02, IP_ACTIVE_HIGH, IPT_JOYSTICK_DOWN) PORT_NAME("DPad Down") + PORT_BIT(0x04, IP_ACTIVE_HIGH, IPT_JOYSTICK_LEFT) PORT_NAME("DPad Left") + PORT_BIT(0x08, IP_ACTIVE_HIGH, IPT_JOYSTICK_RIGHT) PORT_NAME("DPad Right") + + PORT_START("TriggerL") // analog trigger + PORT_BIT(0xff, 0x00, IPT_PEDAL) PORT_NAME("TriggerL") PORT_SENSITIVITY(100) PORT_KEYDELTA(1) PORT_MINMAX(0, 0xff) + PORT_CODE_DEC(KEYCODE_1_PAD) PORT_CODE_INC(KEYCODE_7_PAD) + + PORT_START("TriggerR") // analog trigger + PORT_BIT(0xff, 0x00, IPT_PEDAL) PORT_NAME("TriggerR") PORT_SENSITIVITY(100) PORT_KEYDELTA(1) PORT_MINMAX(0, 0xff) + PORT_CODE_DEC(KEYCODE_3_PAD) PORT_CODE_INC(KEYCODE_9_PAD) + + PORT_START("Buttons") // digital buttons + PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_BUTTON2) PORT_NAME("Start") // Start button + PORT_BIT(0x02, IP_ACTIVE_HIGH, IPT_BUTTON1) PORT_NAME("Back") // Back button + + PORT_START("AGreen") // analog button + PORT_BIT(0xff, 0x00, IPT_PEDAL) PORT_NAME("A-Green") PORT_SENSITIVITY(100) PORT_KEYDELTA(32) PORT_MINMAX(0, 0xff) + PORT_CODE_DEC(KEYCODE_A) PORT_CODE_INC(KEYCODE_Q) + + PORT_START("BRed") // analog button + PORT_BIT(0xff, 0x00, IPT_PEDAL) PORT_NAME("B-Red") PORT_SENSITIVITY(100) PORT_KEYDELTA(32) PORT_MINMAX(0, 0xff) + PORT_CODE_DEC(KEYCODE_S) PORT_CODE_INC(KEYCODE_W) + + PORT_START("XBlue") // analog button + PORT_BIT(0xff, 0x00, IPT_PEDAL) PORT_NAME("X-Blue") PORT_SENSITIVITY(100) PORT_KEYDELTA(32) PORT_MINMAX(0, 0xff) + PORT_CODE_DEC(KEYCODE_D) PORT_CODE_INC(KEYCODE_E) + + PORT_START("YYellow") // analog button + PORT_BIT(0xff, 0x00, IPT_PEDAL) PORT_NAME("Y-Yellow") PORT_SENSITIVITY(100) PORT_KEYDELTA(32) PORT_MINMAX(0, 0xff) + PORT_CODE_DEC(KEYCODE_F) PORT_CODE_INC(KEYCODE_R) + + PORT_START("Black") // analog button + PORT_BIT(0xff, 0x00, IPT_PEDAL) PORT_NAME("Black") PORT_SENSITIVITY(100) PORT_KEYDELTA(32) PORT_MINMAX(0, 0xff) + PORT_CODE_DEC(KEYCODE_G) PORT_CODE_INC(KEYCODE_T) + + PORT_START("White") // analog button + PORT_BIT(0xff, 0x00, IPT_PEDAL) PORT_NAME("White") PORT_SENSITIVITY(100) PORT_KEYDELTA(32) PORT_MINMAX(0, 0xff) + PORT_CODE_DEC(KEYCODE_H) PORT_CODE_INC(KEYCODE_Y) +INPUT_PORTS_END + +const USBStandardDeviceDescriptor ohci_game_controller_device::devdesc = { 18,1,0x110,0x00,0x00,0x00,64,0x45e,0x202,0x100,0,0,0,1 }; +const USBStandardConfigurationDescriptor ohci_game_controller_device::condesc = { 9,2,0x20,1,1,0,0x80,50 }; +const USBStandardInterfaceDescriptor ohci_game_controller_device::intdesc = { 9,4,0,0,2,0x58,0x42,0,0 }; +const USBStandardEndpointDescriptor ohci_game_controller_device::enddesc82 = { 7,5,0x82,3,0x20,4 }; +const USBStandardEndpointDescriptor ohci_game_controller_device::enddesc02 = { 7,5,0x02,3,0x20,4 }; + +const device_type OHCI_GAME_CONTROLLER = &device_creator; + +ohci_game_controller_device::ohci_game_controller_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, OHCI_GAME_CONTROLLER, "OHCI Game Controller", tag, owner, clock, "ohci_gc", __FILE__), + ohci_function_device(), + m_ThumbstickLh(*this, "ThumbstickLh"), + m_ThumbstickLv(*this, "ThumbstickLv"), + m_ThumbstickRh(*this, "ThumbstickRh"), + m_ThumbstickRv(*this, "ThumbstickRv"), + m_DPad(*this, "DPad"), + m_TriggerL(*this, "TriggerL"), + m_TriggerR(*this, "TriggerR"), + m_Buttons(*this, "Buttons"), + m_AGreen(*this, "AGreen"), + m_BRed(*this, "BRed"), + m_XBlue(*this, "XBlue"), + m_YYellow(*this, "YYellow"), + m_Black(*this, "Black"), + m_White(*this, "White") +{ +} + +void ohci_game_controller_device::initialize(running_machine &machine, ohci_usb_controller *usb_bus_manager) +{ + ohci_function_device::initialize(machine, usb_bus_manager); + add_device_descriptor(devdesc); + add_configuration_descriptor(condesc); + add_interface_descriptor(intdesc); + add_endpoint_descriptor(enddesc82); + add_endpoint_descriptor(enddesc02); +} + +int ohci_game_controller_device::handle_nonstandard_request(int endpoint, USBSetupPacket *setup) +{ + // >=8 ==42 !=0 !=0 1,3 2<20 <=20 + static const UINT8 reportinfo[16] = { 0x10,0x42 ,0x32,0x43,1 ,0x65,0x14,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) && (setup->wValue == 0x4200)) + { + endpoints[endpoint].position = (UINT8 *)reportinfo; + 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)) { + int v; + + buffer[0] = 0; + buffer[1] = 20; + v = m_DPad->read(); + v = v | (m_Buttons->read() << 4); + buffer[2] = (UINT8)v; + buffer[3] = 0; + buffer[4] = m_AGreen->read(); + buffer[5] = m_BRed->read(); + buffer[6] = m_XBlue->read(); + buffer[7] = m_YYellow->read(); + buffer[8] = m_Black->read(); + buffer[9] = m_White->read(); + buffer[10] = m_TriggerL->read(); + buffer[11] = m_TriggerR->read(); + v = m_ThumbstickLh->read(); + v = (v - 128) * 256; + buffer[12] = (UINT16)v & 255; + buffer[13] = (UINT16)v >> 8; + v = m_ThumbstickLv->read(); + v = (v - 128) * 256; + buffer[14] = (UINT16)v & 255; + buffer[15] = (UINT16)v >> 8; + v = m_ThumbstickRh->read(); + v = (v - 128) * 256; + buffer[16] = (UINT16)v & 255; + buffer[17] = (UINT16)v >> 8; + v = m_ThumbstickRv->read(); + v = (v - 128) * 256; + buffer[18] = (UINT16)v & 255; + buffer[19] = (UINT16)v >> 8; + return size; + } + return -1; +} + +void ohci_game_controller_device::device_start() +{ +} + +ioport_constructor ohci_game_controller_device::device_input_ports() const +{ + return INPUT_PORTS_NAME(xbox_controller); +} + +WRITE_LINE_MEMBER(xbox_base_state::xbox_ohci_usb_interrupt_changed) +{ + xbox_base_devs.pic8259_1->ir1_w(state); +}