Get rid of most Cxbx-Reloaded, XQEMU and GPL code

This commit is contained in:
StrikerX3 2019-10-26 13:41:11 -03:00
parent 9f86a0812b
commit dc2ee11219
33 changed files with 65 additions and 12688 deletions

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -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_ */

View file

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

View file

@ -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() {

View file

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

View file

@ -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() {

View file

@ -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() {

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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