mirror of
https://github.com/StrikerX3/StrikeBox.git
synced 2024-06-15 19:08:11 -04:00
Get rid of most Cxbx-Reloaded, XQEMU and GPL code
This commit is contained in:
parent
9f86a0812b
commit
dc2ee11219
15
README.md
15
README.md
|
@ -1,6 +1,9 @@
|
|||
**If you're looking for a functional Xbox emulator, check out [XQEMU](http://xqemu.com/)
|
||||
or [Cxbx-Reloaded](https://github.com/Cxbx-Reloaded/Cxbx-Reloaded).**
|
||||
|
||||
**This project is on an indefinite hold as the two above projects are much more
|
||||
complete and functional.**
|
||||
|
||||
---
|
||||
|
||||
# StrikeBox
|
||||
|
@ -66,16 +69,10 @@ $ ./strikebox-cli -m <path-to-MCPX-ROM> -b <path-to-BIOS-ROM> -d <path-to-XBE> -
|
|||
macOS is currently unsupported. Feel free to submit a pull request to add
|
||||
support for this platform!
|
||||
|
||||
## Debugging Guest Code
|
||||
## Kernel Debugging
|
||||
|
||||
The guest can be debugged using the GDB debugger. Once enabled, the emulator
|
||||
will open a TCP socket upon startup and wait for the GDB debugger to connect.
|
||||
Once connected, you can examine the CPU state, set breakpoints, single-step
|
||||
instructions, etc. A sample .gdbinit file is provided with useful GDB default
|
||||
settings to be loaded when you start GDB in this directory.
|
||||
|
||||
Alternatively, on Windows, you can perform kernel debugging of the virtual Xbox
|
||||
by creating a linked pair of virtual null-modem serial ports with [com0com](http://com0com.sourceforge.net/).
|
||||
On Windows, you can perform kernel debugging of the virtual Xbox by creating a
|
||||
linked pair of virtual null-modem serial ports with [com0com](http://com0com.sourceforge.net/).
|
||||
Use a Debug BIOS ROM and attach one side of the pair to the first Super I/O
|
||||
serial port, then connect [WinDbg or KD](https://docs.microsoft.com/en-us/windows-hardware/drivers/debugger/)
|
||||
to the other side to begin kernel debugging.
|
||||
|
|
|
@ -14,9 +14,9 @@ using namespace virt86;
|
|||
#ifdef _WIN32
|
||||
char *basename(char *path)
|
||||
{
|
||||
char name[MAX_PATH];
|
||||
char ext[MAX_PATH];
|
||||
if (_splitpath_s(path, NULL, 0, NULL, 0, name, MAX_PATH, ext, MAX_PATH)) {
|
||||
char name[260];
|
||||
char ext[260];
|
||||
if (_splitpath_s(path, NULL, 0, NULL, 0, name, std::size(name), ext, std::size(ext))) {
|
||||
return NULL;
|
||||
}
|
||||
size_t len = strlen(name) + strlen(ext) + 1;
|
||||
|
@ -81,7 +81,7 @@ int main(int argc, const char *argv[]) {
|
|||
|
||||
bool foundPlatform = false;
|
||||
size_t platformIndex = 0;
|
||||
for (size_t i = 0; i < ARRAYSIZE(PlatformFactories); i++) {
|
||||
for (size_t i = 0; i < std::size(PlatformFactories); i++) {
|
||||
Platform& platform = PlatformFactories[i]();
|
||||
if (platform.GetInitStatus() == PlatformInitStatus::OK) {
|
||||
printf("%s loaded successfully\n", platform.GetName().c_str());
|
||||
|
|
|
@ -1,67 +0,0 @@
|
|||
// This is an open source non-commercial project. Dear PVS-Studio, please check it.
|
||||
// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
|
||||
// ******************************************************************
|
||||
// *
|
||||
// * .,-::::: .,:: .::::::::. .,:: .:
|
||||
// * ,;;;'````' `;;;, .,;; ;;;'';;' `;;;, .,;;
|
||||
// * [[[ '[[,,[[' [[[__[[\. '[[,,[['
|
||||
// * $$$ Y$$$P $$""""Y$$ Y$$$P
|
||||
// * `88bo,__,o, oP"``"Yo, _88o,,od8P oP"``"Yo,
|
||||
// * "YUMMMMMP",m" "Mm,""YUMMMP" ,m" "Mm,
|
||||
// *
|
||||
// * Cxbx->CxbxKrnl->Timer.h
|
||||
// *
|
||||
// * This file is part of the Cxbx project.
|
||||
// *
|
||||
// * Cxbx and Cxbe are free software; you can redistribute them
|
||||
// * and/or modify them under the terms of the GNU General Public
|
||||
// * License as published by the Free Software Foundation; either
|
||||
// * version 2 of the license, or (at your option) any later version.
|
||||
// *
|
||||
// * This program is distributed in the hope that it will be useful,
|
||||
// * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// * GNU General Public License for more details.
|
||||
// *
|
||||
// * You should have recieved a copy of the GNU General Public License
|
||||
// * along with this program; see the file COPYING.
|
||||
// * If not, write to the Free Software Foundation, Inc.,
|
||||
// * 59 Temple Place - Suite 330, Bostom, MA 02111-1307, USA.
|
||||
// *
|
||||
// * (c) 2018 ergo720
|
||||
// *
|
||||
// * All rights reserved
|
||||
// *
|
||||
// ******************************************************************
|
||||
|
||||
#ifndef TIMER_H
|
||||
#define TIMER_H
|
||||
|
||||
#include <atomic>
|
||||
|
||||
namespace strikebox {
|
||||
|
||||
/* typedef of the timer object and the callback function */
|
||||
typedef void(*pTimerCB)(void*);
|
||||
typedef struct _TimerObject {
|
||||
int Type; // timer type (virtual or real)
|
||||
std::atomic<std::uint64_t> ExpireTime_MS; // when the timer expires (ms)
|
||||
std::atomic_bool Exit; // indicates that the timer should be destroyed
|
||||
pTimerCB Callback; // function to call when the timer expires
|
||||
void* Opaque; // opaque argument to pass to the callback
|
||||
unsigned int SlowdownFactor; // how much the time is slowed down (virtual clocks only)
|
||||
}
|
||||
TimerObject;
|
||||
|
||||
|
||||
/* Timer exported functions */
|
||||
TimerObject* Timer_Create(pTimerCB Callback, void* Arg, unsigned int Factor);
|
||||
void Timer_Start(TimerObject* Timer, uint64_t Expire_MS);
|
||||
void Timer_Exit(TimerObject* Timer);
|
||||
void Timer_ChangeExpireTime(TimerObject* Timer, uint64_t Expire_ms);
|
||||
uint64_t GetTime_NS(TimerObject* Timer);
|
||||
void Timer_Init();
|
||||
|
||||
#endif
|
||||
|
||||
}
|
|
@ -1,147 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2017 Matt Borgerson
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <sys/types.h>
|
||||
#ifdef _WIN32
|
||||
# define _WIN32_LEAN_AND_MEAN
|
||||
//# include <WinSock2.h>
|
||||
# include <Ws2tcpip.h>
|
||||
# pragma comment (lib, "ws2_32.lib")
|
||||
#else
|
||||
# include <unistd.h>
|
||||
# include <arpa/inet.h>
|
||||
# include <netinet/in.h>
|
||||
# include <netinet/tcp.h>
|
||||
# include <sys/socket.h>
|
||||
#endif
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "virt86/virt86.hpp"
|
||||
|
||||
namespace strikebox {
|
||||
|
||||
#ifdef _WIN32
|
||||
typedef int socklen_t;
|
||||
typedef int ssize_t;
|
||||
|
||||
#define SOCKET_T SOCKET
|
||||
inline int inet_aton(const char *cp, struct in_addr *inp);
|
||||
inline int close(SOCKET socket);
|
||||
#else
|
||||
#define SOCKET_T int
|
||||
#endif
|
||||
|
||||
typedef uint32_t address;
|
||||
typedef uint32_t reg;
|
||||
|
||||
enum DBG_REGISTER {
|
||||
DBG_CPU_I386_REG_EAX = 0,
|
||||
DBG_CPU_I386_REG_ECX = 1,
|
||||
DBG_CPU_I386_REG_EDX = 2,
|
||||
DBG_CPU_I386_REG_EBX = 3,
|
||||
DBG_CPU_I386_REG_ESP = 4,
|
||||
DBG_CPU_I386_REG_EBP = 5,
|
||||
DBG_CPU_I386_REG_ESI = 6,
|
||||
DBG_CPU_I386_REG_EDI = 7,
|
||||
DBG_CPU_I386_REG_PC = 8,
|
||||
DBG_CPU_I386_REG_PS = 9,
|
||||
DBG_CPU_I386_REG_CS = 10,
|
||||
DBG_CPU_I386_REG_SS = 11,
|
||||
DBG_CPU_I386_REG_DS = 12,
|
||||
DBG_CPU_I386_REG_ES = 13,
|
||||
DBG_CPU_I386_REG_FS = 14,
|
||||
DBG_CPU_I386_REG_GS = 15,
|
||||
DBG_CPU_I386_NUM_REGISTERS = 16
|
||||
};
|
||||
|
||||
struct dbg_state {
|
||||
int signum;
|
||||
reg registers[DBG_CPU_I386_NUM_REGISTERS];
|
||||
};
|
||||
|
||||
typedef int (*dbg_enc_func)(char *buf, size_t buf_len, const char *data, size_t data_len);
|
||||
typedef int (*dbg_dec_func)(const char *buf, size_t buf_len, char *data, size_t data_len);
|
||||
|
||||
class GdbServer {
|
||||
protected:
|
||||
virt86::VirtualProcessor& m_vp;
|
||||
const char *m_bind_host;
|
||||
int m_bind_port;
|
||||
struct sockaddr_in m_bind_addr;
|
||||
struct sockaddr_in m_peer_addr;
|
||||
socklen_t m_peer_addr_len;
|
||||
SOCKET_T m_sockfd, m_peer_sockfd;
|
||||
struct dbg_state m_dbg_state;
|
||||
|
||||
int dbg_sys_getc(void);
|
||||
int dbg_sys_putchar(int ch);
|
||||
int dbg_sys_mem_readb(address addr, char *val);
|
||||
int dbg_sys_mem_writeb(address addr, char val);
|
||||
int dbg_sys_continue();
|
||||
int dbg_sys_step();
|
||||
|
||||
// Communication functions
|
||||
int dbg_write(const char *buf, size_t len);
|
||||
int dbg_read(char *buf, size_t buf_len, size_t len);
|
||||
|
||||
// String processing helper functions
|
||||
static int dbg_is_printable_char(char ch);
|
||||
static char dbg_get_digit(int val);
|
||||
static int dbg_get_val(char digit, int base);
|
||||
static int dbg_strtol(const char *str, size_t len, int base, const char **endptr);
|
||||
|
||||
// Data encoding/decoding
|
||||
static int dbg_enc_hex(char *buf, size_t buf_len, const char *data, size_t data_len);
|
||||
static int dbg_dec_hex(const char *buf, size_t buf_len, char *data, size_t data_len);
|
||||
static int dbg_enc_bin(char *buf, size_t buf_len, const char *data, size_t data_len);
|
||||
static int dbg_dec_bin(const char *buf, size_t buf_len, char *data, size_t data_len);
|
||||
|
||||
// Packet functions
|
||||
int dbg_send_packet(const char *pkt, size_t pkt_len);
|
||||
int dbg_recv_packet(char *pkt_buf, size_t pkt_buf_len, size_t *pkt_len);
|
||||
int dbg_checksum(const char *buf, size_t len);
|
||||
int dbg_recv_ack(void);
|
||||
|
||||
// Packet creation helpers
|
||||
int dbg_send_ok_packet(char *buf, size_t buf_len);
|
||||
int dbg_send_conmsg_packet(char *buf, size_t buf_len, const char *msg);
|
||||
int dbg_send_signal_packet(char *buf, size_t buf_len, char signal);
|
||||
int dbg_send_error_packet(char *buf, size_t buf_len, char error);
|
||||
|
||||
// Command functions
|
||||
int dbg_mem_read(char *buf, size_t buf_len, address addr, size_t len, dbg_enc_func enc);
|
||||
int dbg_mem_write(const char *buf, size_t buf_len, address addr, size_t len, dbg_dec_func dec);
|
||||
|
||||
int dbg_main();
|
||||
|
||||
public:
|
||||
GdbServer(virt86::VirtualProcessor& vp, const char *bind_host, int bind_port);
|
||||
~GdbServer();
|
||||
int Initialize();
|
||||
int WaitForConnection();
|
||||
int Debug(int signal);
|
||||
int Shutdown();
|
||||
};
|
||||
|
||||
}
|
|
@ -1,405 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include <mutex>
|
||||
#include <condition_variable>
|
||||
#include <queue>
|
||||
#include "nv2a_int.h"
|
||||
|
||||
namespace strikebox {
|
||||
|
||||
#define NV2A_SIZE 0x01000000
|
||||
|
||||
#define NV_PMC_ADDR 0x00000000
|
||||
#define NV_PMC_SIZE 0x001000
|
||||
#define NV_PBUS_ADDR 0x00001000
|
||||
#define NV_PBUS_SIZE 0x001000
|
||||
#define NV_PFIFO_ADDR 0x00002000
|
||||
#define NV_PFIFO_SIZE 0x002000
|
||||
#define NV_PRMA_ADDR 0x00007000
|
||||
#define NV_PRMA_SIZE 0x001000
|
||||
#define NV_PVIDEO_ADDR 0x00008000
|
||||
#define NV_PVIDEO_SIZE 0x001000
|
||||
#define NV_PTIMER_ADDR 0x00009000
|
||||
#define NV_PTIMER_SIZE 0x001000
|
||||
#define NV_PCOUNTER_ADDR 0x0000A000
|
||||
#define NV_PCOUNTER_SIZE 0x001000
|
||||
#define NV_PVPE_ADDR 0x0000B000
|
||||
#define NV_PVPE_SIZE 0x001000
|
||||
#define NV_PTV_ADDR 0x0000D000
|
||||
#define NV_PTV_SIZE 0x001000
|
||||
#define NV_PRMFB_ADDR 0x000A0000
|
||||
#define NV_PRMFB_SIZE 0x020000
|
||||
#define NV_PRMVIO_ADDR 0x000C0000
|
||||
#define NV_PRMVIO_SIZE 0x001000
|
||||
#define NV_PFB_ADDR 0x00100000
|
||||
#define NV_PFB_SIZE 0x001000
|
||||
#define NV_PSTRAPS_ADDR 0x00101000
|
||||
#define NV_PSTRAPS_SIZE 0x001000
|
||||
#define NV_PGRAPH_ADDR 0x00400000
|
||||
#define NV_PGRAPH_SIZE 0x002000
|
||||
#define NV_PCRTC_ADDR 0x00600000
|
||||
#define NV_PCRTC_SIZE 0x001000
|
||||
#define NV_PRMCIO_ADDR 0x00601000
|
||||
#define NV_PRMCIO_SIZE 0x001000
|
||||
#define NV_PRAMDAC_ADDR 0x00680000
|
||||
#define NV_PRAMDAC_SIZE 0x001000
|
||||
#define NV_PRMDIO_ADDR 0x00681000
|
||||
#define NV_PRMDIO_SIZE 0x001000
|
||||
#define NV_PRAMIN_ADDR 0x00700000
|
||||
#define NV_PRAMIN_SIZE 0x100000
|
||||
#define NV_USER_ADDR 0x00800000
|
||||
#define NV_USER_SIZE 0x800000
|
||||
|
||||
class NV2ADevice;
|
||||
|
||||
enum FifoMode {
|
||||
FIFO_PIO = 0,
|
||||
FIFO_DMA = 1,
|
||||
};
|
||||
|
||||
enum FIFOEngine {
|
||||
ENGINE_SOFTWARE = 0,
|
||||
ENGINE_GRAPHICS = 1,
|
||||
ENGINE_DVD = 2,
|
||||
};
|
||||
|
||||
typedef struct VGACommonState {
|
||||
uint8_t st00; // Status Register 0
|
||||
uint8_t st01; // Status Register 1
|
||||
} VGACommonState;
|
||||
|
||||
typedef struct ImageBlitState {
|
||||
uint32_t context_surfaces;
|
||||
unsigned int operation;
|
||||
unsigned int in_x, in_y;
|
||||
unsigned int out_x, out_y;
|
||||
unsigned int width, height;
|
||||
} ImageBlitState;
|
||||
|
||||
typedef struct KelvinState {
|
||||
uint32_t dma_notifies;
|
||||
uint32_t dma_state;
|
||||
uint32_t dma_semaphore;
|
||||
unsigned int semaphore_offset;
|
||||
} KelvinState;
|
||||
|
||||
typedef struct ContextSurfaces2DState {
|
||||
uint32_t dma_image_source;
|
||||
uint32_t dma_image_dest;
|
||||
unsigned int color_format;
|
||||
unsigned int source_pitch, dest_pitch;
|
||||
uint32_t source_offset, dest_offset;
|
||||
} ContextSurfaces2DState;
|
||||
|
||||
typedef struct DMAObject {
|
||||
unsigned int dma_class = 0;
|
||||
unsigned int dma_target = 0;
|
||||
uint32_t address = 0;
|
||||
uint32_t limit = 0;
|
||||
} DMAObject;
|
||||
|
||||
typedef struct GraphicsObject {
|
||||
uint8_t graphics_class = 0;
|
||||
union {
|
||||
ContextSurfaces2DState context_surfaces_2d;
|
||||
|
||||
ImageBlitState image_blit;
|
||||
|
||||
KelvinState kelvin;
|
||||
} data;
|
||||
} GraphicsObject;
|
||||
|
||||
typedef struct GraphicsSubchannel {
|
||||
uint32_t object_instance = 0;
|
||||
GraphicsObject object;
|
||||
uint32_t object_cache[5] = { 0 };
|
||||
} GraphicsSubchannel;
|
||||
|
||||
typedef struct GraphicsContext {
|
||||
bool channel_3d = false;
|
||||
unsigned int subchannel = 0;
|
||||
} GraphicsContext;
|
||||
|
||||
typedef struct RAMHTEntry {
|
||||
uint32_t handle = 0;
|
||||
uint32_t instance = 0;
|
||||
enum FIFOEngine engine = ENGINE_SOFTWARE;
|
||||
unsigned int channel_id : 5;
|
||||
bool valid = false;
|
||||
} RAMHTEntry;
|
||||
|
||||
typedef struct {
|
||||
uint32_t offset;
|
||||
uint32_t size;
|
||||
void (*read)(NV2ADevice* nv2a, uint32_t addr, uint32_t *value, uint8_t size);
|
||||
void (*write)(NV2ADevice* nv2a, uint32_t addr, uint32_t value, uint8_t size);
|
||||
} NV2ABlockInfo;
|
||||
|
||||
typedef struct {
|
||||
uint32_t regs[NV_PVIDEO_SIZE];
|
||||
} NV2APVIDEO;
|
||||
|
||||
typedef struct {
|
||||
uint8_t cr_index = 0;
|
||||
uint8_t cr[256] = { 0 }; /* CRT registers */
|
||||
} NV2APRMCIO;
|
||||
|
||||
typedef struct {
|
||||
// Interrupt status. Bits 0-30 are hardware interrupts, bit 31 is software interrupt.
|
||||
// 1 if the relevant input interrupt line is active.
|
||||
// Bits 0-30 are read-only, bit 31 can be written to set/clear the software interrupt.
|
||||
// Bit 31 can only be set to 1 if software interrupts are enabled in INTR_MASK_*.
|
||||
uint32_t pendingInterrupts = 0;
|
||||
|
||||
// bit 0: hardware interrupt enable - if 1, and any of bits 0-30 of INTR_* are active, the corresponding output interrupt line will be asserted.
|
||||
// bit 1: software interrupt enable - if 1, bit 31 of INTR_* is active, the corresponding output interrupt line will be asserted.
|
||||
uint32_t enabledInterrupts = 0;
|
||||
} NV2APMC;
|
||||
|
||||
typedef struct Surface {
|
||||
bool draw_dirty = false;
|
||||
bool buffer_dirty = false;
|
||||
bool write_enabled_cache = false;
|
||||
unsigned int pitch = 0;
|
||||
|
||||
uint32_t offset = 0;
|
||||
} Surface;
|
||||
|
||||
typedef struct SurfaceShape {
|
||||
unsigned int z_format = 0;
|
||||
unsigned int color_format = 0;
|
||||
unsigned int zeta_format = 0;
|
||||
unsigned int log_width = 0, log_height = 0;
|
||||
unsigned int clip_x = 0, clip_y = 0;
|
||||
unsigned int clip_width = 0, clip_height = 0;
|
||||
unsigned int anti_aliasing = 0;
|
||||
} SurfaceShape;
|
||||
|
||||
typedef struct TextureShape {
|
||||
bool cubemap = false;
|
||||
unsigned int dimensionality = 0;
|
||||
unsigned int color_format = 0;
|
||||
unsigned int levels = 0;
|
||||
unsigned int width = 0, height = 0, depth = 0;
|
||||
|
||||
unsigned int min_mipmap_level = 0;
|
||||
unsigned int max_mipmap_level = 0;
|
||||
unsigned int pitch = 0;
|
||||
} TextureShape;
|
||||
|
||||
typedef struct TextureKey {
|
||||
TextureShape state;
|
||||
uint64_t data_hash = 0;
|
||||
uint8_t* texture_data = nullptr;
|
||||
uint8_t* palette_data = nullptr;
|
||||
} TextureKey;
|
||||
|
||||
typedef struct TextureBinding {
|
||||
// FIXME: no OpenGL allowed here
|
||||
//GLenum gl_target;
|
||||
//GLuint gl_texture;
|
||||
unsigned int refcnt = 0;
|
||||
} TextureBinding;
|
||||
|
||||
typedef struct NV2APGRAPH {
|
||||
std::mutex mutex;
|
||||
|
||||
uint32_t pending_interrupts = 0;
|
||||
uint32_t enabled_interrupts = 0;
|
||||
std::condition_variable interrupt_cond;
|
||||
|
||||
uint32_t context_table = 0;
|
||||
uint32_t context_address = 0;
|
||||
|
||||
|
||||
unsigned int trapped_method = 0;
|
||||
unsigned int trapped_subchannel = 0;
|
||||
unsigned int trapped_channel_id = 0;
|
||||
uint32_t trapped_data[2] = { 0 };
|
||||
uint32_t notify_source = 0;
|
||||
|
||||
bool fifo_access = false;
|
||||
std::condition_variable fifo_access_cond;
|
||||
std::condition_variable flip_3d;
|
||||
|
||||
unsigned int channel_id = 0;
|
||||
bool channel_valid = false;
|
||||
GraphicsContext context[NV2A_NUM_CHANNELS];
|
||||
|
||||
uint32_t dma_color = 0;
|
||||
uint32_t dma_zeta = 0;
|
||||
Surface surface_color;
|
||||
Surface surface_zeta;
|
||||
unsigned int surface_type = 0;
|
||||
SurfaceShape surface_shape;
|
||||
SurfaceShape last_surface_shape;
|
||||
|
||||
uint32_t dma_a = 0;
|
||||
uint32_t dma_b = 0;
|
||||
//GLruCache *texture_cache;
|
||||
bool texture_dirty[NV2A_MAX_TEXTURES] = { false };
|
||||
TextureBinding *texture_binding[NV2A_MAX_TEXTURES] = { nullptr };
|
||||
|
||||
//GHashTable *shader_cache;
|
||||
//ShaderBinding *shader_binding;
|
||||
|
||||
bool texture_matrix_enable[NV2A_MAX_TEXTURES] = { false };
|
||||
|
||||
/* FIXME: Move to NV_PGRAPH_BUMPMAT... */
|
||||
float bump_env_matrix[NV2A_MAX_TEXTURES - 1][4]; /* 3 allowed stages with 2x2 matrix each */
|
||||
|
||||
// FIXME: no OpenGL allowed here
|
||||
////wglContext *gl_context;
|
||||
//GLuint gl_framebuffer;
|
||||
//GLuint gl_color_buffer, gl_zeta_buffer;
|
||||
GraphicsSubchannel subchannel_data[NV2A_NUM_SUBCHANNELS];
|
||||
|
||||
uint32_t dma_report = 0;
|
||||
uint32_t report_offset = 0;
|
||||
bool zpass_pixel_count_enable = 0;
|
||||
unsigned int zpass_pixel_count_result = 0;
|
||||
unsigned int gl_zpass_pixel_count_query_count = 0;
|
||||
// FIXME: no OpenGL allowed here
|
||||
//GLuint* gl_zpass_pixel_count_queries;
|
||||
|
||||
uint32_t dma_vertex_a = 0;
|
||||
uint32_t dma_vertex_b = 0;
|
||||
|
||||
unsigned int primitive_mode = 0;
|
||||
|
||||
bool enable_vertex_program_write = false;
|
||||
|
||||
//uint32_t program_data[NV2A_MAX_TRANSFORM_PROGRAM_LENGTH][VSH_TOKEN_SIZE];
|
||||
|
||||
uint32_t vsh_constants[NV2A_VERTEXSHADER_CONSTANTS][4] = { { 0 } };
|
||||
bool vsh_constants_dirty[NV2A_VERTEXSHADER_CONSTANTS] = { 0 };
|
||||
|
||||
/* lighting constant arrays */
|
||||
uint32_t ltctxa[NV2A_LTCTXA_COUNT][4] = { { 0 } };
|
||||
bool ltctxa_dirty[NV2A_LTCTXA_COUNT] = { false };
|
||||
uint32_t ltctxb[NV2A_LTCTXB_COUNT][4] = { { 0 } };
|
||||
bool ltctxb_dirty[NV2A_LTCTXB_COUNT] = { false };
|
||||
uint32_t ltc1[NV2A_LTC1_COUNT][4] = { { 0 } };
|
||||
bool ltc1_dirty[NV2A_LTC1_COUNT] = { false };
|
||||
|
||||
// should figure out where these are in lighting context
|
||||
float light_infinite_half_vector[NV2A_MAX_LIGHTS][3] = { { 0 } };
|
||||
float light_infinite_direction[NV2A_MAX_LIGHTS][3] = { { 0 } };
|
||||
float light_local_position[NV2A_MAX_LIGHTS][3] = { { 0 } };
|
||||
float light_local_attenuation[NV2A_MAX_LIGHTS][3] = { { 0 } };
|
||||
|
||||
//VertexAttribute vertex_attributes[NV2A_VERTEXSHADER_ATTRIBUTES];
|
||||
|
||||
unsigned int inline_array_length = 0;
|
||||
uint32_t inline_array[NV2A_MAX_BATCH_LENGTH] = { 0 };
|
||||
// FIXME: no OpenGL allowed here
|
||||
//GLuint gl_inline_array_buffer;
|
||||
|
||||
unsigned int inline_elements_length = 0;
|
||||
uint32_t inline_elements[NV2A_MAX_BATCH_LENGTH] = { 0 };
|
||||
|
||||
unsigned int inline_buffer_length = 0;
|
||||
|
||||
unsigned int draw_arrays_length = 0;
|
||||
unsigned int draw_arrays_max_count = 0;
|
||||
|
||||
// FIXME: no OpenGL allowed here
|
||||
/* FIXME: Unknown size, possibly endless, 1000 will do for now */
|
||||
//GLint gl_draw_arrays_start[1000];
|
||||
//GLsizei gl_draw_arrays_count[1000];
|
||||
|
||||
//GLuint gl_element_buffer;
|
||||
//GLuint gl_memory_buffer;
|
||||
//GLuint gl_vertex_array;
|
||||
|
||||
uint32_t regs[NV_PGRAPH_SIZE] = { 0 }; // TODO : union
|
||||
} NV2APGRAPH;
|
||||
|
||||
typedef struct {
|
||||
uint32_t pendingInterrupts = 0;
|
||||
uint32_t enabledInterrupts = 0;
|
||||
uint32_t start = 0;
|
||||
uint32_t regs[NV_PCRTC_SIZE] = { 0 }; // TODO : union
|
||||
} NV2APCRTC;
|
||||
|
||||
typedef struct {
|
||||
uint32_t pending_interrupts = 0;
|
||||
uint32_t enabled_interrupts = 0;
|
||||
uint32_t numerator = 0;
|
||||
uint32_t denominator = 0;
|
||||
uint32_t alarm_time = 0;
|
||||
uint32_t regs[NV_PTIMER_SIZE] = { 0 };
|
||||
} NV2APTIMER;
|
||||
|
||||
typedef struct {
|
||||
uint32_t core_clock_coeff = 0;
|
||||
uint64_t core_clock_freq = 0;
|
||||
uint32_t memory_clock_coeff = 0;
|
||||
uint32_t video_clock_coeff = 0;
|
||||
uint32_t regs[NV_PRAMDAC_SIZE] = { 0 };
|
||||
} NV2APRAMDAC;
|
||||
|
||||
typedef struct CacheEntry {
|
||||
unsigned int method : 14;
|
||||
unsigned int subchannel : 3;
|
||||
bool nonincreasing = false;
|
||||
uint32_t parameter = 0;
|
||||
} CacheEntry;
|
||||
|
||||
typedef struct Cache1State {
|
||||
unsigned int channel_id = 0;
|
||||
FifoMode mode = FIFO_PIO;
|
||||
|
||||
/* Pusher state */
|
||||
bool push_enabled = false;
|
||||
bool dma_push_enabled = false;
|
||||
bool dma_push_suspended = false;
|
||||
uint32_t dma_instance = 0;
|
||||
|
||||
bool method_nonincreasing = false;
|
||||
unsigned int method : 14;
|
||||
unsigned int subchannel : 3;
|
||||
unsigned int method_count : 24;
|
||||
uint32_t dcount = 0;
|
||||
|
||||
bool subroutine_active = false;
|
||||
uint32_t subroutine_return = 0;
|
||||
uint32_t get_jmp_shadow = 0;
|
||||
uint32_t rsvd_shadow = 0;
|
||||
uint32_t data_shadow = 0;
|
||||
uint32_t error = 0;
|
||||
|
||||
bool pull_enabled = false;
|
||||
enum FIFOEngine bound_engines[NV2A_NUM_SUBCHANNELS] = { ENGINE_SOFTWARE };
|
||||
enum FIFOEngine last_engine = ENGINE_SOFTWARE;
|
||||
|
||||
/* The actual command queue */
|
||||
std::mutex mutex;
|
||||
std::condition_variable cache_cond;
|
||||
std::queue<CacheEntry*> cache;
|
||||
std::queue<CacheEntry*> working_cache;
|
||||
} Cache1State;
|
||||
|
||||
typedef struct {
|
||||
uint32_t pending_interrupts = 0;
|
||||
uint32_t enabled_interrupts = 0;
|
||||
Cache1State cache1;
|
||||
uint32_t regs[NV_PFIFO_SIZE] = { 0 };
|
||||
std::thread puller_thread;
|
||||
} NV2APFIFO;
|
||||
|
||||
typedef struct {
|
||||
uint32_t registers[NV_PFB_SIZE] = { 0 };
|
||||
} NV2APFB;
|
||||
|
||||
typedef struct ChannelControl {
|
||||
uint32_t dma_put = 0;
|
||||
uint32_t dma_get = 0;
|
||||
uint32_t ref = 0;
|
||||
} ChannelControl;
|
||||
|
||||
typedef struct {
|
||||
ChannelControl channel_control[NV2A_NUM_CHANNELS];
|
||||
} NV2AUSER;
|
||||
|
||||
}
|
File diff suppressed because it is too large
Load diff
|
@ -1,156 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
/*
|
||||
* linux/include/video/vga.h -- standard VGA chipset interaction
|
||||
*
|
||||
* Copyright 1999 Jeff Garzik <jgarzik@pobox.com>
|
||||
*
|
||||
* Copyright history from vga16fb.c:
|
||||
* Copyright 1999 Ben Pfaff and Petr Vandrovec
|
||||
* Based on VGA info at http://www.osdever.net/FreeVGA/home.htm
|
||||
* Based on VESA framebuffer (c) 1998 Gerd Knorr
|
||||
*
|
||||
* This file is subject to the terms and conditions of the GNU General
|
||||
* Public License. See the file COPYING in the main directory of this
|
||||
* archive for more details.
|
||||
*
|
||||
*/
|
||||
|
||||
/* Some of the code below is taken from SVGAlib. The original,
|
||||
unmodified copyright notice for that code is below. */
|
||||
/* VGAlib version 1.2 - (c) 1993 Tommy Frandsen */
|
||||
/* */
|
||||
/* This library is free software; you can redistribute it and/or */
|
||||
/* modify it without any restrictions. This library is distributed */
|
||||
/* in the hope that it will be useful, but without any warranty. */
|
||||
|
||||
/* Multi-chipset support Copyright 1993 Harm Hanemaayer */
|
||||
/* partially copyrighted (C) 1993 by Hartmut Schirmer */
|
||||
|
||||
/* VGA data register ports */
|
||||
#define VGA_CRT_DC 0x3D5 /* CRT Controller Data Register - color emulation */
|
||||
#define VGA_CRT_DM 0x3B5 /* CRT Controller Data Register - mono emulation */
|
||||
#define VGA_ATT_R 0x3C1 /* Attribute Controller Data Read Register */
|
||||
#define VGA_ATT_W 0x3C0 /* Attribute Controller Data Write Register */
|
||||
#define VGA_GFX_D 0x3CF /* Graphics Controller Data Register */
|
||||
#define VGA_SEQ_D 0x3C5 /* Sequencer Data Register */
|
||||
#define VGA_MIS_R 0x3CC /* Misc Output Read Register */
|
||||
#define VGA_MIS_W 0x3C2 /* Misc Output Write Register */
|
||||
#define VGA_FTC_R 0x3CA /* Feature Control Read Register */
|
||||
#define VGA_IS1_RC 0x3DA /* Input Status Register 1 - color emulation */
|
||||
#define VGA_IS1_RM 0x3BA /* Input Status Register 1 - mono emulation */
|
||||
#define VGA_PEL_D 0x3C9 /* PEL Data Register */
|
||||
#define VGA_PEL_MSK 0x3C6 /* PEL mask register */
|
||||
|
||||
/* EGA-specific registers */
|
||||
#define EGA_GFX_E0 0x3CC /* Graphics enable processor 0 */
|
||||
#define EGA_GFX_E1 0x3CA /* Graphics enable processor 1 */
|
||||
|
||||
/* VGA index register ports */
|
||||
#define VGA_CRT_IC 0x3D4 /* CRT Controller Index - color emulation */
|
||||
#define VGA_CRT_IM 0x3B4 /* CRT Controller Index - mono emulation */
|
||||
#define VGA_ATT_IW 0x3C0 /* Attribute Controller Index & Data Write Register */
|
||||
#define VGA_GFX_I 0x3CE /* Graphics Controller Index */
|
||||
#define VGA_SEQ_I 0x3C4 /* Sequencer Index */
|
||||
#define VGA_PEL_IW 0x3C8 /* PEL Write Index */
|
||||
#define VGA_PEL_IR 0x3C7 /* PEL Read Index */
|
||||
|
||||
/* standard VGA indexes max counts */
|
||||
#define VGA_CRT_C 0x19 /* Number of CRT Controller Registers */
|
||||
#define VGA_ATT_C 0x15 /* Number of Attribute Controller Registers */
|
||||
#define VGA_GFX_C 0x09 /* Number of Graphics Controller Registers */
|
||||
#define VGA_SEQ_C 0x05 /* Number of Sequencer Registers */
|
||||
#define VGA_MIS_C 0x01 /* Number of Misc Output Register */
|
||||
|
||||
/* VGA misc register bit masks */
|
||||
#define VGA_MIS_COLOR 0x01
|
||||
#define VGA_MIS_ENB_MEM_ACCESS 0x02
|
||||
#define VGA_MIS_DCLK_28322_720 0x04
|
||||
#define VGA_MIS_ENB_PLL_LOAD (0x04 | 0x08)
|
||||
#define VGA_MIS_SEL_HIGH_PAGE 0x20
|
||||
|
||||
/* VGA CRT controller register indices */
|
||||
#define VGA_CRTC_H_TOTAL 0
|
||||
#define VGA_CRTC_H_DISP 1
|
||||
#define VGA_CRTC_H_BLANK_START 2
|
||||
#define VGA_CRTC_H_BLANK_END 3
|
||||
#define VGA_CRTC_H_SYNC_START 4
|
||||
#define VGA_CRTC_H_SYNC_END 5
|
||||
#define VGA_CRTC_V_TOTAL 6
|
||||
#define VGA_CRTC_OVERFLOW 7
|
||||
#define VGA_CRTC_PRESET_ROW 8
|
||||
#define VGA_CRTC_MAX_SCAN 9
|
||||
#define VGA_CRTC_CURSOR_START 0x0A
|
||||
#define VGA_CRTC_CURSOR_END 0x0B
|
||||
#define VGA_CRTC_START_HI 0x0C
|
||||
#define VGA_CRTC_START_LO 0x0D
|
||||
#define VGA_CRTC_CURSOR_HI 0x0E
|
||||
#define VGA_CRTC_CURSOR_LO 0x0F
|
||||
#define VGA_CRTC_V_SYNC_START 0x10
|
||||
#define VGA_CRTC_V_SYNC_END 0x11
|
||||
#define VGA_CRTC_V_DISP_END 0x12
|
||||
#define VGA_CRTC_OFFSET 0x13
|
||||
#define VGA_CRTC_UNDERLINE 0x14
|
||||
#define VGA_CRTC_V_BLANK_START 0x15
|
||||
#define VGA_CRTC_V_BLANK_END 0x16
|
||||
#define VGA_CRTC_MODE 0x17
|
||||
#define VGA_CRTC_LINE_COMPARE 0x18
|
||||
#define VGA_CRTC_REGS VGA_CRT_C
|
||||
|
||||
/* VGA CRT controller bit masks */
|
||||
#define VGA_CR11_LOCK_CR0_CR7 0x80 /* lock writes to CR0 - CR7 */
|
||||
#define VGA_CR17_H_V_SIGNALS_ENABLED 0x80
|
||||
|
||||
/* VGA attribute controller register indices */
|
||||
#define VGA_ATC_PALETTE0 0x00
|
||||
#define VGA_ATC_PALETTE1 0x01
|
||||
#define VGA_ATC_PALETTE2 0x02
|
||||
#define VGA_ATC_PALETTE3 0x03
|
||||
#define VGA_ATC_PALETTE4 0x04
|
||||
#define VGA_ATC_PALETTE5 0x05
|
||||
#define VGA_ATC_PALETTE6 0x06
|
||||
#define VGA_ATC_PALETTE7 0x07
|
||||
#define VGA_ATC_PALETTE8 0x08
|
||||
#define VGA_ATC_PALETTE9 0x09
|
||||
#define VGA_ATC_PALETTEA 0x0A
|
||||
#define VGA_ATC_PALETTEB 0x0B
|
||||
#define VGA_ATC_PALETTEC 0x0C
|
||||
#define VGA_ATC_PALETTED 0x0D
|
||||
#define VGA_ATC_PALETTEE 0x0E
|
||||
#define VGA_ATC_PALETTEF 0x0F
|
||||
#define VGA_ATC_MODE 0x10
|
||||
#define VGA_ATC_OVERSCAN 0x11
|
||||
#define VGA_ATC_PLANE_ENABLE 0x12
|
||||
#define VGA_ATC_PEL 0x13
|
||||
#define VGA_ATC_COLOR_PAGE 0x14
|
||||
|
||||
#define VGA_AR_ENABLE_DISPLAY 0x20
|
||||
|
||||
/* VGA sequencer register indices */
|
||||
#define VGA_SEQ_RESET 0x00
|
||||
#define VGA_SEQ_CLOCK_MODE 0x01
|
||||
#define VGA_SEQ_PLANE_WRITE 0x02
|
||||
#define VGA_SEQ_CHARACTER_MAP 0x03
|
||||
#define VGA_SEQ_MEMORY_MODE 0x04
|
||||
|
||||
/* VGA sequencer register bit masks */
|
||||
#define VGA_SR01_CHAR_CLK_8DOTS 0x01 /* bit 0: character clocks 8 dots wide are generated */
|
||||
#define VGA_SR01_SCREEN_OFF 0x20 /* bit 5: Screen is off */
|
||||
#define VGA_SR02_ALL_PLANES 0x0F /* bits 3-0: enable access to all planes */
|
||||
#define VGA_SR04_EXT_MEM 0x02 /* bit 1: allows complete mem access to 256K */
|
||||
#define VGA_SR04_SEQ_MODE 0x04 /* bit 2: directs system to use a sequential addressing mode */
|
||||
#define VGA_SR04_CHN_4M 0x08 /* bit 3: selects modulo 4 addressing for CPU access to display memory */
|
||||
|
||||
/* VGA graphics controller register indices */
|
||||
#define VGA_GFX_SR_VALUE 0x00
|
||||
#define VGA_GFX_SR_ENABLE 0x01
|
||||
#define VGA_GFX_COMPARE_VALUE 0x02
|
||||
#define VGA_GFX_DATA_ROTATE 0x03
|
||||
#define VGA_GFX_PLANE_READ 0x04
|
||||
#define VGA_GFX_MODE 0x05
|
||||
#define VGA_GFX_MISC 0x06
|
||||
#define VGA_GFX_COMPARE_MASK 0x07
|
||||
#define VGA_GFX_BIT_MASK 0x08
|
||||
|
||||
/* VGA graphics controller bit masks */
|
||||
#define VGA_GR06_GRAPHICS_MODE 0x01
|
|
@ -1,264 +0,0 @@
|
|||
/*
|
||||
* Portions of the code are based on Cxbx-Reloaded's OHCI LLE implementation.
|
||||
* The original copyright header is included below.
|
||||
*/
|
||||
// This is an open source non-commercial project. Dear PVS-Studio, please check it.
|
||||
// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
|
||||
// ******************************************************************
|
||||
// *
|
||||
// * .,-::::: .,:: .::::::::. .,:: .:
|
||||
// * ,;;;'````' `;;;, .,;; ;;;'';;' `;;;, .,;;
|
||||
// * [[[ '[[,,[[' [[[__[[\. '[[,,[['
|
||||
// * $$$ Y$$$P $$""""Y$$ Y$$$P
|
||||
// * `88bo,__,o, oP"``"Yo, _88o,,od8P oP"``"Yo,
|
||||
// * "YUMMMMMP",m" "Mm,""YUMMMP" ,m" "Mm,
|
||||
// *
|
||||
// * Cxbx->devices->USBController->OHCI.h
|
||||
// *
|
||||
// * This file is part of the Cxbx project.
|
||||
// *
|
||||
// * Cxbx and Cxbe are free software; you can redistribute them
|
||||
// * and/or modify them under the terms of the GNU General Public
|
||||
// * License as published by the Free Software Foundation; either
|
||||
// * version 2 of the license, or (at your option) any later version.
|
||||
// *
|
||||
// * This program is distributed in the hope that it will be useful,
|
||||
// * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// * GNU General Public License for more details.
|
||||
// *
|
||||
// * You should have recieved a copy of the GNU General Public License
|
||||
// * along with this program; see the file COPYING.
|
||||
// * If not, write to the Free Software Foundation, Inc.,
|
||||
// * 59 Temple Place - Suite 330, Bostom, MA 02111-1307, USA.
|
||||
// *
|
||||
// * (c) 2018 ergo720
|
||||
// *
|
||||
// * All rights reserved
|
||||
// *
|
||||
// ******************************************************************
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "virt86/virt86.hpp"
|
||||
|
||||
#include "../pci/usb_pci.h"
|
||||
#include "strikebox/cxbxtimer.h"
|
||||
|
||||
namespace strikebox {
|
||||
|
||||
// Abbreviations used:
|
||||
// OHCI: Open Host Controller Interface; the standard used on the Xbox to comunicate with the usb devices
|
||||
// HC: Host Controller; the hardware which interfaces with the usb device and the usb driver
|
||||
// HCD: Host Controller Driver; software which talks to the HC, it's linked in the xbe
|
||||
// SOF: start of frame; the beginning of a USB-defined frame
|
||||
// EOF: end of frame; the end of a USB-defined frame
|
||||
// ED: endpoint descriptor; a memory structure used by the HC to communicate with an endpoint
|
||||
// TD: transfer descriptor; a memory structure used by the HC to transfer a block of data to/from a device endpoint
|
||||
// HCCA: Host Controller Communications Area; shared memory between the HC and HCD
|
||||
|
||||
|
||||
/* endpoint descriptor */
|
||||
struct OHCI_ED {
|
||||
uint32_t Flags;
|
||||
uint32_t TailP;
|
||||
uint32_t HeadP;
|
||||
uint32_t NextED;
|
||||
};
|
||||
|
||||
/* general transfer descriptor */
|
||||
struct OHCI_TD {
|
||||
uint32_t Flags;
|
||||
uint32_t CurrentBufferPointer;
|
||||
uint32_t NextTD;
|
||||
uint32_t BufferEnd;
|
||||
};
|
||||
|
||||
/* Isochronous transfer descriptor */
|
||||
struct OHCI_ISO_TD {
|
||||
uint32_t Flags;
|
||||
uint32_t BufferPage0;
|
||||
uint32_t NextTD;
|
||||
uint32_t BufferEnd;
|
||||
uint16_t Offset[8];
|
||||
};
|
||||
|
||||
/* enum indicating the current HC state */
|
||||
typedef enum _OHCI_State {
|
||||
Reset = 0x00,
|
||||
Resume = 0x40,
|
||||
Operational = 0x80,
|
||||
Suspend = 0xC0,
|
||||
}
|
||||
OHCI_State;
|
||||
|
||||
/* Host Controller Communications Area */
|
||||
struct OHCI_HCCA {
|
||||
uint32_t HccaInterrruptTable[32];
|
||||
uint16_t HccaFrameNumber, HccaPad1;
|
||||
uint32_t HccaDoneHead;
|
||||
};
|
||||
|
||||
/* Small struct used to hold the HcRhPortStatus register and the usb port status */
|
||||
struct OHCIPort {
|
||||
USBPort UsbPort;
|
||||
uint32_t HcRhPortStatus;
|
||||
};
|
||||
|
||||
/* All these registers are well documented in the OHCI standard */
|
||||
struct OHCI_Registers {
|
||||
// Control and Status partition
|
||||
uint32_t HcRevision;
|
||||
uint32_t HcControl;
|
||||
uint32_t HcCommandStatus;
|
||||
uint32_t HcInterruptStatus;
|
||||
// HcInterruptEnable/Disable are the same so we can merge them together
|
||||
uint32_t HcInterrupt;
|
||||
|
||||
// Memory Pointer partition
|
||||
uint32_t HcHCCA;
|
||||
uint32_t HcPeriodCurrentED;
|
||||
uint32_t HcControlHeadED;
|
||||
uint32_t HcControlCurrentED;
|
||||
uint32_t HcBulkHeadED;
|
||||
uint32_t HcBulkCurrentED;
|
||||
uint32_t HcDoneHead;
|
||||
|
||||
// Frame Counter partition
|
||||
uint32_t HcFmInterval;
|
||||
uint32_t HcFmRemaining;
|
||||
uint32_t HcFmNumber;
|
||||
uint32_t HcPeriodicStart;
|
||||
uint32_t HcLSThreshold;
|
||||
|
||||
// Root Hub partition
|
||||
uint32_t HcRhDescriptorA;
|
||||
uint32_t HcRhDescriptorB;
|
||||
uint32_t HcRhStatus;
|
||||
OHCIPort RhPort[4]; // 4 ports per HC
|
||||
};
|
||||
|
||||
|
||||
/* OHCI class representing the state of the HC */
|
||||
class OHCI {
|
||||
public:
|
||||
// Indicates that the timer thread is accessing the OHCI object. Necessary because the input thread from the
|
||||
// InputDeviceManager will access us when it needs to create or destroy a device
|
||||
std::atomic_bool m_bFrameTime;
|
||||
|
||||
// constructor
|
||||
OHCI(virt86::VirtualProcessor& vp, int Irqn, USBPCIDevice* UsbObj);
|
||||
// destructor
|
||||
~OHCI() {}
|
||||
// read a register
|
||||
uint32_t OHCI_ReadRegister(uint32_t Addr);
|
||||
// write a register
|
||||
void OHCI_WriteRegister(uint32_t Addr, uint32_t Value);
|
||||
|
||||
private:
|
||||
virt86::VirtualProcessor& m_vp;
|
||||
// pointer to g_USB0 or g_USB1
|
||||
USBPCIDevice* m_UsbDevice = nullptr;
|
||||
// all the registers available in the OHCI standard
|
||||
OHCI_Registers m_Registers;
|
||||
// end-of-frame timer
|
||||
TimerObject* m_pEOFtimer = nullptr;
|
||||
// time at which a SOF was sent
|
||||
uint64_t m_SOFtime;
|
||||
// the duration of a usb frame
|
||||
uint64_t m_UsbFrameTime;
|
||||
// ticks per usb tick
|
||||
uint64_t m_TicksPerUsbTick;
|
||||
// pending usb packet to process
|
||||
USBPacket m_UsbPacket = {};
|
||||
// temporary buffer that holds the user data to transfer in a packet
|
||||
uint8_t m_UsbBuffer[8192] = {};
|
||||
// the value of HcControl in the previous frame
|
||||
uint32_t m_OldHcControl;
|
||||
// irq number
|
||||
int m_IrqNum;
|
||||
// Done Queue Interrupt Counter
|
||||
int m_DoneCount;
|
||||
// the address of the pending TD
|
||||
uint32_t m_AsyncTD = 0;
|
||||
// indicates if there is a pending asynchronous packet to process
|
||||
bool m_AsyncComplete = 0;
|
||||
|
||||
// EOF callback wrapper
|
||||
static void OHCI_FrameBoundaryWrapper(void* pVoid);
|
||||
// EOF callback function
|
||||
void OHCI_FrameBoundaryWorker();
|
||||
// inform the HCD that we got a problem here...
|
||||
void OHCI_FatalError();
|
||||
// initialize packet struct
|
||||
void OHCI_PacketInit(USBPacket* packet);
|
||||
// change usb state mode
|
||||
void OHCI_ChangeState(uint32_t Value);
|
||||
// switch the HC to the reset state
|
||||
void OHCI_StateReset();
|
||||
// start sending SOF tokens across the usb bus
|
||||
void OHCI_BusStart();
|
||||
// stop sending SOF tokens across the usb bus
|
||||
void OHCI_BusStop();
|
||||
// generate a SOF event, and start a timer for EOF
|
||||
void OHCI_SOF(bool bCreate);
|
||||
// change interrupt status
|
||||
void OHCI_UpdateInterrupt();
|
||||
// fire an interrupt
|
||||
void OHCI_SetInterrupt(uint32_t Value);
|
||||
// calculate frame time remaining
|
||||
uint32_t OHCI_GetFrameRemaining();
|
||||
// halt the endpoints of the device
|
||||
void OHCI_StopEndpoints();
|
||||
// set root hub status
|
||||
void OHCI_SetHubStatus(uint32_t Value);
|
||||
// update power related bits in HcRhPortStatus
|
||||
void OHCI_PortPower(int i, int p);
|
||||
// set root hub port status
|
||||
void OHCI_PortSetStatus(int PortNum, uint32_t Value);
|
||||
// set a flag in a port status register but only set it if the port is connected,
|
||||
// if not set ConnectStatusChange flag; if flag is enabled return 1
|
||||
int OHCI_PortSetIfConnected(int i, uint32_t Value);
|
||||
// read the HCCA structure in memory
|
||||
bool OHCI_ReadHCCA(uint32_t Paddr, OHCI_HCCA* Hcca);
|
||||
// write the HCCA structure in memory
|
||||
bool OHCI_WriteHCCA(uint32_t Paddr, OHCI_HCCA* Hcca);
|
||||
// read an ED in memory
|
||||
bool OHCI_ReadED(uint32_t Paddr, OHCI_ED* Ed);
|
||||
// write an ED in memory
|
||||
bool OHCI_WriteED(uint32_t Paddr, OHCI_ED* Ed);
|
||||
// read an TD in memory
|
||||
bool OHCI_ReadTD(uint32_t Paddr, OHCI_TD* Td);
|
||||
// write a TD in memory
|
||||
bool OHCI_WriteTD(uint32_t Paddr, OHCI_TD* Td);
|
||||
// read an iso TD in memory
|
||||
bool OHCI_ReadIsoTD(uint32_t Paddr, OHCI_ISO_TD* td);
|
||||
// write an iso TD in memory
|
||||
bool OHCI_WriteIsoTD(uint32_t Paddr, OHCI_ISO_TD* td);
|
||||
// read/write the user buffer pointed to by a TD from/to main memory
|
||||
bool OHCI_CopyTD(OHCI_TD* Td, uint8_t* Buffer, int Length, bool bIsWrite);
|
||||
// read/write the user buffer pointed to by a ISO TD from/to main memory
|
||||
bool OHCI_CopyIsoTD(uint32_t start_addr, uint32_t end_addr, uint8_t* Buffer, int Length, bool bIsWrite);
|
||||
// find a TD buffer in memory and copy it
|
||||
bool OHCI_FindAndCopyTD(uint32_t Paddr, uint8_t* Buffer, int Length, bool bIsWrite);
|
||||
// process an ED list. Returns nonzero if active TD was found
|
||||
int OHCI_ServiceEDlist(uint32_t Head, int Completion);
|
||||
// process a TD. Returns nonzero to terminate processing of this endpoint
|
||||
int OHCI_ServiceTD(OHCI_ED* Ed);
|
||||
// process an isochronous TD
|
||||
int OHCI_ServiceIsoTD(OHCI_ED* ed, int completion);
|
||||
// find the usb device with the supplied address
|
||||
XboxDeviceState* OHCI_FindDevice(uint8_t Addr);
|
||||
// cancel a packet when a device is removed
|
||||
void OHCI_AsyncCancelDevice(XboxDeviceState* dev);
|
||||
// Process Control and Bulk lists
|
||||
void OHCI_ProcessLists(int completion);
|
||||
// see USBPortOps struct for info
|
||||
void OHCI_Attach(USBPort* Port);
|
||||
void OHCI_Detach(USBPort* Port);
|
||||
void OHCI_ChildDetach(XboxDeviceState* child);
|
||||
void OHCI_Wakeup(USBPort* port1);
|
||||
void OHCI_AsyncCompletePacket(USBPort* port, USBPacket* packet);
|
||||
};
|
||||
|
||||
}
|
|
@ -1,458 +0,0 @@
|
|||
/*
|
||||
* Portions of the code are based on Cxbx-Reloaded's OHCI LLE implementation.
|
||||
* The original copyright header is included below.
|
||||
*/
|
||||
// This is an open source non-commercial project. Dear PVS-Studio, please check it.
|
||||
// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
|
||||
// ******************************************************************
|
||||
// *
|
||||
// * .,-::::: .,:: .::::::::. .,:: .:
|
||||
// * ,;;;'````' `;;;, .,;; ;;;'';;' `;;;, .,;;
|
||||
// * [[[ '[[,,[[' [[[__[[\. '[[,,[['
|
||||
// * $$$ Y$$$P $$""""Y$$ Y$$$P
|
||||
// * `88bo,__,o, oP"``"Yo, _88o,,od8P oP"``"Yo,
|
||||
// * "YUMMMMMP",m" "Mm,""YUMMMP" ,m" "Mm,
|
||||
// *
|
||||
// * Cxbx->devices->usb->UsbCommon.h
|
||||
// *
|
||||
// * This file is part of the Cxbx project.
|
||||
// *
|
||||
// * Cxbx and Cxbe are free software; you can redistribute them
|
||||
// * and/or modify them under the terms of the GNU General Public
|
||||
// * License as published by the Free Software Foundation; either
|
||||
// * version 2 of the license, or (at your option) any later version.
|
||||
// *
|
||||
// * This program is distributed in the hope that it will be useful,
|
||||
// * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// * GNU General Public License for more details.
|
||||
// *
|
||||
// * You should have recieved a copy of the GNU General Public License
|
||||
// * along with this program; see the file COPYING.
|
||||
// * If not, write to the Free Software Foundation, Inc.,
|
||||
// * 59 Temple Place - Suite 330, Bostom, MA 02111-1307, USA.
|
||||
// *
|
||||
// * (c) 2018 ergo720
|
||||
// *
|
||||
// * All rights reserved
|
||||
// *
|
||||
// ******************************************************************
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "strikebox/queue.h"
|
||||
#include "strikebox/iovec.h"
|
||||
|
||||
namespace strikebox {
|
||||
|
||||
#define USB_MAX_ENDPOINTS 15
|
||||
#define USB_MAX_INTERFACES 16
|
||||
|
||||
#define USB_STATE_NOTATTACHED 0
|
||||
#define USB_STATE_ATTACHED 1
|
||||
#define USB_STATE_DEFAULT 2
|
||||
|
||||
#define USB_CLASS_HUB 9
|
||||
|
||||
#define USB_ENDPOINT_XFER_CONTROL 0
|
||||
#define USB_ENDPOINT_XFER_ISOC 1
|
||||
#define USB_ENDPOINT_XFER_BULK 2
|
||||
#define USB_ENDPOINT_XFER_INT 3
|
||||
#define USB_ENDPOINT_XFER_INVALID 255
|
||||
|
||||
#define USB_INTERFACE_INVALID 255
|
||||
|
||||
#define USB_DIR_OUT 0
|
||||
#define USB_DIR_IN 0x80
|
||||
|
||||
#define USB_TOKEN_SETUP 0x2D
|
||||
#define USB_TOKEN_IN 0x69 // device -> host
|
||||
#define USB_TOKEN_OUT 0xE1 // host -> device
|
||||
|
||||
#define USB_SPEED_LOW 0
|
||||
#define USB_SPEED_FULL 1
|
||||
|
||||
#define USB_DEVICE_SELF_POWERED 0
|
||||
#define USB_DEVICE_REMOTE_WAKEUP 1
|
||||
|
||||
#define USB_TYPE_MASK (0x03 << 5)
|
||||
#define USB_TYPE_STANDARD (0x00 << 5)
|
||||
#define USB_TYPE_CLASS (0x01 << 5)
|
||||
#define USB_TYPE_VENDOR (0x02 << 5)
|
||||
#define USB_TYPE_RESERVED (0x03 << 5)
|
||||
|
||||
#define USB_RECIP_MASK 0x1F
|
||||
#define USB_RECIP_DEVICE 0x00
|
||||
#define USB_RECIP_INTERFACE 0x01
|
||||
#define USB_RECIP_ENDPOINT 0x02
|
||||
#define USB_RECIP_OTHER 0x03
|
||||
|
||||
#define DeviceRequest ((USB_DIR_IN|USB_TYPE_STANDARD|USB_RECIP_DEVICE)<<8)
|
||||
#define DeviceOutRequest ((USB_DIR_OUT|USB_TYPE_STANDARD|USB_RECIP_DEVICE)<<8)
|
||||
#define VendorDeviceRequest ((USB_DIR_IN|USB_TYPE_VENDOR|USB_RECIP_DEVICE)<<8)
|
||||
#define VendorDeviceOutRequest ((USB_DIR_OUT|USB_TYPE_VENDOR|USB_RECIP_DEVICE)<<8)
|
||||
|
||||
#define InterfaceRequest \
|
||||
((USB_DIR_IN|USB_TYPE_STANDARD|USB_RECIP_INTERFACE)<<8)
|
||||
#define InterfaceOutRequest \
|
||||
((USB_DIR_OUT|USB_TYPE_STANDARD|USB_RECIP_INTERFACE)<<8)
|
||||
#define ClassInterfaceRequest \
|
||||
((USB_DIR_IN|USB_TYPE_CLASS|USB_RECIP_INTERFACE)<<8)
|
||||
#define ClassInterfaceOutRequest \
|
||||
((USB_DIR_OUT|USB_TYPE_CLASS|USB_RECIP_INTERFACE)<<8)
|
||||
#define VendorInterfaceRequest \
|
||||
((USB_DIR_IN|USB_TYPE_VENDOR|USB_RECIP_INTERFACE)<<8)
|
||||
#define VendorInterfaceOutRequest \
|
||||
((USB_DIR_OUT|USB_TYPE_VENDOR|USB_RECIP_INTERFACE)<<8)
|
||||
|
||||
#define EndpointRequest ((USB_DIR_IN|USB_TYPE_STANDARD|USB_RECIP_ENDPOINT)<<8)
|
||||
#define EndpointOutRequest \
|
||||
((USB_DIR_OUT|USB_TYPE_STANDARD|USB_RECIP_ENDPOINT)<<8)
|
||||
|
||||
#define USB_REQ_GET_STATUS 0x00
|
||||
#define USB_REQ_CLEAR_FEATURE 0x01
|
||||
#define USB_REQ_SET_FEATURE 0x03
|
||||
#define USB_REQ_SET_ADDRESS 0x05
|
||||
#define USB_REQ_GET_DESCRIPTOR 0x06
|
||||
#define USB_REQ_SET_DESCRIPTOR 0x07
|
||||
#define USB_REQ_GET_CONFIGURATION 0x08
|
||||
#define USB_REQ_SET_CONFIGURATION 0x09
|
||||
#define USB_REQ_GET_INTERFACE 0x0A
|
||||
#define USB_REQ_SET_INTERFACE 0x0B
|
||||
#define USB_REQ_SYNCH_FRAME 0x0C
|
||||
|
||||
#define USB_DT_DEVICE 0x01
|
||||
#define USB_DT_CONFIG 0x02
|
||||
#define USB_DT_STRING 0x03
|
||||
#define USB_DT_INTERFACE 0x04
|
||||
#define USB_DT_ENDPOINT 0x05
|
||||
|
||||
#define USB_RET_SUCCESS (0)
|
||||
#define USB_RET_NODEV (-1)
|
||||
#define USB_RET_NAK (-2)
|
||||
#define USB_RET_STALL (-3)
|
||||
#define USB_RET_BABBLE (-4)
|
||||
#define USB_RET_IOERROR (-5)
|
||||
#define USB_RET_ASYNC (-6)
|
||||
#define USB_RET_ADD_TO_QUEUE (-7)
|
||||
#define USB_RET_REMOVE_FROM_QUEUE (-8)
|
||||
|
||||
typedef enum _USB_SPEED {
|
||||
USB_SPEED_MASK_LOW = 1 << 0,
|
||||
USB_SPEED_MASK_FULL = 1 << 1,
|
||||
}
|
||||
USB_SPEED;
|
||||
|
||||
typedef enum USBPacketState {
|
||||
USB_PACKET_UNDEFINED = 0,
|
||||
USB_PACKET_SETUP,
|
||||
USB_PACKET_QUEUED,
|
||||
USB_PACKET_ASYNC,
|
||||
USB_PACKET_COMPLETE,
|
||||
USB_PACKET_CANCELED,
|
||||
}
|
||||
USBPacketState;
|
||||
|
||||
/* same as Linux kernel root hubs */
|
||||
typedef enum {
|
||||
STR_MANUFACTURER = 1,
|
||||
STR_PRODUCT,
|
||||
STR_SERIALNUMBER,
|
||||
} STRING_DESC_INDEX;
|
||||
|
||||
// Forward declarations
|
||||
struct USBPacket;
|
||||
struct USBPort;
|
||||
struct USBDeviceClass;
|
||||
struct XboxDeviceState;
|
||||
struct USBPortOps;
|
||||
|
||||
/* String descriptor */
|
||||
struct USBDescString {
|
||||
uint8_t index; // index of this string descriptor
|
||||
std::string str; // the string of this string descriptor
|
||||
QLIST_ENTRY(USBDescString) next;
|
||||
};
|
||||
|
||||
// Device-specific class descriptors, if any. No idea if some Xbox devices use this but, if not, this can be removed
|
||||
struct USBDescOther {
|
||||
uint8_t length;
|
||||
const uint8_t *data;
|
||||
};
|
||||
|
||||
/* Endpoint descriptor */
|
||||
struct USBDescEndpoint {
|
||||
uint8_t bEndpointAddress; // the address of the endpoint on the USB device described by this descriptor
|
||||
uint8_t bmAttributes; // this field describes the endpoint's attributes when it is configured using the bConfigurationValue
|
||||
uint16_t wMaxPacketSize; // maximum packet size this endpoint is capable of sending or receiving when this configuration is selected
|
||||
uint8_t bInterval; // interval for polling endpoint for data transfers, expressed in milliseconds.
|
||||
uint8_t bRefresh; // for audio devices only: the rate at which synchronization feedback is provided
|
||||
uint8_t bSynchAddress; // for audio devices only: the address of the synchronization endpoint
|
||||
|
||||
uint8_t is_audio; // has bRefresh + bSynchAddress
|
||||
uint8_t* extra; // class-specific descriptors (if any) associated with this endpoint
|
||||
|
||||
// Dropped from XQEMU the parameters bMaxBurst, bmAttributes_super and wBytesPerInterval because those are only defined for
|
||||
// superspeed (usb 3.0) devices in the superspeed endpoint companion
|
||||
};
|
||||
|
||||
/* Interface descriptor */
|
||||
struct USBDescIface {
|
||||
uint8_t bInterfaceNumber; // number of interface
|
||||
uint8_t bAlternateSetting; // value used to select the alternate setting for the interface identified by bInterfaceNumber
|
||||
uint8_t bNumEndpoints; // number of endpoints used by this interface (excluding endpoint zero)
|
||||
uint8_t bInterfaceClass; // class code (assigned by the USB)
|
||||
uint8_t bInterfaceSubClass; // subclass code (assigned by the USB)
|
||||
uint8_t bInterfaceProtocol; // protocol code (assigned by the USB)
|
||||
uint8_t iInterface; // index of string descriptor describing this interface
|
||||
|
||||
uint8_t ndesc; // number of device-specific class descriptors (if any)
|
||||
USBDescOther* descs; // pointer to the extra class descriptors
|
||||
const USBDescEndpoint* eps; // endpoints supported by this interface
|
||||
};
|
||||
|
||||
/*
|
||||
* ergo720: I removed the Interface Association Descriptor (IAD) since, at the time of this writing (2018), the xboxdevwiki documents that all
|
||||
* known xid devices don't use them and also, according to the corresponding standard, IAD applies to usb revision 2.0 while the xbox uses
|
||||
* usb revision 1.1 so it shouldn't support them either. If this turns out to be incorrect, then IAD support will have to be added
|
||||
*/
|
||||
|
||||
/* Configuration descriptor */
|
||||
struct USBDescConfig {
|
||||
uint8_t bNumInterfaces; // number of interfaces supported by this configuration
|
||||
uint8_t bConfigurationValue; // value to use as an argument to the SetConfiguration() request to select this configuration
|
||||
uint8_t iConfiguration; // index of string descriptor describing this configuration
|
||||
uint8_t bmAttributes; // configuration characteristics
|
||||
uint8_t bMaxPower; // maximum power consumption of the USB device in this configuration expressed in 2mA units
|
||||
|
||||
/* "normal" interfaces */
|
||||
uint8_t nif; // number of interfaces (again)
|
||||
const USBDescIface* ifs; // interfaces supported by this configuration
|
||||
};
|
||||
|
||||
/* Device descriptor part 1 */
|
||||
struct USBDescDevice {
|
||||
uint16_t bcdUSB; // USB Specification Release Number in Binary-Coded Decimal (i.e., 2.10 is 210H)
|
||||
uint8_t bDeviceClass; // class code (assigned by the USB)
|
||||
uint8_t bDeviceSubClass; // subclass code (assigned by the USB)
|
||||
uint8_t bDeviceProtocol; // protocol code (assigned by the USB)
|
||||
uint8_t bMaxPacketSize0; // maximum packet size for endpoint zero (only 8, 16, 32, or 64 are valid)
|
||||
uint8_t bNumConfigurations; // number of possible configurations
|
||||
const USBDescConfig* confs; // configurations supported by this device
|
||||
};
|
||||
|
||||
/* Device descriptor part 2 */
|
||||
struct USBDescID {
|
||||
uint16_t idVendor; // vendor ID (assigned by the USB)
|
||||
uint16_t idProduct; // product ID (assigned by the manufacturer)
|
||||
uint16_t bcdDevice; // device release number in binary-coded decimal
|
||||
uint8_t iManufacturer; // index of string descriptor describing manufacturer
|
||||
uint8_t iProduct; // index of string descriptor describing product
|
||||
uint8_t iSerialNumber; // index of string descriptor describing the device's serial number
|
||||
};
|
||||
|
||||
/* Global USB Descriptor struct */
|
||||
struct USBDesc {
|
||||
USBDescID id; // id-specific info of the device descriptor
|
||||
const USBDescDevice* full; // remaining fields of the device descriptor
|
||||
const char* const* str;
|
||||
};
|
||||
|
||||
#pragma pack(1)
|
||||
|
||||
// Binary representation of the descriptors
|
||||
// Dropped from XQEMU usb 2.0 and 3.0 only descriptors
|
||||
struct USBDescriptor {
|
||||
uint8_t bLength;
|
||||
uint8_t bDescriptorType;
|
||||
union {
|
||||
struct {
|
||||
uint8_t bcdUSB_lo;
|
||||
uint8_t bcdUSB_hi;
|
||||
uint8_t bDeviceClass;
|
||||
uint8_t bDeviceSubClass;
|
||||
uint8_t bDeviceProtocol;
|
||||
uint8_t bMaxPacketSize0;
|
||||
uint8_t idVendor_lo;
|
||||
uint8_t idVendor_hi;
|
||||
uint8_t idProduct_lo;
|
||||
uint8_t idProduct_hi;
|
||||
uint8_t bcdDevice_lo;
|
||||
uint8_t bcdDevice_hi;
|
||||
uint8_t iManufacturer;
|
||||
uint8_t iProduct;
|
||||
uint8_t iSerialNumber;
|
||||
uint8_t bNumConfigurations;
|
||||
} device; // device descriptor
|
||||
struct {
|
||||
uint8_t wTotalLength_lo;
|
||||
uint8_t wTotalLength_hi;
|
||||
uint8_t bNumInterfaces;
|
||||
uint8_t bConfigurationValue;
|
||||
uint8_t iConfiguration;
|
||||
uint8_t bmAttributes;
|
||||
uint8_t bMaxPower;
|
||||
} config; // configuration descriptor
|
||||
struct {
|
||||
uint8_t bInterfaceNumber;
|
||||
uint8_t bAlternateSetting;
|
||||
uint8_t bNumEndpoints;
|
||||
uint8_t bInterfaceClass;
|
||||
uint8_t bInterfaceSubClass;
|
||||
uint8_t bInterfaceProtocol;
|
||||
uint8_t iInterface;
|
||||
} iface; // interface descriptor
|
||||
struct {
|
||||
uint8_t bEndpointAddress;
|
||||
uint8_t bmAttributes;
|
||||
uint8_t wMaxPacketSize_lo;
|
||||
uint8_t wMaxPacketSize_hi;
|
||||
uint8_t bInterval;
|
||||
uint8_t bRefresh; // only audio ep
|
||||
uint8_t bSynchAddress; // only audio ep
|
||||
} endpoint; // endpoint descriptor
|
||||
} u;
|
||||
};
|
||||
|
||||
#pragma pack()
|
||||
|
||||
/* USB endpoint */
|
||||
struct USBEndpoint {
|
||||
uint8_t Num; // endpoint number
|
||||
uint8_t pid;
|
||||
uint8_t Type; // the type of this endpoint
|
||||
uint8_t IfNum; // interface number this endpoint belongs to
|
||||
int MaxPacketSize; // maximum packet size supported by this endpoint
|
||||
bool Pipeline;
|
||||
bool Halted; // indicates that the endpoint is halted
|
||||
XboxDeviceState* Dev; // device this endpoint belongs to
|
||||
QTAILQ_HEAD(, USBPacket) Queue; // queue of packets to this endpoint
|
||||
};
|
||||
|
||||
/* Struct describing the status of a usb port */
|
||||
struct USBPort {
|
||||
XboxDeviceState* Dev = nullptr; // usb device(if present)
|
||||
USBPortOps* Operations; // functions to call when a port event happens
|
||||
int SpeedMask; // usb speeds supported
|
||||
std::string Path; // the number of the port + 1, used to create a serial number for this device
|
||||
int PortIndex; // internal port index
|
||||
};
|
||||
|
||||
/* Struct which stores general functions/variables regarding the peripheral */
|
||||
struct USBDeviceClass {
|
||||
std::function<int(XboxDeviceState* dev)> init;
|
||||
|
||||
// Walk (enabled) downstream ports, check for a matching device.
|
||||
// Only hubs implement this.
|
||||
std::function<XboxDeviceState*(XboxDeviceState* dev, uint8_t addr)> find_device;
|
||||
|
||||
// Called when a packet is canceled.
|
||||
std::function<void(XboxDeviceState* dev, USBPacket* p)> cancel_packet;
|
||||
|
||||
// Called when device is destroyed.
|
||||
std::function<void(void)> handle_destroy;
|
||||
|
||||
// Attach the device
|
||||
std::function<void(XboxDeviceState* dev)> handle_attach;
|
||||
|
||||
// Reset the device
|
||||
std::function<void(XboxDeviceState* dev)> handle_reset;
|
||||
|
||||
// Process control request.
|
||||
// Called from handle_packet().
|
||||
// Status gets stored in p->status, and if p->status == USB_RET_SUCCESS
|
||||
// then the number of bytes transferred is stored in p->actual_length
|
||||
std::function<void(XboxDeviceState* dev, USBPacket* p, int request, int value,
|
||||
int index, int length, uint8_t *data)> handle_control;
|
||||
|
||||
// Process data transfers (both BULK and ISOC).
|
||||
// Called from handle_packet().
|
||||
// Status gets stored in p->status, and if p->status == USB_RET_SUCCESS
|
||||
// then the number of bytes transferred is stored in p->actual_length
|
||||
std::function<void(XboxDeviceState* dev, USBPacket* p)> handle_data;
|
||||
|
||||
std::function<void(XboxDeviceState* dev, int Interface,
|
||||
int alt_old, int alt_new)> set_interface;
|
||||
|
||||
// Called when the hcd is done queuing packets for an endpoint, only
|
||||
// necessary for devices which can return USB_RET_ADD_TO_QUEUE.
|
||||
std::function<void(XboxDeviceState* dev, USBEndpoint* ep)> flush_ep_queue;
|
||||
|
||||
// Called by the hcd to let the device know the queue for an endpoint
|
||||
// has been unlinked / stopped. Optional may be NULL.
|
||||
std::function<void(XboxDeviceState* Dev, USBEndpoint* EP)> ep_stopped;
|
||||
|
||||
const char* product_desc; // friendly name of the device
|
||||
const USBDesc* usb_desc; // device descriptor
|
||||
};
|
||||
|
||||
/* definition of an Xbox usb device */
|
||||
struct XboxDeviceState {
|
||||
USBPort* Port; // usb port struct of this device
|
||||
int PortPath; // port index to which this device is attached to
|
||||
uint32_t flags;
|
||||
USBDeviceClass* klass; // usb class struct of this device
|
||||
|
||||
int Speed; // actual speed of the connected device
|
||||
int SpeedMask; // supported speeds, not in info because it may be variable (hostdevs)
|
||||
uint8_t Addr; // device function address
|
||||
std::string ProductDesc; // the friendly name of this device
|
||||
int Attached; // device is attached
|
||||
|
||||
int32_t State; // current state of device
|
||||
uint8_t SetupBuffer[8]; // setup packet buffer - 8 bytes (control transfers only)
|
||||
uint8_t DataBuffer[4096]; // buffer where to write the data requested during usb requests
|
||||
int32_t RemoteWakeup; // wakeup flag
|
||||
int32_t SetupState; // result of a control transfer processing operation
|
||||
uint32_t SetupLength; // this field specifies the length of the data transferred during the second phase of the control transfer
|
||||
uint32_t SetupIndex; // index of the parameter in a setup token?
|
||||
|
||||
USBEndpoint EP_ctl; // endpoints for SETUP tokens
|
||||
USBEndpoint EP_in[USB_MAX_ENDPOINTS]; // endpoints for OUT tokens
|
||||
USBEndpoint EP_out[USB_MAX_ENDPOINTS]; // endpoints for IN tokens
|
||||
|
||||
QLIST_HEAD(, USBDescString) Strings; // strings of the string descriptors
|
||||
const USBDesc* UsbDesc; // Overrides class usb_desc if not nullptr
|
||||
const USBDescDevice* Device; // device descriptor part 1
|
||||
|
||||
int Configuration; // number of the selected configuration descriptor
|
||||
int NumInterfaces; // number of available interface descriptors
|
||||
int AltSetting[USB_MAX_INTERFACES]; // alternate setting numbers for the current interface
|
||||
const USBDescConfig* Config; // configuration descriptor in use
|
||||
const USBDescIface* Ifaces[USB_MAX_INTERFACES]; // interface in use
|
||||
};
|
||||
|
||||
/* Structure used to hold information about an active USB packet */
|
||||
struct USBPacket {
|
||||
int Pid; // Packet ID (used to identify the type of packet that is being sent)
|
||||
uint32_t Id; // Paddr of the TD for this packet
|
||||
USBEndpoint* Endpoint; // endpoint this packet is transferred to
|
||||
unsigned int Stream;
|
||||
IOVector IoVec; // used to perform vectored I/O
|
||||
uint64_t Parameter; // this seems to be used only in xhci and it's 0 otherwise. If so, this can be removed
|
||||
bool ShortNotOK; // the bufferRounding mode of the TD for this packet
|
||||
bool IntReq; // whether or not to generate an interrupt for this packet (DelayInterrupt of the TD is zero)
|
||||
int Status; // USB_RET_* status code
|
||||
unsigned int ActualLength; // number of bytes actually written to DataBuffer
|
||||
// Internal use by the USB layer
|
||||
USBPacketState State;
|
||||
QTAILQ_ENTRY(USBPacket) Queue;
|
||||
};
|
||||
|
||||
struct USBPortOps {
|
||||
std::function<void(USBPort* port)> attach;
|
||||
std::function<void(USBPort* port)> detach;
|
||||
/*
|
||||
* This gets called when a device downstream from the device attached to
|
||||
* the port (attached through a hub) gets detached.
|
||||
*/
|
||||
std::function<void(XboxDeviceState* child)> child_detach;
|
||||
std::function<void(USBPort* port)> wakeup;
|
||||
/*
|
||||
* Note that port->dev will be different then the device from which
|
||||
* the packet originated when a hub is involved.
|
||||
*/
|
||||
std::function<void(USBPort* port, USBPacket* p)> complete;
|
||||
};
|
||||
|
||||
}
|
|
@ -1,142 +0,0 @@
|
|||
/*
|
||||
* Portions of the code are based on Cxbx-Reloaded's OHCI LLE implementation.
|
||||
* The original copyright header is included below.
|
||||
*/
|
||||
// This is an open source non-commercial project. Dear PVS-Studio, please check it.
|
||||
// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
|
||||
// ******************************************************************
|
||||
// *
|
||||
// * .,-::::: .,:: .::::::::. .,:: .:
|
||||
// * ,;;;'````' `;;;, .,;; ;;;'';;' `;;;, .,;;
|
||||
// * [[[ '[[,,[[' [[[__[[\. '[[,,[['
|
||||
// * $$$ Y$$$P $$""""Y$$ Y$$$P
|
||||
// * `88bo,__,o, oP"``"Yo, _88o,,od8P oP"``"Yo,
|
||||
// * "YUMMMMMP",m" "Mm,""YUMMMP" ,m" "Mm,
|
||||
// *
|
||||
// * Cxbx->devices->usb->Hub.h
|
||||
// *
|
||||
// * This file is part of the Cxbx project.
|
||||
// *
|
||||
// * Cxbx and Cxbe are free software; you can redistribute them
|
||||
// * and/or modify them under the terms of the GNU General Public
|
||||
// * License as published by the Free Software Foundation; either
|
||||
// * version 2 of the license, or (at your option) any later version.
|
||||
// *
|
||||
// * This program is distributed in the hope that it will be useful,
|
||||
// * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// * GNU General Public License for more details.
|
||||
// *
|
||||
// * You should have recieved a copy of the GNU General Public License
|
||||
// * along with this program; see the file COPYING.
|
||||
// * If not, write to the Free Software Foundation, Inc.,
|
||||
// * 59 Temple Place - Suite 330, Bostom, MA 02111-1307, USA.
|
||||
// *
|
||||
// * (c) 2018 ergo720
|
||||
// *
|
||||
// * All rights reserved
|
||||
// *
|
||||
// ******************************************************************
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "../pci/usb_pci.h"
|
||||
|
||||
namespace strikebox {
|
||||
|
||||
#define NUM_PORTS 8
|
||||
|
||||
#define PORT_STAT_CONNECTION 0x0001
|
||||
#define PORT_STAT_ENABLE 0x0002
|
||||
#define PORT_STAT_SUSPEND 0x0004
|
||||
#define PORT_STAT_OVERCURRENT 0x0008
|
||||
#define PORT_STAT_RESET 0x0010
|
||||
#define PORT_STAT_POWER 0x0100
|
||||
#define PORT_STAT_LOW_SPEED 0x0200
|
||||
|
||||
#define PORT_STAT_C_CONNECTION 0x0001
|
||||
#define PORT_STAT_C_ENABLE 0x0002
|
||||
#define PORT_STAT_C_SUSPEND 0x0004
|
||||
#define PORT_STAT_C_OVERCURRENT 0x0008
|
||||
#define PORT_STAT_C_RESET 0x0010
|
||||
|
||||
#define ClearHubFeature (0x2000 | USB_REQ_CLEAR_FEATURE)
|
||||
#define ClearPortFeature (0x2300 | USB_REQ_CLEAR_FEATURE)
|
||||
#define GetHubDescriptor (0xA000 | USB_REQ_GET_DESCRIPTOR)
|
||||
#define GetHubStatus (0xA000 | USB_REQ_GET_STATUS)
|
||||
#define GetPortStatus (0xA300 | USB_REQ_GET_STATUS)
|
||||
#define SetHubFeature (0x2000 | USB_REQ_SET_FEATURE)
|
||||
#define SetPortFeature (0x2300 | USB_REQ_SET_FEATURE)
|
||||
|
||||
#define PORT_CONNECTION 0
|
||||
#define PORT_ENABLE 1
|
||||
#define PORT_SUSPEND 2
|
||||
#define PORT_OVERCURRENT 3
|
||||
#define PORT_RESET 4
|
||||
#define PORT_POWER 8
|
||||
#define PORT_LOWSPEED 9
|
||||
#define PORT_C_CONNECTION 16
|
||||
#define PORT_C_ENABLE 17
|
||||
#define PORT_C_SUSPEND 18
|
||||
#define PORT_C_OVERCURRENT 19
|
||||
#define PORT_C_RESET 20
|
||||
|
||||
struct USBHubPort {
|
||||
USBPort port; // downstream port status
|
||||
uint16_t wPortStatus; // Port Status Field, in accordance with the standard
|
||||
uint16_t wPortChange; // Port Change Field, in accordance with the standard
|
||||
};
|
||||
|
||||
struct USBHubState {
|
||||
XboxDeviceState dev; // hub device status
|
||||
USBEndpoint* intr; // interrupt endpoint of the hub
|
||||
USBHubPort ports[NUM_PORTS]; // downstream ports of the hub
|
||||
};
|
||||
|
||||
/* Class which implements a usb hub */
|
||||
class Hub {
|
||||
public:
|
||||
// usb device this hub is attached to
|
||||
USBPCIDevice* m_UsbDev = nullptr;
|
||||
|
||||
// initialize this hub
|
||||
int Init(int port);
|
||||
// start hub destruction
|
||||
void HubDestroy();
|
||||
|
||||
|
||||
private:
|
||||
// hub state
|
||||
USBHubState* m_HubState = nullptr;
|
||||
// hub class functions
|
||||
USBDeviceClass* m_pPeripheralFuncStruct = nullptr;
|
||||
|
||||
// initialize various member variables/functions
|
||||
XboxDeviceState* ClassInitFn();
|
||||
// see USBDeviceClass for comments about these functions
|
||||
int UsbHub_Initfn(XboxDeviceState* dev);
|
||||
XboxDeviceState* UsbHub_FindDevice(XboxDeviceState* dev, uint8_t addr);
|
||||
void UsbHub_HandleReset();
|
||||
void UsbHub_HandleControl(XboxDeviceState* dev, USBPacket* p,
|
||||
int request, int value, int index, int length, uint8_t* data);
|
||||
void UsbHub_HandleData(XboxDeviceState* dev, USBPacket* p);
|
||||
void UsbHub_HandleDestroy();
|
||||
// see USBPortOps struct for info
|
||||
void UsbHub_Attach(USBPort* port1);
|
||||
void UsbHub_Detach(USBPort* port1);
|
||||
void UsbHub_ChildDetach(XboxDeviceState* child);
|
||||
void UsbHub_Wakeup(USBPort* port1);
|
||||
void UsbHub_Complete(USBPort* port, USBPacket* packet);
|
||||
// reserve a usb port for this hub
|
||||
int UsbHubClaimPort(XboxDeviceState* dev, int port);
|
||||
// free the usb port used by this hub
|
||||
void UsbHubReleasePort(XboxDeviceState* dev);
|
||||
// retieve the name of the feature of the usb request
|
||||
std::string GetFeatureName(int feature);
|
||||
// destroy hub resources
|
||||
void HubCleanUp();
|
||||
};
|
||||
|
||||
extern Hub* g_HubObjArray[4];
|
||||
|
||||
}
|
|
@ -1,11 +1,6 @@
|
|||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
#include "../defs.h"
|
||||
#include "pci.h"
|
||||
#include "../nv2a/defs.h"
|
||||
#include "../nv2a/vga.h"
|
||||
#include "../basic/irq.h"
|
||||
|
||||
namespace strikebox {
|
||||
|
@ -13,133 +8,21 @@ namespace strikebox {
|
|||
class NV2ADevice : public PCIDevice {
|
||||
public:
|
||||
NV2ADevice(uint8_t *pSystemRAM, uint32_t systemRAMSize, IRQHandler& irqHandler);
|
||||
|
||||
virtual ~NV2ADevice();
|
||||
|
||||
// PCI Device functions
|
||||
void Init();
|
||||
void Reset();
|
||||
|
||||
|
||||
void PCIIORead(int barIndex, uint32_t port, uint32_t *value, uint8_t size) override;
|
||||
void PCIIOWrite(int barIndex, uint32_t port, uint32_t value, uint8_t size) override;
|
||||
void PCIMMIORead(int barIndex, uint32_t addr, uint32_t *value, uint8_t size) override;
|
||||
void PCIMMIOWrite(int barIndex, uint32_t addr, uint32_t value, uint8_t size) override;
|
||||
|
||||
private:
|
||||
const NV2ABlockInfo* FindBlock(uint32_t addr);
|
||||
|
||||
static void PMCRead(NV2ADevice* pNV2A, uint32_t addr, uint32_t *value, uint8_t size);
|
||||
static void PMCWrite(NV2ADevice* pNV2A, uint32_t addr, uint32_t value, uint8_t size);
|
||||
|
||||
static void PBUSRead(NV2ADevice* pNV2A, uint32_t addr, uint32_t *value, uint8_t size);
|
||||
static void PBUSWrite(NV2ADevice* pNV2A, uint32_t addr, uint32_t value, uint8_t size);
|
||||
|
||||
static void PFIFORead(NV2ADevice* pNV2A, uint32_t addr, uint32_t *value, uint8_t size);
|
||||
static void PFIFOWrite(NV2ADevice* pNV2A, uint32_t addr, uint32_t value, uint8_t size);
|
||||
|
||||
static void PRMARead(NV2ADevice* pNV2A, uint32_t addr, uint32_t *value, uint8_t size);
|
||||
static void PRMAWrite(NV2ADevice* pNV2A, uint32_t addr, uint32_t value, uint8_t size);
|
||||
|
||||
static void PVIDEORead(NV2ADevice* pNV2A, uint32_t addr, uint32_t *value, uint8_t size);
|
||||
static void PVIDEOWrite(NV2ADevice* pNV2A, uint32_t addr, uint32_t value, uint8_t size);
|
||||
|
||||
static void PTIMERRead(NV2ADevice* pNV2A, uint32_t addr, uint32_t *value, uint8_t size);
|
||||
static void PTIMERWrite(NV2ADevice* pNV2A, uint32_t addr, uint32_t value, uint8_t size);
|
||||
|
||||
static void PCOUNTERRead(NV2ADevice* pNV2A, uint32_t addr, uint32_t *value, uint8_t size);
|
||||
static void PCOUNTERWrite(NV2ADevice* pNV2A, uint32_t addr, uint32_t value, uint8_t size);
|
||||
|
||||
static void PVPERead(NV2ADevice* pNV2A, uint32_t addr, uint32_t *value, uint8_t size);
|
||||
static void PVPEWrite(NV2ADevice* pNV2A, uint32_t addr, uint32_t value, uint8_t size);
|
||||
|
||||
static void PTVRead(NV2ADevice* pNV2A, uint32_t addr, uint32_t *value, uint8_t size);
|
||||
static void PTVWrite(NV2ADevice* pNV2A, uint32_t addr, uint32_t value, uint8_t size);
|
||||
|
||||
static void PRMFBRead(NV2ADevice* pNV2A, uint32_t addr, uint32_t *value, uint8_t size);
|
||||
static void PRMFBWrite(NV2ADevice* pNV2A, uint32_t addr, uint32_t value, uint8_t size);
|
||||
|
||||
static void PRMVIORead(NV2ADevice* pNV2A, uint32_t addr, uint32_t *value, uint8_t size);
|
||||
static void PRMVIOWrite(NV2ADevice* pNV2A, uint32_t addr, uint32_t value, uint8_t size);
|
||||
|
||||
static void PFBRead(NV2ADevice* pNV2A, uint32_t addr, uint32_t *value, uint8_t size);
|
||||
static void PFBWrite(NV2ADevice* pNV2A, uint32_t addr, uint32_t value, uint8_t size);
|
||||
|
||||
static void PSTRAPSRead(NV2ADevice* pNV2A, uint32_t addr, uint32_t *value, uint8_t size);
|
||||
static void PSTRAPSWrite(NV2ADevice* pNV2A, uint32_t addr, uint32_t value, uint8_t size);
|
||||
|
||||
static void PGRAPHRead(NV2ADevice* pNV2A, uint32_t addr, uint32_t *value, uint8_t size);
|
||||
static void PGRAPHWrite(NV2ADevice* pNV2A, uint32_t addr, uint32_t value, uint8_t size);
|
||||
|
||||
static void PCRTCRead(NV2ADevice* pNV2A, uint32_t addr, uint32_t *value, uint8_t size);
|
||||
static void PCRTCWrite(NV2ADevice* pNV2A, uint32_t addr, uint32_t value, uint8_t size);
|
||||
|
||||
static void PRMCIORead(NV2ADevice* pNV2A, uint32_t addr, uint32_t *value, uint8_t size);
|
||||
static void PRMCIOWrite(NV2ADevice* pNV2A, uint32_t addr, uint32_t value, uint8_t size);
|
||||
|
||||
static void PRAMDACRead(NV2ADevice* pNV2A, uint32_t addr, uint32_t *value, uint8_t size);
|
||||
static void PRAMDACWrite(NV2ADevice* pNV2A, uint32_t addr, uint32_t value, uint8_t size);
|
||||
|
||||
static void PRMDIORead(NV2ADevice* pNV2A, uint32_t addr, uint32_t *value, uint8_t size);
|
||||
static void PRMDIOWrite(NV2ADevice* pNV2A, uint32_t addr, uint32_t value, uint8_t size);
|
||||
|
||||
static void PRAMINRead(NV2ADevice* pNV2A, uint32_t addr, uint32_t *value, uint8_t size);
|
||||
static void PRAMINWrite(NV2ADevice* pNV2A, uint32_t addr, uint32_t value, uint8_t size);
|
||||
|
||||
static void USERRead(NV2ADevice* pNV2A, uint32_t addr, uint32_t *value, uint8_t size);
|
||||
static void USERWrite(NV2ADevice* pNV2A, uint32_t addr, uint32_t value, uint8_t size);
|
||||
|
||||
uint32_t ramht_hash(uint32_t handle);
|
||||
RAMHTEntry ramht_lookup(uint32_t handle);
|
||||
|
||||
uint32_t ptimer_get_clock();
|
||||
|
||||
void pgraph_set_context_user(uint32_t value);
|
||||
void pgraph_context_switch(unsigned int channel_id);
|
||||
void pgraph_wait_fifo_access();
|
||||
void pgraph_method_log(unsigned int subchannel, unsigned int graphics_class, unsigned int method, uint32_t parameter);
|
||||
void pgraph_method(unsigned int subchannel, unsigned int method, uint32_t parameter);
|
||||
bool pgraph_color_write_enabled();
|
||||
bool pgraph_zeta_write_enabled();
|
||||
|
||||
unsigned int kelvin_map_stencil_op(uint32_t parameter);
|
||||
unsigned int kelvin_map_polygon_mode(uint32_t parameter);
|
||||
unsigned int kelvin_map_texgen(uint32_t parameter, unsigned int channel);
|
||||
|
||||
void load_graphics_object(uint32_t instance_address, GraphicsObject *obj);
|
||||
GraphicsObject* lookup_graphics_object(uint32_t instance_address);
|
||||
|
||||
DMAObject nv_dma_load(uint32_t dma_obj_address);
|
||||
void *nv_dma_map(uint32_t dma_obj_address, uint32_t *len);
|
||||
|
||||
void pfifo_run_pusher();
|
||||
|
||||
static void PFIFO_Puller_Thread(NV2ADevice* pNV2a);
|
||||
static void VBlankThread(NV2ADevice* pNV2A);
|
||||
|
||||
void UpdateIRQ();
|
||||
|
||||
uint8_t *m_pSystemRAM;
|
||||
uint32_t m_systemRAMSize;
|
||||
IRQHandler& m_irqHandler;
|
||||
|
||||
uint8_t* m_pRAMIN = nullptr;
|
||||
uint8_t* m_VRAM = nullptr;
|
||||
NV2APRAMDAC m_PRAMDAC;
|
||||
NV2APTIMER m_PTIMER;
|
||||
NV2APVIDEO m_PVIDEO;
|
||||
NV2APMC m_PMC;
|
||||
NV2APCRTC m_PCRTC;
|
||||
NV2APFIFO m_PFIFO;
|
||||
NV2APFB m_PFB;
|
||||
NV2APGRAPH m_PGRAPH;
|
||||
NV2APRMCIO m_PRMCIO;
|
||||
NV2AUSER m_User;
|
||||
|
||||
VGACommonState m_VGAState;
|
||||
|
||||
bool m_running;
|
||||
std::vector<NV2ABlockInfo> m_MemoryRegions;
|
||||
std::thread m_VblankThread;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -1,85 +1,25 @@
|
|||
/*
|
||||
* Portions of the code are based on Cxbx-Reloaded's APU emulator.
|
||||
* The original copyright header is included below.
|
||||
*/
|
||||
// This is an open source non-commercial project. Dear PVS-Studio, please check it.
|
||||
// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
|
||||
// ******************************************************************
|
||||
// *
|
||||
// * .,-::::: .,:: .::::::::. .,:: .:
|
||||
// * ,;;;'````' `;;;, .,;; ;;;'';;' `;;;, .,;;
|
||||
// * [[[ '[[,,[[' [[[__[[\. '[[,,[['
|
||||
// * $$$ Y$$$P $$""""Y$$ Y$$$P
|
||||
// * `88bo,__,o, oP"``"Yo, _88o,,od8P oP"``"Yo,
|
||||
// * "YUMMMMMP",m" "Mm,""YUMMMP" ,m" "Mm,
|
||||
// *
|
||||
// * src->devices->APUDevice.cpp
|
||||
// *
|
||||
// * This file is part of the Cxbx project.
|
||||
// *
|
||||
// * Cxbx and Cxbe are free software; you can redistribute them
|
||||
// * and/or modify them under the terms of the GNU General Public
|
||||
// * License as published by the Free Software Foundation; either
|
||||
// * version 2 of the license, or (at your option) any later version.
|
||||
// *
|
||||
// * This program is distributed in the hope that it will be useful,
|
||||
// * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// * GNU General Public License for more details.
|
||||
// *
|
||||
// * You should have recieved a copy of the GNU General Public License
|
||||
// * along with this program; see the file COPYING.
|
||||
// * If not, write to the Free Software Foundation, Inc.,
|
||||
// * 59 Temple Place - Suite 330, Bostom, MA 02111-1307, USA.
|
||||
// *
|
||||
// * (c) 2018 Luke Usher <luke.usher@outlook.coM>
|
||||
// *
|
||||
// * All rights reserved
|
||||
// *
|
||||
// ******************************************************************
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
#include "../defs.h"
|
||||
#include "pci.h"
|
||||
|
||||
namespace strikebox {
|
||||
|
||||
#define APU_VP_BASE 0x20000
|
||||
#define APU_VP_SIZE 0x10000
|
||||
|
||||
#define APU_GP_BASE 0x30000
|
||||
#define APU_GP_SIZE 0x10000
|
||||
|
||||
#define APU_EP_BASE 0x50000
|
||||
#define APU_EP_SIZE 0x10000
|
||||
#define NVNET_ADDR 0xFEF00000
|
||||
#define NVNET_SIZE 0x00000400
|
||||
|
||||
class NVAPUDevice : public PCIDevice {
|
||||
public:
|
||||
// constructor
|
||||
NVAPUDevice();
|
||||
virtual ~NVAPUDevice();
|
||||
|
||||
// PCI Device functions
|
||||
void Init();
|
||||
void Reset();
|
||||
|
||||
|
||||
void PCIIORead(int barIndex, uint32_t port, uint32_t *value, uint8_t size) override;
|
||||
void PCIIOWrite(int barIndex, uint32_t port, uint32_t value, uint8_t size) override;
|
||||
void PCIMMIORead(int barIndex, uint32_t addr, uint32_t *value, uint8_t size) override;
|
||||
void PCIMMIOWrite(int barIndex, uint32_t addr, uint32_t value, uint8_t size) override;
|
||||
|
||||
private:
|
||||
void GPRead(uint32_t address, uint32_t *value, uint8_t size);
|
||||
void GPWrite(uint32_t address, uint32_t value, uint8_t size);
|
||||
|
||||
void EPRead(uint32_t address, uint32_t *value, uint8_t size);
|
||||
void EPWrite(uint32_t address, uint32_t value, uint8_t size);
|
||||
|
||||
void VPRead(uint32_t address, uint32_t *value, uint8_t size);
|
||||
void VPWrite(uint32_t address, uint32_t value, uint8_t size);
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -1,209 +1,21 @@
|
|||
/*
|
||||
* Portions of the code are based on Cxbx-Reloaded's OHCI LLE implementation.
|
||||
* The original copyright header is included below.
|
||||
*/
|
||||
// This is an open source non-commercial project. Dear PVS-Studio, please check it.
|
||||
// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
|
||||
// ******************************************************************
|
||||
// *
|
||||
// * .,-::::: .,:: .::::::::. .,:: .:
|
||||
// * ,;;;'````' `;;;, .,;; ;;;'';;' `;;;, .,;;
|
||||
// * [[[ '[[,,[[' [[[__[[\. '[[,,[['
|
||||
// * $$$ Y$$$P $$""""Y$$ Y$$$P
|
||||
// * `88bo,__,o, oP"``"Yo, _88o,,od8P oP"``"Yo,
|
||||
// * "YUMMMMMP",m" "Mm,""YUMMMP" ,m" "Mm,
|
||||
// *
|
||||
// * Cxbx->devices->USBController->USBDevice.h
|
||||
// *
|
||||
// * This file is part of the Cxbx project.
|
||||
// *
|
||||
// * Cxbx and Cxbe are free software; you can redistribute them
|
||||
// * and/or modify them under the terms of the GNU General Public
|
||||
// * License as published by the Free Software Foundation; either
|
||||
// * version 2 of the license, or (at your option) any later version.
|
||||
// *
|
||||
// * This program is distributed in the hope that it will be useful,
|
||||
// * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// * GNU General Public License for more details.
|
||||
// *
|
||||
// * You should have recieved a copy of the GNU General Public License
|
||||
// * along with this program; see the file COPYING.
|
||||
// * If not, write to the Free Software Foundation, Inc.,
|
||||
// * 59 Temple Place - Suite 330, Bostom, MA 02111-1307, USA.
|
||||
// *
|
||||
// * (c) 2018 ergo720
|
||||
// *
|
||||
// * All rights reserved
|
||||
// *
|
||||
// ******************************************************************
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
#include "virt86/virt86.hpp"
|
||||
|
||||
#include "../defs.h"
|
||||
#include "pci.h"
|
||||
#include "../ohci/ohci_common.h"
|
||||
|
||||
namespace strikebox {
|
||||
|
||||
typedef enum USBDeviceFlags {
|
||||
USB_DEV_FLAG_FULL_PATH,
|
||||
USB_DEV_FLAG_IS_HOST,
|
||||
USB_DEV_FLAG_MSOS_DESC_ENABLE,
|
||||
USB_DEV_FLAG_MSOS_DESC_IN_USE,
|
||||
}
|
||||
USBDeviceFlags;
|
||||
|
||||
// Forward declare OHCI class for m_HostController pointer
|
||||
class OHCI;
|
||||
|
||||
/* Helper class which provides various functionality to both OHCI and usb device classes */
|
||||
class USBPCIDevice : public PCIDevice {
|
||||
public:
|
||||
// constructor
|
||||
USBPCIDevice(uint8_t irqn, virt86::VirtualProcessor& vp);
|
||||
virtual ~USBPCIDevice();
|
||||
|
||||
// PCI Device functions
|
||||
void Init();
|
||||
void Reset();
|
||||
|
||||
|
||||
void PCIMMIORead(int barIndex, uint32_t addr, uint32_t *value, uint8_t size) override;
|
||||
void PCIMMIOWrite(int barIndex, uint32_t addr, uint32_t value, uint8_t size) override;
|
||||
|
||||
|
||||
|
||||
// USBDevice-specific functions/variables
|
||||
// pointer to the host controller this device refers to
|
||||
OHCI* m_HostController;
|
||||
// PCI path of this usb device
|
||||
const char* m_PciPath;
|
||||
// free usb ports on this device (hubs included)
|
||||
std::vector<USBPort*> m_FreePorts;
|
||||
|
||||
// register a port with the HC
|
||||
void USB_RegisterPort(USBPort* Port, int Index, int SpeedMask, USBPortOps* Ops);
|
||||
// free a port with the HC
|
||||
void USB_UnregisterPort(USBPort* Port);
|
||||
// reset a usb port
|
||||
void USB_PortReset(USBPort* Port);
|
||||
// update device status during an attach
|
||||
void USB_DeviceAttach(XboxDeviceState* dev);
|
||||
// update device status during an detach
|
||||
void USB_DeviceDetach(XboxDeviceState* dev);
|
||||
// update port status when a device is attached
|
||||
void USB_Attach(USBPort* Port);
|
||||
// update port status when a device is detached
|
||||
void USB_Detach(USBPort* Port);
|
||||
// update port status when a device is detached
|
||||
void USB_Wakeup(USBEndpoint* ep);
|
||||
// reset a device
|
||||
void USB_DeviceReset(XboxDeviceState* Dev);
|
||||
// find the device connected to the supplied port and address
|
||||
XboxDeviceState* USB_FindDevice(USBPort* Port, uint8_t Addr);
|
||||
// find the requested endpoint in the supplied device
|
||||
USBEndpoint* USB_GetEP(XboxDeviceState* Dev, int Pid, int Ep);
|
||||
// setup a packet for transfer
|
||||
void USB_PacketSetup(USBPacket* p, int Pid, USBEndpoint* Ep, unsigned int Stream, uint64_t Id, bool ShortNotOK, bool IntReq);
|
||||
// check if the state of the packet is queued or async
|
||||
bool USB_IsPacketInflight(USBPacket* p);
|
||||
// append the user buffer to the packet
|
||||
void USB_PacketAddBuffer(USBPacket* p, void* ptr, size_t len);
|
||||
// transfer and process the packet
|
||||
void USB_HandlePacket(XboxDeviceState* dev, USBPacket* p);
|
||||
// check if the packet has the expected state and assert if not
|
||||
void USB_PacketCheckState(USBPacket* p, USBPacketState expected);
|
||||
// process the packet
|
||||
void USB_ProcessOne(USBPacket* p);
|
||||
// xhci only?
|
||||
void USB_DoParameter(XboxDeviceState* s, USBPacket* p);
|
||||
// process a setup token
|
||||
void USB_DoTokenSetup(XboxDeviceState* s, USBPacket* p);
|
||||
// process an input token
|
||||
void DoTokenIn(XboxDeviceState* s, USBPacket* p);
|
||||
// process an output token
|
||||
void DoTokenOut(XboxDeviceState* s, USBPacket* p);
|
||||
// copy the packet data to the buffer pointed to by ptr
|
||||
void USB_PacketCopy(USBPacket* p, void* ptr, size_t bytes);
|
||||
// Cancel an active packet. The packed must have been deferred by
|
||||
// returning USB_RET_ASYNC from handle_packet, and not yet completed
|
||||
void USB_CancelPacket(USBPacket* p);
|
||||
// queue a packet to an endpoint
|
||||
void USB_QueueOne(USBPacket* p);
|
||||
// call usb class init function
|
||||
int USB_DeviceInit(XboxDeviceState* dev);
|
||||
// call usb class find_device function
|
||||
XboxDeviceState* USB_DeviceFindDevice(XboxDeviceState* Dev, uint8_t Addr);
|
||||
// call usb class cancel_packet function
|
||||
void USB_DeviceCancelPacket(XboxDeviceState* dev, USBPacket* p);
|
||||
// call usb class handle_destroy function
|
||||
void USB_DeviceHandleDestroy(XboxDeviceState* dev);
|
||||
// call usb class handle_attach function
|
||||
void USB_DeviceHandleAttach(XboxDeviceState* dev);
|
||||
// call usb class handle_reset function
|
||||
void USB_DeviceHandleReset(XboxDeviceState* dev);
|
||||
// call usb class handle_control function
|
||||
void USB_DeviceHandleControl(XboxDeviceState* dev, USBPacket* p, int request, int value, int index, int length, uint8_t* data);
|
||||
// call usb class handle_data function
|
||||
void USB_DeviceHandleData(XboxDeviceState* dev, USBPacket* p);
|
||||
// call usb class set_interface function
|
||||
void USB_DeviceSetInterface(XboxDeviceState* dev, int iface, int alt_old, int alt_new);
|
||||
// call usb class flush_ep_queue function
|
||||
void USB_DeviceFlushEPqueue(XboxDeviceState* dev, USBEndpoint* ep);
|
||||
// call usb class ep_stopped function
|
||||
void USB_DeviceEPstopped(XboxDeviceState* Dev, USBEndpoint* Ep);
|
||||
// set the type of the endpoint
|
||||
void USB_EPsetType(XboxDeviceState* dev, int pid, int ep, uint8_t type);
|
||||
// set the interface number of the endpoint
|
||||
void USB_EPsetIfnum(XboxDeviceState* dev, int pid, int ep, uint8_t ifnum);
|
||||
// set the maximum packet size parameter of the endpoint
|
||||
void USB_EPsetMaxPacketSize(XboxDeviceState* dev, int pid, int ep, uint16_t raw);
|
||||
// assign port numbers (also for hubs)
|
||||
void USB_PortLocation(USBPort* downstream, USBPort* upstream, int portnr);
|
||||
// initialize the endpoints of this peripheral
|
||||
void USB_EpInit(XboxDeviceState* dev);
|
||||
// reset all endpoints of this peripheral
|
||||
void USB_EpReset(XboxDeviceState* dev);
|
||||
// create a serial number for the device
|
||||
void USB_CreateSerial(XboxDeviceState* dev, std::string&& str);
|
||||
// start descriptors initialization
|
||||
void USBDesc_Init(XboxDeviceState* dev);
|
||||
// get device descriptor
|
||||
const USBDesc* USBDesc_GetUsbDeviceDesc(XboxDeviceState* dev);
|
||||
// set the descriptors to use for this device
|
||||
void USBDesc_SetDefaults(XboxDeviceState* dev);
|
||||
// set the configuration to use
|
||||
int USBDesc_SetConfig(XboxDeviceState* dev, int value);
|
||||
// set the interface to use
|
||||
int USBDesc_SetInterface(XboxDeviceState* dev, int index, int value);
|
||||
// find the interface to use
|
||||
const USBDescIface* USBDesc_FindInterface(XboxDeviceState* dev, int nif, int alt);
|
||||
// setup endpoints and their descriptors
|
||||
void USBDesc_EpInit(XboxDeviceState* dev);
|
||||
// handle standard control request
|
||||
int USBDesc_HandleControl(XboxDeviceState *dev, USBPacket *p, int request, int value, int index, int length, uint8_t *data);
|
||||
// handle standard GetDescriptor() request
|
||||
int USBDesc_HandleStandardGetDescriptor(XboxDeviceState* dev, USBPacket* p, int value, uint8_t* dest, size_t len);
|
||||
// return the binary rapresentation of a device descriptor
|
||||
int USB_ReadDeviceDesc(const USBDescID* id, const USBDescDevice* dev, uint8_t* dest, size_t len);
|
||||
// return the binary rapresentation of configuration descriptors
|
||||
int USB_ReadConfigurationDesc(const USBDescConfig* conf, int flags, uint8_t* dest, size_t len);
|
||||
// return the binary rapresentation of interface descriptors
|
||||
int USB_ReadInterfaceDesc(const USBDescIface* iface, int flags, uint8_t* dest, size_t len);
|
||||
// return the binary rapresentation of class-specific descriptors
|
||||
size_t USB_ReadOtherDesc(const USBDescOther* desc, uint8_t* dest, size_t len);
|
||||
// return the binary rapresentation of endpoint descriptors
|
||||
int USB_ReadEndpointDesc(const USBDescEndpoint* ep, int flags, uint8_t* dest, size_t len);
|
||||
// return the binary rapresentation of string descriptors
|
||||
int USB_ReadStringDesc(XboxDeviceState* dev, int index, uint8_t* dest, size_t len);
|
||||
// set a string in the string descriptor with the supplied index
|
||||
void USBDesc_SetString(XboxDeviceState* dev, int index, std::string&& str);
|
||||
// get a string in the string descriptor with the supplied index
|
||||
const char* USBDesc_GetString(XboxDeviceState* dev, int index);
|
||||
private:
|
||||
uint8_t m_irqn;
|
||||
virt86::VirtualProcessor& m_vp;
|
||||
|
|
|
@ -1,89 +0,0 @@
|
|||
/*
|
||||
* Portions of the code are based on Cxbx-Reloaded's OHCI LLE implementation.
|
||||
* The original copyright header is included below.
|
||||
*/
|
||||
// This is an open source non-commercial project. Dear PVS-Studio, please check it.
|
||||
// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
|
||||
// ******************************************************************
|
||||
// *
|
||||
// * .,-::::: .,:: .::::::::. .,:: .:
|
||||
// * ,;;;'````' `;;;, .,;; ;;;'';;' `;;;, .,;;
|
||||
// * [[[ '[[,,[[' [[[__[[\. '[[,,[['
|
||||
// * $$$ Y$$$P $$""""Y$$ Y$$$P
|
||||
// * `88bo,__,o, oP"``"Yo, _88o,,od8P oP"``"Yo,
|
||||
// * "YUMMMMMP",m" "Mm,""YUMMMP" ,m" "Mm,
|
||||
// *
|
||||
// * Cxbx->devices->usb->XidGamepad.h
|
||||
// *
|
||||
// * This file is part of the Cxbx project.
|
||||
// *
|
||||
// * Cxbx and Cxbe are free software; you can redistribute them
|
||||
// * and/or modify them under the terms of the GNU General Public
|
||||
// * License as published by the Free Software Foundation; either
|
||||
// * version 2 of the license, or (at your option) any later version.
|
||||
// *
|
||||
// * This program is distributed in the hope that it will be useful,
|
||||
// * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// * GNU General Public License for more details.
|
||||
// *
|
||||
// * You should have recieved a copy of the GNU General Public License
|
||||
// * along with this program; see the file COPYING.
|
||||
// * If not, write to the Free Software Foundation, Inc.,
|
||||
// * 59 Temple Place - Suite 330, Bostom, MA 02111-1307, USA.
|
||||
// *
|
||||
// * (c) 2018 ergo720
|
||||
// *
|
||||
// * All rights reserved
|
||||
// *
|
||||
// ******************************************************************
|
||||
|
||||
#include "../ohci/ohci_hub.h"
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace strikebox {
|
||||
|
||||
struct USBXIDState; // forward declare
|
||||
|
||||
/* Class which implements an xbox gamepad */
|
||||
class XidGamepad {
|
||||
public:
|
||||
// initialize this peripheral
|
||||
int Init(int port);
|
||||
// destroy gamepad resources
|
||||
void XidCleanUp();
|
||||
|
||||
|
||||
private:
|
||||
// usb device this gamepad is attached to through the hub
|
||||
USBPCIDevice* m_UsbDev = nullptr;
|
||||
// gamepad state
|
||||
USBXIDState* m_XidState = nullptr;
|
||||
// gamepad class functions
|
||||
USBDeviceClass* m_pPeripheralFuncStruct = nullptr;
|
||||
// xbox port this gamepad is attached to
|
||||
int m_Port = 0;
|
||||
|
||||
// initialize various member variables/functions
|
||||
XboxDeviceState* ClassInitFn();
|
||||
// reserve a usb port for this gamepad
|
||||
int UsbXidClaimPort(XboxDeviceState* dev, int port);
|
||||
// free the usb port used by this gamepad
|
||||
void UsbXidReleasePort(XboxDeviceState* dev);
|
||||
// see USBDeviceClass for comments about these functions
|
||||
int UsbXid_Initfn(XboxDeviceState* dev);
|
||||
void UsbXid_HandleDestroy();
|
||||
void UsbXid_Attach(XboxDeviceState* dev);
|
||||
void UsbXid_HandleReset();
|
||||
void UsbXid_HandleControl(XboxDeviceState* dev, USBPacket* p,
|
||||
int request, int value, int index, int length, uint8_t* data);
|
||||
void UsbXid_HandleData(XboxDeviceState* dev, USBPacket* p);
|
||||
// this should update the vibration strength of the real controller this gamepad represents.
|
||||
// It doesn't do anything at the moment
|
||||
void UpdateForceFeedback();
|
||||
};
|
||||
|
||||
extern XidGamepad* g_XidControllerObjArray[4];
|
||||
|
||||
}
|
|
@ -1,66 +0,0 @@
|
|||
/*
|
||||
* Portions of the code are based on Cxbx-Reloaded's OHCI LLE implementation.
|
||||
* The original copyright header is included below.
|
||||
*/
|
||||
// ******************************************************************
|
||||
// *
|
||||
// * .,-::::: .,:: .::::::::. .,:: .:
|
||||
// * ,;;;'````' `;;;, .,;; ;;;'';;' `;;;, .,;;
|
||||
// * [[[ '[[,,[[' [[[__[[\. '[[,,[['
|
||||
// * $$$ Y$$$P $$""""Y$$ Y$$$P
|
||||
// * `88bo,__,o, oP"``"Yo, _88o,,od8P oP"``"Yo,
|
||||
// * "YUMMMMMP",m" "Mm,""YUMMMP" ,m" "Mm,
|
||||
// *
|
||||
// * Cxbx->Cxbx.h
|
||||
// *
|
||||
// * This file is part of the Cxbx project.
|
||||
// *
|
||||
// * Cxbx and Cxbe are free software; you can redistribute them
|
||||
// * and/or modify them under the terms of the GNU General Public
|
||||
// * License as published by the Free Software Foundation; either
|
||||
// * version 2 of the license, or (at your option) any later version.
|
||||
// *
|
||||
// * This program is distributed in the hope that it will be useful,
|
||||
// * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// * GNU General Public License for more details.
|
||||
// *
|
||||
// * You should have recieved a copy of the GNU General Public License
|
||||
// * along with this program; see the file COPYING.
|
||||
// * If not, write to the Free Software Foundation, Inc.,
|
||||
// * 59 Temple Place - Suite 330, Bostom, MA 02111-1307, USA.
|
||||
// *
|
||||
// * (c) 2002-2003 Aaron Robinson <caustik@caustik.com>
|
||||
// *
|
||||
// * All rights reserved
|
||||
// *
|
||||
// ******************************************************************
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <cstdlib>
|
||||
|
||||
namespace strikebox {
|
||||
|
||||
/* This is a linux struct for vectored I/O. See readv() and writev() */
|
||||
struct IoVec {
|
||||
void* Iov_Base; // Starting address
|
||||
size_t Iov_Len; // Number of bytes to transfer
|
||||
};
|
||||
|
||||
struct IOVector {
|
||||
IoVec* IoVecStruct;
|
||||
int IoVecNumber; // number of I/O buffers supplied
|
||||
int AllocNumber; // number of IoVec structs currently allocated
|
||||
size_t Size; // total size of all I/O buffers supplied
|
||||
};
|
||||
|
||||
void IoVecReset(IOVector* qiov);
|
||||
void IoVecAdd(IOVector* qiov, void* base, size_t len);
|
||||
size_t IoVecTobuffer(const IoVec* iov, const unsigned int iov_cnt, size_t offset, void *buf, size_t bytes);
|
||||
size_t IoVecFromBuffer(const IoVec* iov, unsigned int iov_cnt, size_t offset, void* buf, size_t bytes);
|
||||
|
||||
#define GET_WORD_LOW(value) (uint8_t)((value) & 0xFF)
|
||||
#define GET_WORD_HIGH(value) (uint8_t)(((value) >> 8) & 0xFF)
|
||||
|
||||
}
|
|
@ -1,414 +0,0 @@
|
|||
/* $NetBSD: queue.h,v 1.52 2009/04/20 09:56:08 mschuett Exp $ */
|
||||
|
||||
/*
|
||||
* QEMU version: Copy from netbsd, removed debug code, removed some of
|
||||
* the implementations. Left in singly-linked lists, lists, simple
|
||||
* queues, and tail queues.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (c) 1991, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* @(#)queue.h 8.5 (Berkeley) 8/20/94
|
||||
*/
|
||||
|
||||
#ifndef QEMU_SYS_QUEUE_H_
|
||||
#define QEMU_SYS_QUEUE_H_
|
||||
|
||||
/*
|
||||
* This file defines four types of data structures: singly-linked lists,
|
||||
* lists, simple queues, and tail queues.
|
||||
*
|
||||
* A singly-linked list is headed by a single forward pointer. The
|
||||
* elements are singly linked for minimum space and pointer manipulation
|
||||
* overhead at the expense of O(n) removal for arbitrary elements. New
|
||||
* elements can be added to the list after an existing element or at the
|
||||
* head of the list. Elements being removed from the head of the list
|
||||
* should use the explicit macro for this purpose for optimum
|
||||
* efficiency. A singly-linked list may only be traversed in the forward
|
||||
* direction. Singly-linked lists are ideal for applications with large
|
||||
* datasets and few or no removals or for implementing a LIFO queue.
|
||||
*
|
||||
* A list is headed by a single forward pointer (or an array of forward
|
||||
* pointers for a hash table header). The elements are doubly linked
|
||||
* so that an arbitrary element can be removed without a need to
|
||||
* traverse the list. New elements can be added to the list before
|
||||
* or after an existing element or at the head of the list. A list
|
||||
* may only be traversed in the forward direction.
|
||||
*
|
||||
* A simple queue is headed by a pair of pointers, one the head of the
|
||||
* list and the other to the tail of the list. The elements are singly
|
||||
* linked to save space, so elements can only be removed from the
|
||||
* head of the list. New elements can be added to the list after
|
||||
* an existing element, at the head of the list, or at the end of the
|
||||
* list. A simple queue may only be traversed in the forward direction.
|
||||
*
|
||||
* A tail queue is headed by a pair of pointers, one to the head of the
|
||||
* list and the other to the tail of the list. The elements are doubly
|
||||
* linked so that an arbitrary element can be removed without a need to
|
||||
* traverse the list. New elements can be added to the list before or
|
||||
* after an existing element, at the head of the list, or at the end of
|
||||
* the list. A tail queue may be traversed in either direction.
|
||||
*
|
||||
* For details on the use of these macros, see the queue(3) manual page.
|
||||
*/
|
||||
|
||||
// #include "qemu/atomic.h" /* for smp_wmb() */
|
||||
|
||||
/*
|
||||
* List definitions.
|
||||
*/
|
||||
#define QLIST_HEAD(name, type) \
|
||||
struct name { \
|
||||
struct type *lh_first; /* first element */ \
|
||||
}
|
||||
|
||||
#define QLIST_HEAD_INITIALIZER(head) \
|
||||
{ NULL }
|
||||
|
||||
#define QLIST_ENTRY(type) \
|
||||
struct { \
|
||||
struct type *le_next; /* next element */ \
|
||||
struct type **le_prev; /* address of previous next element */ \
|
||||
}
|
||||
|
||||
/*
|
||||
* List functions.
|
||||
*/
|
||||
#define QLIST_INIT(head) do { \
|
||||
(head)->lh_first = NULL; \
|
||||
} while (/*CONSTCOND*/0)
|
||||
|
||||
#define QLIST_INSERT_AFTER(listelm, elm, field) do { \
|
||||
if (((elm)->field.le_next = (listelm)->field.le_next) != NULL) \
|
||||
(listelm)->field.le_next->field.le_prev = \
|
||||
&(elm)->field.le_next; \
|
||||
(listelm)->field.le_next = (elm); \
|
||||
(elm)->field.le_prev = &(listelm)->field.le_next; \
|
||||
} while (/*CONSTCOND*/0)
|
||||
|
||||
#define QLIST_INSERT_BEFORE(listelm, elm, field) do { \
|
||||
(elm)->field.le_prev = (listelm)->field.le_prev; \
|
||||
(elm)->field.le_next = (listelm); \
|
||||
*(listelm)->field.le_prev = (elm); \
|
||||
(listelm)->field.le_prev = &(elm)->field.le_next; \
|
||||
} while (/*CONSTCOND*/0)
|
||||
|
||||
#define QLIST_INSERT_HEAD(head, elm, field) do { \
|
||||
if (((elm)->field.le_next = (head)->lh_first) != NULL) \
|
||||
(head)->lh_first->field.le_prev = &(elm)->field.le_next;\
|
||||
(head)->lh_first = (elm); \
|
||||
(elm)->field.le_prev = &(head)->lh_first; \
|
||||
} while (/*CONSTCOND*/0)
|
||||
|
||||
#define QLIST_INSERT_HEAD_RCU(head, elm, field) do { \
|
||||
(elm)->field.le_prev = &(head)->lh_first; \
|
||||
(elm)->field.le_next = (head)->lh_first; \
|
||||
smp_wmb(); /* fill elm before linking it */ \
|
||||
if ((head)->lh_first != NULL) { \
|
||||
(head)->lh_first->field.le_prev = &(elm)->field.le_next; \
|
||||
} \
|
||||
(head)->lh_first = (elm); \
|
||||
smp_wmb(); \
|
||||
} while (/* CONSTCOND*/0)
|
||||
|
||||
#define QLIST_REMOVE(elm, field) do { \
|
||||
if ((elm)->field.le_next != NULL) \
|
||||
(elm)->field.le_next->field.le_prev = \
|
||||
(elm)->field.le_prev; \
|
||||
*(elm)->field.le_prev = (elm)->field.le_next; \
|
||||
} while (/*CONSTCOND*/0)
|
||||
|
||||
#define QLIST_FOREACH(var, head, field) \
|
||||
for ((var) = ((head)->lh_first); \
|
||||
(var); \
|
||||
(var) = ((var)->field.le_next))
|
||||
|
||||
#define QLIST_FOREACH_SAFE(var, head, field, next_var) \
|
||||
for ((var) = ((head)->lh_first); \
|
||||
(var) && ((next_var) = ((var)->field.le_next), 1); \
|
||||
(var) = (next_var))
|
||||
|
||||
/*
|
||||
* List access methods.
|
||||
*/
|
||||
#define QLIST_EMPTY(head) ((head)->lh_first == NULL)
|
||||
#define QLIST_FIRST(head) ((head)->lh_first)
|
||||
#define QLIST_NEXT(elm, field) ((elm)->field.le_next)
|
||||
|
||||
|
||||
/*
|
||||
* Singly-linked List definitions.
|
||||
*/
|
||||
#define QSLIST_HEAD(name, type) \
|
||||
struct name { \
|
||||
struct type *slh_first; /* first element */ \
|
||||
}
|
||||
|
||||
#define QSLIST_HEAD_INITIALIZER(head) \
|
||||
{ NULL }
|
||||
|
||||
#define QSLIST_ENTRY(type) \
|
||||
struct { \
|
||||
struct type *sle_next; /* next element */ \
|
||||
}
|
||||
|
||||
/*
|
||||
* Singly-linked List functions.
|
||||
*/
|
||||
#define QSLIST_INIT(head) do { \
|
||||
(head)->slh_first = NULL; \
|
||||
} while (/*CONSTCOND*/0)
|
||||
|
||||
#define QSLIST_INSERT_AFTER(slistelm, elm, field) do { \
|
||||
(elm)->field.sle_next = (slistelm)->field.sle_next; \
|
||||
(slistelm)->field.sle_next = (elm); \
|
||||
} while (/*CONSTCOND*/0)
|
||||
|
||||
#define QSLIST_INSERT_HEAD(head, elm, field) do { \
|
||||
(elm)->field.sle_next = (head)->slh_first; \
|
||||
(head)->slh_first = (elm); \
|
||||
} while (/*CONSTCOND*/0)
|
||||
|
||||
#define QSLIST_REMOVE_HEAD(head, field) do { \
|
||||
(head)->slh_first = (head)->slh_first->field.sle_next; \
|
||||
} while (/*CONSTCOND*/0)
|
||||
|
||||
#define QSLIST_REMOVE_AFTER(slistelm, field) do { \
|
||||
(slistelm)->field.sle_next = \
|
||||
QSLIST_NEXT(QSLIST_NEXT((slistelm), field), field); \
|
||||
} while (/*CONSTCOND*/0)
|
||||
|
||||
#define QSLIST_FOREACH(var, head, field) \
|
||||
for((var) = (head)->slh_first; (var); (var) = (var)->field.sle_next)
|
||||
|
||||
#define QSLIST_FOREACH_SAFE(var, head, field, tvar) \
|
||||
for ((var) = QSLIST_FIRST((head)); \
|
||||
(var) && ((tvar) = QSLIST_NEXT((var), field), 1); \
|
||||
(var) = (tvar))
|
||||
|
||||
/*
|
||||
* Singly-linked List access methods.
|
||||
*/
|
||||
#define QSLIST_EMPTY(head) ((head)->slh_first == NULL)
|
||||
#define QSLIST_FIRST(head) ((head)->slh_first)
|
||||
#define QSLIST_NEXT(elm, field) ((elm)->field.sle_next)
|
||||
|
||||
|
||||
/*
|
||||
* Simple queue definitions.
|
||||
*/
|
||||
#define QSIMPLEQ_HEAD(name, type) \
|
||||
struct name { \
|
||||
struct type *sqh_first; /* first element */ \
|
||||
struct type **sqh_last; /* addr of last next element */ \
|
||||
}
|
||||
|
||||
#define QSIMPLEQ_HEAD_INITIALIZER(head) \
|
||||
{ NULL, &(head).sqh_first }
|
||||
|
||||
#define QSIMPLEQ_ENTRY(type) \
|
||||
struct { \
|
||||
struct type *sqe_next; /* next element */ \
|
||||
}
|
||||
|
||||
/*
|
||||
* Simple queue functions.
|
||||
*/
|
||||
#define QSIMPLEQ_INIT(head) do { \
|
||||
(head)->sqh_first = NULL; \
|
||||
(head)->sqh_last = &(head)->sqh_first; \
|
||||
} while (/*CONSTCOND*/0)
|
||||
|
||||
#define QSIMPLEQ_INSERT_HEAD(head, elm, field) do { \
|
||||
if (((elm)->field.sqe_next = (head)->sqh_first) == NULL) \
|
||||
(head)->sqh_last = &(elm)->field.sqe_next; \
|
||||
(head)->sqh_first = (elm); \
|
||||
} while (/*CONSTCOND*/0)
|
||||
|
||||
#define QSIMPLEQ_INSERT_TAIL(head, elm, field) do { \
|
||||
(elm)->field.sqe_next = NULL; \
|
||||
*(head)->sqh_last = (elm); \
|
||||
(head)->sqh_last = &(elm)->field.sqe_next; \
|
||||
} while (/*CONSTCOND*/0)
|
||||
|
||||
#define QSIMPLEQ_INSERT_AFTER(head, listelm, elm, field) do { \
|
||||
if (((elm)->field.sqe_next = (listelm)->field.sqe_next) == NULL) \
|
||||
(head)->sqh_last = &(elm)->field.sqe_next; \
|
||||
(listelm)->field.sqe_next = (elm); \
|
||||
} while (/*CONSTCOND*/0)
|
||||
|
||||
#define QSIMPLEQ_REMOVE_HEAD(head, field) do { \
|
||||
if (((head)->sqh_first = (head)->sqh_first->field.sqe_next) == NULL)\
|
||||
(head)->sqh_last = &(head)->sqh_first; \
|
||||
} while (/*CONSTCOND*/0)
|
||||
|
||||
#define QSIMPLEQ_REMOVE(head, elm, type, field) do { \
|
||||
if ((head)->sqh_first == (elm)) { \
|
||||
QSIMPLEQ_REMOVE_HEAD((head), field); \
|
||||
} else { \
|
||||
struct type *curelm = (head)->sqh_first; \
|
||||
while (curelm->field.sqe_next != (elm)) \
|
||||
curelm = curelm->field.sqe_next; \
|
||||
if ((curelm->field.sqe_next = \
|
||||
curelm->field.sqe_next->field.sqe_next) == NULL) \
|
||||
(head)->sqh_last = &(curelm)->field.sqe_next; \
|
||||
} \
|
||||
} while (/*CONSTCOND*/0)
|
||||
|
||||
#define QSIMPLEQ_FOREACH(var, head, field) \
|
||||
for ((var) = ((head)->sqh_first); \
|
||||
(var); \
|
||||
(var) = ((var)->field.sqe_next))
|
||||
|
||||
#define QSIMPLEQ_FOREACH_SAFE(var, head, field, next) \
|
||||
for ((var) = ((head)->sqh_first); \
|
||||
(var) && ((next = ((var)->field.sqe_next)), 1); \
|
||||
(var) = (next))
|
||||
|
||||
#define QSIMPLEQ_CONCAT(head1, head2) do { \
|
||||
if (!QSIMPLEQ_EMPTY((head2))) { \
|
||||
*(head1)->sqh_last = (head2)->sqh_first; \
|
||||
(head1)->sqh_last = (head2)->sqh_last; \
|
||||
QSIMPLEQ_INIT((head2)); \
|
||||
} \
|
||||
} while (/*CONSTCOND*/0)
|
||||
|
||||
#define QSIMPLEQ_LAST(head, type, field) \
|
||||
(QSIMPLEQ_EMPTY((head)) ? \
|
||||
NULL : \
|
||||
((struct type *)(void *) \
|
||||
((char *)((head)->sqh_last) - offsetof(struct type, field))))
|
||||
|
||||
/*
|
||||
* Simple queue access methods.
|
||||
*/
|
||||
#define QSIMPLEQ_EMPTY(head) ((head)->sqh_first == NULL)
|
||||
#define QSIMPLEQ_FIRST(head) ((head)->sqh_first)
|
||||
#define QSIMPLEQ_NEXT(elm, field) ((elm)->field.sqe_next)
|
||||
|
||||
|
||||
/*
|
||||
* Tail queue definitions.
|
||||
*/
|
||||
#define Q_TAILQ_HEAD(name, type, qual) \
|
||||
struct name { \
|
||||
qual type *tqh_first; /* first element */ \
|
||||
qual type *qual *tqh_last; /* addr of last next element */ \
|
||||
}
|
||||
#define QTAILQ_HEAD(name, type) Q_TAILQ_HEAD(name, struct type,)
|
||||
|
||||
#define QTAILQ_HEAD_INITIALIZER(head) \
|
||||
{ NULL, &(head).tqh_first }
|
||||
|
||||
#define Q_TAILQ_ENTRY(type, qual) \
|
||||
struct { \
|
||||
qual type *tqe_next; /* next element */ \
|
||||
qual type *qual *tqe_prev; /* address of previous next element */\
|
||||
}
|
||||
#define QTAILQ_ENTRY(type) Q_TAILQ_ENTRY(struct type,)
|
||||
|
||||
/*
|
||||
* Tail queue functions.
|
||||
*/
|
||||
#define QTAILQ_INIT(head) do { \
|
||||
(head)->tqh_first = NULL; \
|
||||
(head)->tqh_last = &(head)->tqh_first; \
|
||||
} while (/*CONSTCOND*/0)
|
||||
|
||||
#define QTAILQ_INSERT_HEAD(head, elm, field) do { \
|
||||
if (((elm)->field.tqe_next = (head)->tqh_first) != NULL) \
|
||||
(head)->tqh_first->field.tqe_prev = \
|
||||
&(elm)->field.tqe_next; \
|
||||
else \
|
||||
(head)->tqh_last = &(elm)->field.tqe_next; \
|
||||
(head)->tqh_first = (elm); \
|
||||
(elm)->field.tqe_prev = &(head)->tqh_first; \
|
||||
} while (/*CONSTCOND*/0)
|
||||
|
||||
#define QTAILQ_INSERT_TAIL(head, elm, field) do { \
|
||||
(elm)->field.tqe_next = NULL; \
|
||||
(elm)->field.tqe_prev = (head)->tqh_last; \
|
||||
*(head)->tqh_last = (elm); \
|
||||
(head)->tqh_last = &(elm)->field.tqe_next; \
|
||||
} while (/*CONSTCOND*/0)
|
||||
|
||||
#define QTAILQ_INSERT_AFTER(head, listelm, elm, field) do { \
|
||||
if (((elm)->field.tqe_next = (listelm)->field.tqe_next) != NULL)\
|
||||
(elm)->field.tqe_next->field.tqe_prev = \
|
||||
&(elm)->field.tqe_next; \
|
||||
else \
|
||||
(head)->tqh_last = &(elm)->field.tqe_next; \
|
||||
(listelm)->field.tqe_next = (elm); \
|
||||
(elm)->field.tqe_prev = &(listelm)->field.tqe_next; \
|
||||
} while (/*CONSTCOND*/0)
|
||||
|
||||
#define QTAILQ_INSERT_BEFORE(listelm, elm, field) do { \
|
||||
(elm)->field.tqe_prev = (listelm)->field.tqe_prev; \
|
||||
(elm)->field.tqe_next = (listelm); \
|
||||
*(listelm)->field.tqe_prev = (elm); \
|
||||
(listelm)->field.tqe_prev = &(elm)->field.tqe_next; \
|
||||
} while (/*CONSTCOND*/0)
|
||||
|
||||
#define QTAILQ_REMOVE(head, elm, field) do { \
|
||||
if (((elm)->field.tqe_next) != NULL) \
|
||||
(elm)->field.tqe_next->field.tqe_prev = \
|
||||
(elm)->field.tqe_prev; \
|
||||
else \
|
||||
(head)->tqh_last = (elm)->field.tqe_prev; \
|
||||
*(elm)->field.tqe_prev = (elm)->field.tqe_next; \
|
||||
} while (/*CONSTCOND*/0)
|
||||
|
||||
#define QTAILQ_FOREACH(var, head, field) \
|
||||
for ((var) = ((head)->tqh_first); \
|
||||
(var); \
|
||||
(var) = ((var)->field.tqe_next))
|
||||
|
||||
#define QTAILQ_FOREACH_SAFE(var, head, field, next_var) \
|
||||
for ((var) = ((head)->tqh_first); \
|
||||
(var) && ((next_var) = ((var)->field.tqe_next), 1); \
|
||||
(var) = (next_var))
|
||||
|
||||
#define QTAILQ_FOREACH_REVERSE(var, head, headname, field) \
|
||||
for ((var) = (*(((struct headname *)((head)->tqh_last))->tqh_last)); \
|
||||
(var); \
|
||||
(var) = (*(((struct headname *)((var)->field.tqe_prev))->tqh_last)))
|
||||
|
||||
/*
|
||||
* Tail queue access methods.
|
||||
*/
|
||||
#define QTAILQ_EMPTY(head) ((head)->tqh_first == NULL)
|
||||
#define QTAILQ_FIRST(head) ((head)->tqh_first)
|
||||
#define QTAILQ_NEXT(elm, field) ((elm)->field.tqe_next)
|
||||
|
||||
#define QTAILQ_LAST(head, headname) \
|
||||
(*(((struct headname *)((head)->tqh_last))->tqh_last))
|
||||
#define QTAILQ_PREV(elm, headname, field) \
|
||||
(*(((struct headname *)((elm)->field.tqe_prev))->tqh_last))
|
||||
|
||||
#endif /* !QEMU_SYS_QUEUE_H_ */
|
|
@ -12,7 +12,6 @@
|
|||
|
||||
#include "virt86/virt86.hpp"
|
||||
|
||||
#include "strikebox/gdbserver.h"
|
||||
#include "strikebox/log.h"
|
||||
#include "strikebox/mem.h"
|
||||
#include "strikebox/util.h"
|
||||
|
@ -167,9 +166,6 @@ protected:
|
|||
uint32_t m_kExp_XboxKrnlVersion = 0x00000000;
|
||||
|
||||
bool LocateKernelData();
|
||||
|
||||
// ----- Debugger ---------------------------------------------------------
|
||||
GdbServer *m_gdb;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -4,9 +4,9 @@
|
|||
|
||||
namespace strikebox {
|
||||
|
||||
#define VXN_VERSION_MAJOR 0
|
||||
#define VXN_VERSION_MINOR 0
|
||||
#define VXN_VERSION_PATCH 1
|
||||
#define SBX_VERSION_MAJOR 0
|
||||
#define SBX_VERSION_MINOR 0
|
||||
#define SBX_VERSION_PATCH 1
|
||||
#define STRFY(x) #x
|
||||
|
||||
// TODO: add other things:
|
||||
|
@ -18,8 +18,8 @@ namespace strikebox {
|
|||
#define MAKE_VERSION_ID(major, minor, patch) ((((uint64_t)major) << 48ull) | (((uint64_t)minor) << 32ull) | ((uint64_t)patch))
|
||||
|
||||
static const StrikeBoxInfo g_StrikeBoxInfo = {
|
||||
MAKE_VERSION_STRING(VXN_VERSION_MAJOR, VXN_VERSION_MINOR, VXN_VERSION_PATCH),
|
||||
MAKE_VERSION_ID(VXN_VERSION_MAJOR, VXN_VERSION_MINOR, VXN_VERSION_PATCH)
|
||||
MAKE_VERSION_STRING(SBX_VERSION_MAJOR, SBX_VERSION_MINOR, SBX_VERSION_PATCH),
|
||||
MAKE_VERSION_ID(SBX_VERSION_MAJOR, SBX_VERSION_MINOR, SBX_VERSION_PATCH)
|
||||
};
|
||||
|
||||
const struct StrikeBoxInfo * GetStrikeBoxInfo() {
|
||||
|
|
|
@ -1,136 +0,0 @@
|
|||
// This is an open source non-commercial project. Dear PVS-Studio, please check it.
|
||||
// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
|
||||
// ******************************************************************
|
||||
// *
|
||||
// * .,-::::: .,:: .::::::::. .,:: .:
|
||||
// * ,;;;'````' `;;;, .,;; ;;;'';;' `;;;, .,;;
|
||||
// * [[[ '[[,,[[' [[[__[[\. '[[,,[['
|
||||
// * $$$ Y$$$P $$""""Y$$ Y$$$P
|
||||
// * `88bo,__,o, oP"``"Yo, _88o,,od8P oP"``"Yo,
|
||||
// * "YUMMMMMP",m" "Mm,""YUMMMP" ,m" "Mm,
|
||||
// *
|
||||
// * Cxbx->CxbxKrnl->Timer.cpp
|
||||
// *
|
||||
// * This file is part of the Cxbx project.
|
||||
// *
|
||||
// * Cxbx and Cxbe are free software; you can redistribute them
|
||||
// * and/or modify them under the terms of the GNU General Public
|
||||
// * License as published by the Free Software Foundation; either
|
||||
// * version 2 of the license, or (at your option) any later version.
|
||||
// *
|
||||
// * This program is distributed in the hope that it will be useful,
|
||||
// * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// * GNU General Public License for more details.
|
||||
// *
|
||||
// * You should have recieved a copy of the GNU General Public License
|
||||
// * along with this program; see the file COPYING.
|
||||
// * If not, write to the Free Software Foundation, Inc.,
|
||||
// * 59 Temple Place - Suite 330, Bostom, MA 02111-1307, USA.
|
||||
// *
|
||||
// * (c) 2018 ergo720
|
||||
// *
|
||||
// * All rights reserved
|
||||
// *
|
||||
// ******************************************************************
|
||||
|
||||
#include <thread>
|
||||
#include <vector>
|
||||
#include <chrono>
|
||||
#include "strikebox/cxbxtimer.h"
|
||||
|
||||
namespace strikebox {
|
||||
|
||||
#define CLOCK_REALTIME 0
|
||||
#define CLOCK_VIRTUALTIME 1
|
||||
#define SCALE_S 1000000000ULL
|
||||
#define SCALE_MS 1000000ULL
|
||||
#define SCALE_US 1000ULL
|
||||
#define SCALE_NS 1ULL
|
||||
|
||||
|
||||
// Vector storing all the timers created
|
||||
static std::vector<TimerObject*> TimerList;
|
||||
|
||||
|
||||
// Returns the current time of the timer
|
||||
uint64_t GetTime_NS(TimerObject* Timer) {
|
||||
using namespace std::chrono;
|
||||
uint64_t Ret = high_resolution_clock::now().time_since_epoch().count();
|
||||
return Timer->Type == CLOCK_REALTIME ? Ret : Ret / Timer->SlowdownFactor;
|
||||
}
|
||||
|
||||
// Calculates the next expire time of the timer
|
||||
static inline uint64_t GetNextExpireTime(TimerObject* Timer) {
|
||||
return GetTime_NS(Timer) + Timer->ExpireTime_MS.load();
|
||||
}
|
||||
|
||||
// Deallocates the memory of the timer
|
||||
void Timer_Destroy(TimerObject* Timer) {
|
||||
unsigned int index;
|
||||
for (unsigned int i = 0; i < TimerList.size(); i++) {
|
||||
if (Timer == TimerList[i]) {
|
||||
index = i;
|
||||
}
|
||||
}
|
||||
|
||||
delete Timer;
|
||||
TimerList.erase(TimerList.begin() + index);
|
||||
}
|
||||
|
||||
// Thread that runs the timer
|
||||
void ClockThread(TimerObject* Timer) {
|
||||
uint64_t NewExpireTime = GetNextExpireTime(Timer);
|
||||
|
||||
while (true) {
|
||||
if (GetTime_NS(Timer) > NewExpireTime) {
|
||||
if (Timer->Exit.load()) {
|
||||
Timer_Destroy(Timer);
|
||||
return;
|
||||
}
|
||||
Timer->Callback(Timer->Opaque);
|
||||
if (Timer->Exit.load()) {
|
||||
Timer_Destroy(Timer);
|
||||
return;
|
||||
}
|
||||
NewExpireTime = GetNextExpireTime(Timer);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Changes the expire time of a timer
|
||||
void Timer_ChangeExpireTime(TimerObject* Timer, uint64_t Expire_ms) {
|
||||
Timer->ExpireTime_MS.store(Expire_ms);
|
||||
}
|
||||
|
||||
// Destroys the timer
|
||||
void Timer_Exit(TimerObject* Timer) {
|
||||
Timer->Exit.store(true);
|
||||
}
|
||||
|
||||
// Allocates the memory for the timer object
|
||||
TimerObject* Timer_Create(pTimerCB Callback, void* Arg, unsigned int Factor) {
|
||||
TimerObject* pTimer = new TimerObject;
|
||||
pTimer->Type = Factor <= 1 ? CLOCK_REALTIME : CLOCK_VIRTUALTIME;
|
||||
pTimer->Callback = Callback;
|
||||
pTimer->ExpireTime_MS.store(0);
|
||||
pTimer->Exit.store(false);
|
||||
pTimer->Opaque = Arg;
|
||||
pTimer->SlowdownFactor = Factor < 1 ? 1 : Factor;
|
||||
TimerList.emplace_back(pTimer);
|
||||
|
||||
return pTimer;
|
||||
}
|
||||
|
||||
// Starts the timer
|
||||
// Expire_MS must be expressed in NS
|
||||
void Timer_Start(TimerObject* Timer, uint64_t Expire_MS) {
|
||||
Timer->ExpireTime_MS.store(Expire_MS);
|
||||
std::thread(ClockThread, Timer).detach();
|
||||
}
|
||||
|
||||
// Retrives the frequency of the high resolution clock of the host
|
||||
void Timer_Init() {
|
||||
}
|
||||
|
||||
}
|
File diff suppressed because it is too large
Load diff
|
@ -21,7 +21,7 @@ namespace ata {
|
|||
DummyDVDDriveATADeviceDriver::DummyDVDDriveATADeviceDriver() {
|
||||
strcpy(m_serialNumber, "0123456789");
|
||||
strcpy(m_firmwareRevision, "1.0.0");
|
||||
strcpy(m_modelNumber, "vXn DDVDD0010000");
|
||||
strcpy(m_modelNumber, "SBx DDVDD0010000");
|
||||
}
|
||||
|
||||
DummyDVDDriveATADeviceDriver::~DummyDVDDriveATADeviceDriver() {
|
||||
|
|
|
@ -26,7 +26,7 @@ using namespace atapi;
|
|||
ImageDVDDriveATADeviceDriver::ImageDVDDriveATADeviceDriver() {
|
||||
strcpy(m_serialNumber, "9876543210");
|
||||
strcpy(m_firmwareRevision, "1.0.0");
|
||||
strcpy(m_modelNumber, "vXn VDVDD0010000");
|
||||
strcpy(m_modelNumber, "SBx VDVDD0010000");
|
||||
}
|
||||
|
||||
ImageDVDDriveATADeviceDriver::~ImageDVDDriveATADeviceDriver() {
|
||||
|
|
|
@ -32,7 +32,7 @@ static void padString(uint8_t *dest, const char *src, uint32_t length) {
|
|||
DummyHardDriveATADeviceDriver::DummyHardDriveATADeviceDriver() {
|
||||
strcpy(m_serialNumber, "0123456789");
|
||||
strcpy(m_firmwareRevision, "1.0.0");
|
||||
strcpy(m_modelNumber, "vXn DHDD0010000");
|
||||
strcpy(m_modelNumber, "SBx DHDD0010000");
|
||||
|
||||
// Initialize with parameters for a 10 GiB hard drive
|
||||
m_numCylinders = 20480;
|
||||
|
|
|
@ -33,7 +33,7 @@ ImageHardDriveATADeviceDriver::ImageHardDriveATADeviceDriver() {
|
|||
// TODO: fill in with appropriate data
|
||||
strcpy(m_serialNumber, "9876543210");
|
||||
strcpy(m_firmwareRevision, "1.0.0");
|
||||
strcpy(m_modelNumber, "vXn VHDD0010000");
|
||||
strcpy(m_modelNumber, "SBx VHDD0010000");
|
||||
|
||||
// Initialize an empty (invalid) disk
|
||||
m_numCylinders = 0;
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -1,671 +0,0 @@
|
|||
/*
|
||||
* Portions of the code are based on Cxbx-Reloaded's OHCI LLE implementation.
|
||||
* The original copyright header is included below.
|
||||
*/
|
||||
// This is an open source non-commercial project. Dear PVS-Studio, please check it.
|
||||
// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
|
||||
// ******************************************************************
|
||||
// *
|
||||
// * .,-::::: .,:: .::::::::. .,:: .:
|
||||
// * ,;;;'````' `;;;, .,;; ;;;'';;' `;;;, .,;;
|
||||
// * [[[ '[[,,[[' [[[__[[\. '[[,,[['
|
||||
// * $$$ Y$$$P $$""""Y$$ Y$$$P
|
||||
// * `88bo,__,o, oP"``"Yo, _88o,,od8P oP"``"Yo,
|
||||
// * "YUMMMMMP",m" "Mm,""YUMMMP" ,m" "Mm,
|
||||
// *
|
||||
// * Cxbx->devices->usb->Hub.cpp
|
||||
// *
|
||||
// * This file is part of the Cxbx project.
|
||||
// *
|
||||
// * Cxbx and Cxbe are free software; you can redistribute them
|
||||
// * and/or modify them under the terms of the GNU General Public
|
||||
// * License as published by the Free Software Foundation; either
|
||||
// * version 2 of the license, or (at your option) any later version.
|
||||
// *
|
||||
// * This program is distributed in the hope that it will be useful,
|
||||
// * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// * GNU General Public License for more details.
|
||||
// *
|
||||
// * You should have recieved a copy of the GNU General Public License
|
||||
// * along with this program; see the file COPYING.
|
||||
// * If not, write to the Free Software Foundation, Inc.,
|
||||
// * 59 Temple Place - Suite 330, Bostom, MA 02111-1307, USA.
|
||||
// *
|
||||
// * (c) 2018 ergo720
|
||||
// *
|
||||
// * All rights reserved
|
||||
// *
|
||||
// ******************************************************************
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "strikebox/hw/ohci/ohci.h"
|
||||
#include "strikebox/hw/ohci/ohci_hub.h"
|
||||
|
||||
#include "strikebox/log.h"
|
||||
|
||||
namespace strikebox {
|
||||
|
||||
Hub* g_HubObjArray[4] = { nullptr };
|
||||
|
||||
static const USBDescEndpoint desc_endp_hub = {
|
||||
USB_DIR_IN | 0x01, // bEndpointAddress;
|
||||
USB_ENDPOINT_XFER_INT, // bmAttributes;
|
||||
1 + (NUM_PORTS + 7) / 8, // wMaxPacketSize;
|
||||
0xFF, // bInterval;
|
||||
0, // bRefresh;
|
||||
0, // bSynchAddress
|
||||
0, // is_audio
|
||||
nullptr // extra
|
||||
};
|
||||
|
||||
static const USBDescIface desc_iface_hub = {
|
||||
0, // bInterfaceNumber;
|
||||
0, // bAlternateSetting;
|
||||
1, // bNumEndpoints;
|
||||
USB_CLASS_HUB, // bInterfaceClass;
|
||||
0, // bInterfaceSubClass
|
||||
0, // bInterfaceProtocol
|
||||
0, // iInterface
|
||||
0, // ndesc
|
||||
nullptr, // descs
|
||||
&desc_endp_hub
|
||||
};
|
||||
|
||||
static const USBDescConfig desc_config_hub = {
|
||||
1, // bNumInterfaces
|
||||
1, // bConfigurationValue
|
||||
0, // iConfiguration
|
||||
0xE0, // bmAttributes
|
||||
0, // bMaxPower
|
||||
1, // nif
|
||||
&desc_iface_hub
|
||||
};
|
||||
|
||||
static const USBDescDevice desc_device_hub = {
|
||||
0x0110, // bcdUSB
|
||||
USB_CLASS_HUB, // bDeviceClass
|
||||
0, // bDeviceSubClass
|
||||
0, // bDeviceProtocol
|
||||
8, // bMaxPacketSize0
|
||||
1, // bNumConfigurations
|
||||
&desc_config_hub
|
||||
};
|
||||
|
||||
static const USBDesc desc_hub = {
|
||||
{
|
||||
0x0409, // idVendor
|
||||
0x55AA, // idProduct
|
||||
0x0101, // bcdDevice
|
||||
STR_MANUFACTURER, // iManufacturer
|
||||
STR_PRODUCT, // iProduct
|
||||
STR_SERIALNUMBER // iSerialNumber
|
||||
},
|
||||
&desc_device_hub
|
||||
};
|
||||
|
||||
// Class-specific hub descriptor. Remember to update DeviceRemovable and PortPwrCtrlMask if you change NUM_PORTS since their values depend on
|
||||
// the number of downstream ports available on the hub! Also note that this descriptor cannot be put in the descs member of the interface descriptor
|
||||
// because then this descriptor will be retrieved during a standard GetDescriptor request instead of the hub-specific GetHubDescriptor request
|
||||
static const uint8_t HubDescriptor[] = {
|
||||
0x0A, // u8 bDescLength; 10 bytes
|
||||
0x29, // u8 bDescriptorType; Hub-descriptor
|
||||
NUM_PORTS, // u8 bNbrPorts; 0x08
|
||||
0x0a, // u16 wHubCharacteristics; (individual port over-current protection, no power switching)
|
||||
0x00,
|
||||
0x01, // u8 bPwrOn2pwrGood; 2 ms
|
||||
0x00, // u8 bHubContrCurrent; 0 mA
|
||||
0x00, // u16 DeviceRemovable; all devices are removable
|
||||
0x00,
|
||||
0xFF, // u8 PortPwrCtrlMask; all 1's for compatibility reasons
|
||||
};
|
||||
|
||||
int Hub::Init(int port) {
|
||||
if (port > 4 || port < 1) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
XboxDeviceState* dev = ClassInitFn();
|
||||
int rc = UsbHubClaimPort(dev, port);
|
||||
if (rc != 0) {
|
||||
m_UsbDev->m_HostController->m_bFrameTime = false;
|
||||
return rc;
|
||||
}
|
||||
m_UsbDev->USB_EpInit(dev);
|
||||
m_UsbDev->USB_DeviceInit(dev);
|
||||
m_UsbDev->USB_DeviceAttach(dev);
|
||||
|
||||
m_UsbDev->m_HostController->m_bFrameTime = false;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
XboxDeviceState* Hub::ClassInitFn() {
|
||||
m_pPeripheralFuncStruct = new USBDeviceClass();
|
||||
m_HubState = new USBHubState();
|
||||
XboxDeviceState* dev = &m_HubState->dev;
|
||||
|
||||
dev->ProductDesc = "Cxbx-Reloaded USB Hub";
|
||||
QLIST_INIT(&dev->Strings);
|
||||
dev->klass = m_pPeripheralFuncStruct;
|
||||
|
||||
{
|
||||
using namespace std::placeholders;
|
||||
|
||||
m_pPeripheralFuncStruct->init = std::bind(&Hub::UsbHub_Initfn, this, _1);
|
||||
m_pPeripheralFuncStruct->find_device = std::bind(&Hub::UsbHub_FindDevice, this, _1, _2);
|
||||
m_pPeripheralFuncStruct->handle_reset = std::bind(&Hub::UsbHub_HandleReset, this);
|
||||
m_pPeripheralFuncStruct->handle_control = std::bind(&Hub::UsbHub_HandleControl, this, _1, _2, _3, _4, _5, _6, _7);
|
||||
m_pPeripheralFuncStruct->handle_data = std::bind(&Hub::UsbHub_HandleData, this, _1, _2);
|
||||
m_pPeripheralFuncStruct->handle_destroy = std::bind(&Hub::UsbHub_HandleDestroy, this);
|
||||
m_pPeripheralFuncStruct->product_desc = dev->ProductDesc.c_str();
|
||||
m_pPeripheralFuncStruct->usb_desc = &desc_hub;
|
||||
}
|
||||
|
||||
return dev;
|
||||
}
|
||||
|
||||
int Hub::UsbHubClaimPort(XboxDeviceState* dev, int port) {
|
||||
int i;
|
||||
std::vector<USBPort*>::iterator it;
|
||||
|
||||
assert(dev->Port == nullptr);
|
||||
|
||||
if (port > 2) {
|
||||
//m_UsbDev = g_USB1; // FIXME: how to retrieve these?
|
||||
}
|
||||
else {
|
||||
//m_UsbDev = g_USB0; // FIXME: how to retrieve these?
|
||||
}
|
||||
|
||||
while (m_UsbDev->m_HostController->m_bFrameTime) {}
|
||||
m_UsbDev->m_HostController->m_bFrameTime = true;
|
||||
|
||||
i = 0;
|
||||
for (auto usb_port : m_UsbDev->m_FreePorts) {
|
||||
if (usb_port->Path == std::to_string(port)) {
|
||||
it = m_UsbDev->m_FreePorts.begin() + i;
|
||||
break;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
if (it == m_UsbDev->m_FreePorts.end()) {
|
||||
log_warning("OHCI: Port requested %d not found (in use?)", port);
|
||||
return -1;
|
||||
}
|
||||
dev->Port = *it;
|
||||
(*it)->Dev = dev;
|
||||
m_UsbDev->m_FreePorts.erase(it);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void Hub::UsbHubReleasePort(XboxDeviceState* dev) {
|
||||
USBPort * port = dev->Port;
|
||||
|
||||
assert(port != nullptr);
|
||||
|
||||
port->Dev = nullptr;
|
||||
dev->Port = nullptr;
|
||||
}
|
||||
|
||||
int Hub::UsbHub_Initfn(XboxDeviceState* dev) {
|
||||
USBHubPort* port;
|
||||
USBPortOps* ops;
|
||||
int i;
|
||||
|
||||
m_UsbDev->USB_CreateSerial(dev, std::string("314159"));
|
||||
m_UsbDev->USBDesc_SetString(dev, STR_MANUFACTURER, std::string("Cxbx-Reloaded"));
|
||||
m_UsbDev->USBDesc_SetString(dev, STR_PRODUCT, std::string("Cxbx-Reloaded USB Hub"));
|
||||
m_UsbDev->USBDesc_Init(dev);
|
||||
m_HubState->intr = m_UsbDev->USB_GetEP(dev, USB_TOKEN_IN, 1);
|
||||
|
||||
ops = new USBPortOps();
|
||||
{
|
||||
using namespace std::placeholders;
|
||||
|
||||
ops->attach = std::bind(&Hub::UsbHub_Attach, this, _1);
|
||||
ops->detach = std::bind(&Hub::UsbHub_Detach, this, _1);
|
||||
ops->child_detach = std::bind(&Hub::UsbHub_ChildDetach, this, _1);
|
||||
ops->wakeup = std::bind(&Hub::UsbHub_Wakeup, this, _1);
|
||||
ops->complete = std::bind(&Hub::UsbHub_Complete, this, _1, _2);
|
||||
}
|
||||
|
||||
for (i = 0; i < NUM_PORTS; i++) {
|
||||
port = &m_HubState->ports[i];
|
||||
m_UsbDev->USB_RegisterPort(&port->port, i, USB_SPEED_MASK_LOW | USB_SPEED_MASK_FULL, ops);
|
||||
m_UsbDev->USB_PortLocation(&port->port, dev->Port, i + 1);
|
||||
}
|
||||
UsbHub_HandleReset();
|
||||
return 0;
|
||||
}
|
||||
|
||||
XboxDeviceState* Hub::UsbHub_FindDevice(XboxDeviceState* dev, uint8_t addr) {
|
||||
USBHubPort * port;
|
||||
XboxDeviceState * downstream;
|
||||
|
||||
for (int i = 0; i < NUM_PORTS; i++) {
|
||||
port = &m_HubState->ports[i];
|
||||
if (!(port->wPortStatus & PORT_STAT_ENABLE)) {
|
||||
continue;
|
||||
}
|
||||
downstream = m_UsbDev->USB_FindDevice(&port->port, addr);
|
||||
if (downstream != nullptr) {
|
||||
return downstream;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void Hub::UsbHub_HandleReset() {
|
||||
USBHubPort* port;
|
||||
|
||||
for (int i = 0; i < NUM_PORTS; i++) {
|
||||
port = m_HubState->ports + i;
|
||||
port->wPortStatus = PORT_STAT_POWER;
|
||||
port->wPortChange = 0;
|
||||
if (port->port.Dev && port->port.Dev->Attached) {
|
||||
port->wPortStatus |= PORT_STAT_CONNECTION;
|
||||
port->wPortChange |= PORT_STAT_C_CONNECTION;
|
||||
if (port->port.Dev->Speed == USB_SPEED_LOW) {
|
||||
port->wPortStatus |= PORT_STAT_LOW_SPEED;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
void Hub::UsbHub_HandleControl(XboxDeviceState* dev, USBPacket* p, int request, int value, int index, int length, uint8_t* data) {
|
||||
int ret;
|
||||
ret = m_UsbDev->USBDesc_HandleControl(dev, p, request, value, index, length, data);
|
||||
if (ret >= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
switch (request) {
|
||||
case EndpointOutRequest | USB_REQ_CLEAR_FEATURE:
|
||||
{
|
||||
// clear ep halt and bEndpointAddress of hub is 0x81
|
||||
if (value == 0 && index != 0x81) {
|
||||
goto fail;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case GetHubStatus:
|
||||
{
|
||||
// From the standard: "This request returns the current hub status and the states that have changed since the previous acknowledgment.
|
||||
// The first word of data contains wHubStatus. The second word of data contains wHubChange"
|
||||
// We always report that the local power supply is good and that currently there is no over-power condition
|
||||
data[0] = 0;
|
||||
data[1] = 0;
|
||||
data[2] = 0;
|
||||
data[3] = 0;
|
||||
p->ActualLength = 4;
|
||||
break;
|
||||
}
|
||||
|
||||
case GetPortStatus:
|
||||
{
|
||||
// From the standard: "This request returns the current port status and the current value of the port status change bits.
|
||||
// The first word of data contains wPortStatus. The second word of data contains wPortChange"
|
||||
unsigned int n = index - 1;
|
||||
USBHubPort* port;
|
||||
if (n >= NUM_PORTS) {
|
||||
goto fail;
|
||||
}
|
||||
port = &m_HubState->ports[n];
|
||||
log_debug("OHCI Hub: %s GetPortStatus -> Address 0x%X, wIndex %d, wPortStatus %d, wPortChange %d",
|
||||
__func__, m_HubState->dev.Addr, index, port->wPortStatus, port->wPortChange);
|
||||
data[0] = port->wPortStatus;
|
||||
data[1] = port->wPortStatus >> 8;
|
||||
data[2] = port->wPortChange;
|
||||
data[3] = port->wPortChange >> 8;
|
||||
p->ActualLength = 4;
|
||||
break;
|
||||
}
|
||||
|
||||
case SetHubFeature:
|
||||
case ClearHubFeature:
|
||||
{
|
||||
if (value != 0 && value != 1) {
|
||||
goto fail;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case SetPortFeature:
|
||||
{
|
||||
// From the standard: "This request sets a value reported in the port status. Features that can be set with this request are PORT_RESET,
|
||||
// PORT_SUSPEND and PORT_POWER; others features are not required to be set by this request"
|
||||
unsigned int n = index - 1;
|
||||
USBHubPort* port;
|
||||
XboxDeviceState* dev;
|
||||
|
||||
log_debug("OHCI Hub: %s SetPortFeature -> Address 0x%X, wIndex %d, Feature %s",
|
||||
__func__, m_HubState->dev.Addr, index, GetFeatureName(value));
|
||||
|
||||
if (n >= NUM_PORTS) {
|
||||
goto fail;
|
||||
}
|
||||
port = &m_HubState->ports[n];
|
||||
dev = port->port.Dev;
|
||||
switch (value) {
|
||||
case PORT_SUSPEND:
|
||||
{
|
||||
port->wPortStatus |= PORT_STAT_SUSPEND;
|
||||
break;
|
||||
}
|
||||
|
||||
case PORT_RESET:
|
||||
{
|
||||
if (dev && dev->Attached) {
|
||||
m_UsbDev->USB_DeviceReset(dev);
|
||||
port->wPortChange |= PORT_STAT_C_RESET;
|
||||
port->wPortStatus |= PORT_STAT_ENABLE;
|
||||
m_UsbDev->USB_Wakeup(m_HubState->intr);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case PORT_POWER:
|
||||
break;
|
||||
|
||||
default:
|
||||
goto fail;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case ClearPortFeature:
|
||||
{
|
||||
// From the standard: "This request resets a value reported in the port status"
|
||||
unsigned int n = index - 1;
|
||||
USBHubPort *port;
|
||||
|
||||
log_debug("OHCI Hub: %s ClearPortFeature -> Address 0x%X, wIndex %d, Feature %s",
|
||||
__func__, m_HubState->dev.Addr, index, GetFeatureName(value));
|
||||
|
||||
if (n >= NUM_PORTS) {
|
||||
goto fail;
|
||||
}
|
||||
port = &m_HubState->ports[n];
|
||||
switch (value) {
|
||||
case PORT_ENABLE:
|
||||
{
|
||||
port->wPortStatus &= ~PORT_STAT_ENABLE;
|
||||
break;
|
||||
}
|
||||
|
||||
case PORT_C_ENABLE:
|
||||
{
|
||||
port->wPortChange &= ~PORT_STAT_C_ENABLE;
|
||||
break;
|
||||
}
|
||||
|
||||
case PORT_SUSPEND:
|
||||
{
|
||||
port->wPortStatus &= ~PORT_STAT_SUSPEND;
|
||||
break;
|
||||
}
|
||||
|
||||
case PORT_C_SUSPEND:
|
||||
{
|
||||
port->wPortChange &= ~PORT_STAT_C_SUSPEND;
|
||||
break;
|
||||
}
|
||||
|
||||
case PORT_C_CONNECTION:
|
||||
{
|
||||
port->wPortChange &= ~PORT_STAT_C_CONNECTION;
|
||||
break;
|
||||
}
|
||||
|
||||
case PORT_C_OVERCURRENT:
|
||||
{
|
||||
port->wPortChange &= ~PORT_STAT_C_OVERCURRENT;
|
||||
break;
|
||||
}
|
||||
|
||||
case PORT_C_RESET:
|
||||
{
|
||||
port->wPortChange &= ~PORT_STAT_C_RESET;
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
goto fail;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case GetHubDescriptor:
|
||||
{
|
||||
memcpy(data, HubDescriptor, sizeof(HubDescriptor));
|
||||
p->ActualLength = sizeof(HubDescriptor);
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
fail:
|
||||
p->Status = USB_RET_STALL;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void Hub::UsbHub_HandleData(XboxDeviceState* dev, USBPacket* p) {
|
||||
switch (p->Pid) {
|
||||
case USB_TOKEN_IN:
|
||||
{
|
||||
if (p->Endpoint->Num == 1) {
|
||||
USBHubPort* port;
|
||||
unsigned int status;
|
||||
uint8_t buf[4];
|
||||
int i, n;
|
||||
status = 0;
|
||||
for (i = 0; i < NUM_PORTS; i++) {
|
||||
port = &m_HubState->ports[i];
|
||||
if (port->wPortChange) {
|
||||
status |= (1 << (i + 1));
|
||||
}
|
||||
}
|
||||
if (status != 0) {
|
||||
n = (NUM_PORTS + 1 + 7) / 8;
|
||||
if (p->IoVec.Size == 1) { // FreeBSD workaround
|
||||
n = 1;
|
||||
}
|
||||
else if ((unsigned int)n > p->IoVec.Size) {
|
||||
p->Status = USB_RET_BABBLE;
|
||||
return;
|
||||
}
|
||||
log_debug("OHCI Hub: %s Address 0x%X, Status %d", __func__, m_HubState->dev.Addr, status);
|
||||
for (i = 0; i < n; i++) {
|
||||
buf[i] = status >> (8 * i);
|
||||
}
|
||||
m_UsbDev->USB_PacketCopy(p, buf, n);
|
||||
}
|
||||
else {
|
||||
p->Status = USB_RET_NAK; // usb11 11.13.1
|
||||
}
|
||||
}
|
||||
else {
|
||||
goto fail;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case USB_TOKEN_OUT:
|
||||
default:
|
||||
fail:
|
||||
p->Status = USB_RET_STALL;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void Hub::UsbHub_HandleDestroy() {
|
||||
// Inform upstream that the hub is detached and gone
|
||||
m_UsbDev->USB_DeviceDetach(&m_HubState->dev);
|
||||
m_UsbDev->m_FreePorts.push_back(m_HubState->dev.Port);
|
||||
|
||||
for (int i = 0; i < NUM_PORTS; i++) {
|
||||
if (m_HubState->ports[i].port.Dev) {
|
||||
// Also destroy attached downstream device
|
||||
m_HubState->ports[i].port.Dev->klass->handle_destroy();
|
||||
}
|
||||
else {
|
||||
m_UsbDev->USB_UnregisterPort(&m_HubState->ports[i].port);
|
||||
}
|
||||
}
|
||||
UsbHubReleasePort(&m_HubState->dev);
|
||||
HubCleanUp();
|
||||
}
|
||||
|
||||
void Hub::UsbHub_Attach(USBPort* port1) {
|
||||
USBHubPort* port = &m_HubState->ports[port1->PortIndex];
|
||||
|
||||
port->wPortStatus |= PORT_STAT_CONNECTION;
|
||||
port->wPortChange |= PORT_STAT_C_CONNECTION;
|
||||
if (port->port.Dev->Speed == USB_SPEED_LOW) {
|
||||
port->wPortStatus |= PORT_STAT_LOW_SPEED;
|
||||
}
|
||||
else {
|
||||
port->wPortStatus &= ~PORT_STAT_LOW_SPEED;
|
||||
}
|
||||
m_UsbDev->USB_Wakeup(m_HubState->intr);
|
||||
}
|
||||
|
||||
void Hub::UsbHub_Detach(USBPort* port1) {
|
||||
USBHubPort* port = &m_HubState->ports[port1->PortIndex];
|
||||
|
||||
m_UsbDev->USB_Wakeup(m_HubState->intr);
|
||||
|
||||
// Let upstream know the device on this port is gone
|
||||
m_HubState->dev.Port->Operations->child_detach(port1->Dev);
|
||||
|
||||
port->wPortStatus &= ~PORT_STAT_CONNECTION;
|
||||
port->wPortChange |= PORT_STAT_C_CONNECTION;
|
||||
if (port->wPortStatus & PORT_STAT_ENABLE) {
|
||||
port->wPortStatus &= ~PORT_STAT_ENABLE;
|
||||
port->wPortChange |= PORT_STAT_C_ENABLE;
|
||||
}
|
||||
m_UsbDev->USB_Wakeup(m_HubState->intr);
|
||||
}
|
||||
|
||||
void Hub::UsbHub_ChildDetach(XboxDeviceState* child) {
|
||||
// Pass along to upstream
|
||||
m_HubState->dev.Port->Operations->child_detach(child);
|
||||
}
|
||||
|
||||
void Hub::UsbHub_Wakeup(USBPort* port1) {
|
||||
USBHubPort* port = &m_HubState->ports[port1->PortIndex];
|
||||
|
||||
if (port->wPortStatus & PORT_STAT_SUSPEND) {
|
||||
port->wPortChange |= PORT_STAT_C_SUSPEND;
|
||||
m_UsbDev->USB_Wakeup(m_HubState->intr);
|
||||
}
|
||||
}
|
||||
|
||||
void Hub::UsbHub_Complete(USBPort* port, USBPacket* packet) {
|
||||
// Just pass it along to upstream
|
||||
m_HubState->dev.Port->Operations->complete(m_HubState->dev.Port, packet);
|
||||
}
|
||||
|
||||
std::string Hub::GetFeatureName(int feature) {
|
||||
std::string str;
|
||||
|
||||
switch (feature) {
|
||||
case PORT_CONNECTION:
|
||||
{
|
||||
str = "connection";
|
||||
break;
|
||||
}
|
||||
|
||||
case PORT_ENABLE:
|
||||
{
|
||||
str = "enable";
|
||||
break;
|
||||
}
|
||||
|
||||
case PORT_SUSPEND:
|
||||
{
|
||||
str = "suspend";
|
||||
break;
|
||||
}
|
||||
|
||||
case PORT_OVERCURRENT:
|
||||
{
|
||||
str = "overcurrent";
|
||||
break;
|
||||
}
|
||||
|
||||
case PORT_RESET:
|
||||
{
|
||||
str = "reset";
|
||||
break;
|
||||
}
|
||||
|
||||
case PORT_POWER:
|
||||
{
|
||||
str = "power";
|
||||
break;
|
||||
}
|
||||
|
||||
case PORT_LOWSPEED:
|
||||
{
|
||||
str = "lowspeed";
|
||||
break;
|
||||
}
|
||||
|
||||
case PORT_C_CONNECTION:
|
||||
{
|
||||
str = "change_connection";
|
||||
break;
|
||||
}
|
||||
|
||||
case PORT_C_ENABLE:
|
||||
{
|
||||
str = "change_enable";
|
||||
break;
|
||||
}
|
||||
|
||||
case PORT_C_SUSPEND:
|
||||
{
|
||||
str = "change_suspend";
|
||||
break;
|
||||
}
|
||||
|
||||
case PORT_C_OVERCURRENT:
|
||||
{
|
||||
str = "change_overcurrent";
|
||||
break;
|
||||
}
|
||||
|
||||
case PORT_C_RESET:
|
||||
{
|
||||
str = "change_reset";
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
str = "?";
|
||||
break;
|
||||
}
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
void Hub::HubCleanUp() {
|
||||
delete m_pPeripheralFuncStruct;
|
||||
delete m_HubState->ports[0].port.Operations;
|
||||
delete m_HubState;
|
||||
m_pPeripheralFuncStruct = nullptr;
|
||||
m_HubState = nullptr;
|
||||
}
|
||||
|
||||
void Hub::HubDestroy() {
|
||||
while (m_UsbDev->m_HostController->m_bFrameTime) {}
|
||||
m_UsbDev->m_HostController->m_bFrameTime = true;
|
||||
m_pPeripheralFuncStruct->handle_destroy();
|
||||
m_UsbDev->m_HostController->m_bFrameTime = false;
|
||||
}
|
||||
|
||||
}
|
File diff suppressed because it is too large
Load diff
|
@ -1,43 +1,3 @@
|
|||
/*
|
||||
* Portions of the code are based on Cxbx-Reloaded's APU emulator.
|
||||
* The original copyright header is included below.
|
||||
*/
|
||||
// This is an open source non-commercial project. Dear PVS-Studio, please check it.
|
||||
// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
|
||||
// ******************************************************************
|
||||
// *
|
||||
// * .,-::::: .,:: .::::::::. .,:: .:
|
||||
// * ,;;;'````' `;;;, .,;; ;;;'';;' `;;;, .,;;
|
||||
// * [[[ '[[,,[[' [[[__[[\. '[[,,[['
|
||||
// * $$$ Y$$$P $$""""Y$$ Y$$$P
|
||||
// * `88bo,__,o, oP"``"Yo, _88o,,od8P oP"``"Yo,
|
||||
// * "YUMMMMMP",m" "Mm,""YUMMMP" ,m" "Mm,
|
||||
// *
|
||||
// * src->devices->APUDevice.cpp
|
||||
// *
|
||||
// * This file is part of the Cxbx project.
|
||||
// *
|
||||
// * Cxbx and Cxbe are free software; you can redistribute them
|
||||
// * and/or modify them under the terms of the GNU General Public
|
||||
// * License as published by the Free Software Foundation; either
|
||||
// * version 2 of the license, or (at your option) any later version.
|
||||
// *
|
||||
// * This program is distributed in the hope that it will be useful,
|
||||
// * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// * GNU General Public License for more details.
|
||||
// *
|
||||
// * You should have recieved a copy of the GNU General Public License
|
||||
// * along with this program; see the file COPYING.
|
||||
// * If not, write to the Free Software Foundation, Inc.,
|
||||
// * 59 Temple Place - Suite 330, Bostom, MA 02111-1307, USA.
|
||||
// *
|
||||
// * (c) 2018 Luke Usher <luke.usher@outlook.coM>
|
||||
// *
|
||||
// * All rights reserved
|
||||
// *
|
||||
// ******************************************************************
|
||||
|
||||
#include "strikebox/hw/pci/nvapu.h"
|
||||
|
||||
#include "strikebox/log.h"
|
||||
|
@ -50,9 +10,6 @@ uint32_t GetAPUTime() {
|
|||
return static_cast<uint32_t>(t.time_since_epoch().count() * 0.000048000);
|
||||
}
|
||||
|
||||
// TODO: Everything :P
|
||||
// TODO: Audio Processing/Thread
|
||||
|
||||
NVAPUDevice::NVAPUDevice()
|
||||
: PCIDevice(PCI_HEADER_TYPE_NORMAL, PCI_VENDOR_ID_NVIDIA, 0x01B0, 0xB1,
|
||||
0x04, 0x01, 0x00) // Multimedia Audio Controller
|
||||
|
@ -89,84 +46,33 @@ void NVAPUDevice::Reset() {
|
|||
}
|
||||
|
||||
void NVAPUDevice::PCIIORead(int barIndex, uint32_t port, uint32_t *value, uint8_t size) {
|
||||
log_spew("NVAPUDevice::PCIIORead: Unimplemented! bar = %d, port = 0x%x, size = %u\n", barIndex, port, size);
|
||||
log_spew("NVAPUDevice::PCIIORead: Unimplemented read! bar = %d, port = 0x%x, size = %u\n", barIndex, port, size);
|
||||
*value = 0;
|
||||
}
|
||||
|
||||
void NVAPUDevice::PCIIOWrite(int barIndex, uint32_t port, uint32_t value, uint8_t size) {
|
||||
log_spew("NVAPUDevice::PCIIOWrite: Unimplemented! bar = %d, port = 0x%x, value = 0x%x, size = %u\n", barIndex, port, value, size);
|
||||
log_spew("NVAPUDevice::PCIIOWrite: Unimplemented write! bar = %d, port = 0x%x, value = 0x%x, size = %u\n", barIndex, port, value, size);
|
||||
}
|
||||
|
||||
void NVAPUDevice::PCIMMIORead(int barIndex, uint32_t addr, uint32_t *value, uint8_t size) {
|
||||
if (addr >= APU_VP_BASE && addr < APU_VP_BASE + APU_VP_SIZE) {
|
||||
VPRead(addr - APU_VP_BASE, value, size);
|
||||
return;
|
||||
}
|
||||
|
||||
if (addr >= APU_GP_BASE && addr < APU_GP_BASE + APU_GP_SIZE) {
|
||||
GPRead(addr - APU_GP_BASE, value, size);
|
||||
return;
|
||||
}
|
||||
|
||||
if (addr >= APU_EP_BASE && addr < APU_EP_BASE + APU_EP_SIZE) {
|
||||
EPRead(addr - APU_EP_BASE, value, size);
|
||||
return;
|
||||
}
|
||||
|
||||
// FIXME: this satisfies the most basic needs of the guest software
|
||||
if (addr == 0x200C) {
|
||||
*value = GetAPUTime();
|
||||
log_spew("NVAPUDevice::PCIMMIORead: Reading dummy value! bar = %d, address = 0x%x, size = %u\n", barIndex, addr, size);
|
||||
}
|
||||
// HACK: Pretend the FIFO is always empty, bypasses hangs when APU isn't fully implemented
|
||||
else if (addr == 0x20010) {
|
||||
*value = 0x80;
|
||||
log_spew("NVAPUDevice::PCIMMIORead: Reading dummy value! bar = %d, address = 0x%x, size = %u\n", barIndex, addr, size);
|
||||
}
|
||||
else {
|
||||
*value = 0;
|
||||
log_spew("NVAPUDevice::PCIMMIORead: Unimplemented read! bar = %d, address = 0x%x, size = %u\n", barIndex, addr, size);
|
||||
}
|
||||
|
||||
log_spew("NVAPUDevice::PCIMMIORead: Unhandled read! bar = %d, address = 0x%x, size = %u\n", barIndex, addr, size);
|
||||
}
|
||||
|
||||
void NVAPUDevice::PCIMMIOWrite(int barIndex, uint32_t addr, uint32_t value, uint8_t size) {
|
||||
if (addr >= APU_VP_BASE && addr < APU_VP_BASE + APU_VP_SIZE) {
|
||||
VPWrite(addr - APU_VP_BASE, value, size);
|
||||
return;
|
||||
}
|
||||
|
||||
if (addr >= APU_GP_BASE && addr < APU_GP_BASE + APU_GP_SIZE) {
|
||||
VPWrite(addr - APU_GP_BASE, value, size);
|
||||
return;
|
||||
}
|
||||
|
||||
if (addr >= APU_EP_BASE && addr < APU_EP_BASE + APU_EP_SIZE) {
|
||||
VPWrite(addr - APU_EP_BASE, value, size);
|
||||
return;
|
||||
}
|
||||
|
||||
log_spew("NVAPUDevice::PCIMMIOWrite: Unhandled write! bar = %d, address = 0x%x, value = 0x%x, size = %u\n", barIndex, addr, value, size);
|
||||
}
|
||||
|
||||
void NVAPUDevice::GPRead(uint32_t address, uint32_t *value, uint8_t size) {
|
||||
log_spew("NVAPUDevice::GPRead: Unimplemented! address = 0x%x, size = %u\n", address, size);
|
||||
}
|
||||
|
||||
void NVAPUDevice::GPWrite(uint32_t address, uint32_t value, uint8_t size) {
|
||||
log_spew("NVAPUDevice::GPWrite: Unimplemented! address = 0x%x, value = 0x%x, size = %u\n", address, value, size);
|
||||
}
|
||||
|
||||
void NVAPUDevice::EPRead(uint32_t address, uint32_t *value, uint8_t size) {
|
||||
log_spew("NVAPUDevice::EPRead: Unimplemented! address = 0x%x, size = %u\n", address, size);
|
||||
}
|
||||
|
||||
void NVAPUDevice::EPWrite(uint32_t address, uint32_t value, uint8_t size) {
|
||||
log_spew("NVAPUDevice::EPWrite: Unimplemented! address = 0x%x, value = 0x%x, size = %u\n", address, value, size);
|
||||
}
|
||||
|
||||
void NVAPUDevice::VPRead(uint32_t address, uint32_t *value, uint8_t size) {
|
||||
// FIXME: HACK: Pretend the FIFO is always empty, bypasses hangs when APU isn't fully implemented
|
||||
if (address == 0x10) {
|
||||
*value = 0x80;
|
||||
return;
|
||||
}
|
||||
|
||||
log_spew("NVAPUDevice::VPRead: Unimplemented! address = 0x%x, size = %u\n", address, size);
|
||||
}
|
||||
|
||||
void NVAPUDevice::VPWrite(uint32_t address, uint32_t value, uint8_t size) {
|
||||
log_spew("NVAPUDevice::VPWrite: Unimplemented! address = 0x%x, value = 0x%x, size = %u\n", address, value, size);
|
||||
log_spew("NVAPUDevice::PCIMMIOWrite: Unimplemented write! bar = %d, address = 0x%x, value = 0x%x, size = %u\n", barIndex, addr, value, size);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,483 +1,9 @@
|
|||
/*
|
||||
* Portions of the code are based on XQEMU's nForce Ethernet Controller implementation.
|
||||
* The original copyright header is included below.
|
||||
*/
|
||||
/*
|
||||
* QEMU nForce Ethernet Controller implementation
|
||||
*
|
||||
* Copyright (c) 2013 espes
|
||||
* Copyright (c) 2015 Matt Borgerson
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 or
|
||||
* (at your option) version 3 of the License.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include "strikebox/hw/pci/nvnet.h"
|
||||
|
||||
#include "strikebox/log.h"
|
||||
|
||||
namespace strikebox {
|
||||
|
||||
// NVNET Register Definitions
|
||||
// Taken from XQEMU
|
||||
enum {
|
||||
NvRegIrqStatus = 0x000,
|
||||
# define NVREG_IRQSTAT_BIT1 0x002
|
||||
# define NVREG_IRQSTAT_BIT4 0x010
|
||||
# define NVREG_IRQSTAT_MIIEVENT 0x040
|
||||
# define NVREG_IRQSTAT_MASK 0x1ff
|
||||
NvRegIrqMask = 0x004,
|
||||
# define NVREG_IRQ_RX 0x0002
|
||||
# define NVREG_IRQ_RX_NOBUF 0x0004
|
||||
# define NVREG_IRQ_TX_ERR 0x0008
|
||||
# define NVREG_IRQ_TX2 0x0010
|
||||
# define NVREG_IRQ_TIMER 0x0020
|
||||
# define NVREG_IRQ_LINK 0x0040
|
||||
# define NVREG_IRQ_TX1 0x0100
|
||||
# define NVREG_IRQMASK_WANTED_1 0x005f
|
||||
# define NVREG_IRQMASK_WANTED_2 0x0147
|
||||
# define NVREG_IRQ_UNKNOWN (~(NVREG_IRQ_RX|NVREG_IRQ_RX_NOBUF|\
|
||||
NVREG_IRQ_TX_ERR|NVREG_IRQ_TX2|NVREG_IRQ_TIMER|NVREG_IRQ_LINK|\
|
||||
NVREG_IRQ_TX1))
|
||||
NvRegUnknownSetupReg6 = 0x008,
|
||||
# define NVREG_UNKSETUP6_VAL 3
|
||||
/*
|
||||
* NVREG_POLL_DEFAULT is the interval length of the timer source on the nic
|
||||
* NVREG_POLL_DEFAULT=97 would result in an interval length of 1 ms
|
||||
*/
|
||||
NvRegPollingInterval = 0x00c,
|
||||
# define NVREG_POLL_DEFAULT 970
|
||||
NvRegMisc1 = 0x080,
|
||||
# define NVREG_MISC1_HD 0x02
|
||||
# define NVREG_MISC1_FORCE 0x3b0f3c
|
||||
NvRegTransmitterControl = 0x084,
|
||||
# define NVREG_XMITCTL_START 0x01
|
||||
NvRegTransmitterStatus = 0x088,
|
||||
# define NVREG_XMITSTAT_BUSY 0x01
|
||||
NvRegPacketFilterFlags = 0x8c,
|
||||
# define NVREG_PFF_ALWAYS 0x7F0008
|
||||
# define NVREG_PFF_PROMISC 0x80
|
||||
# define NVREG_PFF_MYADDR 0x20
|
||||
NvRegOffloadConfig = 0x90,
|
||||
# define NVREG_OFFLOAD_HOMEPHY 0x601
|
||||
# define NVREG_OFFLOAD_NORMAL 0x5ee
|
||||
NvRegReceiverControl = 0x094,
|
||||
# define NVREG_RCVCTL_START 0x01
|
||||
NvRegReceiverStatus = 0x98,
|
||||
# define NVREG_RCVSTAT_BUSY 0x01
|
||||
NvRegRandomSeed = 0x9c,
|
||||
# define NVREG_RNDSEED_MASK 0x00ff
|
||||
# define NVREG_RNDSEED_FORCE 0x7f00
|
||||
NvRegUnknownSetupReg1 = 0xA0,
|
||||
# define NVREG_UNKSETUP1_VAL 0x16070f
|
||||
NvRegUnknownSetupReg2 = 0xA4,
|
||||
# define NVREG_UNKSETUP2_VAL 0x16
|
||||
NvRegMacAddrA = 0xA8,
|
||||
NvRegMacAddrB = 0xAC,
|
||||
NvRegMulticastAddrA = 0xB0,
|
||||
# define NVREG_MCASTADDRA_FORCE 0x01
|
||||
NvRegMulticastAddrB = 0xB4,
|
||||
NvRegMulticastMaskA = 0xB8,
|
||||
NvRegMulticastMaskB = 0xBC,
|
||||
NvRegTxRingPhysAddr = 0x100,
|
||||
NvRegRxRingPhysAddr = 0x104,
|
||||
NvRegRingSizes = 0x108,
|
||||
# define NVREG_RINGSZ_TXSHIFT 0
|
||||
# define NVREG_RINGSZ_RXSHIFT 16
|
||||
NvRegUnknownTransmitterReg = 0x10c,
|
||||
NvRegLinkSpeed = 0x110,
|
||||
# define NVREG_LINKSPEED_FORCE 0x10000
|
||||
# define NVREG_LINKSPEED_10 10
|
||||
# define NVREG_LINKSPEED_100 100
|
||||
# define NVREG_LINKSPEED_1000 1000
|
||||
NvRegUnknownSetupReg5 = 0x130,
|
||||
# define NVREG_UNKSETUP5_BIT31 (1<<31)
|
||||
NvRegUnknownSetupReg3 = 0x134,
|
||||
# define NVREG_UNKSETUP3_VAL1 0x200010
|
||||
NvRegUnknownSetupReg8 = 0x13C,
|
||||
# define NVREG_UNKSETUP8_VAL1 0x300010
|
||||
NvRegUnknownSetupReg7 = 0x140,
|
||||
# define NVREG_UNKSETUP7_VAL 0x300010
|
||||
NvRegTxRxControl = 0x144,
|
||||
# define NVREG_TXRXCTL_KICK 0x0001
|
||||
# define NVREG_TXRXCTL_BIT1 0x0002
|
||||
# define NVREG_TXRXCTL_BIT2 0x0004
|
||||
# define NVREG_TXRXCTL_IDLE 0x0008
|
||||
# define NVREG_TXRXCTL_RESET 0x0010
|
||||
NvRegMIIStatus = 0x180,
|
||||
# define NVREG_MIISTAT_ERROR 0x0001
|
||||
# define NVREG_MIISTAT_LINKCHANGE 0x0008
|
||||
# define NVREG_MIISTAT_MASK 0x000f
|
||||
# define NVREG_MIISTAT_MASK2 0x000f
|
||||
NvRegUnknownSetupReg4 = 0x184,
|
||||
# define NVREG_UNKSETUP4_VAL 8
|
||||
NvRegAdapterControl = 0x188,
|
||||
# define NVREG_ADAPTCTL_START 0x02
|
||||
# define NVREG_ADAPTCTL_LINKUP 0x04
|
||||
# define NVREG_ADAPTCTL_PHYVALID 0x4000
|
||||
# define NVREG_ADAPTCTL_RUNNING 0x100000
|
||||
# define NVREG_ADAPTCTL_PHYSHIFT 24
|
||||
NvRegMIISpeed = 0x18c,
|
||||
# define NVREG_MIISPEED_BIT8 (1<<8)
|
||||
# define NVREG_MIIDELAY 5
|
||||
NvRegMIIControl = 0x190,
|
||||
# define NVREG_MIICTL_INUSE 0x10000
|
||||
# define NVREG_MIICTL_WRITE 0x08000
|
||||
# define NVREG_MIICTL_ADDRSHIFT 5
|
||||
NvRegMIIData = 0x194,
|
||||
NvRegWakeUpFlags = 0x200,
|
||||
# define NVREG_WAKEUPFLAGS_VAL 0x7770
|
||||
# define NVREG_WAKEUPFLAGS_BUSYSHIFT 24
|
||||
# define NVREG_WAKEUPFLAGS_ENABLESHIFT 16
|
||||
# define NVREG_WAKEUPFLAGS_D3SHIFT 12
|
||||
# define NVREG_WAKEUPFLAGS_D2SHIFT 8
|
||||
# define NVREG_WAKEUPFLAGS_D1SHIFT 4
|
||||
# define NVREG_WAKEUPFLAGS_D0SHIFT 0
|
||||
# define NVREG_WAKEUPFLAGS_ACCEPT_MAGPAT 0x01
|
||||
# define NVREG_WAKEUPFLAGS_ACCEPT_WAKEUPPAT 0x02
|
||||
# define NVREG_WAKEUPFLAGS_ACCEPT_LINKCHANGE 0x04
|
||||
NvRegPatternCRC = 0x204,
|
||||
NvRegPatternMask = 0x208,
|
||||
NvRegPowerCap = 0x268,
|
||||
# define NVREG_POWERCAP_D3SUPP (1<<30)
|
||||
# define NVREG_POWERCAP_D2SUPP (1<<26)
|
||||
# define NVREG_POWERCAP_D1SUPP (1<<25)
|
||||
NvRegPowerState = 0x26c,
|
||||
# define NVREG_POWERSTATE_POWEREDUP 0x8000
|
||||
# define NVREG_POWERSTATE_VALID 0x0100
|
||||
# define NVREG_POWERSTATE_MASK 0x0003
|
||||
# define NVREG_POWERSTATE_D0 0x0000
|
||||
# define NVREG_POWERSTATE_D1 0x0001
|
||||
# define NVREG_POWERSTATE_D2 0x0002
|
||||
# define NVREG_POWERSTATE_D3 0x0003
|
||||
};
|
||||
|
||||
#define IOPORT_SIZE 0x8
|
||||
#define MMIO_SIZE 0x400
|
||||
|
||||
#define NV_TX_LASTPACKET (1<<0)
|
||||
#define NV_TX_RETRYERROR (1<<3)
|
||||
#define NV_TX_LASTPACKET1 (1<<8)
|
||||
#define NV_TX_DEFERRED (1<<10)
|
||||
#define NV_TX_CARRIERLOST (1<<11)
|
||||
#define NV_TX_LATECOLLISION (1<<12)
|
||||
#define NV_TX_UNDERFLOW (1<<13)
|
||||
#define NV_TX_ERROR (1<<14)
|
||||
#define NV_TX_VALID (1<<15)
|
||||
#define NV_RX_DESCRIPTORVALID (1<<0)
|
||||
#define NV_RX_MISSEDFRAME (1<<1)
|
||||
#define NV_RX_SUBSTRACT1 (1<<3)
|
||||
#define NV_RX_BIT4 (1<<4)
|
||||
#define NV_RX_ERROR1 (1<<7)
|
||||
#define NV_RX_ERROR2 (1<<8)
|
||||
#define NV_RX_ERROR3 (1<<9)
|
||||
#define NV_RX_ERROR4 (1<<10)
|
||||
#define NV_RX_CRCERR (1<<11)
|
||||
#define NV_RX_OVERFLOW (1<<12)
|
||||
#define NV_RX_FRAMINGERR (1<<13)
|
||||
#define NV_RX_ERROR (1<<14)
|
||||
#define NV_RX_AVAIL (1<<15)
|
||||
|
||||
/* Miscelaneous hardware related defines: */
|
||||
#define NV_PCI_REGSZ 0x270
|
||||
|
||||
/* various timeout delays: all in usec */
|
||||
#define NV_TXRX_RESET_DELAY 4
|
||||
#define NV_TXSTOP_DELAY1 10
|
||||
#define NV_TXSTOP_DELAY1MAX 500000
|
||||
#define NV_TXSTOP_DELAY2 100
|
||||
#define NV_RXSTOP_DELAY1 10
|
||||
#define NV_RXSTOP_DELAY1MAX 500000
|
||||
#define NV_RXSTOP_DELAY2 100
|
||||
#define NV_SETUP5_DELAY 5
|
||||
#define NV_SETUP5_DELAYMAX 50000
|
||||
#define NV_POWERUP_DELAY 5
|
||||
#define NV_POWERUP_DELAYMAX 5000
|
||||
#define NV_MIIBUSY_DELAY 50
|
||||
#define NV_MIIPHY_DELAY 10
|
||||
#define NV_MIIPHY_DELAYMAX 10000
|
||||
#define NV_WAKEUPPATTERNS 5
|
||||
#define NV_WAKEUPMASKENTRIES 4
|
||||
|
||||
/* General driver defaults */
|
||||
#define NV_WATCHDOG_TIMEO (2*HZ)
|
||||
#define DEFAULT_MTU 1500
|
||||
|
||||
#define RX_RING 4
|
||||
#define TX_RING 2
|
||||
/* limited to 1 packet until we understand NV_TX_LASTPACKET */
|
||||
#define TX_LIMIT_STOP 10
|
||||
#define TX_LIMIT_START 5
|
||||
|
||||
/* rx/tx mac addr + type + vlan + align + slack*/
|
||||
#define RX_NIC_BUFSIZE (DEFAULT_MTU + 64)
|
||||
/* even more slack */
|
||||
#define RX_ALLOC_BUFSIZE (DEFAULT_MTU + 128)
|
||||
|
||||
#define OOM_REFILL (1+HZ/20)
|
||||
#define POLL_WAIT (1+HZ/100)
|
||||
|
||||
#define MII_READ (-1)
|
||||
#define MII_PHYSID1 0x02 /* PHYS ID 1 */
|
||||
#define MII_PHYSID2 0x03 /* PHYS ID 2 */
|
||||
#define MII_BMCR 0x00 /* Basic mode control register */
|
||||
#define MII_BMSR 0x01 /* Basic mode status register */
|
||||
#define MII_ADVERTISE 0x04 /* Advertisement control reg */
|
||||
#define MII_LPA 0x05 /* Link partner ability reg */
|
||||
|
||||
#define BMSR_ANEGCOMPLETE 0x0020 /* Auto-negotiation complete */
|
||||
#define BMSR_BIT2 0x0004 /* Unknown... */
|
||||
|
||||
/* Link partner ability register. */
|
||||
#define LPA_SLCT 0x001f /* Same as advertise selector */
|
||||
#define LPA_10HALF 0x0020 /* Can do 10mbps half-duplex */
|
||||
#define LPA_10FULL 0x0040 /* Can do 10mbps full-duplex */
|
||||
#define LPA_100HALF 0x0080 /* Can do 100mbps half-duplex */
|
||||
#define LPA_100FULL 0x0100 /* Can do 100mbps full-duplex */
|
||||
#define LPA_100BASE4 0x0200 /* Can do 100mbps 4k packets */
|
||||
#define LPA_RESV 0x1c00 /* Unused... */
|
||||
#define LPA_RFAULT 0x2000 /* Link partner faulted */
|
||||
#define LPA_LPACK 0x4000 /* Link partner acked us */
|
||||
#define LPA_NPAGE 0x8000 /* Next page bit */
|
||||
|
||||
/*******************************************************************************
|
||||
* Primary State Structure
|
||||
******************************************************************************/
|
||||
|
||||
struct NvNetState {
|
||||
uint8_t regs[MMIO_SIZE / 4];
|
||||
uint32_t phy_regs[6];
|
||||
uint8_t tx_ring_index;
|
||||
uint8_t tx_ring_size;
|
||||
uint8_t rx_ring_index;
|
||||
uint8_t rx_ring_size;
|
||||
uint8_t txrx_dma_buf[RX_ALLOC_BUFSIZE];
|
||||
FILE *packet_dump_file;
|
||||
char *packet_dump_path;
|
||||
} NvNetState;
|
||||
|
||||
struct RingDesc {
|
||||
uint32_t packet_buffer;
|
||||
uint16_t length;
|
||||
uint16_t flags;
|
||||
};
|
||||
|
||||
const char* EmuNVNet_GetRegisterName(uint32_t addr) {
|
||||
switch (addr) {
|
||||
case NvRegIrqStatus: return "NvRegIrqStatus";
|
||||
case NvRegIrqMask: return "NvRegIrqMask";
|
||||
case NvRegUnknownSetupReg6: return "NvRegUnknownSetupReg6";
|
||||
case NvRegPollingInterval: return "NvRegPollingInterval";
|
||||
case NvRegMisc1: return "NvRegMisc1";
|
||||
case NvRegTransmitterControl: return "NvRegTransmitterControl";
|
||||
case NvRegTransmitterStatus: return "NvRegTransmitterStatus";
|
||||
case NvRegPacketFilterFlags: return "NvRegPacketFilterFlags";
|
||||
case NvRegOffloadConfig: return "NvRegOffloadConfig";
|
||||
case NvRegReceiverControl: return "NvRegReceiverControl";
|
||||
case NvRegReceiverStatus: return "NvRegReceiverStatus";
|
||||
case NvRegRandomSeed: return "NvRegRandomSeed";
|
||||
case NvRegUnknownSetupReg1: return "NvRegUnknownSetupReg1";
|
||||
case NvRegUnknownSetupReg2: return "NvRegUnknownSetupReg2";
|
||||
case NvRegMacAddrA: return "NvRegMacAddrA";
|
||||
case NvRegMacAddrB: return "NvRegMacAddrB";
|
||||
case NvRegMulticastAddrA: return "NvRegMulticastAddrA";
|
||||
case NvRegMulticastAddrB: return "NvRegMulticastAddrB";
|
||||
case NvRegMulticastMaskA: return "NvRegMulticastMaskA";
|
||||
case NvRegMulticastMaskB: return "NvRegMulticastMaskB";
|
||||
case NvRegTxRingPhysAddr: return "NvRegTxRingPhysAddr";
|
||||
case NvRegRxRingPhysAddr: return "NvRegRxRingPhysAddr";
|
||||
case NvRegRingSizes: return "NvRegRingSizes";
|
||||
case NvRegUnknownTransmitterReg: return "NvRegUnknownTransmitterReg";
|
||||
case NvRegLinkSpeed: return "NvRegLinkSpeed";
|
||||
case NvRegUnknownSetupReg5: return "NvRegUnknownSetupReg5";
|
||||
case NvRegUnknownSetupReg3: return "NvRegUnknownSetupReg3";
|
||||
case NvRegUnknownSetupReg8: return "NvRegUnknownSetupReg8";
|
||||
case NvRegUnknownSetupReg7: return "NvRegUnknownSetupReg7";
|
||||
case NvRegTxRxControl: return "NvRegTxRxControl";
|
||||
case NvRegMIIStatus: return "NvRegMIIStatus";
|
||||
case NvRegUnknownSetupReg4: return "NvRegUnknownSetupReg4";
|
||||
case NvRegAdapterControl: return "NvRegAdapterControl";
|
||||
case NvRegMIISpeed: return "NvRegMIISpeed";
|
||||
case NvRegMIIControl: return "NvRegMIIControl";
|
||||
case NvRegMIIData: return "NvRegMIIData";
|
||||
case NvRegWakeUpFlags: return "NvRegWakeUpFlags";
|
||||
case NvRegPatternCRC: return "NvRegPatternCRC";
|
||||
case NvRegPatternMask: return "NvRegPatternMask";
|
||||
case NvRegPowerCap: return "NvRegPowerCap";
|
||||
case NvRegPowerState: return "NvRegPowerState";
|
||||
default: return "Unknown";
|
||||
}
|
||||
}
|
||||
|
||||
const char* EmuNVNet_GetMiiRegisterName(uint8_t reg) {
|
||||
switch (reg) {
|
||||
case MII_PHYSID1: return "MII_PHYSID1";
|
||||
case MII_PHYSID2: return "MII_PHYSID2";
|
||||
case MII_BMCR: return "MII_BMCR";
|
||||
case MII_BMSR: return "MII_BMSR";
|
||||
case MII_ADVERTISE: return "MII_ADVERTISE";
|
||||
case MII_LPA: return "MII_LPA";
|
||||
default: return "Unknown";
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t EmuNVNet_GetRegister(uint32_t addr, unsigned int size) {
|
||||
switch (size) {
|
||||
case sizeof(uint32_t) :
|
||||
return ((uint32_t *)NvNetState.regs)[addr >> 2];
|
||||
case sizeof(uint16_t) :
|
||||
return ((uint16_t *)NvNetState.regs)[addr >> 1];
|
||||
case sizeof(uint8_t) :
|
||||
return NvNetState.regs[addr];
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void EmuNVNet_SetRegister(uint32_t addr, uint32_t value, unsigned int size) {
|
||||
switch (size) {
|
||||
case sizeof(uint32_t) :
|
||||
((uint32_t *)NvNetState.regs)[addr >> 2] = value;
|
||||
break;
|
||||
case sizeof(uint16_t) :
|
||||
((uint16_t *)NvNetState.regs)[addr >> 1] = (uint16_t)value;
|
||||
break;
|
||||
case sizeof(uint8_t) :
|
||||
NvNetState.regs[addr] = (uint8_t)value;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void EmuNVNet_UpdateIRQ() {
|
||||
if (EmuNVNet_GetRegister(NvRegIrqMask, 4) &&
|
||||
EmuNVNet_GetRegister(NvRegIrqStatus, 4)) {
|
||||
log_debug("EmuNVNet: Asserting IRQ\n");
|
||||
// TODO: HalSystemInterrupts[4].Assert(true);
|
||||
}
|
||||
else {
|
||||
// TODO: HalSystemInterrupts[4].Assert(false);
|
||||
}
|
||||
}
|
||||
|
||||
int EmuNVNet_MiiReadWrite(uint64_t val) {
|
||||
uint32_t mii_ctl;
|
||||
int write, retval, phy_addr, reg;
|
||||
|
||||
retval = 0;
|
||||
mii_ctl = EmuNVNet_GetRegister(NvRegMIIControl, 4);
|
||||
|
||||
phy_addr = (mii_ctl >> NVREG_MIICTL_ADDRSHIFT) & 0x1f;
|
||||
reg = mii_ctl & ((1 << NVREG_MIICTL_ADDRSHIFT) - 1);
|
||||
write = mii_ctl & NVREG_MIICTL_WRITE;
|
||||
|
||||
log_debug("nvnet mii %s: phy 0x%x %s [0x%x]\n", write ? "write" : "read", phy_addr, EmuNVNet_GetMiiRegisterName(reg), reg);
|
||||
|
||||
if (phy_addr != 1) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (write) {
|
||||
return retval;
|
||||
}
|
||||
|
||||
switch (reg) {
|
||||
case MII_BMSR:
|
||||
/* Phy initialization code waits for BIT2 to be set.. If not set,
|
||||
* software may report controller as not running */
|
||||
retval = BMSR_ANEGCOMPLETE | BMSR_BIT2;
|
||||
break;
|
||||
case MII_ADVERTISE:
|
||||
/* Fall through... */
|
||||
case MII_LPA:
|
||||
retval = LPA_10HALF | LPA_10FULL;
|
||||
retval |= LPA_100HALF | LPA_100FULL | LPA_100BASE4;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
uint32_t EmuNVNet_Read(uint32_t addr, int size) {
|
||||
//log_debug("NET : Read%d: %s (0x%.8X)\n", size, EmuNVNet_GetRegisterName(addr), addr);
|
||||
|
||||
switch (addr) {
|
||||
case NvRegMIIData:
|
||||
return EmuNVNet_MiiReadWrite(MII_READ);
|
||||
case NvRegMIIControl:
|
||||
return EmuNVNet_GetRegister(addr, size) & ~NVREG_MIICTL_INUSE;
|
||||
case NvRegMIIStatus:
|
||||
return 0;
|
||||
}
|
||||
|
||||
return EmuNVNet_GetRegister(addr, size);
|
||||
}
|
||||
|
||||
void EmuNVNet_Write(uint32_t addr, uint32_t value, int size) {
|
||||
switch (addr) {
|
||||
case NvRegRingSizes:
|
||||
EmuNVNet_SetRegister(addr, value, size);
|
||||
NvNetState.rx_ring_size = ((value >> NVREG_RINGSZ_RXSHIFT) & 0xffff) + 1;
|
||||
NvNetState.tx_ring_size = ((value >> NVREG_RINGSZ_TXSHIFT) & 0xffff) + 1;
|
||||
break;
|
||||
case NvRegMIIData:
|
||||
EmuNVNet_MiiReadWrite(value);
|
||||
break;
|
||||
case NvRegTxRxControl:
|
||||
if (value == NVREG_TXRXCTL_KICK) {
|
||||
//log_debug("NvRegTxRxControl = NVREG_TXRXCTL_KICK!\n");
|
||||
//log_warning("TODO: nvnet_dma_packet_from_guest");
|
||||
// nvnet_dma_packet_from_guest(s);
|
||||
}
|
||||
|
||||
if (value & NVREG_TXRXCTL_BIT2) {
|
||||
EmuNVNet_SetRegister(NvRegTxRxControl, NVREG_TXRXCTL_IDLE, 4);
|
||||
break;
|
||||
}
|
||||
|
||||
if (value & NVREG_TXRXCTL_BIT1) {
|
||||
EmuNVNet_SetRegister(NvRegIrqStatus, 0, 4);
|
||||
break;
|
||||
}
|
||||
else if (value == 0) {
|
||||
uint32_t temp = EmuNVNet_GetRegister(NvRegUnknownSetupReg3, 4);
|
||||
if (temp == NVREG_UNKSETUP3_VAL1) {
|
||||
/* forcedeth waits for this bit to be set... */
|
||||
EmuNVNet_SetRegister(NvRegUnknownSetupReg5,
|
||||
NVREG_UNKSETUP5_BIT31, 4);
|
||||
break;
|
||||
}
|
||||
}
|
||||
EmuNVNet_SetRegister(NvRegTxRxControl, value, size);
|
||||
break;
|
||||
case NvRegIrqMask:
|
||||
EmuNVNet_SetRegister(addr, value, size);
|
||||
EmuNVNet_UpdateIRQ();
|
||||
break;
|
||||
case NvRegIrqStatus:
|
||||
EmuNVNet_SetRegister(addr, EmuNVNet_GetRegister(addr, size) & ~value, size);
|
||||
EmuNVNet_UpdateIRQ();
|
||||
break;
|
||||
default:
|
||||
EmuNVNet_SetRegister(addr, value, size);
|
||||
break;
|
||||
}
|
||||
|
||||
//log_debug("NET : Write%d: %s (0x%.8X) = 0x%.8X\n", size, EmuNVNet_GetRegisterName(addr), addr, value);
|
||||
}
|
||||
|
||||
/* NVNetDevice */
|
||||
|
||||
NVNetDevice::NVNetDevice()
|
||||
: PCIDevice(PCI_HEADER_TYPE_NORMAL, PCI_VENDOR_ID_NVIDIA, 0x01C3, 0xB1,
|
||||
0x02, 0x00, 0x00) // Ethernet controller
|
||||
|
@ -541,8 +67,8 @@ void NVNetDevice::PCIMMIORead(int barIndex, uint32_t addr, uint32_t *value, uint
|
|||
return;
|
||||
}
|
||||
|
||||
*value = EmuNVNet_Read(addr, size * 8); // For now, forward
|
||||
return;
|
||||
*value = 0;
|
||||
log_warning("NVNetDevice::PCIMMIORead: Unimplemented read! bar = %d, address = 0x%x, size = %u\n", barIndex, addr, size);
|
||||
}
|
||||
|
||||
void NVNetDevice::PCIMMIOWrite(int barIndex, uint32_t addr, uint32_t value, uint8_t size) {
|
||||
|
@ -552,7 +78,7 @@ void NVNetDevice::PCIMMIOWrite(int barIndex, uint32_t addr, uint32_t value, uint
|
|||
return;
|
||||
}
|
||||
|
||||
EmuNVNet_Write(addr, value, size * 8); // For now, forward
|
||||
log_warning("NVNetDevice::PCIMMIOWrite: Unimplemented write! bar = %d, address = 0x%x, value = 0x%x, size = %u\n", barIndex, addr, value, size);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -1,535 +0,0 @@
|
|||
/*
|
||||
* Portions of the code are based on Cxbx-Reloaded's OHCI LLE implementation.
|
||||
* The original copyright header is included below.
|
||||
*/
|
||||
// This is an open source non-commercial project. Dear PVS-Studio, please check it.
|
||||
// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
|
||||
// ******************************************************************
|
||||
// *
|
||||
// * .,-::::: .,:: .::::::::. .,:: .:
|
||||
// * ,;;;'````' `;;;, .,;; ;;;'';;' `;;;, .,;;
|
||||
// * [[[ '[[,,[[' [[[__[[\. '[[,,[['
|
||||
// * $$$ Y$$$P $$""""Y$$ Y$$$P
|
||||
// * `88bo,__,o, oP"``"Yo, _88o,,od8P oP"``"Yo,
|
||||
// * "YUMMMMMP",m" "Mm,""YUMMMP" ,m" "Mm,
|
||||
// *
|
||||
// * Cxbx->devices->usb->XidGamepad.cpp
|
||||
// *
|
||||
// * This file is part of the Cxbx project.
|
||||
// *
|
||||
// * Cxbx and Cxbe are free software; you can redistribute them
|
||||
// * and/or modify them under the terms of the GNU General Public
|
||||
// * License as published by the Free Software Foundation; either
|
||||
// * version 2 of the license, or (at your option) any later version.
|
||||
// *
|
||||
// * This program is distributed in the hope that it will be useful,
|
||||
// * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// * GNU General Public License for more details.
|
||||
// *
|
||||
// * You should have recieved a copy of the GNU General Public License
|
||||
// * along with this program; see the file COPYING.
|
||||
// * If not, write to the Free Software Foundation, Inc.,
|
||||
// * 59 Temple Place - Suite 330, Bostom, MA 02111-1307, USA.
|
||||
// *
|
||||
// * (c) 2018 ergo720
|
||||
// *
|
||||
// * All rights reserved
|
||||
// *
|
||||
// ******************************************************************
|
||||
|
||||
#include "strikebox/hw/xid/xid_gamepad.h"
|
||||
|
||||
#include "strikebox/hw/ohci/ohci.h"
|
||||
#include "strikebox/hw/pci/usb_pci.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace strikebox {
|
||||
|
||||
XidGamepad* g_XidControllerObjArray[4];
|
||||
|
||||
#define USB_CLASS_XID 0x58
|
||||
#define USB_DT_XID 0x42
|
||||
|
||||
#define HID_GET_REPORT 0x01
|
||||
#define HID_SET_REPORT 0x09
|
||||
#define XID_GET_CAPABILITIES 0x01
|
||||
|
||||
|
||||
#pragma pack(1)
|
||||
|
||||
/* Class-specific xid descriptor */
|
||||
struct XIDDesc {
|
||||
uint8_t bLength;
|
||||
uint8_t bDescriptorType;
|
||||
uint16_t bcdXid;
|
||||
uint8_t bType;
|
||||
uint8_t bSubType;
|
||||
uint8_t bMaxInputReportSize;
|
||||
uint8_t bMaxOutputReportSize;
|
||||
uint16_t wAlternateProductIds[4];
|
||||
};
|
||||
|
||||
/* Struct used by the Get_Report request -> state of the buttons */
|
||||
struct XIDGamepadReport {
|
||||
uint8_t bReportId;
|
||||
uint8_t bLength;
|
||||
uint16_t wButtons; // all non-analog buttons
|
||||
uint8_t bAnalogButtons[8]; // X, Y, A, B, white, black, left/right trigger
|
||||
int16_t sThumbLX; // analog stick, left X
|
||||
int16_t sThumbLY; // analog stick, left Y
|
||||
int16_t sThumbRX; // analog stick, right X
|
||||
int16_t sThumbRY; // analog stick, right Y
|
||||
};
|
||||
|
||||
/* Struct used by the Set_Report request -> vibration strenght */
|
||||
struct XIDGamepadOutputReport {
|
||||
uint8_t report_id; // From XQEMU: FIXME: is this correct?
|
||||
uint8_t length;
|
||||
uint16_t left_actuator_strength; // strenght of left vibration motor
|
||||
uint16_t right_actuator_strength; // strenght of right vibration motor
|
||||
};
|
||||
|
||||
#pragma pack()
|
||||
|
||||
struct USBXIDState {
|
||||
XboxDeviceState dev; // gamepad device status
|
||||
USBEndpoint* intr; // interrupt endpoint of the gamepad
|
||||
|
||||
const XIDDesc* xid_desc; // xid-specific descriptor
|
||||
|
||||
XIDGamepadReport in_state; // Get_Report struct
|
||||
XIDGamepadReport in_state_capabilities; // Get_Capabilities struct (in)
|
||||
XIDGamepadOutputReport out_state; // Set_Report struct
|
||||
XIDGamepadOutputReport out_state_capabilities; // Get_Capabilities struct (out)
|
||||
};
|
||||
|
||||
static const USBDescEndpoint desc_endp_xbox_gamepad[2] = {
|
||||
{
|
||||
USB_DIR_IN | 0x02, // bEndpointAddress;
|
||||
USB_ENDPOINT_XFER_INT, // bmAttributes;
|
||||
0x20, // wMaxPacketSize;
|
||||
4, // bInterval;
|
||||
0, // bRefresh;
|
||||
0, // bSynchAddress
|
||||
0, // is_audio
|
||||
nullptr // extra
|
||||
},
|
||||
{
|
||||
USB_DIR_OUT | 0x02,
|
||||
USB_ENDPOINT_XFER_INT,
|
||||
0x20,
|
||||
4,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
nullptr
|
||||
}
|
||||
};
|
||||
|
||||
static const USBDescIface desc_iface_xbox_gamepad = {
|
||||
0, // bInterfaceNumber;
|
||||
0, // bAlternateSetting;
|
||||
2, // bNumEndpoints;
|
||||
USB_CLASS_XID, // bInterfaceClass;
|
||||
0x42, // bInterfaceSubClass
|
||||
0x00, // bInterfaceProtocol
|
||||
0, // iInterface
|
||||
0, // ndesc
|
||||
nullptr, // descs
|
||||
desc_endp_xbox_gamepad
|
||||
};
|
||||
|
||||
static const USBDescConfig desc_config_xbox_gamepad = {
|
||||
1, // bNumInterfaces
|
||||
1, // bConfigurationValue
|
||||
0, // iConfiguration
|
||||
0x80, // bmAttributes
|
||||
50, // bMaxPower
|
||||
1, // nif
|
||||
&desc_iface_xbox_gamepad
|
||||
};
|
||||
|
||||
static const USBDescDevice desc_device_xbox_gamepad = {
|
||||
0x0110, // bcdUSB
|
||||
0, // bDeviceClass
|
||||
0, // bDeviceSubClass
|
||||
0, // bDeviceProtocol
|
||||
0x40, // bMaxPacketSize0
|
||||
1, // bNumConfigurations
|
||||
&desc_config_xbox_gamepad
|
||||
};
|
||||
|
||||
static const USBDesc desc_xbox_gamepad = {
|
||||
{
|
||||
0x045E, // idVendor
|
||||
0x0202, // idProduct
|
||||
0x0100, // bcdDevice
|
||||
STR_MANUFACTURER, // iManufacturer
|
||||
STR_PRODUCT, // iProduct
|
||||
STR_SERIALNUMBER // iSerialNumber
|
||||
},
|
||||
&desc_device_xbox_gamepad
|
||||
};
|
||||
|
||||
static const XIDDesc desc_xid_xbox_gamepad = {
|
||||
0x10, // bLength
|
||||
USB_DT_XID, // bDescriptorType
|
||||
0x100, // bcdXid
|
||||
1, // bType
|
||||
1, // bSubType
|
||||
20, // bMaxInputReportSize
|
||||
6, // bMaxOutputReportSize
|
||||
{ 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF } // wAlternateProductIds
|
||||
};
|
||||
|
||||
int XidGamepad::Init(int port) {
|
||||
if (port > 4 || port < 1) { return -1; }
|
||||
|
||||
XboxDeviceState* dev = ClassInitFn();
|
||||
int rc = UsbXidClaimPort(dev, port);
|
||||
if (rc != 0) {
|
||||
m_UsbDev->m_HostController->m_bFrameTime = false;
|
||||
return rc;
|
||||
}
|
||||
m_UsbDev->USB_EpInit(dev);
|
||||
m_UsbDev->USB_DeviceInit(dev);
|
||||
m_UsbDev->USB_DeviceAttach(dev);
|
||||
m_UsbDev->m_HostController->m_bFrameTime = false;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
XboxDeviceState* XidGamepad::ClassInitFn() {
|
||||
m_pPeripheralFuncStruct = new USBDeviceClass();
|
||||
m_XidState = new USBXIDState();
|
||||
XboxDeviceState* dev = &m_XidState->dev;
|
||||
|
||||
dev->ProductDesc = "Microsoft Xbox Controller";
|
||||
QLIST_INIT(&dev->Strings);
|
||||
dev->klass = m_pPeripheralFuncStruct;
|
||||
|
||||
{
|
||||
using namespace std::placeholders;
|
||||
|
||||
m_pPeripheralFuncStruct->init = std::bind(&XidGamepad::UsbXid_Initfn, this, _1);
|
||||
m_pPeripheralFuncStruct->handle_reset = std::bind(&XidGamepad::UsbXid_HandleReset, this);
|
||||
m_pPeripheralFuncStruct->handle_control = std::bind(&XidGamepad::UsbXid_HandleControl, this, _1, _2, _3, _4, _5, _6, _7);
|
||||
m_pPeripheralFuncStruct->handle_data = std::bind(&XidGamepad::UsbXid_HandleData, this, _1, _2);
|
||||
m_pPeripheralFuncStruct->handle_destroy = std::bind(&XidGamepad::UsbXid_HandleDestroy, this);
|
||||
m_pPeripheralFuncStruct->handle_attach = std::bind(&XidGamepad::UsbXid_Attach, this, _1);
|
||||
m_pPeripheralFuncStruct->product_desc = dev->ProductDesc.c_str();
|
||||
m_pPeripheralFuncStruct->usb_desc = &desc_xbox_gamepad;
|
||||
}
|
||||
|
||||
return dev;
|
||||
}
|
||||
|
||||
int XidGamepad::UsbXidClaimPort(XboxDeviceState* dev, int port) {
|
||||
int i;
|
||||
std::vector<USBPort*>::iterator it;
|
||||
|
||||
assert(dev->Port == nullptr);
|
||||
|
||||
for (int j = 0; j < 4; j++) {
|
||||
if (g_HubObjArray[j]) {
|
||||
i = 0;
|
||||
for (auto usb_port : g_HubObjArray[j]->m_UsbDev->m_FreePorts) {
|
||||
if (usb_port->Path == (std::to_string(port) + ".2")) {
|
||||
m_UsbDev = g_HubObjArray[j]->m_UsbDev;
|
||||
break;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (m_UsbDev == nullptr) {
|
||||
log_warning("XID: Port requested %d.2 not found (in use?)", port);
|
||||
return -1;
|
||||
}
|
||||
|
||||
while (m_UsbDev->m_HostController->m_bFrameTime) {}
|
||||
m_UsbDev->m_HostController->m_bFrameTime = true;
|
||||
|
||||
m_Port = port;
|
||||
it = m_UsbDev->m_FreePorts.begin() + i;
|
||||
dev->Port = *it;
|
||||
(*it)->Dev = dev;
|
||||
m_UsbDev->m_FreePorts.erase(it);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void XidGamepad::UsbXidReleasePort(XboxDeviceState* dev) {
|
||||
USBPort* port = dev->Port;
|
||||
|
||||
assert(port != nullptr);
|
||||
|
||||
port->Dev = nullptr;
|
||||
dev->Port = nullptr;
|
||||
}
|
||||
|
||||
int XidGamepad::UsbXid_Initfn(XboxDeviceState* dev) {
|
||||
m_UsbDev->USB_CreateSerial(dev, std::string("1"));
|
||||
m_UsbDev->USBDesc_SetString(dev, STR_MANUFACTURER, std::string("Cxbx-Reloaded"));
|
||||
m_UsbDev->USBDesc_SetString(dev, STR_PRODUCT, std::string("Microsoft Gamepad"));
|
||||
m_UsbDev->USBDesc_Init(dev);
|
||||
m_XidState->intr = m_UsbDev->USB_GetEP(dev, USB_TOKEN_IN, 2);
|
||||
|
||||
m_XidState->in_state.bLength = sizeof(m_XidState->in_state);
|
||||
m_XidState->in_state.bReportId = 0;
|
||||
m_XidState->out_state.length = sizeof(m_XidState->out_state);
|
||||
m_XidState->out_state.report_id = 0;
|
||||
|
||||
memset(&m_XidState->in_state_capabilities, 0xFF, sizeof(m_XidState->in_state_capabilities));
|
||||
m_XidState->in_state_capabilities.bLength = sizeof(m_XidState->in_state_capabilities);
|
||||
m_XidState->in_state_capabilities.bReportId = 0;
|
||||
memset(&m_XidState->out_state_capabilities, 0xFF, sizeof(m_XidState->out_state_capabilities));
|
||||
m_XidState->out_state_capabilities.length = sizeof(m_XidState->out_state_capabilities);
|
||||
m_XidState->out_state_capabilities.report_id = 0;
|
||||
|
||||
m_XidState->xid_desc = &desc_xid_xbox_gamepad;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void XidGamepad::UsbXid_HandleDestroy() {
|
||||
UsbXidReleasePort(&m_XidState->dev);
|
||||
XidCleanUp();
|
||||
}
|
||||
|
||||
void XidGamepad::UsbXid_Attach(XboxDeviceState* dev) {
|
||||
if ((dev->Port->SpeedMask & USB_SPEED_MASK_FULL)) {
|
||||
dev->Speed = USB_SPEED_FULL;
|
||||
}
|
||||
else {
|
||||
return;
|
||||
}
|
||||
m_UsbDev->USBDesc_SetDefaults(dev);
|
||||
}
|
||||
|
||||
void XidGamepad::UsbXid_HandleReset() {
|
||||
log_debug("XID: Gamepad reset event");
|
||||
}
|
||||
|
||||
void XidGamepad::UsbXid_HandleControl(XboxDeviceState* dev, USBPacket* p,
|
||||
int request, int value, int index, int length, uint8_t* data) {
|
||||
int ret = m_UsbDev->USBDesc_HandleControl(dev, p, request, value, index, length, data);
|
||||
if (ret >= 0) {
|
||||
log_debug("XID: Gamepad handled by USBDesc_HandleControl, ret is %d", ret);
|
||||
return;
|
||||
}
|
||||
|
||||
switch (request) {
|
||||
// HID-specific requests
|
||||
case ClassInterfaceRequest | HID_GET_REPORT:
|
||||
{
|
||||
// From the HID standard: "The Get_Report request allows the host to receive a report via the Control pipe.
|
||||
// The wValue field specifies the Report Type in the high byte and the Report ID in the low byte. Set Report ID
|
||||
// to 0 (zero) if Report IDs are not used. 01 = input, 02 = output, 03 = feature, 04-FF = reserved"
|
||||
log_debug("XID: Gamepad GET_REPORT 0x%X", value);
|
||||
// JayFoxRox's analysis: "This 0x0100 case is for input.
|
||||
// This is the case where the Xbox wants to read input data from the controller.
|
||||
// Confirmed with a real Duke controller :
|
||||
// If the buffer provided by the Xbox is too small, the controller will cut the transfer when the buffer is full (actual_length is patched).
|
||||
// If the buffer is too large the controller will STALL instead.
|
||||
// If the buffer has the correct length the full input data is transferred."
|
||||
if (value == 0x0100) {
|
||||
if (length <= m_XidState->in_state.bLength) {
|
||||
// TODO: implement input devices
|
||||
//SDL2Devices* controller = g_InputDeviceManager->FindDeviceFromXboxPort(m_Port);
|
||||
//if (controller != nullptr) {
|
||||
// controller->ReadButtonState(&m_XidState->in_state.wButtons, m_XidState->in_state.bAnalogButtons,
|
||||
// &m_XidState->in_state.sThumbLX, &m_XidState->in_state.sThumbLY, &m_XidState->in_state.sThumbRX,
|
||||
// &m_XidState->in_state.sThumbRY);
|
||||
//}
|
||||
//else
|
||||
//{
|
||||
// // ergo720: this shouldn't really happen. If it does, it either means that m_Port is wrong or there's a bug
|
||||
// // in the InputDeviceManager
|
||||
// p->Status = USB_RET_STALL;
|
||||
// assert(0);
|
||||
//}
|
||||
memcpy(data, &m_XidState->in_state, m_XidState->in_state.bLength);
|
||||
p->ActualLength = length;
|
||||
}
|
||||
else {
|
||||
p->Status = USB_RET_STALL;
|
||||
}
|
||||
}
|
||||
else {
|
||||
p->Status = USB_RET_STALL;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case ClassInterfaceOutRequest | HID_SET_REPORT:
|
||||
{
|
||||
// From the HID standard: "The Set_Report request allows the host to send a report to the device, possibly
|
||||
// setting the state of input, output, or feature controls. The meaning of the request fields for the Set_Report
|
||||
// request is the same as for the Get_Report request, however the data direction is reversed and the Report
|
||||
// Data is sent from host to device."
|
||||
log_debug("XID: Gamepad SET_REPORT 0x%X", value);
|
||||
// JayFoxRox's analysis: "The 0x0200 case below is for output.
|
||||
// This is the case where the Xbox wants to write rumble data to the controller.
|
||||
// To my knowledge :
|
||||
// If the buffer provided by the Xbox is too small the transfer will STALL.
|
||||
// If the buffer is too large the transfer will STALL.
|
||||
// If the buffer has the correct length the full output data is transferred."
|
||||
if (value == 0x0200) {
|
||||
if (length == m_XidState->out_state.length) {
|
||||
// Read length, then the entire packet
|
||||
memcpy(&m_XidState->out_state, data, sizeof(m_XidState->out_state));
|
||||
/* FIXME: This should also be a STALL */
|
||||
assert(m_XidState->out_state.length == sizeof(m_XidState->out_state));
|
||||
p->ActualLength = length;
|
||||
}
|
||||
else {
|
||||
p->Status = USB_RET_STALL;
|
||||
}
|
||||
UpdateForceFeedback();
|
||||
}
|
||||
else {
|
||||
p->Status = USB_RET_STALL;
|
||||
assert(0);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
// XID-specific requests
|
||||
case VendorInterfaceRequest | USB_REQ_GET_DESCRIPTOR:
|
||||
{
|
||||
log_debug("XID: Gamepad GET_DESCRIPTOR 0x%x", value);
|
||||
if (value == 0x4200) {
|
||||
assert(m_XidState->xid_desc->bLength <= length);
|
||||
memcpy(data, m_XidState->xid_desc, m_XidState->xid_desc->bLength);
|
||||
p->ActualLength = m_XidState->xid_desc->bLength;
|
||||
}
|
||||
else {
|
||||
p->Status = USB_RET_STALL;
|
||||
assert(0);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case VendorInterfaceRequest | XID_GET_CAPABILITIES:
|
||||
{
|
||||
log_debug("XID: Gamepad XID_GET_CAPABILITIES 0x%x", value);
|
||||
if (value == 0x0100) {
|
||||
if (length > m_XidState->in_state_capabilities.bLength) {
|
||||
length = m_XidState->in_state_capabilities.bLength;
|
||||
}
|
||||
memcpy(data, &m_XidState->in_state_capabilities, length);
|
||||
p->ActualLength = length;
|
||||
}
|
||||
else if (value == 0x0200) {
|
||||
if (length > m_XidState->out_state_capabilities.length) {
|
||||
length = m_XidState->out_state_capabilities.length;
|
||||
}
|
||||
memcpy(data, &m_XidState->out_state_capabilities, length);
|
||||
p->ActualLength = length;
|
||||
}
|
||||
else {
|
||||
p->Status = USB_RET_STALL;
|
||||
assert(0);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case ((USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_DEVICE) << 8) | USB_REQ_GET_DESCRIPTOR:
|
||||
{
|
||||
/* FIXME: ! */
|
||||
log_debug("XID: Gamepad unknown xpad request 0x%X: value = 0x%X", request, value);
|
||||
memset(data, 0x00, length);
|
||||
//FIXME: Intended for the hub: usbd_get_hub_descriptor, UT_READ_CLASS?!
|
||||
p->Status = USB_RET_STALL;
|
||||
//assert(false);
|
||||
break;
|
||||
}
|
||||
|
||||
case ((USB_DIR_OUT | USB_TYPE_STANDARD | USB_RECIP_ENDPOINT) << 8) | USB_REQ_CLEAR_FEATURE:
|
||||
{
|
||||
/* FIXME: ! */
|
||||
log_debug("XID: Gamepad unknown xpad request 0x%X: value = 0x%X", request, value);
|
||||
memset(data, 0x00, length);
|
||||
p->Status = USB_RET_STALL;
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
log_debug("XID: Gamepad USB stalled on request 0x%X value 0x%X", request, value);
|
||||
p->Status = USB_RET_STALL;
|
||||
assert(0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void XidGamepad::UsbXid_HandleData(XboxDeviceState* dev, USBPacket* p) {
|
||||
switch (p->Pid) {
|
||||
case USB_TOKEN_IN:
|
||||
{
|
||||
if (p->Endpoint->Num == 2) {
|
||||
//SDL2Devices* controller = g_InputDeviceManager->FindDeviceFromXboxPort(m_Port);
|
||||
//if (controller != nullptr) {
|
||||
// bool ret;
|
||||
// ret = controller->ReadButtonState(&m_XidState->in_state.wButtons, m_XidState->in_state.bAnalogButtons,
|
||||
// &m_XidState->in_state.sThumbLX, &m_XidState->in_state.sThumbLY, &m_XidState->in_state.sThumbRX,
|
||||
// &m_XidState->in_state.sThumbRY);
|
||||
// if (ret) {
|
||||
// m_UsbDev->USB_PacketCopy(p, &m_XidState->in_state, m_XidState->in_state.bLength);
|
||||
// }
|
||||
// else {
|
||||
p->Status = USB_RET_NAK;
|
||||
// }
|
||||
//}
|
||||
//else
|
||||
//{
|
||||
// p->Status = USB_RET_STALL;
|
||||
// assert(0);
|
||||
//}
|
||||
}
|
||||
else {
|
||||
assert(0);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case USB_TOKEN_OUT:
|
||||
{
|
||||
if (p->Endpoint->Num == 2) {
|
||||
m_UsbDev->USB_PacketCopy(p, &m_XidState->out_state, m_XidState->out_state.length);
|
||||
UpdateForceFeedback();
|
||||
}
|
||||
else {
|
||||
assert(0);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
p->Status = USB_RET_STALL;
|
||||
assert(0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void XidGamepad::XidCleanUp() {
|
||||
delete m_pPeripheralFuncStruct;
|
||||
delete m_XidState;
|
||||
m_pPeripheralFuncStruct = nullptr;
|
||||
m_XidState = nullptr;
|
||||
}
|
||||
|
||||
void XidGamepad::UpdateForceFeedback() {
|
||||
// JayFoxRox's remarks: "Xbox -> XID packets were not tested
|
||||
// The handling of output packets / force feedback was not checked."
|
||||
// For the above reason we don't implement vibration support for now since the current
|
||||
// implementation is untested and could potentially contain errors
|
||||
/* FIXME: Check actuator endianess */
|
||||
log_debug("XID: Set rumble power to left: 0x%X and right: 0x%X\n",
|
||||
m_XidState->out_state.left_actuator_strength,
|
||||
m_XidState->out_state.right_actuator_strength);
|
||||
}
|
||||
|
||||
}
|
|
@ -1,111 +0,0 @@
|
|||
/*
|
||||
* Portions of the code are based on Cxbx-Reloaded's OHCI LLE implementation.
|
||||
* The original copyright header is included below.
|
||||
*/
|
||||
// ******************************************************************
|
||||
// *
|
||||
// * .,-::::: .,:: .::::::::. .,:: .:
|
||||
// * ,;;;'````' `;;;, .,;; ;;;'';;' `;;;, .,;;
|
||||
// * [[[ '[[,,[[' [[[__[[\. '[[,,[['
|
||||
// * $$$ Y$$$P $$""""Y$$ Y$$$P
|
||||
// * `88bo,__,o, oP"``"Yo, _88o,,od8P oP"``"Yo,
|
||||
// * "YUMMMMMP",m" "Mm,""YUMMMP" ,m" "Mm,
|
||||
// *
|
||||
// * Cxbx->Cxbx.h
|
||||
// *
|
||||
// * This file is part of the Cxbx project.
|
||||
// *
|
||||
// * Cxbx and Cxbe are free software; you can redistribute them
|
||||
// * and/or modify them under the terms of the GNU General Public
|
||||
// * License as published by the Free Software Foundation; either
|
||||
// * version 2 of the license, or (at your option) any later version.
|
||||
// *
|
||||
// * This program is distributed in the hope that it will be useful,
|
||||
// * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// * GNU General Public License for more details.
|
||||
// *
|
||||
// * You should have recieved a copy of the GNU General Public License
|
||||
// * along with this program; see the file COPYING.
|
||||
// * If not, write to the Free Software Foundation, Inc.,
|
||||
// * 59 Temple Place - Suite 330, Bostom, MA 02111-1307, USA.
|
||||
// *
|
||||
// * (c) 2002-2003 Aaron Robinson <caustik@caustik.com>
|
||||
// *
|
||||
// * All rights reserved
|
||||
// *
|
||||
// ******************************************************************
|
||||
#include "strikebox/iovec.h"
|
||||
|
||||
#include <cassert>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
|
||||
#ifndef MIN
|
||||
#define MIN(a, b) (((a) < (b)) ? (a) : (b))
|
||||
#endif
|
||||
|
||||
namespace strikebox {
|
||||
|
||||
void IoVecReset(IOVector* qiov) {
|
||||
assert(qiov->AllocNumber != -1);
|
||||
|
||||
qiov->IoVecNumber = 0;
|
||||
qiov->Size = 0;
|
||||
}
|
||||
|
||||
void IoVecAdd(IOVector* qiov, void* base, size_t len) {
|
||||
assert(qiov->AllocNumber != -1);
|
||||
|
||||
if (qiov->IoVecNumber == qiov->AllocNumber) {
|
||||
qiov->AllocNumber = 2 * qiov->AllocNumber + 1;
|
||||
qiov->IoVecStruct = static_cast<IoVec*>(std::realloc(qiov->IoVecStruct, qiov->AllocNumber * sizeof(IOVector)));
|
||||
}
|
||||
qiov->IoVecStruct[qiov->IoVecNumber].Iov_Base = base;
|
||||
qiov->IoVecStruct[qiov->IoVecNumber].Iov_Len = len;
|
||||
qiov->Size += len;
|
||||
++qiov->IoVecNumber;
|
||||
}
|
||||
|
||||
// This takes "iov_cnt" of "iov" buffers as input and copies sequentially their contents to the "buf" output buffer.
|
||||
// "offset" indicates the offset inside "bytes" (total lenght of "iov" buffers) where the copy is going to start.
|
||||
// "offset" must be less than "bytes" or else the assertion will fail. "done" is the number of bytes actually copied
|
||||
size_t IoVecTobuffer(const IoVec* iov, const unsigned int iov_cnt, size_t offset, void* buf, size_t bytes) {
|
||||
size_t done;
|
||||
unsigned int i;
|
||||
for (i = 0, done = 0; (offset || done < bytes) && i < iov_cnt; i++) {
|
||||
if (offset < iov[i].Iov_Len) {
|
||||
size_t len = MIN(iov[i].Iov_Len - offset, bytes - done);
|
||||
std::memcpy(static_cast<uint8_t*>(buf) + done, static_cast<uint8_t*>(iov[i].Iov_Base) + offset, len);
|
||||
done += len;
|
||||
offset = 0;
|
||||
}
|
||||
else {
|
||||
offset -= iov[i].Iov_Len;
|
||||
}
|
||||
}
|
||||
assert(offset == 0);
|
||||
return done;
|
||||
}
|
||||
|
||||
// This does the opposite of IoVecTobuffer: it takes "buf" as input and copies sequentially its contents to the
|
||||
// "iov" output buffers.
|
||||
size_t IoVecFromBuffer(const IoVec* iov, unsigned int iov_cnt, size_t offset, void* buf, size_t bytes) {
|
||||
size_t done;
|
||||
unsigned int i;
|
||||
for (i = 0, done = 0; (offset || done < bytes) && i < iov_cnt; i++) {
|
||||
if (offset < iov[i].Iov_Len) {
|
||||
size_t len = MIN(iov[i].Iov_Len - offset, bytes - done);
|
||||
memcpy(static_cast<uint8_t*>(iov[i].Iov_Base) + offset, static_cast<uint8_t*>(buf) + done, len);
|
||||
done += len;
|
||||
offset = 0;
|
||||
}
|
||||
else {
|
||||
offset -= iov[i].Iov_Len;
|
||||
}
|
||||
}
|
||||
assert(offset == 0);
|
||||
return done;
|
||||
}
|
||||
|
||||
}
|
|
@ -570,28 +570,7 @@ EmulatorStatus Xbox::InitHardware() {
|
|||
}
|
||||
|
||||
EmulatorStatus Xbox::InitDebugger() {
|
||||
// GDB Server
|
||||
if (m_settings.gdb_enable) {
|
||||
m_gdb = new GdbServer(m_vm->get().GetVirtualProcessor(0)->get(), "127.0.0.1", 9269);
|
||||
// TODO: handle result properly
|
||||
int result = m_gdb->Initialize();
|
||||
if (result) {
|
||||
return EMUS_INIT_DEBUGGER_FAILED;
|
||||
}
|
||||
|
||||
// Allow debugging before running so client can setup breakpoints, etc
|
||||
log_debug("Starting GDB Server\n");
|
||||
m_gdb->WaitForConnection();
|
||||
m_gdb->Debug(1);
|
||||
}
|
||||
|
||||
/*HardwareBreakpoints bps = { 0 };
|
||||
bps.bp[0].globalEnable = true;
|
||||
bps.bp[0].address = 0x80016756;
|
||||
bps.bp[0].length = HWBP_LENGTH_1_BYTE;
|
||||
bps.bp[0].trigger = HWBP_TRIGGER_EXECUTION;
|
||||
vp.SetHardwareBreakpoints(bps);*/
|
||||
|
||||
// TODO: Start GDB server
|
||||
return EMUS_OK;
|
||||
}
|
||||
|
||||
|
@ -925,7 +904,7 @@ void Xbox::Cleanup() {
|
|||
}
|
||||
|
||||
if (m_settings.gdb_enable) {
|
||||
m_gdb->Shutdown();
|
||||
// TODO: Stop GDB server
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue