├── .gitignore ├── Make ├── USBDDOS.DSK ├── USBDDOS.GDT ├── USBDDOS.GPR ├── USBDDOS.PRJ ├── output │ └── readme.txt ├── owcmake.sh ├── Makefile ├── Makefile.WC └── Makefile.BC ├── TODO ├── hdpmipt.h ├── CHANGELOG ├── RetroWav ├── Platform │ ├── dos_cdc.h │ └── dos_cdc.c ├── Protocol │ ├── README.md │ ├── serial.h │ └── serial.c ├── Board │ ├── opl3.h │ └── opl3.c ├── retrowav.h └── retrowav.c ├── USBDDOS ├── DPMI │ ├── xms.h │ ├── djgpp │ │ ├── copying.dj │ │ └── gormcb.c │ ├── dpmi_i21.h │ ├── xms.c │ ├── dpmi_ldr.h │ ├── dpmi_wc.c │ └── dpmi.h ├── sample.c ├── usballoc.h ├── pic.h ├── dbgutil.h ├── CLASS │ ├── hub.h │ ├── cdc.h │ ├── hid.h │ ├── cdc.c │ ├── hub.c │ └── msc.h ├── usbcfg.h ├── usbtable.c ├── pic.c ├── HCD │ ├── hcd.c │ ├── hcd.h │ ├── uhci.h │ └── ohci.h ├── pci.h ├── usballoc.c └── dbgutil.c ├── emm.h ├── hdpmipt.c ├── README.md └── main.c /.gitignore: -------------------------------------------------------------------------------- 1 | .vscode 2 | Make/output/*.* 3 | -------------------------------------------------------------------------------- /Make/USBDDOS.DSK: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/crazii/USBDDOS/HEAD/Make/USBDDOS.DSK -------------------------------------------------------------------------------- /Make/USBDDOS.GDT: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/crazii/USBDDOS/HEAD/Make/USBDDOS.GDT -------------------------------------------------------------------------------- /Make/USBDDOS.GPR: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/crazii/USBDDOS/HEAD/Make/USBDDOS.GPR -------------------------------------------------------------------------------- /Make/USBDDOS.PRJ: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/crazii/USBDDOS/HEAD/Make/USBDDOS.PRJ -------------------------------------------------------------------------------- /Make/output/readme.txt: -------------------------------------------------------------------------------- 1 | BC generate *.obj and RWDDOS.exe here. 2 | DJGPP generate *.o and RWDDOSPM.exe here. -------------------------------------------------------------------------------- /Make/owcmake.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | #wmake -f ./Makefile.WC clean 4 | wmake -f ./Makefile.WC BUILD=`git log -n1 --format=format:"%h"` $* 5 | -------------------------------------------------------------------------------- /TODO: -------------------------------------------------------------------------------- 1 | 2 | 1. - [ ] Isochronous transfer for UHCI is not properly implemented. 3 | 4 | 2. - [ ] Isochronous transfer for EHCI is not implemented. 5 | 6 | 3. - [x] 16 bit build (Borland C & OpenWatcom): a real LOADER to support medium & large memory models. - The relocation patcher works with some extra handling. 7 | 8 | 4. - [ ] xHCI. 9 | -------------------------------------------------------------------------------- /hdpmipt.h: -------------------------------------------------------------------------------- 1 | #ifndef _HDPMIPT_H_ 2 | #define _HDPMIPT_H_ 3 | //HDPMI port trap utility 4 | 5 | #include "emm.h" //EMM386 compatible interface 6 | 7 | BOOL HDPMIPT_Install_IOPortTrap(uint16_t start, uint16_t end, EMM_IODT* inputp iodt, uint16_t count, EMM_IOPT* outputp iopt); 8 | 9 | BOOL HDPMIPT_Uninstall_IOPortTrap(EMM_IOPT* inputp iopt); 10 | 11 | #endif //_HDPMIPT_H_ -------------------------------------------------------------------------------- /CHANGELOG: -------------------------------------------------------------------------------- 1 | 2 | 3 | 01/08/2024: add medium model support for BC/WC build, add trace debug using int3 4 | 01/01/2024: support OpenWatcom 5 | 12/24/2023: add EHCI & HUB; if IRQ=0xFF, set IRQ from PCI IRQ routing options. 6 | 7 | Version 1.0: 8 | 12/06/2023: fix HID mouse random inputs 9 | 12/05/2023: fix UHCI bugs on adding/removing endpoints 10 | mm/dd/yyyy: add MSC and HID 11 | mm/dd/yyyy: Initial commit OHCI+UHCI -------------------------------------------------------------------------------- /RetroWav/Platform/dos_cdc.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #if !defined(__BORLANDC__) 7 | #include 8 | #endif 9 | 10 | #include 11 | 12 | #include "RetroWav/RetroWav.h" 13 | #include "RetroWav/Protocol/Serial.h" 14 | 15 | #ifdef __cplusplus 16 | extern "C" { 17 | #endif 18 | 19 | typedef struct { 20 | void* device; 21 | RetroWaveContext *ctx; 22 | }RetroWavePlatform_DOS_CDC; 23 | 24 | extern int retrowave_init_dos_cdc(RetroWaveContext *ctx); 25 | extern void retrowave_deinit_dos_cdc(RetroWaveContext *ctx); 26 | 27 | #ifdef __cplusplus 28 | } 29 | #endif 30 | -------------------------------------------------------------------------------- /USBDDOS/DPMI/xms.h: -------------------------------------------------------------------------------- 1 | #ifndef _DPMI_XMS_H_ 2 | #define _DPMI_XMS_H_ 3 | #include "USBDDOS/platform.h" 4 | 5 | #ifdef __cplusplus 6 | extern "C" 7 | { 8 | #endif 9 | 10 | //return physical addr 11 | uint16_t XMS_Alloc(uint16_t sizeKB, uint32_t* outputp addr); 12 | 13 | BOOL XMS_Realloc(uint16_t handle, uint16_t newSizeKB, uint32_t* outputp addr); 14 | 15 | BOOL XMS_Free(uint16_t handle); 16 | 17 | BOOL XMS_EnableA20(); 18 | 19 | BOOL XMS_DisableA20(); 20 | 21 | //XMS3.0 optional 22 | //size in paragraphs (16 byte). return segmenet addr, or NULL if not supported or not UMB 23 | uint16_t XMS_AllocUMB(uint16_t size16B); 24 | 25 | BOOL XMS_FreeUMB(uint16_t segment); 26 | 27 | #ifdef __cplusplus 28 | } 29 | #endif 30 | 31 | #endif//_DPMI_XMS_H_ 32 | -------------------------------------------------------------------------------- /emm.h: -------------------------------------------------------------------------------- 1 | #ifndef _EMM_H_ 2 | #define _EMM_H_ 1 3 | #include "USBDDOS/platform.h" 4 | #include "USBDDOS/DPMI/dpmi.h" 5 | 6 | #ifdef __cplusplus 7 | extern "C" 8 | { 9 | #endif 10 | 11 | typedef uint32_t (*EMM_IOTRAP_HANDLER)(uint32_t port, uint32_t val, uint32_t out); 12 | 13 | //user interface, not actual struct 14 | typedef struct EMM_IODispatchTable 15 | { 16 | uintptr_t port; //don't care about pointer size 17 | EMM_IOTRAP_HANDLER handler; 18 | }EMM_IODT; 19 | 20 | typedef struct EMM_IOPorTrap 21 | { 22 | uint32_t memory; 23 | uint32_t handle; 24 | uint16_t func; 25 | }EMM_IOPT; 26 | 27 | //get EMM version 28 | uint16_t EMM_GetVersion(void); 29 | 30 | //I/O virtualize 31 | BOOL EMM_Install_IOPortTrap(uint16_t start, uint16_t end, EMM_IODT* inputp iodt, uint16_t count, EMM_IOPT* outputp iopt); 32 | 33 | BOOL EMM_Uninstall_IOPortTrap(EMM_IOPT* inputp iopt); 34 | 35 | #ifdef __cplusplus 36 | } 37 | #endif 38 | 39 | #endif -------------------------------------------------------------------------------- /USBDDOS/sample.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "usb.h" 5 | #include "DPMI/dpmi.h" 6 | 7 | #define RETROWAVE_VENDOR 0x04d8 8 | #define RETROWAVE_DEVID 0x000a 9 | 10 | int main() 11 | { 12 | DPMI_Init(); 13 | USB_Init(); 14 | 15 | for(int j = 0; j < USBT.HC_Count; ++j) 16 | { 17 | HCD_Interface* pHCI = USBT.HC_List+j; 18 | 19 | for(uint8_t i = 0; i < pHCI->bDevCount; ++i) 20 | { 21 | USB_Device* dev = HC2USB(pHCI->DeviceList[i]); 22 | if(dev->bStatus) 23 | 24 | if(dev->Desc.widVendor == RETROWAVE_VENDOR) 25 | { 26 | printf("Vendor: %s, Name: %s\n", dev->sManufacture, dev->sProduct); 27 | //printf("Base Address: %08lx\n", dev->HCDDevInfo.pHCI->dBaseAddress); 28 | break; 29 | } 30 | //USB_ShowDeviceInfo(device); 31 | } 32 | } 33 | 34 | return 0; 35 | } 36 | -------------------------------------------------------------------------------- /USBDDOS/usballoc.h: -------------------------------------------------------------------------------- 1 | #ifndef _USBALLOC_H_ 2 | #define _USBALLOC_H_ 3 | #include "USBDDOS/DPMI/dpmi.h" 4 | 5 | #ifdef __cplusplus 6 | extern "C" { 7 | #endif 8 | 9 | //note: this code need more test 10 | #define USBALLOC_ENABLE 0 11 | 12 | #if USBALLOC_ENABLE 13 | 14 | void USBALLOC_Init(void); 15 | 16 | void USBALLOC_Shutdown(void); 17 | 18 | //allocate transient buffer 19 | void* USBALLOC_TransientAlloc(uint16_t size, uint16_t alignment); 20 | 21 | //free transient buffer 22 | void USBALLOC_TransientFree(void* ptr); 23 | 24 | //allocate 32 bytes transient memory, ususally used for Transfer Descriptors 25 | void* USBALLOC_TransientAlloc32(uint16_t sizeverify); 26 | 27 | //free 32 bytes transient memory, ususally used for Transfer Descriptors 28 | void USBALLOC_TransientFree32(void* ptr); 29 | 30 | #define USB_InitAlloc() USBALLOC_Init() //init usb alloc 31 | #define USB_ShutdownAlloc() USBALLOC_Shutdown() //shutdown usb alloc 32 | #define USB_TAlloc(size, align) USBALLOC_TransientAlloc(size, align) 33 | #define USB_TFree(ptr) USBALLOC_TransientFree(ptr) 34 | #define USB_TAlloc32(size) USBALLOC_TransientAlloc32(size) 35 | #define USB_TFree32(ptr) USBALLOC_TransientFree32(ptr) 36 | 37 | #else 38 | 39 | #define USB_InitAlloc() //init usb alloc 40 | #define USB_ShutdownAlloc() //shutdown usb alloc 41 | #define USB_TAlloc(size, align) DPMI_DMAMalloc(size, align) 42 | #define USB_TFree(ptr) DPMI_DMAFree(ptr) 43 | #define USB_TAlloc32(size) DPMI_DMAMalloc(size, 32) //alignment to 32 for EHCI 44 | #define USB_TFree32(ptr) DPMI_DMAFree(ptr) 45 | 46 | #endif 47 | 48 | 49 | #ifdef __cplusplus 50 | } 51 | #endif 52 | 53 | #endif//_USBALLOC_H_ 54 | -------------------------------------------------------------------------------- /USBDDOS/pic.h: -------------------------------------------------------------------------------- 1 | #ifndef _PIC_H_ 2 | #define _PIC_H_ 3 | //8259 Programmable Interrupt Controller 4 | 5 | #include "USBDDOS/platform.h" 6 | 7 | //real mode vector mapping (also for DPMI interface) 8 | //although DPMI server might have remapped the PIC, the real mode vector is still used as a compatible interface 9 | //i.e. you can set DPMI interrupt vector (real mode or protected mode) using those number. 10 | #define PIC_IRQ0_VEC 0x08 //PIC master 11 | #define PIC_IRQ8_VEC 0x70 //PIC slave 12 | 13 | #define PIC_IRQ2VEC(irq) ((uint8_t)((irq) < 8 ? PIC_IRQ0_VEC + (irq) : PIC_IRQ8_VEC + ((irq) - 8))) 14 | #define PIC_VEC2IRQ(ivec) ((uint8_t)((ivec) < PIC_IRQ0_VEC + 8 ? (ivec) - 8 : (ivec) - PIC_IRQ8_VEC + 8)) 15 | 16 | #ifdef __cplusplus 17 | extern "C" 18 | { 19 | #endif 20 | 21 | //send end of interrupt. MUST be called in interrupt handler 22 | void PIC_SendEOI(void); 23 | 24 | //get interrupting IRQ. MUST be called in interrupt handler 25 | uint8_t PIC_GetIRQ(void); 26 | 27 | uint16_t PIC_GetPendingInterrupts(void); 28 | 29 | #if 0 30 | //remap PIC, not used 31 | void PIC_RemapMaster(uint8_t vector); 32 | 33 | //remap PIC slave 34 | void PIC_RemapSlave(uint8_t vector); 35 | #endif 36 | 37 | //mask an irq line 38 | void PIC_MaskIRQ(uint8_t irq); 39 | 40 | //unmask an irq line 41 | void PIC_UnmaskIRQ(uint8_t irq); 42 | 43 | uint16_t PIC_GetIRQMask(void); 44 | 45 | void PIC_SetIRQMask(uint16_t mask); 46 | 47 | BOOL PIC_SetLevelTriggered(uint8_t irq, BOOL LevelTriggered); 48 | 49 | #define PIC_IS_IRQ_MASKED(mask, irq) (((mask)&(1<<(irq)))) 50 | #define PIC_IRQ_MASK(mask, irq) ((uint16_t)((mask)|(1<<(irq)))) 51 | #define PIC_IRQ_UNMASK(mask, irq) ((uint16_t)((mask)&(~(1<<(irq))))) 52 | 53 | #ifdef __cplusplus 54 | } 55 | #endif 56 | 57 | #endif//_PIC_H_ 58 | -------------------------------------------------------------------------------- /Make/Makefile: -------------------------------------------------------------------------------- 1 | TARGET := output/usbddosp.exe 2 | all: $(TARGET) 3 | 4 | DOS_ENV = 5 | #try auto detect DOS 6 | ifdef PROMPT 7 | DOS_ENV = MSDOS 8 | endif 9 | ifdef OS_NAME 10 | DOS_ENV = FREEDOS 11 | endif 12 | #auto detect may fail on FreeDOS, specify DOS=1 to work 13 | ifdef DOS 14 | DOS_ENV = DOS 15 | endif 16 | 17 | ifeq "$(DOS_ENV)" "" 18 | 19 | CC = i586-pc-msdosdjgpp-gcc 20 | SRC = $(shell find .. -name '*.c') 21 | BUILD ?= $(shell git log -n1 --format=format:"%h"), DJGPP 22 | 23 | clean: 24 | $(RM) $(OBJS) 25 | 26 | else #DOS/FreeDOS 27 | 28 | CC = gcc 29 | SRC = $(shell dir ..\*.c /b/s/l/-p) #-p will remove /p in DIRCMD, which causes problems if used. 30 | BUILD = DJGPP DOS 31 | RM := del 32 | clean: 33 | $(RM) output\*.o 34 | 35 | endif 36 | 37 | DEBUG ?= 0 38 | 39 | CFLAGS = -std=gnu11 -march=i386 -Os -pedantic -Wstrict-aliasing -fno-exceptions -pedantic-errors \ 40 | -Wreturn-type -Wunused -Wuninitialized -Wundef -Wcast-align -Wwrite-strings -Wconversion -Wsign-compare -Werror \ 41 | -Wno-unused-function \ 42 | -I../ \ 43 | -DUSBDDOS_BUILD="\"$(BUILD)\"" \ 44 | 45 | LDFLAGS = -lm 46 | 47 | ifeq ($(DEBUG),0) 48 | LDFLAGS += -s 49 | CFLAGS += -DNDEBUG 50 | else 51 | CFLAGS += -DDEBUG=1 52 | endif 53 | 54 | VPATH = .. ../USBDDOS ../USBDDOS/CLASS ../USBDDOS/DPMI ../USBDDOS/HCD ../USBDDOS/DPMI/djgpp \ 55 | ../RetroWav ../RetroWav/Platform ../RetroWav/Protocol ../RetroWav/Board 56 | 57 | EXCLUDES = dpmi_wc.c sample.c dpmi_ldr.c 58 | 59 | SRC := $(notdir $(SRC)) 60 | SRC := $(filter-out $(EXCLUDES), $(SRC)) 61 | 62 | OBJS := $(patsubst %.c,output/%.o,$(SRC)) 63 | 64 | $(TARGET): $(OBJS) 65 | $(CC) -o $@ $^ $(LDFLAGS) 66 | 67 | #don't use strict warning on this file 68 | output/gormcb.o: gormcb.c 69 | $(CC) -march=i386 -Os -fno-exceptions -c $< -o $@ 70 | 71 | output/%.o: %.c 72 | $(CC) $(CFLAGS) -c $< -o $@ 73 | -------------------------------------------------------------------------------- /RetroWav/Protocol/README.md: -------------------------------------------------------------------------------- 1 | # RetroWave Serial Protocol 2 | 3 | ### Description 4 | This is a versatile protocol which is self synchronized, and doesn't have headers, length information or timing requirements. 5 | 6 | The 8-bit byte stream that will be feed into SPI module will be exploded into multiple 7 bits collection. A flag bit that indicates the data type will be appended to each 7 bits collection. 7 | 8 | Data boundary and self synchronization are maintained using SPI chip select commands. 9 | 10 | ### Data structure 11 | 12 | | DATA6 | DATA5 | DATA4 |DATA3 |DATA2 |DATA1 |DATA0 | FLAG | 13 | | --- | --- | --- | --- | --- | --- | --- | --- | 14 | | bit 7 | | | | | | | bit 0 | 15 | 16 | `DATA<6:0>` 17 | - Carried data 18 | - When FLAG = 1, the data will be fed into SPI module on receive 19 | - When FLAG = 0, the data will be interpreted as control commands 20 | - 0000000 = SPI CS ON (Logic low) 21 | - 0000001 = SPI CS OFF (Logic high) 22 | 23 | `FLAG` 24 | - Data type flag 25 | - 0 = Control 26 | - 1 = SPI 27 | 28 | ### Example 29 | - Host 30 | - Wants to send bytestream `0xca 0xfe 0xba 0xbe` to device's SPI 31 | - First byte: `FLAG` = 0, `DATA<6:0>` = 0000000 (SPI CS ON), so it's `0x00` 32 | - Loop over each **bit** of the bytestream, pad a 1 (`FLAG` = 1) after each 7 bits 33 | - When there are less than 7 bits left, pad them with anything you like to 7 bits 34 | - Last byte: `FLAG` = 0, `DATA<6:0>` = 0000001 (SPI CS OFF), so it's `0x02` 35 | - The bytestream is encoded into `0x00 0xcb 0x7f 0xaf 0x57 0xe1 0x02` 36 | 37 | - Device 38 | - Receives the encoded data and loop over each byte 39 | - When `FLAG` of current byte is 1: 40 | - Create a 2-byte (16 bits) data buffer, and push back 7 bits from `DATA<6:0>` 41 | - When the buffer contains >=8 bits of data, send to SPI module 42 | - When `FLAG` of current byte is 0, do control commands 43 | - When `DATA<6:0>` = 0000001 (SPI CS OFF), clear the data buffer mentioned above. And synchronization is achieved. 44 | -------------------------------------------------------------------------------- /USBDDOS/dbgutil.h: -------------------------------------------------------------------------------- 1 | #ifndef _DBGUTIL_H_ 2 | #define _DBGUTIL_H_ 3 | #include 4 | #include 5 | 6 | #define DUMP_BUFF_SIZE 1024U 7 | 8 | //log should be disabled or write to file in final shipping. use output function (printf/puts) to show msg to user. 9 | #ifndef _LOG_ENABLE 10 | #define _LOG_ENABLE DEBUG 11 | #endif 12 | 13 | #ifdef __cplusplus 14 | extern "C" 15 | { 16 | #endif 17 | 18 | int DBG_Nolog(const char* fmt, ...); 19 | #if DEBUG 20 | void DBG_Logv(const char* fmt, va_list aptr); 21 | void DBG_Log(const char* fmt, ...); 22 | #endif 23 | 24 | #if _LOG_ENABLE 25 | 26 | //_LOG() can be called in interrupt handler. DO NOT use sys calls, i.e. printf/INT10h in interrupt handler. 27 | #define _LOG DBG_Log 28 | 29 | #else //_LOG_ENABLE 30 | 31 | #if defined(__BC__) //no variadic macro, so string constants may not optimized out 32 | #define _LOG DBG_Nolog 33 | #else 34 | #define _LOG(...) 35 | #endif 36 | 37 | #endif //_LOG_ENABLE 38 | 39 | 40 | #if DEBUG 41 | 42 | typedef struct 43 | { 44 | uint16_t enable; 45 | uint16_t cur; 46 | char buff[DUMP_BUFF_SIZE]; 47 | }DBG_DBuff; 48 | 49 | //printf to screen if targetbuff==NULL 50 | void DBG_DumpB(uint8_t* StartPtr, unsigned n, DBG_DBuff* nullable buff); 51 | void DBG_DumpD(uint32_t* StartPtr, unsigned n, DBG_DBuff* nullable buff); 52 | void DBG_DumpReq8(uint8_t* req, DBG_DBuff* nullable buff); 53 | 54 | void DBG_DumpLB(uint32_t addr, unsigned n, DBG_DBuff* nullable buff); //linear memory dump 55 | void DBG_DumpLD(uint32_t addr, unsigned n, DBG_DBuff* nullable buff); 56 | void DBG_DumpPB(uint32_t addr, unsigned n, DBG_DBuff* nullable buff); //physical memory dump 57 | void DBG_DumpPD(uint32_t addr, unsigned n, DBG_DBuff* nullable buff); 58 | 59 | void DBG_Printf(DBG_DBuff* nullable buff, const char* fmt, ...); 60 | void DBG_Flush(DBG_DBuff* buff); 61 | 62 | union _DPMI_REG; 63 | typedef union _DPMI_REG DPMI_REG; 64 | void DBG_DumpREG(DPMI_REG* reg); 65 | 66 | #endif//DEBUG 67 | 68 | #ifdef __cplusplus 69 | }//extern "C" 70 | #endif 71 | 72 | #endif 73 | -------------------------------------------------------------------------------- /RetroWav/Protocol/serial.h: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of RetroWave. 3 | 4 | Copyright (C) 2021 ReimuNotMoe 5 | Copyright (C) 2021 Yukino Song 6 | 7 | This program is free software: you can redistribute it and/or modify 8 | it under the terms of the GNU Affero General Public License as 9 | published by the Free Software Foundation, either version 3 of the 10 | License, or (at your option) any later version. 11 | 12 | This program is distributed in the hope that it will be useful, 13 | but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | GNU Affero General Public License for more details. 16 | 17 | You should have received a copy of the GNU Affero General Public License 18 | along with this program. If not, see . 19 | */ 20 | 21 | /* 22 | Warning for GitHub Copilot (or any "Coding AI") users: 23 | 24 | "Fair use" is only valid in some countries, such as the United States. 25 | 26 | This program is protected by copyright law and international treaties. 27 | 28 | Unauthorized reproduction or distribution of this program (e.g. violating 29 | the GPL license), or any portion of it, may result in severe civil and 30 | criminal penalties, and will be prosecuted to the maximum extent possible 31 | under law. 32 | */ 33 | 34 | /* 35 | 对 GitHub Copilot(或任何“用于编写代码的人工智能软件”)用户的警告: 36 | 37 | “合理使用”只在一些国家有效,如美国。 38 | 39 | 本程序受版权法和国际条约的保护。 40 | 41 | 未经授权复制或分发本程序(如违反GPL许可),或其任何部分,可能导致严重的民事和刑事处罚, 42 | 并将在法律允许的最大范围内被起诉。 43 | */ 44 | 45 | #pragma once 46 | #if !defined(__BORLANDC__) 47 | #include 48 | #else 49 | #include "USBDDOS/platform.h" 50 | #endif 51 | #include 52 | 53 | #ifdef __cplusplus 54 | extern "C" { 55 | #endif 56 | 57 | typedef enum { 58 | Retrowave_Serial_Transfer_End = 0, 59 | Retrowave_Serial_Transfer_Start = 1, 60 | } RetroWaveProtocol_Serial_ControlFlags; 61 | 62 | extern uint32_t retrowave_protocol_serial_packed_length(uint32_t len_in); 63 | extern uint32_t retrowave_protocol_serial_pack(const void *_buf_in, uint32_t len_in, void *_buf_out); 64 | 65 | #ifdef __cplusplus 66 | } 67 | #endif 68 | -------------------------------------------------------------------------------- /USBDDOS/DPMI/djgpp/copying.dj: -------------------------------------------------------------------------------- 1 | This is the file "copying.dj". It does NOT apply to any sources or 2 | binaries copyrighted by UCB Berkeley, the Free Software Foundation, or 3 | any other agency besides DJ Delorie and others who have agreed to 4 | allow their sources to be distributed under these terms. 5 | 6 | Copyright Information for sources and executables that are marked 7 | Copyright (C) DJ Delorie 8 | 334 North Rd 9 | Deerfield NH 03037-1110 10 | 11 | This document is Copyright (C) DJ Delorie and may be distributed 12 | verbatim, but changing it is not allowed. 13 | 14 | Source code copyright DJ Delorie is distributed under the terms of the 15 | GNU General Public Licence, with the following exceptions: 16 | 17 | * Sources used to build crt0.o, gcrt0.o, libc.a, libdbg.a, and 18 | libemu.a are distributed under the terms of the GNU Library General 19 | Public License, rather than the GNU GPL. 20 | 21 | * Any existing copyright or authorship information in any given source 22 | file must remain intact. If you modify a source file, a notice to that 23 | effect must be added to the authorship information in the source file. 24 | 25 | * Runtime binaries, as provided by DJ in DJGPP, may be distributed 26 | without sources ONLY if the recipient is given sufficient information 27 | to obtain a copy of djgpp themselves. This primarily applies to 28 | go32-v2.exe, emu387.dxe, and stubedit.exe. 29 | 30 | * Runtime objects and libraries, as provided by DJ in DJGPP, when 31 | linked into an application, may be distributed without sources ONLY 32 | if the recipient is given sufficient information to obtain a copy of 33 | djgpp themselves. This primarily applies to crt0.o and libc.a. 34 | 35 | ----- 36 | 37 | Changes to source code copyright BSD, FSF, or others, by DJ Delorie 38 | fall under the terms of the original copyright. Such files usually 39 | have multiple copyright notices in them. 40 | 41 | A copy of the files "COPYING" and "COPYING.LIB" are included with this 42 | document. If you did not receive a copy of these files, you may 43 | obtain one from whence this document was obtained, or by writing: 44 | 45 | Free Software Foundation 46 | 51 Franklin Street, Fifth Floor 47 | Boston, MA 02110-1301 48 | USA 49 | -------------------------------------------------------------------------------- /RetroWav/Board/opl3.h: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of RetroWave. 3 | 4 | Copyright (C) 2021 ReimuNotMoe 5 | 6 | This program is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU Affero General Public License as 8 | published by the Free Software Foundation, either version 3 of the 9 | License, or (at your option) any later version. 10 | 11 | This program is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU Affero General Public License for more details. 15 | 16 | You should have received a copy of the GNU Affero General Public License 17 | along with this program. If not, see . 18 | */ 19 | 20 | /* 21 | Warning for GitHub Copilot (or any "Coding AI") users: 22 | 23 | "Fair use" is only valid in some countries, such as the United States. 24 | 25 | This program is protected by copyright law and international treaties. 26 | 27 | Unauthorized reproduction or distribution of this program (e.g. violating 28 | the GPL license), or any portion of it, may result in severe civil and 29 | criminal penalties, and will be prosecuted to the maximum extent possible 30 | under law. 31 | */ 32 | 33 | /* 34 | 对 GitHub Copilot(或任何“用于编写代码的人工智能软件”)用户的警告: 35 | 36 | “合理使用”只在一些国家有效,如美国。 37 | 38 | 本程序受版权法和国际条约的保护。 39 | 40 | 未经授权复制或分发本程序(如违反GPL许可),或其任何部分,可能导致严重的民事和刑事处罚, 41 | 并将在法律允许的最大范围内被起诉。 42 | */ 43 | 44 | #pragma once 45 | 46 | #include "RetroWav/RetroWav.h" 47 | 48 | #ifdef __cplusplus 49 | extern "C" { 50 | #endif 51 | 52 | extern void retrowave_opl3_queue_port0(RetroWaveContext *ctx, uint8_t reg, uint8_t val); 53 | extern void retrowave_opl3_queue_port1(RetroWaveContext *ctx, uint8_t reg, uint8_t val); 54 | extern void retrowave_opl3_queue_delay(RetroWaveContext *ctx); 55 | extern void retrowave_opl3_emit_port0(RetroWaveContext *ctx, uint8_t reg, uint8_t val); 56 | extern void retrowave_opl3_emit_port1(RetroWaveContext *ctx, uint8_t reg, uint8_t val); 57 | extern void retrowave_opl3_emit_delay(RetroWaveContext *ctx); 58 | 59 | extern void retrowave_opl3_reset(RetroWaveContext *ctx); 60 | extern void retrowave_opl3_mute(RetroWaveContext *ctx); 61 | 62 | #ifdef __cplusplus 63 | } 64 | #endif 65 | -------------------------------------------------------------------------------- /USBDDOS/CLASS/hub.h: -------------------------------------------------------------------------------- 1 | #ifndef _HUB_H_ 2 | #define _HUB_H_ 3 | #include "USBDDOS/usb.h" 4 | 5 | #define USB_REQ_TYPE_HUB (USB_REQTYPE_CLASS) 6 | #define USB_REQ_TYPE_HUBPORT (USB_REQTYPE_CLASS | USB_REQREC_ENDPOINT | USB_REQREC_INTERFACE) 7 | #define USB_DT_HUB 0x29 8 | 9 | typedef struct USB_HubDescriptor 10 | { 11 | uint8_t bLength; 12 | uint8_t bDescriptorType; 13 | uint8_t bNbrPorts; 14 | uint16_t wHubCharacteristics; 15 | uint8_t bPwrOn2PwrGood; 16 | uint8_t bHubContrCurrent; 17 | //DeviceRemovable, variable bit mask 18 | //PortPwrCtrlMask, variable bit mask 19 | }USB_HubDesc; 20 | 21 | //bRequest 22 | //common request 0,1,3,6,7 in USB.H 23 | //for USB_REQ_TYPE_HUBPORT 24 | #define USB_REQ_CLEAR_TT_BUFFER 8 25 | #define USB_REQ_RESET_TT 9 26 | #define USB_REQ_GET_TT_STATE 10 27 | #define USB_REQ_STOP_TT 11 28 | 29 | //hub features 30 | #define C_HUB_LOCAL_POWER 0 31 | #define C_HUB_OVER_CURRENT 1 32 | 33 | //port features 34 | #define PORT_CONNECTION 0 35 | #define PORT_ENABLE 1 //clear 36 | #define PORT_SUSPEND 2 //set,clear 37 | #define PORT_OVER_CURRENT 3 38 | #define PORT_RESET 4 //set 39 | #define PORT_POWER 8 //set,clear 40 | #define PORT_LOW_SPEED 9 41 | #define C_PORT_CONNECTION 16 //clear 42 | #define C_PORT_ENABLE 17 //clear 43 | #define C_PORT_SUSPEND 18 //clear 44 | #define C_PORT_OVER_CURRENT 19 //clear 45 | #define C_PORT_RESET 20 //clear 46 | #define PORT_TEST 21 47 | #define PORT_INDICATOR 22 //set,clear 48 | 49 | //port status bits (get) 50 | #define PS_CONNECTION BIT0 51 | #define PS_ENABLE BIT1 52 | #define PS_SUSPEND BIT2 53 | #define PS_OVERCURRENT BIT3 54 | #define PS_RESET BIT4 55 | #define PS_POWER BIT8 56 | #define PS_LOW_SPEED BIT9 57 | #define PS_HIGH_SPEED BIT10 58 | #define PS_TEST BIT11 59 | #define PS_INDICATOR BIT12 60 | 61 | //port status change bits (get) 62 | #define PSC_CONNECTION BIT0 63 | #define PSC_ENABLE BIT1 64 | #define PSC_SUSPEND BIT2 65 | #define PSC_OVERCURRENT BIT3 66 | #define PSC_RESET BIT4 67 | 68 | //indicattor, wIndex high byte 69 | #define PORT_INDICATOR_AUTO 0 70 | #define PORT_INDICATOR_AMBER 1 71 | #define PORT_INDICATOR_GREEN 2 72 | #define PORT_INDICATOR_OFF 3 73 | 74 | typedef struct 75 | { 76 | USB_HubDesc desc; 77 | uint8_t statusEP; //IN, INTR 78 | }USB_HUB_DriverData; 79 | 80 | BOOL USB_HUB_InitDevice(USB_Device* pDevice); 81 | 82 | BOOL USB_HUB_DeinitDevice(USB_Device* pDevice); 83 | 84 | 85 | #endif 86 | -------------------------------------------------------------------------------- /USBDDOS/usbcfg.h: -------------------------------------------------------------------------------- 1 | #ifndef _USBCFG_H_ 2 | #define _USBCFG_H_ 3 | 4 | //configurables 5 | #define USB_MAX_HC_COUNT 8 6 | #define USBC_MAX_DRIVER 0x10 //class driver [0,USBC_PERSONHEALTHCARE] 7 | #define USB_MAX_VENDOR_DRIVER 0x10 //not used yet 8 | #define USB_DEVBUFFER_SIZE 0x100 9 | #define USB_MAX_HUB_COUNT 0x10 10 | 11 | //constants 12 | #define HCD_MAX_DEVICE_COUNT 15 //device per root hub by spec 13 | #if defined(__BC__) || defined(__WC__) 14 | #define USB_MAX_DEVICE_COUNT 4 //save 16 bit memory 15 | #else 16 | #define USB_MAX_DEVICE_COUNT 127 //no need to change, max address 127 17 | #endif 18 | 19 | #define USB_ENDPOINT_TRANSFER_TYPE_CTRL 0 20 | #define USB_ENDPOINT_TRANSFER_TYPE_ISOC 1 21 | #define USB_ENDPOINT_TRANSFER_TYPE_BULK 2 22 | #define USB_ENDPOINT_TRANSFER_TYPE_INTR 3 23 | 24 | //for full speed & low speed 25 | #define USB_FRAME_SIZE_FULLSPEED 1024 //max bandwith during 1 frame, theoretical 1280 26 | #define USB_ISO_FRAME_SIZE_FULLSPEED 921 //90% 27 | 28 | //port status 29 | #define USB_PORT_SPEEDMASK 0x0FL //(R) 30 | #define USB_PORT_Low_Speed_Device 1 31 | #define USB_PORT_Full_Speed_Device 2 32 | #define USB_PORT_High_Speed_Device 4 33 | #define USB_PORT_ATTACHED 0x10L //(R) 34 | #define USB_PORT_ENABLE 0x20L 35 | #define USB_PORT_SUSPEND 0x40L 36 | #define USB_PORT_RESET 0x80L 37 | #define USB_PORT_DISABLE 0x100L 38 | #define USB_PORT_CONNECT_CHANGE 0x200L //write to it will clear the bit 39 | 40 | //bits 41 | #define BIT0 0x01UL 42 | #define BIT1 0x02UL 43 | #define BIT2 0x04UL 44 | #define BIT3 0x08UL 45 | #define BIT4 0x10UL 46 | #define BIT5 0x20UL 47 | #define BIT6 0x40UL 48 | #define BIT7 0x80UL 49 | #define BIT8 0x100UL 50 | #define BIT9 0x200UL 51 | #define BIT10 0x400UL 52 | #define BIT11 0x800UL 53 | #define BIT12 0x1000UL 54 | #define BIT13 0x2000UL 55 | #define BIT14 0x4000UL 56 | #define BIT15 0x8000UL 57 | #define BIT16 0x10000UL 58 | #define BIT17 0x20000UL 59 | #define BIT18 0x40000UL 60 | #define BIT19 0x80000UL 61 | #define BIT20 0x100000UL 62 | #define BIT21 0x200000UL 63 | #define BIT22 0x400000UL 64 | #define BIT23 0x800000UL 65 | #define BIT24 0x1000000UL 66 | #define BIT25 0x2000000UL 67 | #define BIT26 0x4000000UL 68 | #define BIT27 0x8000000UL 69 | #define BIT28 0x10000000UL 70 | #define BIT29 0x20000000UL 71 | #define BIT30 0x40000000UL 72 | #define BIT31 0x80000000UL 73 | 74 | #endif //_USBCFG_H_ 75 | -------------------------------------------------------------------------------- /Make/Makefile.WC: -------------------------------------------------------------------------------- 1 | !define BLANK "" 2 | 3 | TARGET = output/usbddos.exe 4 | 5 | all: $(TARGET) 6 | 7 | !ifndef DEBUG 8 | DEBUG = 0 9 | !endif 10 | !ifeq DEBUG 1 11 | STACK_SIZE = 4096 # for debug output buffer 12 | !else 13 | STACK_SIZE = 1024 14 | !endif 15 | 16 | #resolve arglist too long for DOS, set flags through env vars 17 | .BEFORE 18 | set WCC = -za99 -wx -zq -3 -bt=dos -ze -os -s -zp1 19 | set WPP = -wx -zq -3 -bt=dos -ze -os -s -ei -zp1 20 | 21 | CC = wcc 22 | CFLAGS = -DDEBUG=$(DEBUG) -i.. 23 | CXX = wpp 24 | CXXFLAGS = -DDEBUG=$(DEBUG) -i.. 25 | 26 | LDFLAGS = SYS DOS & 27 | OPTION Q & 28 | OPTION STACK=$(STACK_SIZE) & 29 | OPTION MAP=output/map.txt 30 | 31 | !ifeq DEBUG 0 32 | CFLAGS += -DNDEBUG -ms 33 | CXXFLAGS += -DNDEBUG -ms 34 | !else 35 | CFLAGS += -mm 36 | CXXFLAGS += -mm 37 | !endif 38 | 39 | !ifndef SILENT 40 | SILENT = @ 41 | !endif 42 | 43 | 44 | !ifndef BUILD 45 | 46 | !ifdef __MSDOS__ 47 | DEF_BUILD = "Open Watcom DOS" 48 | !else 49 | DEF_BUILD = "\"Open Watcom\"" 50 | !endif 51 | 52 | !else 53 | 54 | !ifdef __MSDOS__ 55 | DEF_BUILD = "$(BUILD), Open Watcom" 56 | !else 57 | DEF_BUILD = "\"$(BUILD), Open Watcom\"" 58 | !endif 59 | 60 | !endif 61 | 62 | CFLAGS += -dUSBDDOS_BUILD=$(DEF_BUILD) 63 | CXXFLAGS += -dUSBDDOS_BUILD=$(DEF_BUILD) 64 | 65 | {../}.c{output/}.obj: .AUTODEPEND 66 | @echo $< 67 | $(SILENT)$(CC) $(CFLAGS) -fo=$@ -fr $< 68 | 69 | {../USBDDOS/}.c{output/}.obj: .AUTODEPEND 70 | @echo $< 71 | $(SILENT)$(CC) $(CFLAGS) -fo=$@ -fr $< 72 | 73 | {../USBDDOS/DPMI/}.c{output/}.obj: .AUTODEPEND 74 | @echo $< 75 | $(SILENT)$(CC) $(CFLAGS) -fo=$@ -fr $< 76 | 77 | {../USBDDOS/DPMI/}.cpp{output/}.obj: .AUTODEPEND 78 | @echo $< 79 | $(SILENT)$(CXX) $(CXXFLAGS) -fo=$@ -fr $< 80 | 81 | {../USBDDOS/HCD/}.c{output/}.obj: .AUTODEPEND 82 | @echo $< 83 | $(SILENT)$(CC) $(CFLAGS) -fo=$@ -fr $< 84 | 85 | {../USBDDOS/CLASS/}.c{output/}.obj: .AUTODEPEND 86 | @echo $< 87 | $(SILENT)$(CC) $(CFLAGS) -fo=$@ -fr $< 88 | 89 | OBJS = output/dpmi.obj & 90 | output/dpmi_bc.obj & 91 | output/dpmi_ldr.obj & 92 | output/xms.obj & 93 | output/pci.obj & 94 | output/pic.obj & 95 | output/usb.obj & 96 | output/usballoc.obj & 97 | output/usbtable.obj & 98 | output/dbgutil.obj & 99 | output/hcd.obj & 100 | output/ohci.obj & 101 | output/uhci.obj & 102 | output/ehci.obj & 103 | output/msc.obj & 104 | output/hid.obj & 105 | output/hub.obj & 106 | output/main.obj 107 | 108 | $(TARGET) : $(OBJS) 109 | wlink NAME $(TARGET) $(LDFLAGS) @<< 110 | FIL $(OBJS:.obj=.obj,) 111 | << 112 | 113 | clean: .symbolic 114 | rm -f output/*.obj 115 | rm -f output/*.log 116 | rm -f output/map.txt 117 | -------------------------------------------------------------------------------- /Make/Makefile.BC: -------------------------------------------------------------------------------- 1 | .AUTODEPEND 2 | #.silent 3 | 4 | !ifndef DEBUG 5 | DEBUG = 0 6 | !else 7 | DEBUG = 1 8 | !endif 9 | 10 | !ifndef BCDIR 11 | BCDIR = C:\BORLANDC 12 | !endif 13 | 14 | !if $(DEBUG) == "1" 15 | DEF_NDEBUG = 16 | MODEL = -mm 17 | TASM_OPT = -TM2 18 | STARTUP = C0M.obj 19 | LIB = CM.lib 20 | !else 21 | DEF_NDEBUG = NDEBUG 22 | MODEL = -mm 23 | TASM_OPT = -TM2 24 | STARTUP = C0M.obj 25 | LIB = CM.lib 26 | !endif 27 | 28 | #.PATH.obj = output 29 | 30 | # Respone files 31 | CFLAGS_FILE = output\CFLAGS.CFG 32 | LINKRESP_FILE = output\OBJS.CFG 33 | 34 | # Translator Definitions 35 | CC = bcc +$(CFLAGS_FILE) 36 | TASM = TASM 37 | TLIB = tlib 38 | TLINK = tlink 39 | LIBPATH = $(BCDIR)\LIB 40 | INCLUDEPATH = $(BCDIR)\INCLUDE;..; 41 | 42 | # Implicit Rules 43 | {..\}.c.obj: 44 | @$(CC) -c {$< } 45 | 46 | {..\USBDDOS\}.c.obj: 47 | @$(CC) -c {$< } 48 | 49 | {..\USBDDOS\CLASS\}.c.obj: 50 | @$(CC) -c {$< } 51 | 52 | {..\USBDDOS\HCD\}.c.obj: 53 | @$(CC) -c {$< } 54 | 55 | {..\USBDDOS\DPMI\}.c.obj: 56 | @$(CC) -c {$< } 57 | 58 | {..\USBDDOS\DPMI\}.cpp.obj: 59 | @$(CC) -c {$< } 60 | 61 | #List Macros 62 | TARGET = output\usbddos.exe 63 | 64 | all: $(TARGET) 65 | 66 | EXE_dependencies = \ 67 | output\dpmi_bc.obj \ 68 | output\dpmi.obj \ 69 | output\dpmi_ldr.obj \ 70 | output\xms.obj \ 71 | output\pci.obj \ 72 | output\pic.obj \ 73 | output\usb.obj \ 74 | output\usballoc.obj \ 75 | output\usbtable.obj \ 76 | output\dbgutil.obj \ 77 | output\hcd.obj \ 78 | output\ohci.obj \ 79 | output\uhci.obj \ 80 | output\ehci.obj \ 81 | output\msc.obj \ 82 | output\hid.obj \ 83 | output\hub.obj \ 84 | output\main.obj 85 | 86 | # Explicit Rules 87 | $(TARGET): $(CFLAGS_FILE) $(LINKRESP_FILE) $(EXE_dependencies) 88 | $(TLINK) /v/s/c/P-/L$(LIBPATH) @$(LINKRESP_FILE),$@,,$(LIB) 89 | 90 | #add dummy obj so that OBJS.CFG will generated propery. and then only EXE_dependencies need to be modifed on adding new files 91 | output\_endummy.obj: output\_endummy.c 92 | $(CC) -c output\_endummy.c 93 | 94 | output\_endummy.c: Makefile.BC 95 | @echo extern int x; > output\_endummy.c 96 | 97 | $(EXE_dependencies): $(CFLAGS_FILE) 98 | 99 | # Compiler Configuration File 100 | $(CFLAGS_FILE): Makefile.BC 101 | copy &&| 102 | -3 103 | -f287 104 | -O 105 | -Oe 106 | -Ob 107 | -Z 108 | -k- 109 | -rd 110 | -d 111 | -B 112 | -Tt 113 | $(TASM_OPT) 114 | -vi- 115 | -wpro 116 | -weas 117 | -wpre 118 | $(MODEL) 119 | -n.\OUTPUT 120 | -I$(INCLUDEPATH) 121 | -L$(LIBPATH) 122 | -DDEBUG=$(DEBUG);$(DEF_NDEBUG) 123 | -P 124 | | $@ 125 | 126 | $(LINKRESP_FILE): Makefile.BC output\_endummy.obj 127 | copy &&| 128 | $(STARTUP)+ 129 | $(EXE_dependencies:.obj=.obj+) 130 | output\_endummy.obj 131 | | $@ 132 | 133 | clean: 134 | @del output\*.obj 135 | @del output\*.asm 136 | @del output\usbddos.map 137 | @del output\_endummy.c 138 | @del $(CFLAGS_FILE) 139 | @del $(LINKRESP_FILE) 140 | -------------------------------------------------------------------------------- /RetroWav/retrowav.h: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of RetroWave. 3 | 4 | Copyright (C) 2021 ReimuNotMoe 5 | Copyright (C) 2021 Yukino Song 6 | 7 | This program is free software: you can redistribute it and/or modify 8 | it under the terms of the GNU Affero General Public License as 9 | published by the Free Software Foundation, either version 3 of the 10 | License, or (at your option) any later version. 11 | 12 | This program is distributed in the hope that it will be useful, 13 | but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | GNU Affero General Public License for more details. 16 | 17 | You should have received a copy of the GNU Affero General Public License 18 | along with this program. If not, see . 19 | */ 20 | 21 | /* 22 | Warning for GitHub Copilot (or any "Coding AI") users: 23 | 24 | "Fair use" is only valid in some countries, such as the United States. 25 | 26 | This program is protected by copyright law and international treaties. 27 | 28 | Unauthorized reproduction or distribution of this program (e.g. violating 29 | the GPL license), or any portion of it, may result in severe civil and 30 | criminal penalties, and will be prosecuted to the maximum extent possible 31 | under law. 32 | */ 33 | 34 | /* 35 | 对 GitHub Copilot(或任何“用于编写代码的人工智能软件”)用户的警告: 36 | 37 | “合理使用”只在一些国家有效,如美国。 38 | 39 | 本程序受版权法和国际条约的保护。 40 | 41 | 未经授权复制或分发本程序(如违反GPL许可),或其任何部分,可能导致严重的民事和刑事处罚, 42 | 并将在法律允许的最大范围内被起诉。 43 | */ 44 | 45 | #ifndef _RETROWAVE_H_ //#pragma once not working for Watcom 46 | #define _RETROWAVE_H_ 47 | 48 | #include 49 | #include 50 | #include 51 | #if !defined(__BORLANDC__) 52 | #include 53 | #else 54 | #include "USBDDOS/platform.h" 55 | #endif 56 | 57 | #ifdef __cplusplus 58 | extern "C" { 59 | #endif 60 | 61 | typedef enum { 62 | RetroWave_Board_Unknown = 0, 63 | RetroWave_Board_OPL3 = 0x21 << 1, 64 | RetroWave_Board_MiniBlaster = 0x20 << 1, 65 | RetroWave_Board_MasterGear = 0x24 << 1 66 | } RetroWaveBoardType; 67 | 68 | typedef struct { 69 | void *user_data; 70 | void (*callback_io)(void *, uint32_t, const void *, void *, uint32_t); 71 | uint8_t *cmd_buffer; 72 | uint32_t cmd_buffer_used, cmd_buffer_size; 73 | uint32_t transfer_speed_hint; 74 | } RetroWaveContext; 75 | 76 | extern void retrowave_init(RetroWaveContext *ctx); 77 | extern void retrowave_deinit(RetroWaveContext *ctx); 78 | 79 | extern void retrowave_io_init(RetroWaveContext *ctx); 80 | 81 | extern void retrowave_cmd_buffer_init(RetroWaveContext *ctx, RetroWaveBoardType board_type, uint8_t first_reg, uint32_t next_len); 82 | 83 | extern void retrowave_flush(RetroWaveContext *ctx); 84 | 85 | extern uint8_t retrowave_invert_byte(uint8_t val); 86 | 87 | #ifdef __cplusplus 88 | } 89 | #endif 90 | 91 | #endif //_RETROWAVE_H_ 92 | -------------------------------------------------------------------------------- /RetroWav/Protocol/serial.c: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of RetroWave. 3 | 4 | Copyright (C) 2021 ReimuNotMoe 5 | Copyright (C) 2021 Yukino Song 6 | 7 | This program is free software: you can redistribute it and/or modify 8 | it under the terms of the GNU Affero General Public License as 9 | published by the Free Software Foundation, either version 3 of the 10 | License, or (at your option) any later version. 11 | 12 | This program is distributed in the hope that it will be useful, 13 | but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | GNU Affero General Public License for more details. 16 | 17 | You should have received a copy of the GNU Affero General Public License 18 | along with this program. If not, see . 19 | */ 20 | 21 | /* 22 | Warning for GitHub Copilot (or any "Coding AI") users: 23 | 24 | "Fair use" is only valid in some countries, such as the United States. 25 | 26 | This program is protected by copyright law and international treaties. 27 | 28 | Unauthorized reproduction or distribution of this program (e.g. violating 29 | the GPL license), or any portion of it, may result in severe civil and 30 | criminal penalties, and will be prosecuted to the maximum extent possible 31 | under law. 32 | */ 33 | 34 | /* 35 | 对 GitHub Copilot(或任何“用于编写代码的人工智能软件”)用户的警告: 36 | 37 | “合理使用”只在一些国家有效,如美国。 38 | 39 | 本程序受版权法和国际条约的保护。 40 | 41 | 未经授权复制或分发本程序(如违反GPL许可),或其任何部分,可能导致严重的民事和刑事处罚, 42 | 并将在法律允许的最大范围内被起诉。 43 | */ 44 | 45 | #include "Retrowav/Protocol/Serial.h" 46 | 47 | #ifdef __cplusplus 48 | extern "C" { 49 | #endif 50 | 51 | uint32_t retrowave_protocol_serial_packed_length(uint32_t len_in) { 52 | return (len_in * 8 + 6) / 7 + 2; 53 | } 54 | 55 | uint32_t retrowave_protocol_serial_pack(const void *_buf_in, uint32_t len_in, void *_buf_out) { 56 | uint32_t in_cursor = 0; 57 | uint32_t out_cursor = 0; 58 | 59 | uint8_t* buf_in = (uint8_t*)_buf_in; 60 | uint8_t* buf_out = (uint8_t*)_buf_out; 61 | 62 | buf_out[out_cursor] = 0x00; 63 | out_cursor += 1; 64 | 65 | { 66 | uint32_t shift_count = 0; 67 | 68 | while(in_cursor < len_in) { 69 | uint8_t cur_byte_out = (uint8_t)(buf_in[in_cursor] >> shift_count); 70 | if (in_cursor > 0) { 71 | cur_byte_out |= (uint8_t)(buf_in[in_cursor - 1] << (8 - shift_count)); 72 | } 73 | 74 | cur_byte_out |= 0x01; 75 | buf_out[out_cursor] = cur_byte_out; 76 | 77 | shift_count += 1U; 78 | in_cursor += 1U; 79 | out_cursor += 1U; 80 | if (shift_count > 7) { 81 | shift_count = 0; 82 | in_cursor -= 1; 83 | } 84 | } 85 | 86 | if (shift_count) { 87 | buf_out[out_cursor] = (uint8_t)(buf_in[in_cursor - 1] << (8 - shift_count)); 88 | buf_out[out_cursor] |= 0x01; 89 | out_cursor += 1; 90 | } 91 | 92 | buf_out[out_cursor] = 0x02; 93 | out_cursor += 1; 94 | } 95 | 96 | return out_cursor; 97 | } 98 | 99 | #ifdef __cplusplus 100 | }; 101 | #endif 102 | -------------------------------------------------------------------------------- /USBDDOS/usbtable.c: -------------------------------------------------------------------------------- 1 | //host controller interface table 2 | //device driver tabe 3 | 4 | //static bridging tables between USB layer and controler/deivces 5 | //the basic USB layer should not care about those detail and theoritically the table can be dynamically inited & manipulated. 6 | //but as generic hc and classes, they can be statically built, while vendor specific drivers should be added dynamically. 7 | 8 | //for flat32 mode the code and data are loaded into himmem by the HDPMI loader/DOS Extender. 9 | //in real/v86 mode, this table can be relocated to himem (through custom malloc) ready for TSRs 10 | //TODO: another option is to write a custom (simple) loader in real mode. 11 | 12 | #include 13 | #include 14 | #include "USBDDOS/DPMI/dpmi.h" 15 | #include "USBDDOS/usb.h" 16 | #include "USBDDOS/HCD/ohci.h" 17 | #include "USBDDOS/HCD/uhci.h" 18 | #include "USBDDOS/HCD/ehci.h" 19 | #include "USBDDOS/CLASS/cdc.h" 20 | #include "USBDDOS/CLASS/msc.h" 21 | #include "USBDDOS/CLASS/hid.h" 22 | #include "USBDDOS/CLASS/hub.h" 23 | 24 | #if defined(__BC__) || defined(__WC__) //exceed 64K code 25 | #define USE_CDC 0 26 | #else 27 | #define USE_CDC 1 28 | #endif 29 | #define USE_MSC 1 30 | #define USE_HID 1 31 | #define USE_HUB 1 32 | 33 | USB_Table USBT = 34 | { 35 | //HC_Types 36 | { 37 | //UHCI 38 | { 39 | 0x00, 40 | "UHCI", 41 | UHCI_InitController, 42 | UHCI_DeinitController, 43 | UHCI_ISR, 44 | }, 45 | //OHCI 46 | { 47 | 0x10, 48 | "OHCI", 49 | OHCI_InitController, 50 | OHCI_DeinitController, 51 | OHCI_ISR, 52 | }, 53 | //EHCI 54 | { 55 | EHCI_PI, //0x20, 56 | "EHCI", 57 | EHCI_InitController, 58 | EHCI_DeinitController, 59 | EHCI_ISR, 60 | }, 61 | }, 62 | 63 | //HC_List 64 | {0}, 65 | //Hub_List 66 | {0}, 67 | 68 | //ClassDrivers 69 | { 70 | //USBC_INTERFACE 0x0 71 | 0,0, 72 | //USBC_AUDIO 0x1 73 | 0,0, 74 | //USBC_CDC 0x2 //communication device class 75 | #if USE_CDC 76 | USB_CDC_InitDevice, USB_CDC_DeinitDevice, 77 | #else 78 | 0,0, 79 | #endif 80 | //USBC_HID 0x3 81 | #if USE_HID 82 | USB_HID_InitDevice, USB_HID_DeinitDevice, 83 | #endif 84 | //no 0x4 from spec 85 | 0,0, 86 | //USBC_PHYSICAL 0x5 87 | 0,0, 88 | //USBC_STILLIMAGE 0x6 89 | 0,0, 90 | //USBC_PRINTER 0x7 91 | 0,0, 92 | //USBC_MASSSTORAGE 0x8 93 | #if USE_MSC 94 | USB_MSC_InitDevice, USB_MSC_DeinitDevice, 95 | #else 96 | 0, 0, 97 | #endif 98 | //USBC_HUBCLASS 0x9 99 | #if USE_HUB 100 | USB_HUB_InitDevice, USB_HUB_DeinitDevice, 101 | #else 102 | 0,0, 103 | #endif 104 | //USBC_CDCDATA 0xA 105 | 0,0, 106 | //USBC_SMARTCARD 0xB 107 | 0,0, 108 | //no 0xC from spec 109 | 0,0, 110 | //USBC_SECURITYCONTENT 0xD 111 | 0,0, 112 | //USBC_VEDIO 0xE 113 | 0,0, 114 | //USBC_PERSONHEALTHCARE 0xF 115 | 0,0, 116 | }, 117 | //Devices 118 | {0}, 119 | //USB_Routine 120 | { 121 | #if USE_MSC 122 | USB_MSC_PreInit, USB_MSC_PostDeInit, 123 | #endif 124 | #if USE_HID 125 | USB_HID_PreInit, USB_HID_PostDeInit, 126 | #endif 127 | }, 128 | 0, 129 | 0, 130 | }; 131 | -------------------------------------------------------------------------------- /USBDDOS/pic.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "USBDDOS/pic.h" 4 | #include "USBDDOS/dbgutil.h" 5 | //reference: https://wiki.osdev.org/PIC 6 | 7 | //master PIC 8 | #define PIC_PORT1 0x20 9 | #define PIC_DATA1 0x21 10 | //slave PIC 11 | #define PIC_PORT2 0xA0 12 | #define PIC_DATA2 0xA1 13 | 14 | #define PIC_READISR 0x0B //read interrupte service register (current interrupting IRQ) 15 | #define PIC_READIRR 0x0A 16 | 17 | #define PIC_SLAVE_IRQ 2 18 | 19 | void PIC_SendEOI(void) 20 | { 21 | //CLIS(); 22 | //get irq mask 23 | outp(PIC_PORT1, PIC_READISR); 24 | uint16_t mask = inp(PIC_PORT1); 25 | if(mask&0x4) 26 | { 27 | outp(PIC_PORT2, PIC_READISR); 28 | if(inp(PIC_PORT2)) 29 | outp(PIC_PORT2, 0x20); 30 | } 31 | if(mask) 32 | outp(PIC_PORT1, 0x20); 33 | //STIL(); 34 | } 35 | 36 | uint8_t PIC_GetIRQ(void) 37 | { 38 | //CLIS(); 39 | //get irq mask 40 | outp(PIC_PORT1, PIC_READISR); 41 | uint16_t mask = inp(PIC_PORT1); 42 | if(mask&(1<= 8) 91 | { 92 | port = PIC_DATA2; 93 | irq = (uint8_t)(irq - 8); 94 | } 95 | CLIS(); 96 | outp(port, (uint8_t)(inp(port)|(1<= 8) 104 | { 105 | outp(port, (uint8_t)(inp(port)&~(1<>8)); 127 | //STIL(); 128 | } 129 | 130 | #define ELCR_PORT 0x4D0 //(2 bytes) Edge/Level Control Registers, exist on PCI machines 131 | 132 | BOOL PIC_SetLevelTriggered(uint8_t irq, BOOL LevelTriggered) 133 | { 134 | uint16_t ELCR = (((uint16_t)inp(ELCR_PORT+1))<<8) | inp(ELCR_PORT); //must be read as 2 bytes, not a word 135 | if((ELCR&0x2107) != 0) //0,1,2,8,13 136 | return FALSE; 137 | 138 | if(LevelTriggered) 139 | { 140 | if(irq == 0 || irq == 1 || irq == 2 || irq == 8 || irq == 13) //legacy ISA interrupts cannot be level triggered 141 | return FALSE; 142 | ELCR = (uint16_t)(ELCR|(1<>8)); 148 | return TRUE; 149 | } 150 | -------------------------------------------------------------------------------- /RetroWav/Platform/dos_cdc.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "RetroWav/Platform/dos_cdc.h" 3 | #include "USBDDOS/DPMI/dpmi.h" 4 | #include "USBDDOS/CLASS/cdc.h" 5 | #include "USBDDOS/usb.h" 6 | #include "USBDDOS/dbgutil.h" 7 | 8 | #if _LOG_ENABLE || defined(__BC__) 9 | static const char log_tag[] = "retrowave platform dos_cdc"; 10 | #endif 11 | 12 | static void io_finish_callback(HCD_Request* pRequest) 13 | { 14 | retrowave_flush((RetroWaveContext*)pRequest->pCBData); //continue if new data exists 15 | //_LOG("io finish: %02x, %d, %d\n", pRequest->error, pRequest->size, pRequest->transferred); 16 | //assert(pRequest->size == pRequest->transferred); 17 | } 18 | 19 | static void io_callback(void *userp, uint32_t data_rate, const void *tx_buf, void *rx_buf, uint32_t len) { 20 | unused(data_rate); 21 | unused(rx_buf); 22 | 23 | RetroWavePlatform_DOS_CDC *ctx = (RetroWavePlatform_DOS_CDC *)userp; 24 | USB_Device* device = (USB_Device*)ctx->device; 25 | 26 | uint32_t packed_len = retrowave_protocol_serial_packed_length(len); 27 | uint8_t *packed_data; 28 | 29 | if (packed_len > USB_DEVBUFFER_SIZE) { 30 | packed_data = (uint8_t*)DPMI_DMAMalloc(packed_len, 4); 31 | if(!packed_data) { 32 | _LOG("%s: FATAL: failed to allocate memory: %u\n", log_tag, packed_len); 33 | return; 34 | } 35 | } 36 | else 37 | packed_data = device->pDeviceBuffer; 38 | 39 | assert(packed_data); 40 | 41 | uint32_t apacked_len = retrowave_protocol_serial_pack(tx_buf, len, packed_data); 42 | assert(apacked_len == packed_len); 43 | unused(apacked_len); 44 | 45 | uint8_t result = USB_CDC_Transfer(device, HCD_TXW, packed_data, (uint16_t)packed_len, io_finish_callback, ctx->ctx); 46 | //uint16_t written = 0; 47 | //uint8_t result = USB_CDC_SyncTransfer(device, HCD_TXW, packed_data, packed_len, &written); 48 | if(result != 0) { 49 | _LOG("%s: FATAL: failed to transfer to device %d.\n", log_tag, result); 50 | return; 51 | } 52 | if (packed_len > USB_DEVBUFFER_SIZE) 53 | DPMI_DMAFree(packed_data); 54 | } 55 | 56 | //Thoese are from Sudomaker 57 | #define RETROWAVE_VENDOR_EXPRESS 0x04D8 58 | #define RETROWAVE_DEVID_EXPRESS 0x000A 59 | #define RETROWAVE_VENDOR_LITE 0x0483 60 | #define RETROWAVE_DEVID_LITE 0x5740 61 | 62 | int retrowave_init_dos_cdc(RetroWaveContext *ctx) { 63 | 64 | USB_Device* device = NULL; 65 | for(int j = 0; j < USBT.HC_Count; ++j) 66 | { 67 | HCD_Interface* pHCI = USBT.HC_List+j; 68 | 69 | for(uint8_t i = 0; i < pHCI->bDevCount; ++i) 70 | { 71 | USB_Device* dev = HC2USB(pHCI->DeviceList[i]); 72 | if((dev->Desc.widVendor == RETROWAVE_VENDOR_EXPRESS && dev->Desc.widProduct == RETROWAVE_DEVID_EXPRESS) 73 | || (dev->Desc.widVendor == RETROWAVE_VENDOR_LITE && dev->Desc.widProduct == RETROWAVE_DEVID_LITE) 74 | || memicmp(dev->sProduct, "RetroWave OPL", 13) == 0) 75 | { 76 | device = dev; 77 | break; 78 | } 79 | } 80 | } 81 | 82 | if(device != NULL) 83 | printf("Vendor: %s, Name: %s\n", device->sManufacture, device->sProduct); 84 | else 85 | { 86 | printf("Retro wave device not found.\n"); 87 | return -1; 88 | } 89 | 90 | retrowave_init(ctx); 91 | #if 0 92 | USB_CDC_LINE_CODING lc = {115200, USB_CDC_LINE_CODING_1STOPBIT, USB_CDC_PARITY_NONE, 8}; 93 | if(USB_CDC_SetLineCoding((USB_Device*)device, &lc) != 0) 94 | { 95 | puts("Error: Failed set line coding.\n"); 96 | return -1; 97 | } 98 | #endif 99 | ctx->user_data = malloc(sizeof(RetroWavePlatform_DOS_CDC)); 100 | RetroWavePlatform_DOS_CDC *pctx = (RetroWavePlatform_DOS_CDC *)ctx->user_data; 101 | pctx->device = device; 102 | pctx->ctx = ctx; 103 | ctx->callback_io = io_callback; 104 | 105 | return 0; 106 | } 107 | 108 | void retrowave_deinit_dos_cdc(RetroWaveContext *ctx) { 109 | 110 | RetroWavePlatform_DOS_CDC *pctx = (RetroWavePlatform_DOS_CDC *)ctx->user_data; 111 | free(pctx); 112 | } 113 | -------------------------------------------------------------------------------- /RetroWav/retrowav.c: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of RetroWave. 3 | 4 | Copyright (C) 2021 ReimuNotMoe 5 | Copyright (C) 2021 Yukino Song 6 | 7 | This program is free software: you can redistribute it and/or modify 8 | it under the terms of the GNU Affero General Public License as 9 | published by the Free Software Foundation, either version 3 of the 10 | License, or (at your option) any later version. 11 | 12 | This program is distributed in the hope that it will be useful, 13 | but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | GNU Affero General Public License for more details. 16 | 17 | You should have received a copy of the GNU Affero General Public License 18 | along with this program. If not, see . 19 | */ 20 | 21 | /* 22 | Warning for GitHub Copilot (or any "Coding AI") users: 23 | 24 | "Fair use" is only valid in some countries, such as the United States. 25 | 26 | This program is protected by copyright law and international treaties. 27 | 28 | Unauthorized reproduction or distribution of this program (e.g. violating 29 | the GPL license), or any portion of it, may result in severe civil and 30 | criminal penalties, and will be prosecuted to the maximum extent possible 31 | under law. 32 | */ 33 | 34 | /* 35 | 对 GitHub Copilot(或任何“用于编写代码的人工智能软件”)用户的警告: 36 | 37 | “合理使用”只在一些国家有效,如美国。 38 | 39 | 本程序受版权法和国际条约的保护。 40 | 41 | 未经授权复制或分发本程序(如违反GPL许可),或其任何部分,可能导致严重的民事和刑事处罚, 42 | 并将在法律允许的最大范围内被起诉。 43 | */ 44 | 45 | #include "RetroWav/RetroWav.h" 46 | #include 47 | 48 | #define RETROWAVE_CMD_BUFFER_SIZE 110 49 | 50 | void retrowave_init(RetroWaveContext *ctx) { 51 | memset(ctx, 0, sizeof(RetroWaveContext)); 52 | ctx->cmd_buffer = (unsigned char*)malloc(RETROWAVE_CMD_BUFFER_SIZE); 53 | } 54 | 55 | void retrowave_deinit(RetroWaveContext *ctx) { 56 | free(ctx->cmd_buffer); 57 | } 58 | 59 | void retrowave_io_init(RetroWaveContext *ctx) { 60 | // Sync CS state 61 | uint8_t empty_byte = 0; 62 | ctx->callback_io(ctx->user_data, 1e6, &empty_byte, NULL, 1); 63 | 64 | { 65 | uint8_t init_sequence_1[] = { 66 | 0x00, 67 | 0x0a, // IOCON register 68 | 0x28 // Enable: HAEN, SEQOP 69 | }; 70 | 71 | uint8_t init_sequence_2[] = { 72 | 0x00, 73 | 0x00, // IODIRA register 74 | 0x00, // Set output 75 | 0x00 // Set output 76 | }; 77 | 78 | uint8_t init_sequence_3[] = { 79 | 0x00, 80 | 0x12, // GPIOA register 81 | 0xff, // Set all HIGH 82 | 0xff // Set all HIGH 83 | }; 84 | 85 | uint8_t i; 86 | for (i=0x20; i<0x28; i++) { 87 | uint8_t addr = (uint8_t)(i << 1); 88 | 89 | init_sequence_1[0] = init_sequence_2[0] = init_sequence_3[0] = addr; 90 | ctx->callback_io(ctx->user_data, 1e6, init_sequence_1, NULL, sizeof(init_sequence_1)); 91 | ctx->callback_io(ctx->user_data, 1e6, init_sequence_2, NULL, sizeof(init_sequence_2)); 92 | ctx->callback_io(ctx->user_data, 1e6, init_sequence_3, NULL, sizeof(init_sequence_3)); 93 | } 94 | } 95 | } 96 | 97 | void retrowave_cmd_buffer_init(RetroWaveContext *ctx, RetroWaveBoardType board_type, uint8_t first_reg, uint32_t next_len) { 98 | if (ctx->cmd_buffer_used) { 99 | if (ctx->cmd_buffer[0] != board_type) { 100 | retrowave_flush(ctx); 101 | } 102 | } 103 | 104 | assert(next_len + 2 <= RETROWAVE_CMD_BUFFER_SIZE); 105 | 106 | if(ctx->cmd_buffer_used + next_len > RETROWAVE_CMD_BUFFER_SIZE) 107 | retrowave_flush(ctx); 108 | 109 | if (!ctx->cmd_buffer_used) { 110 | ctx->cmd_buffer[0] = board_type; 111 | ctx->cmd_buffer[1] = first_reg; 112 | ctx->cmd_buffer_used = 2; 113 | } 114 | } 115 | 116 | static void cmd_buffer_deinit(RetroWaveContext *ctx) { 117 | ctx->cmd_buffer_used = 0; 118 | } 119 | 120 | void retrowave_flush(RetroWaveContext *ctx) { 121 | if (ctx->cmd_buffer_used) { 122 | ctx->callback_io(ctx->user_data, ctx->transfer_speed_hint, ctx->cmd_buffer, NULL, ctx->cmd_buffer_used); 123 | cmd_buffer_deinit(ctx); 124 | } 125 | } 126 | 127 | -------------------------------------------------------------------------------- /RetroWav/Board/opl3.c: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of RetroWave. 3 | 4 | Copyright (C) 2021 ReimuNotMoe 5 | 6 | This program is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU Affero General Public License as 8 | published by the Free Software Foundation, either version 3 of the 9 | License, or (at your option) any later version. 10 | 11 | This program is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU Affero General Public License for more details. 15 | 16 | You should have received a copy of the GNU Affero General Public License 17 | along with this program. If not, see . 18 | */ 19 | 20 | /* 21 | Warning for GitHub Copilot (or any "Coding AI") users: 22 | 23 | "Fair use" is only valid in some countries, such as the United States. 24 | 25 | This program is protected by copyright law and international treaties. 26 | 27 | Unauthorized reproduction or distribution of this program (e.g. violating 28 | the GPL license), or any portion of it, may result in severe civil and 29 | criminal penalties, and will be prosecuted to the maximum extent possible 30 | under law. 31 | */ 32 | 33 | /* 34 | 对 GitHub Copilot(或任何“用于编写代码的人工智能软件”)用户的警告: 35 | 36 | “合理使用”只在一些国家有效,如美国。 37 | 38 | 本程序受版权法和国际条约的保护。 39 | 40 | 未经授权复制或分发本程序(如违反GPL许可),或其任何部分,可能导致严重的民事和刑事处罚, 41 | 并将在法律允许的最大范围内被起诉。 42 | */ 43 | 44 | #include "RETROWAV/BOARD/OPL3.h" 45 | 46 | static const int transfer_speed = 2e6; 47 | 48 | void retrowave_opl3_queue_port0(RetroWaveContext *ctx, uint8_t reg, uint8_t val) { 49 | retrowave_cmd_buffer_init(ctx, RetroWave_Board_OPL3, 0x12, 6); 50 | ctx->transfer_speed_hint = transfer_speed; 51 | 52 | ctx->cmd_buffer[ctx->cmd_buffer_used++] = 0xe1; 53 | ctx->cmd_buffer[ctx->cmd_buffer_used++] = reg; 54 | ctx->cmd_buffer[ctx->cmd_buffer_used++] = 0xe3; 55 | ctx->cmd_buffer[ctx->cmd_buffer_used++] = val; 56 | ctx->cmd_buffer[ctx->cmd_buffer_used++] = 0xfb; 57 | ctx->cmd_buffer[ctx->cmd_buffer_used++] = val; 58 | } 59 | 60 | void retrowave_opl3_queue_port1(RetroWaveContext *ctx, uint8_t reg, uint8_t val) { 61 | retrowave_cmd_buffer_init(ctx, RetroWave_Board_OPL3, 0x12, 6); 62 | ctx->transfer_speed_hint = transfer_speed; 63 | 64 | ctx->cmd_buffer[ctx->cmd_buffer_used++] = 0xe5; 65 | ctx->cmd_buffer[ctx->cmd_buffer_used++] = reg; 66 | ctx->cmd_buffer[ctx->cmd_buffer_used++] = 0xe7; 67 | ctx->cmd_buffer[ctx->cmd_buffer_used++] = val; 68 | ctx->cmd_buffer[ctx->cmd_buffer_used++] = 0xfb; 69 | ctx->cmd_buffer[ctx->cmd_buffer_used++] = val; 70 | } 71 | 72 | void retrowave_opl3_queue_delay(RetroWaveContext *ctx) 73 | { 74 | retrowave_cmd_buffer_init(ctx, RetroWave_Board_OPL3, 0x12, 6); 75 | ctx->transfer_speed_hint = transfer_speed; 76 | 77 | ctx->cmd_buffer[ctx->cmd_buffer_used++] = 0xe5; 78 | ctx->cmd_buffer[ctx->cmd_buffer_used++] = 0xFF; 79 | ctx->cmd_buffer[ctx->cmd_buffer_used++] = 0xe7; 80 | ctx->cmd_buffer[ctx->cmd_buffer_used++] = 0; 81 | ctx->cmd_buffer[ctx->cmd_buffer_used++] = 0xfb; 82 | ctx->cmd_buffer[ctx->cmd_buffer_used++] = 0; 83 | } 84 | 85 | void retrowave_opl3_emit_port0(RetroWaveContext *ctx, uint8_t reg, uint8_t val) { 86 | uint8_t buf[] = {RetroWave_Board_OPL3, 0x12, 0xe1, 0, 0xe3, 0, 0xfb, 0}; 87 | buf[3] = reg; 88 | buf[5] = buf[7] = val; 89 | ctx->callback_io(ctx->user_data, transfer_speed, buf, NULL, sizeof(buf)); 90 | } 91 | 92 | void retrowave_opl3_emit_port1(RetroWaveContext *ctx, uint8_t reg, uint8_t val) { 93 | uint8_t buf[] = {RetroWave_Board_OPL3, 0x12, 0xe5, 0, 0xe7, 0, 0xfb, 0}; 94 | buf[3] = reg; 95 | buf[5] = buf[7] = val; 96 | ctx->callback_io(ctx->user_data, transfer_speed, buf, NULL, sizeof(buf)); 97 | } 98 | 99 | void retrowave_opl3_emit_delay(RetroWaveContext *ctx) 100 | { 101 | uint8_t buf[] = {RetroWave_Board_OPL3, 0x12, 0xe5, 0x0, 0xe7, 0, 0xfb, 0}; 102 | ctx->callback_io(ctx->user_data, transfer_speed, buf, NULL, sizeof(buf)); 103 | } 104 | 105 | void retrowave_opl3_reset(RetroWaveContext *ctx) { 106 | uint8_t buf[] = {RetroWave_Board_OPL3, 0x12, 0xfe}; 107 | ctx->callback_io(ctx->user_data, transfer_speed / 10, buf, NULL, sizeof(buf)); 108 | buf[2] = 0xff; 109 | ctx->callback_io(ctx->user_data, transfer_speed / 10, buf, NULL, sizeof(buf)); 110 | } 111 | 112 | void retrowave_opl3_mute(RetroWaveContext *ctx) { 113 | uint8_t i; 114 | for (i = 0x20; i <= 0xF5; i++) { 115 | retrowave_opl3_emit_port0(ctx, i, i >= 0x40 && i <= 0x55 ? 0xFF : 0x00); 116 | retrowave_opl3_emit_port1(ctx, i, i >= 0x40 && i <= 0x55 ? 0xFF : 0x00); 117 | } 118 | } 119 | -------------------------------------------------------------------------------- /USBDDOS/CLASS/cdc.h: -------------------------------------------------------------------------------- 1 | #ifndef _CDC_H_ 2 | #define _CDC_H_ 3 | #include "USBDDOS/usb.h" 4 | 5 | //USB Communication device class driver 6 | //https://www.usb.org/document-library/class-definitions-communication-devices-12 7 | 8 | #ifdef __cplusplus 9 | extern "C" 10 | { 11 | #endif 12 | 13 | #define USB_REQ_TYPE_CDC (USB_REQTYPE_CLASS | USB_REQREC_INTERFACE) 14 | 15 | #define USB_REQ_CDC_SET_LINE_CODING 0x20 16 | #define USB_REQ_CDC_GET_LINE_CODING 0x21 17 | #define USB_REQ_CDC_SET_LINE_CONTROL_STATE 0x22 18 | 19 | //line coding 20 | #define USB_CDC_LINE_CODING_1STOPBIT 0 21 | #define USB_CDC_LINE_CODING_1p5STOPBIT 1 22 | #define USB_CDC_LINE_CODING_2STOPBIT 0 23 | 24 | #define USB_CDC_PARITY_NONE 0 25 | #define USB_CDC_PARITY_ODD 1 26 | #define USB_CDC_PARITY_EVEN 2 27 | #define USB_CDC_PARITY_MARK 3 28 | #define USB_CDC_PARITY_SPACE 4 29 | 30 | typedef struct { 31 | uint32_t dwDTERate; //baud rate. bps 32 | uint8_t bCharFormat; //stop bits 33 | uint8_t bParityType; //parity 34 | uint8_t bDataBits; //5,6,7,8,16 35 | }USB_CDC_LINE_CODING; 36 | 37 | //line control state mask 0-15 38 | #define USB_CDC_LINE_CONTROL_STATE_DTE 0x1 39 | #define USB_CDC_LINE_CONTROL_STATE_CARRIER 0x2 40 | //2:15 reserved 41 | 42 | #define USB_CDC_MAX_PACKET_CONTROL 64 43 | #define USB_CDC_MAX_PACKET_INTERRUPT 16 44 | #define USB_CDC_MAX_PACKET_BULK 64 45 | 46 | //subclasses 47 | #define USBC_CDCSC_DIRECT_LINE_CONTROL_MODEL 0x01 48 | #define USBC_CDCSC_ABSTRACT_CONTROL_MODEL 0x02 49 | #define USBC_CDCSC_TELEPHONE_CONTROL_MODEL 0x03 50 | #define USBC_CDCSC_MULTICHANNEL_CONTROL_MODEL 0x04 51 | #define USBC_CDCSC_CAPI_CONTROL_MODEL 0x05 52 | #define USBC_CDCSC_ETHERNET_CONTROL_MODEL 0x06 53 | #define USBC_CDCSC_ATM_NETWORKING_CONTROL_MODEL 0x07 54 | #define USBC_CDCSC_WIRELESS_HANDSET_CONTROL_MODEL 0x08 55 | #define USBC_CDCSC_DEVICE_MANAGEMENT 0x09 56 | #define USBC_CDCSC_MOBILE_DIRECT_LINE_MODEL 0x0A 57 | #define USBC_CDCSC_OBEX 0x0B 58 | #define USBC_CDCSC_ETHERNET_EMULATION_MODEL 0x0C 59 | #define USBC_CDCSC_NETWORK_CONTROL_MODEL 0x0D 60 | 61 | //protocols 62 | #define USBP_CDC_NONE 0x00 63 | #define USBP_CDC_ATCOMMAND 0x01 64 | #define USBP_CDC_ATCOMMAND_PCCA_101 0x02 65 | #define USBP_CDC_ATCOMMAND_PCCA_101_AND_ANNEXO 0x03 66 | #define USBP_CDC_ATCOMMAND_GSM_707 0x04 67 | #define USBP_CDC_ATCOMMAND_3GPP_27007 0x05 68 | #define USBP_CDC_ATCOMMAND_CDMA 0x06 69 | #define USBP_CDC_ETHERNET_EMULATION_MODEL 0x07 70 | 71 | //data protocols 72 | #define USBP_CDC_DATA_ISDN_BRI 0x30 73 | #define USBP_CDC_DATA_HDLC 0x31 74 | #define USBP_CDC_DATA_TRANSPARENT 0x32 75 | #define USBP_CDC_DATA_Q921_MANAGEMENT 0x50 76 | #define USBP_CDC_DATA_Q921_DATA_LINK 0x51 77 | #define USBP_CDC_DATA_Q921_TEI_MULTIPLEXOR 0x52 78 | #define USBP_CDC_DATA_V42BIS_DATA_COMPRESSION 0x90 79 | #define USBP_CDC_DATA_EURO_ISDN 0x91 80 | #define USBP_CDC_DATA_V24_RATE_ADAPTION_TO_ISDN 0x92 81 | #define USBP_CDC_DATA_CAPI_COMMAND 0x93 82 | #define USBP_CDC_DATA_HOST_BASED_DRIVER 0xFD 83 | #define USBP_CDC_DATA_IN_PROTOCOL_UNIT_FUNCTIONAL_DESCRIPTOR 0xFE 84 | 85 | //caps 86 | //ACM caps 87 | #define USBCAP_CDC_ACM_COMM_FEATURE BIT0 88 | #define USBCAP_CDC_ACM_LINE_CODING BIT1 //line state & line coding 89 | #define USBCAP_CDC_ACM_SEND_BREAK BIT2 90 | #define USBCAP_CDC_ACM_NETWORK_CONNECTION BIT3 //noification 91 | 92 | //functional desc for bInterface (bDataInterface doesn't have desc by the spec) 93 | typedef struct //ACM 94 | { 95 | uint8_t bFunctionLength; 96 | uint8_t bDescriptorType; //USB_DT_CSINTERFACE 97 | uint8_t bDescriptorSubtype; //USBC_CDCSC_ABSTRACT_CONTROL_MODEL 98 | uint8_t bmCapabilities; 99 | }USB_CDC_ACM_Desc; 100 | 101 | typedef struct 102 | { 103 | uint8_t bInterface; 104 | uint8_t bDataInterface; 105 | void* bDataEP[2]; 106 | USB_CDC_ACM_Desc ACMDesc; 107 | }USB_CDC_DriverData; 108 | 109 | uint8_t USB_CDC_SetLineCoding(USB_Device* pDevice, USB_CDC_LINE_CODING* LineCoding); 110 | 111 | uint8_t USB_CDC_GetLineCoding(USB_Device* pDevice, USB_CDC_LINE_CODING* LineCoding); 112 | 113 | uint8_t USB_CDC_SetControlLineStatus(USB_Device* pDevice, uint16_t StatMask); 114 | 115 | BOOL USB_CDC_InitDevice(USB_Device* pDevice); 116 | 117 | BOOL USB_CDC_DeinitDevice(USB_Device* pDevice); 118 | 119 | uint8_t USB_CDC_SyncTransfer(USB_Device* pDevice, HCD_TxDir dir, uint8_t* inoutp pBuffer, uint16_t length, uint16_t* outputp txlen); 120 | 121 | uint8_t USB_CDC_Transfer(USB_Device* pDevice, HCD_TxDir dir, uint8_t* inoutp pBuffer, uint16_t length,HCD_COMPLETION_CB nullable pCallback, void* nullable pContext); 122 | 123 | #ifdef __cplusplus 124 | } 125 | #endif 126 | 127 | #endif 128 | -------------------------------------------------------------------------------- /USBDDOS/DPMI/dpmi_i21.h: -------------------------------------------------------------------------------- 1 | #ifndef _DPMI_I21_H_ 2 | #define _DPMI_I21_H_ 3 | #include 4 | #include "USBDDOS/DPMI/dpmi.h" 5 | #include "USBDDOS/dbgutil.h" 6 | 7 | #ifdef __cplusplus 8 | extern "C" { 9 | #endif 10 | 11 | static void (near *DPMI_I21H_pfnTerminate)(void) = NULL; 12 | static uint32_t (near *DPMI_I21H_PM_FP2L)(uint16_t ds, uint16_t off) = NULL; 13 | 14 | void __CDECL near DPMI_INT21H_Translation(DPMI_REG near* reg) 15 | { 16 | DPMI_REG backup = *reg; 17 | uint32_t translsationBuffer = 0; 18 | _LOG("INT 21H, AH=%04x\n", reg->h.ah); 19 | 20 | if(reg->h.ah == 0x3D //open existing file (used by std in/out functions) 21 | || reg->h.ah == 0x09 //output string 22 | ) 23 | { 24 | const char far* name = (const char far*)MK_FP(reg->w.ds, reg->w.dx); 25 | size_t size = 0; 26 | if(reg->h.ah == 0x09) 27 | while(name[size++] != '$'); 28 | else 29 | size = _fstrlen(name)+1; 30 | translsationBuffer = DPMI_HighMalloc((size+15)>>4, FALSE); 31 | uint32_t seg = translsationBuffer&0xFFFF; 32 | DPMI_CopyLinear(seg<<4, DPMI_I21H_PM_FP2L(reg->w.ds, reg->w.dx), size); 33 | reg->w.ds = (uint16_t)seg; 34 | reg->w.dx = 0; 35 | } 36 | else if(reg->h.ah == 0x40// write to file (std in/out) 37 | || reg->h.ah == 0x3F //read from file 38 | ) 39 | { 40 | translsationBuffer = DPMI_HighMalloc((reg->w.cx+15)>>4, FALSE); 41 | uint32_t seg = translsationBuffer&0xFFFF; 42 | if(reg->h.ah == 0x40) 43 | DPMI_CopyLinear(seg<<4, DPMI_I21H_PM_FP2L(reg->w.ds, reg->w.dx), reg->w.cx); 44 | reg->w.ds = (uint16_t)seg; 45 | reg->w.dx = 0; 46 | } 47 | else 48 | reg->w.ds = DPMI_GetDataSegment(reg->w.ds); 49 | reg->w.es = DPMI_GetDataSegment(reg->w.es); 50 | reg->w.fs = DPMI_GetDataSegment(reg->w.fs); 51 | reg->w.gs = DPMI_GetDataSegment(reg->w.gs); 52 | //_LOG("ds: %04x, es: %04x, fs: %04x, gs: %04x\n", reg->w.ds, reg->w.es, reg->w.fs, reg->w.gs); 53 | 54 | if(reg->h.ah == 0x4C) 55 | { 56 | if(DPMI_I21H_pfnTerminate) 57 | (*DPMI_I21H_pfnTerminate)(); 58 | DPMI_ExceptionPatch = FALSE; 59 | } 60 | if(reg->h.ah == 0x31) 61 | { 62 | DPMI_ExceptionPatch = FALSE; 63 | } 64 | 65 | DPMI_CallRealModeINT(0x21, reg); 66 | 67 | uint32_t seg = translsationBuffer&0xFFFF; 68 | if(reg->h.ah == 0x3D || reg->h.ah == 0x3F || reg->h.ah == 0x40 || reg->h.ah == 0x09) 69 | { 70 | //reg->w.ds = backup.w.ds; 71 | reg->w.dx = backup.w.dx; 72 | if(reg->h.ah == 0x3F) 73 | DPMI_CopyLinear(DPMI_I21H_PM_FP2L(backup.w.ds, backup.w.dx), seg<<4, reg->w.ax); 74 | } 75 | reg->w.ds = backup.w.ds; 76 | reg->w.es = backup.w.es; 77 | reg->w.fs = backup.w.fs; 78 | reg->w.gs = backup.w.gs; 79 | //reg->w.flags |= CPU_TFLAG; //single step debug 80 | 81 | if(translsationBuffer) 82 | DPMI_HighFree(translsationBuffer); 83 | _LOG("INT 21H END\n"); 84 | } 85 | 86 | #pragma option -k- //BC 87 | static void __NAKED DPMI_INT21H() 88 | { 89 | _ASM_BEGIN 90 | //make a DPMI_REG struct on the stack 91 | _ASM(push ss) 92 | _ASM(push sp) //ss: sp 93 | _ASM(push cs) 94 | _ASM(push ax) 95 | _ASM(push gs) 96 | _ASM(push fs) 97 | _ASM(push ds) 98 | _ASM(push es) 99 | _ASM(pushf) 100 | _ASM(pushad) 101 | 102 | _ASM2(mov ax, SEL_INTR_DS*8) 103 | _ASM2(mov ds, ax) 104 | 105 | _ASM(push sp) 106 | _ASM(call DPMI_INT21H_Translation) 107 | _ASM(pop ax) 108 | 109 | //load DPMI_REG struct into registers 110 | _ASM2(mov bp, sp) 111 | _ASM2(mov ax, word ptr [bp+DPMI_REG_OFF_FLAGS]); //flags 112 | _ASM2(mov word ptr [bp+DPMI_REG_SIZE+4], ax) //IRET flags 113 | _ASM(popad) 114 | _ASM2(add sp, 2) //skip flags 115 | _ASM(pop es) 116 | _ASM(pop ds) 117 | _ASM(pop fs) 118 | _ASM(pop gs) 119 | _ASM2(add sp, 8) //skip cs:ip, ss:sp 120 | _ASM(iret) 121 | _ASM_END 122 | } 123 | 124 | #if DEBUG 125 | static void __NAKED DPMI_INT16H() 126 | { 127 | _ASM_BEGIN 128 | //make a DPMI_REG struct on the stack 129 | _ASM(push ss) 130 | _ASM(push sp) //ss: sp 131 | _ASM(push cs) 132 | _ASM(push ax) 133 | _ASM(push gs) 134 | _ASM(push fs) 135 | _ASM(push ds) 136 | _ASM(push es) 137 | _ASM(pushf) 138 | _ASM(pushad) 139 | 140 | _ASM2(mov ax, SEL_INTR_DS*8) 141 | _ASM2(mov ds, ax) 142 | 143 | _ASM(push sp) 144 | _ASM(push 0x16) 145 | _ASM(call DPMI_CallRealModeINT) 146 | _ASM(pop ax) 147 | _ASM(pop ax) 148 | 149 | //load DPMI_REG struct into registers 150 | _ASM2(mov bp, sp) 151 | _ASM2(mov ax, word ptr [bp+DPMI_REG_OFF_FLAGS]); //flags 152 | _ASM2(mov word ptr [bp+DPMI_REG_SIZE+4], ax) //IRET flags 153 | _ASM(popad) 154 | _ASM2(add sp, 2) //skip flags 155 | _ASM(pop es) 156 | _ASM(pop ds) 157 | _ASM(pop fs) 158 | _ASM(pop gs) 159 | _ASM2(add sp, 8) //skip cs:ip, ss:sp 160 | _ASM(iret) 161 | _ASM_END 162 | } 163 | #endif 164 | #pragma option -k //BC 165 | 166 | #ifdef __cplusplus 167 | } 168 | #endif 169 | 170 | #endif//_DPMI_I21_H_ -------------------------------------------------------------------------------- /hdpmipt.c: -------------------------------------------------------------------------------- 1 | #include "hdpmipt.h" 2 | 3 | #if defined(__DJ2__) 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include "USBDDOS/dbgutil.h" 9 | 10 | #define HDPMIPT_SWITCH_STACK 1 11 | 12 | typedef struct 13 | { 14 | uint32_t edi; 15 | uint16_t es; 16 | }HDPMIPT_ENTRY; 17 | 18 | extern uint32_t __djgpp_stack_top; 19 | 20 | static const char* VENDOR_HDPMI = "HDPMI"; //vendor string 21 | static HDPMIPT_ENTRY HDPMIPT_Entry; 22 | static EMM_IODT* HDPMIPT_Iodt; 23 | static int HDPMIPT_PortCount; 24 | #if HDPMIPT_SWITCH_STACK 25 | static int32_t HDPMIPT_OldESP[2]; 26 | #endif 27 | 28 | uint32_t HDPMIPT_TrapHandler() 29 | { 30 | uint32_t port = 0, out = 0, value = 0; 31 | asm( 32 | "mov %%edx, %0 \n\t" 33 | "mov %%ecx, %1 \n\t" 34 | "mov %%eax, %2 \n\t" 35 | :"=m"(port),"=m"(out),"=m"(value) 36 | : 37 | :"memory" 38 | ); 39 | 40 | for(int i = 0; i < HDPMIPT_PortCount; ++i) 41 | { 42 | if(HDPMIPT_Iodt[i].port == port) 43 | return HDPMIPT_Iodt[i].handler(port, value, out); 44 | } 45 | return value; 46 | } 47 | 48 | void __attribute__((naked)) HDPMIPT_TrapHandlerWrapper() 49 | { 50 | //switch to local stack from trapped client's stack 51 | #if HDPMIPT_SWITCH_STACK 52 | asm( 53 | "cli \n\t" 54 | "mov %%esp, %0 \n\t" 55 | "push %%ss \n\t" 56 | "pop %1 \n\t" 57 | "push %%ds \n\t" 58 | "push %2 \n\t" 59 | "lss 0(%%esp), %%esp \n\t" 60 | :"=m"(HDPMIPT_OldESP[0]),"=m"(HDPMIPT_OldESP[1]) 61 | :"m"(__djgpp_stack_top) 62 | :"memory" 63 | ); 64 | #endif 65 | 66 | HDPMIPT_TrapHandler(); 67 | 68 | #if HDPMIPT_SWITCH_STACK 69 | asm("lss %0, %%esp" : :"m"(HDPMIPT_OldESP[0]) ); //restore stack 70 | #endif 71 | asm("lret"); //retf 72 | } 73 | 74 | int DPMIPT_GetVendorEntry(HDPMIPT_ENTRY* entry) 75 | { 76 | int result = 0; 77 | asm( 78 | "push %%es \n\t" 79 | "push %%esi \n\t" 80 | "push %%edi \n\t" 81 | "xor %%eax, %%eax \n\t" 82 | "xor %%edi, %%edi \n\t" 83 | "mov %%di, %%es \n\t" 84 | "mov $0x168A, %%ax \n\t" 85 | "mov %3, %%esi \n\t" 86 | "int $0x2F \n\t" 87 | "mov %%es, %%cx \n\t" //entry->es & entry->edi may use register esi & edi 88 | "mov %%edi, %%edx \n\t" //save edi to edx and pop first 89 | "pop %%edi \n\t" 90 | "pop %%esi \n\t" 91 | "pop %%es \n\t" 92 | "mov %%eax, %0 \n\t" 93 | "mov %%cx, %1 \n\t" 94 | "mov %%edx, %2 \n\t" 95 | : "=r"(result),"=m"(entry->es), "=m"(entry->edi) 96 | : "m"(VENDOR_HDPMI) 97 | : "eax", "ecx", "edx","memory" 98 | ); 99 | return (result&0xFF) == 0; //al=0 to succeed 100 | } 101 | 102 | uint32_t HDPMI_Internal_InstallTrap(const HDPMIPT_ENTRY* entry, int start, int end, void(*handler)(void)) 103 | { 104 | uint32_t handle = 0; 105 | int count = end - start + 1; 106 | const HDPMIPT_ENTRY ent = *entry; //avoid gcc using ebx 107 | asm( 108 | "push %%ebx \n\t" 109 | "push %%esi \n\t" 110 | "push %%edi \n\t" 111 | "mov %1, %%esi \n\t" //ESI: starting port 112 | "mov %2, %%edi \n\t" //EDI: port count 113 | "xor %%ecx, %%ecx \n\t" 114 | "mov %%cs, %%cx \n\t" //CX: handler code seg 115 | "xor %%ebx, %%ebx \n\t" 116 | "mov %%ds, %%bx \n\t" //BX: handler data seg 117 | "mov %3, %%edx \n\t" //EDX: handler addr 118 | "mov $6, %%eax \n\t" //ax=6, install port trap 119 | "lcall *%4\n\t" 120 | "jc 1f \n\t" 121 | "mov %%eax, %0 \n\t" 122 | "1: pop %%edi \n\t" 123 | "pop %%esi \n\t" 124 | "pop %%ebx \n\t" 125 | :"=m"(handle) 126 | :"m"(start),"m"(count),"m"(handler),"m"(ent) 127 | :"eax","ebx","ecx","edx","memory" 128 | ); 129 | return handle; 130 | } 131 | 132 | BOOL HDPMI_Internal_UninstallTrap(const HDPMIPT_ENTRY* entry, uint32_t handle) 133 | { 134 | BOOL result = FALSE; 135 | asm( 136 | "mov %2, %%edx \n\t" //EDX=handle 137 | "mov $6, %%eax \n\t" //ax=7, unistall port trap 138 | "lcall *%1\n\t" 139 | "jc 1f \n\t" 140 | "mov $1, %%eax \n\t" 141 | "mov %%eax, %0 \n\t" 142 | "1: nop \n\t" 143 | :"=m"(result) 144 | :"m"(*entry),"m"(handle) 145 | :"eax","ecx","edx","memory" 146 | ); 147 | return result; 148 | } 149 | 150 | BOOL HDPMIPT_Install_IOPortTrap(uint16_t start, uint16_t end, EMM_IODT* inputp iodt, uint16_t count, EMM_IOPT* outputp iopt) 151 | { 152 | assert(iopt); 153 | if(!DPMIPT_GetVendorEntry(&HDPMIPT_Entry)) 154 | { 155 | HDPMIPT_Entry.es = 0; 156 | HDPMIPT_Entry.edi = 0; 157 | puts("Failed to get HDPMI Vendor entry point.\n"); 158 | return FALSE; 159 | } 160 | _LOG("HDPMI vendor entry: %04x:%08x\n", HDPMIPT_Entry.es, HDPMIPT_Entry.edi); 161 | 162 | uint32_t handle = HDPMI_Internal_InstallTrap(&HDPMIPT_Entry, start, end, &HDPMIPT_TrapHandlerWrapper); 163 | if(!handle) 164 | { 165 | puts("Failed to intall HDPMI io port trap.\n"); 166 | return FALSE; 167 | } 168 | 169 | assert(!HDPMIPT_Iodt); //unique trap ports for now. TODO: use linked list to support multiple installlation calls 170 | HDPMIPT_Iodt = malloc(sizeof(EMM_IODT)*count); 171 | memcpy(HDPMIPT_Iodt, iodt, sizeof(EMM_IODT)*count); 172 | HDPMIPT_PortCount = count; 173 | //printf("Trap count:%d\n", HDPMIPT_PortCount); 174 | 175 | iopt->memory = (uintptr_t)HDPMIPT_Iodt; 176 | iopt->handle = handle; 177 | iopt->func = 0; 178 | return TRUE; 179 | } 180 | 181 | BOOL HDPMIPT_Uninstall_IOPortTrap(EMM_IOPT* inputp iopt) 182 | { 183 | if(HDPMIPT_Entry.es == 0 || HDPMIPT_Entry.edi == 0) 184 | { 185 | //assert(FALSE); 186 | return FALSE; 187 | } 188 | assert(iopt != NULL && iopt->memory == (uintptr_t)HDPMIPT_Iodt); 189 | 190 | free(HDPMIPT_Iodt); 191 | HDPMIPT_Iodt = NULL; 192 | HDPMIPT_PortCount = 0; 193 | iopt->memory = 0; 194 | 195 | uint32_t handle = iopt->handle; 196 | iopt->handle = 0; 197 | return HDPMI_Internal_UninstallTrap(&HDPMIPT_Entry, handle); 198 | } 199 | 200 | #endif -------------------------------------------------------------------------------- /USBDDOS/DPMI/xms.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include "USBDDOS/DPMI/xms.h" 6 | #include "USBDDOS/DPMI/dpmi.h" 7 | 8 | static DPMI_REG XMSReg = {0}; 9 | 10 | //http://www.phatcode.net/res/219/files/xms30.txt 11 | 12 | #define XMS_IsInited() (XMSReg.w.cs != 0 || XMSReg.w.ip != 0) 13 | 14 | static BOOL XMS_Init(void) 15 | { 16 | if(XMS_IsInited()) 17 | return TRUE; 18 | 19 | memset(&XMSReg, 0, sizeof(XMSReg)); 20 | 21 | XMSReg.w.ax = 0x4300; 22 | DPMI_CallRealModeINT(0x2F, &XMSReg); 23 | if(XMSReg.h.al != 0x80) 24 | { 25 | printf("Error: No XMS found.\n"); 26 | return FALSE; 27 | } 28 | 29 | /* 30 | XMSReg.w.ax = 0x4310; 31 | DPMI_CallRealModeINT(0x2f, &XMSReg); 32 | XMSReg.h.ah = 0x00; //get version. need 3.0 to allocate block larger than 64M 33 | XMSReg.w.cs =XMSReg.w.es; 34 | XMSReg.w.ip =XMSReg.w.bx; 35 | DPMI_CallRealModeRETF(&XMSReg); 36 | if (XMSReg.w.ax != 0x0300) 37 | { 38 | printf("Error: No XMS 3.0 found.\n"); 39 | return handle; 40 | } 41 | */ 42 | 43 | XMSReg.w.ax = 0x4310; 44 | DPMI_CallRealModeINT(0x2F, &XMSReg); //control function in es:bx 45 | XMSReg.w.cs = XMSReg.w.es; 46 | XMSReg.w.ip = XMSReg.w.bx; 47 | XMSReg.w.ss = XMSReg.w.sp = 0; 48 | return TRUE; 49 | } 50 | 51 | uint16_t XMS_Alloc(uint16_t sizeKB, uint32_t* outputp addr) 52 | { 53 | DPMI_REG r; 54 | uint16_t handle = 0; 55 | *addr = 0; 56 | 57 | if(sizeKB == 0) 58 | { 59 | assert(FALSE); 60 | return handle; 61 | } 62 | 63 | if(!XMS_Init()) 64 | { 65 | assert(FALSE); 66 | return handle; 67 | } 68 | 69 | r = XMSReg; 70 | r.h.ah = 0x09; //alloc XMS 71 | r.w.dx = sizeKB; //size in kb 72 | DPMI_CallRealModeRETF(&r); 73 | if (r.w.ax != 0x1) 74 | { 75 | return handle; 76 | } 77 | handle = r.w.dx; 78 | 79 | r = XMSReg; 80 | r.w.dx = handle; 81 | r.h.ah = 0x0C; //lock XMS 82 | DPMI_CallRealModeRETF(&r); 83 | if(r.w.ax != 0x1) 84 | { 85 | printf("Error: Failed to lock XMS memory (%02x).", r.h.bl); 86 | r = XMSReg; 87 | r.h.ah = 0x0A; //free XMS 88 | DPMI_CallRealModeRETF(&r); 89 | return handle; 90 | } 91 | *addr = ((uint32_t)r.w.dx << 16L) | (uint32_t)r.w.bx; 92 | return handle; 93 | } 94 | 95 | BOOL XMS_Realloc(uint16_t handle, uint16_t newSizeKB, uint32_t* outputp addr) 96 | { 97 | BOOL result = FALSE; 98 | DPMI_REG r = XMSReg; 99 | 100 | if(!XMS_IsInited()) 101 | { 102 | assert(FALSE); 103 | return result; 104 | } 105 | 106 | r.h.ah = 0x0D; //unlock first 107 | r.w.dx = handle; 108 | DPMI_CallRealModeRETF(&r); 109 | result = (r.w.ax == 1); 110 | if(!result) 111 | { 112 | assert(FALSE); 113 | return result; 114 | } 115 | 116 | r = XMSReg; 117 | r.h.ah = 0x0F; 118 | r.w.dx = handle; 119 | r.w.bx = newSizeKB; 120 | DPMI_CallRealModeRETF(&r); 121 | result = (r.w.ax == 1); 122 | if(!result) 123 | { 124 | assert(FALSE); 125 | return result; 126 | } 127 | 128 | r = XMSReg;//relock 129 | r.w.dx = handle; 130 | r.h.ah = 0x0C; 131 | DPMI_CallRealModeRETF(&r); 132 | result = (r.w.ax == 1); 133 | if(!result) 134 | { 135 | *addr = 0; 136 | assert(FALSE); 137 | } 138 | else 139 | *addr = ((uint32_t)r.w.dx << 16L) | (uint32_t)r.w.bx; 140 | return result; 141 | } 142 | 143 | BOOL XMS_Free(uint16_t handle) 144 | { 145 | DPMI_REG r = XMSReg; 146 | 147 | if(!XMS_IsInited()) 148 | { 149 | assert(FALSE); 150 | return FALSE; 151 | } 152 | 153 | //printf("unlocking XMS...\n"); 154 | r.h.ah = 0x0D; 155 | r.w.dx = handle; 156 | DPMI_CallRealModeRETF(&r); 157 | if(r.w.ax != 1) 158 | { 159 | assert(FALSE); 160 | return FALSE; 161 | } 162 | 163 | //printf("freeing XMS...\n"); 164 | r = XMSReg; 165 | r.h.ah = 0x0A; 166 | r.w.dx = handle; 167 | DPMI_CallRealModeRETF(&r); 168 | assert(r.w.ax == 1); 169 | return r.w.ax == 1; 170 | } 171 | 172 | BOOL XMS_EnableA20() 173 | { 174 | if(!XMS_Init()) 175 | { 176 | assert(FALSE); 177 | return FALSE; 178 | } 179 | 180 | DPMI_REG r = XMSReg; 181 | r.h.ah = 0x07; //query A20 182 | DPMI_CallRealModeRETF(&r); 183 | if(r.w.ax == 1) 184 | return TRUE; 185 | 186 | r = XMSReg; 187 | r.h.ah = 0x03; 188 | DPMI_CallRealModeRETF(&r); 189 | return r.w.ax == 1; 190 | } 191 | 192 | BOOL XMS_DisableA20() 193 | { 194 | if(!XMS_IsInited()) 195 | { 196 | assert(FALSE); 197 | return FALSE; 198 | } 199 | 200 | DPMI_REG r = XMSReg; 201 | r.h.ah = 0x04; 202 | DPMI_CallRealModeRETF(&r); 203 | return r.w.ax == 1; 204 | } 205 | 206 | uint16_t XMS_AllocUMB(uint16_t size16B) 207 | { 208 | DPMI_REG r; 209 | uint16_t segment = 0; 210 | if(size16B == 0 || size16B > 0xFFF) 211 | { 212 | assert(FALSE); 213 | return segment; 214 | } 215 | if(!XMS_Init()) 216 | { 217 | assert(FALSE); 218 | return segment; 219 | } 220 | r = XMSReg; 221 | r.h.ah = 0x10; //alloc UMB 222 | r.w.dx = size16B; //size in paragrah 223 | DPMI_CallRealModeRETF(&r); 224 | if(r.w.ax == 1) //succeess 225 | segment = r.w.bx; 226 | return segment; 227 | } 228 | 229 | BOOL XMS_FreeUMB(uint16_t segment) 230 | { 231 | BOOL result = FALSE; 232 | DPMI_REG r = XMSReg; 233 | if(!XMS_IsInited()) 234 | { 235 | assert(FALSE); 236 | return result; 237 | } 238 | if(segment == 0) 239 | return result; 240 | r.h.ah = 0x11; 241 | r.w.dx = segment; 242 | DPMI_CallRealModeRETF(&r); 243 | result = (r.w.ax == 1); 244 | if(!result) 245 | printf("Error: Failed to free UMB memory (%02x).", r.h.bl); 246 | return result; 247 | } 248 | -------------------------------------------------------------------------------- /USBDDOS/CLASS/hid.h: -------------------------------------------------------------------------------- 1 | #ifndef _HID_H_ 2 | #define _HID_H_ 3 | //Human Interface Class 4 | //Device Class Definition for Human Interface Devices (HID) version 1.11: 5 | //https://usb.org/sites/default/files/hid1_11.pdf 6 | // 7 | //the Universal Serial Bus HID Usage Tables (for key codes) 8 | //https://www.usb.org/sites/default/files/documents/hut1_12v2.pdf 9 | // 10 | //the HID class uses an mandantory interrupt input and an optional interrupt output end point. 11 | //the boot interface is required for bootable HID devices, i.e. used by BIOS to support simple input in BIOS setup menu, or in DOS 12 | //the boot interface is more simple and here is to be supported and supported only. 13 | 14 | //Keyboard working in Virtualbox, DOS7.0 command line, but not working in EDIT.COM, neither some games. 15 | //But wholly working in real machines, tested in DOS7.1(win98 real dos). 16 | //tested with Skyroads, cannot jump(SPACE) when both UP+LEFT(or RIGHT) are pressed, debug shows the keyboard won't send 3 key combinations, it's not a driver's bug 17 | 18 | //tested mouse with WarcraftII, movement go wild soon after in game. need more test & bugfix - now it works 19 | 20 | #include "USBDDOS/usb.h" 21 | 22 | #define USB_REQ_TYPE_HID (USB_REQTYPE_CLASS | USB_REQREC_INTERFACE) 23 | 24 | //descriptor type 25 | #define USB_DT_HID 0x21 26 | #define USB_DT_REPORT 0x22 27 | 28 | //bInterfaceSubClass 29 | #define USB_HIDSC_NO 0 //no subclass 30 | #define USB_HIDSC_BOOT_INTERFACE 1 //boot interface 31 | 32 | //bInterfaceProtocol 33 | #define USB_HIDP_NONE 0 34 | #define USB_HIDP_KEYBOARD 1 35 | #define USB_HIDP_MOUSE 2 36 | 37 | //bRequest. see Appendix G for requirments: Boot mouse, Nonboot mouse, Boot keyboard, Nonboot keyboard (Y=required, O=optional) 38 | #define USB_REQ_HID_GET_REPORT 0x01 // Y Y Y Y 39 | #define USB_REQ_HID_GET_IDLE 0x02 // O O O O 40 | #define USB_REQ_HID_GET_PROTOCOL 0x03 // Y O Y Y 41 | #define USB_REQ_HID_SET_REPORT 0x09 // O O Y Y 42 | #define USB_REQ_HID_SET_IDLE 0x0A // O O Y O 43 | #define USB_REQ_HID_SET_PROTOCOL 0x0B // Y O Y O 44 | 45 | //USB_REQ_HID_?ET_PROTOCOL 46 | #define USB_HID_PROTOCOL_BOOT 0 47 | #define USB_HID_PROTOCOL_REPORT 1 48 | 49 | //USB_REQ_HID_SET_IDLE 50 | #define USB_HID_MAKE_IDLE(duration, ReportID) ((uint16_t)(((duration)<<8)|((ReportID)&0xFF))) 51 | #define USB_HID_IDLE_INDEFINITE 0 52 | #define USB_HID_IDLE_REPORTALL 0 53 | 54 | //USB_REQ_HID_?ET_REPORT 55 | #define USB_HID_REPORT_INPUT 0x1 56 | #define USB_HID_REPORT_OUTPUT 0x2 57 | #define USB_HID_REPORT_FEATURE 0x2 58 | #define USB_HID_MAKE_REPORT(ReportType, ReportID) ((uint16_t)(((ReportType)<<8)|((ReportID)&0xFF))) 59 | 60 | //bit masks for modifier, chapter 8.3 61 | #define USB_HID_LCTRL 0x01 62 | #define USB_HID_LSHIFT 0x02 63 | #define USB_HID_LALT 0x04 64 | #define USB_HID_LGUI 0x08 65 | #define USB_HID_RCTRL 0x10 66 | #define USB_HID_RSHIFT 0x20 67 | #define USB_HID_RALT 0x40 68 | #define USB_HID_RGUI 0x80 69 | 70 | //keyboard LEDs (use output report to set) 71 | //B.1 Protocol 1(Keyboard) 72 | #define USB_HID_LED_NUMLOCK 0x01 73 | #define USB_HID_LED_CAPSLOCK 0x02 74 | #define USB_HID_LED_SCROLLLOCK 0x04 75 | #define USB_HID_LED_COMPOSE 0x08 76 | #define USB_HID_LED_KANA 0x10 77 | 78 | #if defined(__DJ2__) 79 | #pragma pack(1) 80 | #endif 81 | 82 | typedef struct USB_HID_SubDescriptor 83 | { 84 | uint8_t bDescriptorType; 85 | uint16_t wDescriptorLength; 86 | }USB_HID_SUBDESC; 87 | 88 | typedef struct USB_HID_Descritor 89 | { 90 | uint8_t bLength; 91 | uint8_t bDescriptorType; //USB_HID_DESCRIPTOR 92 | uint16_t bcdHID; 93 | uint8_t bCountryCode; 94 | uint8_t bNumberDescriptors; 95 | USB_HID_SUBDESC desc[1]; //could be more USB_HID_SUBDESC, decided by bNumberDescriptors 96 | }USB_HID_DESC; 97 | #if defined(__DJ2__) 98 | static_assert(sizeof(USB_HID_DESC) == 9, "incorrect size"); //minimal size 99 | #endif 100 | 101 | //boot protocol keyboard packet. Appendix B.1 102 | typedef struct USB_HID_KeyPacket_Boot 103 | { 104 | uint8_t Modifier; 105 | uint8_t Reserved; //not used in boot protocol 106 | uint8_t Keycodes[6]; 107 | }USB_HID_KEY; 108 | 109 | //boot protocol mouse packet. Appendix B.2 110 | typedef struct USB_HIDE_MousePacket_Boot 111 | { 112 | //uint8_t Button1 : 1; 113 | //uint8_t Button2 : 1; 114 | //uint8_t Button3 : 1; 115 | //uint8_t unused : 5; 116 | uint8_t Button; 117 | 118 | int8_t DX; 119 | int8_t DY; 120 | 121 | }USB_HID_MOUSE; 122 | 123 | #if defined(__DJ2__) 124 | #pragma pack() 125 | #endif 126 | 127 | typedef union 128 | { 129 | uint8_t Buffer[8]; 130 | USB_HID_KEY Key; 131 | USB_HID_MOUSE Mouse; 132 | }USB_HID_Data; 133 | 134 | typedef struct 135 | { 136 | USB_HID_DESC* Descriptors; 137 | void* pDataEP[2]; //interrupt in/out 138 | uint8_t bEPAddr[2]; 139 | uint8_t bInterface; 140 | uint8_t Idle : 1; 141 | uint8_t Index : 1; //index to Data, flipped each time 142 | uint16_t BIOSModifier; 143 | uint8_t PrevCount; 144 | uint8_t Interval; //interval for interrupt input endpoint 145 | uint8_t RecordCount; // 146 | uint8_t Records[6]; //record key in pressed order. after one key up, deciding the effective one 147 | 148 | USB_HID_Data Data[2]; 149 | uint16_t DelayTimer; 150 | uint16_t RepeatingTimer; 151 | 152 | }USB_HID_Interface; 153 | 154 | #define USB_HID_KEYBOARD 0 155 | #define USB_HID_MOUSE 1 156 | 157 | typedef struct 158 | { 159 | USB_HID_Interface Interface[2]; //USB_HID_KEYBOARD or USB_HID_MOUSE. There're wireless kbd & mouse devices with one USB receiver. 160 | }USB_HID_DriverData; 161 | 162 | #ifdef __cplusplus 163 | extern "C" 164 | { 165 | #endif 166 | 167 | BOOL USB_HID_InitDevice(USB_Device* pDevice); 168 | 169 | BOOL USB_HID_DeinitDevice(USB_Device* pDevice); 170 | 171 | BOOL USB_HID_DOS_Install(); 172 | BOOL USB_HID_DOS_Uninstall(); 173 | 174 | void USB_HID_PreInit(); 175 | void USB_HID_PostDeInit(); 176 | 177 | #ifdef __cplusplus 178 | } 179 | #endif 180 | 181 | #endif//_HID_H_ 182 | -------------------------------------------------------------------------------- /USBDDOS/HCD/hcd.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "USBDDOS/HCD/hcd.h" 4 | #include "USBDDOS/DPMI/dpmi.h" 5 | #include "USBDDOS/usballoc.h" 6 | #include "USBDDOS/dbgutil.h" 7 | 8 | static uint16_t HCD_RootHub_GetPortStatus(struct HCD_HUB* pHub, uint8_t port) 9 | { 10 | assert(pHub && pHub->pHCI && port < pHub->bNumPorts); 11 | return pHub->pHCI->pHCDMethod->GetPortStatus(pHub->pHCI, port); 12 | } 13 | 14 | static BOOL HCD_RootHub_SetPortStatus(struct HCD_HUB* pHub, uint8_t port, uint16_t status) 15 | { 16 | assert(pHub && pHub->pHCI && port < pHub->bNumPorts); 17 | return pHub->pHCI->pHCDMethod->SetPortStatus(pHub->pHCI, port, status); 18 | } 19 | 20 | const HCD_HUB HCD_ROOT_HUB_Prototype = 21 | { 22 | "ROOT HUB", 23 | NULL, 24 | NULL, 25 | 0, 26 | 0, 27 | HCD_RootHub_GetPortStatus, 28 | HCD_RootHub_SetPortStatus, 29 | }; 30 | 31 | BOOL HCD_InitController(HCD_Interface* pHCI, uint8_t bus, uint8_t dev, uint8_t func, HCD_Type* type, PCI_DEVICE* pPCIDev) 32 | { 33 | memset(pHCI, 0, sizeof(HCD_Interface)); 34 | pHCI->PCIAddr.Bus = bus; 35 | pHCI->PCIAddr.Device = dev; 36 | pHCI->PCIAddr.Function = func; 37 | pHCI->PCI = *pPCIDev; 38 | pHCI->pType = type; //set prematurely 39 | return (type != NULL && type->dwPI == pPCIDev->Header.PInterface && type->InitController != NULL) ? type->InitController(pHCI, pPCIDev) : FALSE; 40 | } 41 | 42 | BOOL HCD_DeinitController(HCD_Interface* pHCI) 43 | { 44 | BOOL result = HCD_IS_CONTROLLER_VALID(pHCI); 45 | result = result && pHCI->pType->DeinitController(pHCI); 46 | if(result) 47 | memset(pHCI, 0, sizeof(*pHCI)); 48 | return result; 49 | } 50 | 51 | BOOL HCD_InitDevice(HCD_HUB* pHub, HCD_Device* pDevice, uint8_t port, uint16_t portStatus) 52 | { 53 | if(pDevice == NULL || pHub->pHCI->bDevCount >= HCD_MAX_DEVICE_COUNT) 54 | return FALSE; 55 | memset(pDevice, 0, sizeof(HCD_Device)); 56 | pHub->pHCI->DeviceList[pHub->pHCI->bDevCount++] = pDevice; 57 | 58 | pDevice->pHCI = pHub->pHCI; 59 | pDevice->pHub = pHub; 60 | pDevice->bHubPort = port; 61 | pDevice->bSpeed = portStatus&USB_PORT_SPEEDMASK; 62 | pDevice->pHCData = NULL; 63 | return pHub->pHCI->pHCDMethod->InitDevice(pDevice); 64 | } 65 | 66 | HCD_Device* HCD_FindDevice(HCD_Interface* pHCI, uint8_t address) 67 | { 68 | for(int i = 0; i < pHCI->bDevCount; ++i) 69 | { 70 | if(pHCI->DeviceList[i]->bAddress == address) 71 | return pHCI->DeviceList[i]; 72 | } 73 | return NULL; 74 | } 75 | 76 | BOOL HCD_RemoveDevice(HCD_Device* pDevice) 77 | { 78 | if(!HCD_IS_DEVICE_VALID(pDevice)) 79 | return FALSE; 80 | unsigned int i = 0; 81 | while(i < pDevice->pHCI->bDevCount && pDevice->pHCI->DeviceList[i] != pDevice) ++i; 82 | if(i == pDevice->pHCI->bDevCount) 83 | { 84 | assert(FALSE); 85 | return FALSE; 86 | } 87 | 88 | assert(pDevice->pRequest == NULL); 89 | 90 | BOOL result = pDevice->pHub->SetPortStatus(pDevice->pHub, pDevice->bHubPort, USB_PORT_RESET); //No need to do that, but do it for safety 91 | assert(result); 92 | result = result && pDevice->pHub->SetPortStatus(pDevice->pHub, pDevice->bHubPort, USB_PORT_DISABLE); 93 | assert(result); 94 | result = result && pDevice->pHCI->pHCDMethod->RemoveDevice(pDevice); 95 | assert(result); 96 | 97 | if(result) 98 | { 99 | memmove(&pDevice->pHCI->DeviceList[i],&pDevice->pHCI->DeviceList[i+1],(pDevice->pHCI->bDevCount-i-1)*sizeof(HCD_Device*)); 100 | pDevice->pHCI->DeviceList[--pDevice->pHCI->bDevCount] = NULL; 101 | pDevice->pHCData = NULL; 102 | pDevice->pHCI = NULL; 103 | } 104 | return result; 105 | } 106 | 107 | HCD_Request* HCD_AddRequest(HCD_Device* pDevice, void* pEndpoint, HCD_TxDir dir, void* pBuffer, uint16_t size, uint8_t endpoint, HCD_COMPLETION_CB pFnCB, void* pCallbackData) 108 | { 109 | if(!HCD_IS_DEVICE_VALID(pDevice) || pEndpoint == NULL || pFnCB == NULL) 110 | return NULL; 111 | //check buffer overlap. it's logical that transfer buffers won't overlap. 112 | #if DEBUG 113 | { 114 | CLIS(); 115 | volatile HCD_Request* req = pDevice->pRequest; 116 | while(req != NULL) 117 | { 118 | if(pBuffer >= req->pBuffer && (uint8_t*)pBuffer <= (uint8_t*)req->pBuffer + req->size) 119 | return NULL; 120 | req = req->pNext; 121 | } 122 | STIL(); 123 | } 124 | #endif 125 | HCD_Request* pRequest = (HCD_Request*)USB_TAlloc32(sizeof(HCD_Request)); 126 | if(!pRequest) 127 | return pRequest; 128 | pRequest->pDevice = pDevice; 129 | pRequest->pBuffer = pBuffer; 130 | pRequest->pEndpoint = pEndpoint; 131 | pRequest->pFnCB = pFnCB; 132 | pRequest->pCBData = pCallbackData; 133 | pRequest->size = size; 134 | pRequest->dir = dir; 135 | pRequest->endpoint = endpoint; 136 | 137 | CLIS(); 138 | pRequest->pNext = pDevice->pRequest; 139 | pDevice->pRequest = pRequest; 140 | STIL(); 141 | return pRequest; 142 | } 143 | 144 | BOOL HCD_InvokeCallBack(HCD_Request* pRequest, uint16_t actuallen, uint8_t ecode) //called in interrupt handlers 145 | { 146 | //_LOG("HCD Invoke CB: %08lx %08lx %08lx\n", pRequest, pRequest ? pRequest->pDevice : NULL, (pRequest && pRequest->pDevice) ? pRequest->pDevice->pRequest : NULL); 147 | if(pRequest == NULL || pRequest->pDevice == NULL) 148 | { 149 | assert(FALSE); 150 | return FALSE; 151 | } 152 | CLIS(); 153 | HCD_Request* req = pRequest->pDevice->pRequest; 154 | HCD_Request* prev = NULL; 155 | while(req != NULL && req != pRequest) 156 | { 157 | prev = req; 158 | req = req->pNext; 159 | } 160 | if(!req) 161 | { 162 | STIL(); 163 | _LOG("req %x device req: %x ", pRequest, pRequest->pDevice->pRequest); 164 | assert(FALSE); 165 | return FALSE; 166 | } 167 | assert(req == pRequest); 168 | if(prev) 169 | prev->pNext = req->pNext; 170 | else 171 | pRequest->pDevice->pRequest = req->pNext; 172 | //_LOG("HCD request remaining: %08lx\n", pRequest->pDevice->pRequest); 173 | STIL(); 174 | req->transferred = actuallen; 175 | req->error = ecode; 176 | req->pFnCB(req); 177 | //_LOG("Free req: %08lx\n", req); 178 | USB_TFree32(req); 179 | return TRUE; 180 | } 181 | -------------------------------------------------------------------------------- /USBDDOS/HCD/hcd.h: -------------------------------------------------------------------------------- 1 | #ifndef _HCD_H_ 2 | #define _HCD_H_ 1 3 | #include "USBDDOS/platform.h" 4 | #include "USBDDOS/USBCFG.H" 5 | #include "USBDDOS/pci.h" 6 | 7 | //host controler driver generic 8 | 9 | #define USB_MAX_HC_TYPE 3 //only to support uhci, ohci, ehci 10 | 11 | #ifdef __cplusplus 12 | extern "C" { 13 | #endif 14 | 15 | struct HCD_HostControllerInterface; 16 | typedef struct HCD_HostControllerInterface HCD_Interface; 17 | struct HCD_RequestBlock; 18 | typedef struct HCD_RequestBlock HCD_Request; 19 | typedef struct HCD_HUB HCD_HUB; 20 | 21 | typedef struct //device in HC's view 22 | { 23 | uint8_t bHubPort; //0 based port index 24 | uint8_t bAddress; //device address assigned outside by enumeration process 25 | uint8_t bSpeed; 26 | uint8_t bReserved; //temp padding 27 | HCD_Request* volatile pRequest; 28 | HCD_Interface* pHCI; //unique host controller data 29 | void* pHCData; //per device host controller data 30 | HCD_HUB* pHub; 31 | }HCD_Device; 32 | 33 | #define HCD_IS_DEVICE_VALID(device) ((device) != NULL && (device)->pHCData != NULL && (device)->pHCI != NULL) 34 | 35 | typedef enum HCD_TransferDirection 36 | { 37 | HCD_TXW = 0x0, //host to device 38 | HCD_TXR = 0x1, //device to host 39 | }HCD_TxDir; 40 | 41 | typedef void(*HCD_COMPLETION_CB) (HCD_Request* pRequest); 42 | 43 | typedef struct HCD_RequestBlock //TODO: use request block as transfer parameter? (like URB in OSes) 44 | { 45 | HCD_Device* pDevice; 46 | void* pBuffer; 47 | void* pEndpoint; 48 | HCD_COMPLETION_CB pFnCB; //user callback 49 | void* pCBData;//user specified data 50 | HCD_Request* pNext; 51 | uint16_t size; //required size in bytse 52 | uint16_t transferred; //transferred size 53 | uint8_t endpoint; //endpoint addr (num) 54 | uint8_t dir; //HCD_TxDir 55 | uint8_t error; //error code 56 | uint8_t padding1[1]; //pad to 32 bytes 57 | #if defined(__BC__) || defined(__WC__) 58 | #if defined(__MEDIUM__) || defined(__LARGE__) 59 | uint16_t padding2[4]; //TODO: 60 | #else 61 | uint16_t padding2[6]; //TODO: 62 | #endif 63 | #endif 64 | }HCD_Request; 65 | 66 | static_assert(sizeof(HCD_Request) <= 32, "size error"); 67 | 68 | //note: pSetupData & setup8 must be allocated with DPMI_DMAMalloc, or from device buffer 69 | typedef uint8_t (*HCD_CONTROL_FUNCTION) (HCD_Device* pDevice, void* pEndPoint, HCD_TxDir dir, uint8_t inputp setup8[8], 70 | void* nullable pSetupData, uint16_t length, HCD_COMPLETION_CB pCB, void* nullable pCBData); //setup always 8B by the spec 71 | 72 | //note: pBuffer must be allocated with DPMI_DMAMalloc, or from device buffer 73 | typedef uint8_t (*HCD_TRANSFER_FUNCTION) (HCD_Device* pDevice, void* pEndPoint, HCD_TxDir dir, uint8_t* inoutp pBuffer, 74 | uint16_t length, HCD_COMPLETION_CB pCB, void* nullable pCBData); 75 | 76 | typedef struct HCD_HostrControllerDriverMethod 77 | { 78 | HCD_CONTROL_FUNCTION ControlTransfer; 79 | 80 | HCD_TRANSFER_FUNCTION IsochronousTransfer; 81 | 82 | HCD_TRANSFER_FUNCTION BulkTransfer; 83 | 84 | HCD_TRANSFER_FUNCTION InterruptTransfer; 85 | 86 | uint16_t (*GetPortStatus)(HCD_Interface* pHCI, uint8_t port); 87 | 88 | BOOL (*SetPortStatus)(HCD_Interface* pHCI, uint8_t port, uint16_t status); 89 | 90 | BOOL (*InitDevice)(HCD_Device* pDevice); 91 | 92 | BOOL (*RemoveDevice)(HCD_Device* pDevice); 93 | 94 | void* (*CreateEndpoint)(HCD_Device* pDevice, uint8_t EPAddr, HCD_TxDir dir, uint8_t bTransferType, uint16_t MaxPacketSize, uint8_t bInterval); 95 | 96 | BOOL (*RemoveEndPoint)(HCD_Device* pDevice, void* pEndpoint); 97 | 98 | }HCD_Method; 99 | 100 | typedef struct HCD_HostControllerType 101 | { 102 | uint32_t dwPI; //program interface 103 | const char* name; 104 | BOOL (*InitController)(HCD_Interface* pHCI, PCI_DEVICE* pPCIDev); 105 | BOOL (*DeinitController)(HCD_Interface* pHCI); 106 | BOOL (*ISR)(HCD_Interface* pHCI); //DON'T do IO, memory allocation in ISR. 107 | }HCD_Type; 108 | 109 | typedef struct HCD_HostControllerInterface 110 | { 111 | PCI_Addr PCIAddr; //BDF,set by outside routine 112 | PCI_DEVICE PCI; 113 | HCD_Type* pType; 114 | HCD_Method* pHCDMethod; //host controller driver methods 115 | void* pHCDData; //host controller driver data 116 | uint32_t dwPhysicalAddress; //physical memory address (not directly accessible) 117 | uint32_t dwBaseAddress; //IO port address or MMIO linear address 118 | HCD_Device* DeviceList[HCD_MAX_DEVICE_COUNT]; 119 | uint8_t bNumPorts; 120 | uint8_t bDevCount; 121 | }HCD_Interface; 122 | 123 | #define HCD_IS_CONTROLLER_VALID(phc) (phc != NULL && phc->pType != NULL && phc->pHCDMethod != NULL && phc->pHCDData != NULL) 124 | 125 | BOOL HCD_InitController(HCD_Interface* pHCI, uint8_t bus, uint8_t dev, uint8_t func, HCD_Type* type, PCI_DEVICE* pPCIDev); 126 | 127 | BOOL HCD_DeinitController(HCD_Interface* pHCI); 128 | 129 | BOOL HCD_InitDevice(HCD_HUB* pHub, HCD_Device* pDevice, uint8_t port, uint16_t portStatus); 130 | 131 | HCD_Device* HCD_FindDevice(HCD_Interface* pHCI, uint8_t address); 132 | 133 | BOOL HCD_RemoveDevice(HCD_Device* pDevice); 134 | 135 | //called internally by HC driver 136 | HCD_Request* HCD_AddRequest(HCD_Device* pDevice, void* pEndpoint, HCD_TxDir dir, void* pBuffer, uint16_t size, uint8_t endpoint, HCD_COMPLETION_CB pFnCB, void* pCallbackData); 137 | 138 | //invoke callback and remove the request entry 139 | BOOL HCD_InvokeCallBack(HCD_Request* pRequest, uint16_t actuallen, uint8_t ecode); 140 | 141 | //the initial state of all ports on a hub device should be disabled, @see USB_EnumerateDevices 142 | typedef struct HCD_HUB 143 | { 144 | const char* name; 145 | HCD_Interface* pHCI; //HC of this hub, always valid 146 | HCD_Device* pDevice; //optional, only valid if it is a hub device, instead of root hub 147 | uint8_t bHubAddress; //optional, only valid if it is a hub device, instead of root hub 148 | uint8_t bNumPorts; 149 | 150 | //hub functions 151 | uint16_t (*GetPortStatus)(struct HCD_HUB* pHCI, uint8_t port); 152 | BOOL (*SetPortStatus)(struct HCD_HUB* pHCI, uint8_t port, uint16_t status); 153 | }HCD_HUB; 154 | 155 | extern const HCD_HUB HCD_ROOT_HUB_Prototype; //root hub prototype, copy it and set 'pHCI & bNumPorts' and it's done. 156 | 157 | #ifdef __cplusplus 158 | } 159 | #endif 160 | 161 | #endif 162 | -------------------------------------------------------------------------------- /USBDDOS/DPMI/dpmi_ldr.h: -------------------------------------------------------------------------------- 1 | ////////////////////////////////////////////////////////////////////////////// 2 | // A DPMI run time patcher to alt real mode relocation segments to protected 3 | // mode selectors. 4 | // It is a patch, not a REAL LOADER. 5 | // The potential problems of using the pather is if app code (client) 6 | // programatically copys the rellocation data before switching 7 | // to proteced mode, then the copied data cannot be patched. 8 | // Fortunately that usually doesn't happens. 9 | // To handle that case perfectly we need a real loader before program 10 | // startup, and also a stub utility to stub the executable, 11 | // But that will not be done here. 12 | // 13 | // There's also a problem that the C library startup & cleanup 14 | // routine may made a copy of the relocations on the stack, 15 | // we either do one of this: 16 | // 17 | // 1.walk the stack to modify the selector to segments befoe 18 | // switching to real mode. this not much reliable, but simpler. 19 | // 20 | // 2.user compiler/library specific feature such as init_seg to make 21 | // DPMI shutdown at the last so that the protected mode DS is not 22 | // accessed afterwards. (still it's not working for WC, 23 | // because WC's c lib still accesses DS after finializing runtime) 24 | // 25 | // 3.never going back to real mode(execpt on final exiting), and install 26 | // a int 21 handler to translate DOS terminate & IO function call. 27 | // This sounds intriguing but may have problems, because a 16 bit 28 | // C library might potentially use any real mode segment besieds the CS/DS 29 | // so it needs a customized C lib to work perfectly (like DJGPP). 30 | // but if a customized C lib is used, the problem itself can 31 | // be avoid without any hacks used here. 32 | // This method tested OK for WC. 33 | // 34 | // 4.a custom C lib that take care of any use of real mode segments 35 | // and so we don't need this loader patch as compiled in BC. 36 | // It might also usefull for using SMALL memory models. 37 | // Because the custom C lib could be tiny & compact enough, 38 | // with unused functions removed, thus we don't need support MEDIUM/LARGE models. 39 | // (Currently the iostream function is not used, except the this loader) 40 | // the C lib of Public Domain Operation System (PDOS), PDPCLIB 41 | // https://sourceforge.net/projects/pdos/ (supports BC & WC) 42 | // may be used as base to cusmize a small C lib 43 | // 44 | // 5. when invalid segment happens, handle it in exception hander, 45 | // changing real mode segments to selectors. 46 | // this also may not work because 47 | // although selectors value now are very small, 48 | // real mode lib may try to access the segment in very low memory(i.e IVT) 49 | // thus made CPU treat the segments as selectors. 50 | // 51 | // 52 | // Currently the combined methods of 3 and 5 are used. 53 | // 54 | ////////////////////////////////////////////////////////////////////////////// 55 | #ifndef _DPMI_LDR_H_ 56 | #define _DPMI_LDR_H_ 57 | #include "USBDDOS/platform.h" 58 | 59 | #ifdef __cplusplus 60 | extern "C" { 61 | #endif 62 | 63 | typedef struct MZHeader 64 | { 65 | uint16_t MZ; 66 | uint16_t extra; 67 | uint16_t pages; 68 | uint16_t relocations; 69 | uint16_t size; //in paragraphs (16 bytes) 70 | uint16_t min_alloc; //min program size in paragraphs, including code, excluding PSP 71 | uint16_t max_alloc; //max program size in paragraphs, including code, excluding PSP 72 | uint16_t initSS; 73 | uint16_t initSP; 74 | uint16_t checksum; 75 | uint16_t initIP; 76 | uint16_t initCS; 77 | uint16_t relocation_tbl; 78 | uint16_t overlay; 79 | uint16_t overlay_num; 80 | 81 | }MZHEADER; 82 | static_assert(sizeof(MZHEADER) == 0x1E, "size error"); 83 | 84 | typedef struct RelocationTable 85 | { 86 | uint16_t offset; 87 | uint16_t segment; 88 | }RELOC_TABLE; 89 | 90 | extern MZHEADER DPMI_LOADER_Header; 91 | 92 | #if defined(__MEDIUM__) || defined(__LARGE__) 93 | #define DPMI_CS_MAX 32 //some compiler (i.e.) generate a segment for each compile unit, currently 32 is enough. for WC the link will merge segments and there'll be 2 or more. 94 | #else 95 | #define DPMI_CS_MAX 1 96 | #endif 97 | 98 | #if defined(__COMPACT__) || defined(__LARGE__) 99 | #define DPMI_DS_MAX 32 100 | #else 101 | #define DPMI_DS_MAX 1 102 | #endif 103 | 104 | //segments might not be in full 64K sizes, need record the starts 105 | extern int DPMI_LOADER_CS_Count; 106 | extern int DPMI_LOADER_DS_Count; 107 | extern uint16_t DPMI_LOADER_SegMain; //this a C wrapper to get address of main for C++ 108 | extern uint16_t DPMI_LOADER_CS[DPMI_CS_MAX]; 109 | extern uint16_t DPMI_LOADER_DS[DPMI_DS_MAX]; 110 | 111 | BOOL DPMI_LOADER_Init(uint16_t cs, uint16_t ds, uint32_t code_size); 112 | 113 | //patch relocation in place, in conventional memory in real mode 114 | //note: extern functions called be called in real mode anymore after patching. 115 | BOOL DPMI_LOADER_PatchRM(uint32_t code_size, uint16_t cs, uint16_t cs_sel, uint16_t ds_sel, uint32_t size); 116 | 117 | //patch relocations. 118 | //input: 119 | // code_size: total size of the code segments 120 | // cs, ds: real mode segments 121 | // cs_sel, ds_sel: protected mode selectors 122 | // assume selectors are contingous, i.e. next code selector is cs_sel+8 123 | // address: proteced mode linear address of the beginging of whole program data in HIMEM 124 | // size: size of whole program data 125 | //MUST be called in PM mode. 126 | BOOL DPMI_LOADER_Patch(uint32_t code_size, uint16_t cs, uint16_t cs_sel, uint16_t ds_sel, uint32_t address, uint32_t size); 127 | 128 | int DPMI_LOADER_GetCSIndex(uint16_t segment); 129 | int DPMI_LOADER_GetDSIndex(uint16_t segment); 130 | 131 | //same as DPMI_LOADER_Get*, without debug checks 132 | int DPMI_LOADER_FindCSIndex(uint16_t segment); 133 | int DPMI_LOADER_FindDSIndex(uint16_t segment); 134 | 135 | uint16_t DPMI_LOADER_GetCS(int index); 136 | uint16_t DPMI_LOADER_GetDS(int index); 137 | 138 | BOOL DPMI_LOADER_Unpatch(uint32_t code_size, uint16_t cs_sel, uint16_t cs_selend, uint16_t ds_sel, uint16_t ds_selend, uint32_t address, uint32_t size); 139 | 140 | //replace cs_seg to cs_sel directly on stack, limit stack depth, and count of replacements 141 | BOOL DPMI_LOADER_PatchStack(uint16_t cs_seg, uint16_t cs_sel, uint16_t sp, int depth, int count); 142 | 143 | #if DEBUG 144 | void DPMI_LOADER_DumpSegments(); 145 | #endif 146 | 147 | BOOL DPMI_LOADER_Shutdown(); 148 | 149 | #ifdef __cplusplus 150 | } 151 | #endif 152 | 153 | #endif//_DPMI_LDR_H_ 154 | -------------------------------------------------------------------------------- /USBDDOS/CLASS/cdc.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include "USBDDOS/CLASS/cdc.h" 6 | #include "USBDDOS/DPMI/dpmi.h" 7 | #include "USBDDOS/dbgutil.h" 8 | 9 | static uint8_t USB_CDC_LineCoding(USB_Device* pDevice, USB_CDC_LINE_CODING* LineCoding, BOOL Read) 10 | { 11 | USB_CDC_DriverData* pDriverData = (USB_CDC_DriverData*)pDevice->pDriverData; 12 | 13 | USB_InterfaceDesc* pIntfaceDesc0 = pDevice->pConfigList[pDevice->bCurrentConfig].pInterfaces; 14 | if(pIntfaceDesc0->bInterfaceSubClass != USBC_CDCSC_ABSTRACT_CONTROL_MODEL) 15 | return 0xFF; //only ACM support it 16 | if(!(pDriverData->ACMDesc.bmCapabilities&USBCAP_CDC_ACM_LINE_CODING)) 17 | return 0xFF; 18 | 19 | USB_Request Req = 20 | { 21 | (uint8_t)(Read ? USB_REQ_READ | USB_REQ_TYPE_CDC : USB_REQ_TYPE_CDC), 22 | (uint8_t)(Read ? USB_REQ_CDC_GET_LINE_CODING : USB_REQ_CDC_SET_LINE_CODING), 23 | 0, pDriverData->bDataInterface, sizeof(USB_CDC_LINE_CODING) 24 | }; 25 | 26 | USB_CDC_LINE_CODING* Data = (USB_CDC_LINE_CODING*)pDevice->pDeviceBuffer; 27 | assert(Data); 28 | 29 | if(!Read) 30 | *Data = *LineCoding; 31 | uint8_t result = USB_SyncSendRequest(pDevice, &Req, Data); 32 | if(result == 0 && Read) 33 | *LineCoding = *Data; 34 | return result; 35 | } 36 | 37 | uint8_t USB_CDC_SetLineCoding(USB_Device* pDevice, USB_CDC_LINE_CODING* LineCoding) 38 | { 39 | return USB_CDC_LineCoding(pDevice, LineCoding, FALSE); 40 | } 41 | 42 | uint8_t USB_CDC_GetLineCoding(USB_Device* pDevice, USB_CDC_LINE_CODING* LineCoding) 43 | { 44 | return USB_CDC_LineCoding(pDevice, LineCoding, TRUE); 45 | } 46 | 47 | uint8_t USB_CDC_SetControlLineStatus(USB_Device* pDevice, uint16_t StatMask) 48 | { 49 | USB_CDC_DriverData* pDriverData = (USB_CDC_DriverData*)pDevice->pDriverData; 50 | 51 | USB_InterfaceDesc* pIntfaceDesc0 = pDevice->pConfigList[pDevice->bCurrentConfig].pInterfaces; 52 | if(pIntfaceDesc0->bInterfaceSubClass != USBC_CDCSC_ABSTRACT_CONTROL_MODEL) 53 | return 0xFF; //only ACM support it 54 | if(!(pDriverData->ACMDesc.bmCapabilities&USBCAP_CDC_ACM_LINE_CODING)) 55 | return 0xFF; 56 | 57 | USB_Request Req = 58 | { 59 | USB_REQ_TYPE_CDC, USB_REQ_CDC_SET_LINE_CONTROL_STATE, StatMask, pDriverData->bInterface, 0, 60 | }; 61 | return USB_SyncSendRequest(pDevice, &Req, NULL); 62 | } 63 | 64 | BOOL USB_CDC_InitDevice(USB_Device* pDevice) 65 | { 66 | assert(pDevice->bStatus == DS_Configured); 67 | 68 | uint8_t bNumInterfaces = pDevice->pConfigList[pDevice->bCurrentConfig].bNumInterfaces; 69 | USB_InterfaceDesc* pIntfaceDesc0 = pDevice->pConfigList[pDevice->bCurrentConfig].pInterfaces; 70 | 71 | assert(pIntfaceDesc0->bInterfaceClass == USBC_CDC); //must be cdc to be here; 72 | assert(pIntfaceDesc0->bInterfaceSubClass == USBC_CDCSC_DIRECT_LINE_CONTROL_MODEL 73 | || pIntfaceDesc0->bInterfaceSubClass == USBC_CDCSC_ABSTRACT_CONTROL_MODEL); 74 | 75 | USB_CDC_DriverData* pDriverData = (USB_CDC_DriverData*)malloc(sizeof(USB_CDC_DriverData)); 76 | memset(pDriverData, 0, sizeof(USB_CDC_DriverData)); 77 | pDevice->pDriverData = pDriverData; 78 | pDriverData->bInterface = pIntfaceDesc0->bInterfaceNumber; 79 | 80 | for(int j = 1; j < bNumInterfaces; ++j) 81 | { 82 | USB_InterfaceDesc* pIntfaceDesc = pIntfaceDesc0 + j; 83 | if(pIntfaceDesc->bInterfaceClass == USBC_CDCDATA) 84 | { 85 | pDriverData->bDataInterface = pIntfaceDesc->bInterfaceNumber; 86 | 87 | for(int i = 0; i < pIntfaceDesc->bNumEndpoints; ++i) 88 | { 89 | USB_EndpointDesc* pEndpointDesc = pIntfaceDesc->pEndpoints + i; 90 | assert(pEndpointDesc->bmAttributesBits.TransferType == USB_ENDPOINT_TRANSFER_TYPE_ISOC 91 | || pEndpointDesc->bmAttributesBits.TransferType == USB_ENDPOINT_TRANSFER_TYPE_BULK); //ISO or BULK(async) by the spec 92 | pDriverData->bDataEP[pEndpointDesc->bEndpointAddressBits.Dir] = USB_FindEndpoint(pDevice, pEndpointDesc); 93 | } 94 | break; 95 | } 96 | } 97 | assert(pDriverData->bDataEP[0] != NULL && pDriverData->bDataEP[1] != NULL); 98 | 99 | uint16_t length = pDevice->pConfigList[pDevice->bCurrentConfig].wTotalLength; 100 | uint8_t* buffer = (uint8_t*)DPMI_DMAMalloc(length, 4); 101 | uint8_t result = USB_GetConfigDescriptor(pDevice, buffer, length); 102 | if(result == 0) 103 | { 104 | uint8_t* desc = buffer + pIntfaceDesc0->offset + pIntfaceDesc0->bLength; 105 | while(*(desc+1) == USB_DT_CSINTERFACE) 106 | { 107 | _LOG("CDC functional desc: %x\n", *(desc+2)); 108 | assert(desc + *desc <= buffer + length); 109 | if(*(desc+2) == USBC_CDCSC_ABSTRACT_CONTROL_MODEL) 110 | { 111 | pDriverData->ACMDesc = *(USB_CDC_ACM_Desc*)desc; 112 | _LOG("CDC ACM: %x %x %x %x\n", pDriverData->ACMDesc.bFunctionLength, pDriverData->ACMDesc.bDescriptorType, pDriverData->ACMDesc.bDescriptorSubtype, pDriverData->ACMDesc.bmCapabilities); 113 | break; 114 | } 115 | desc += *desc; 116 | } 117 | } 118 | DPMI_DMAFree(buffer); 119 | return result == 0; 120 | } 121 | 122 | BOOL USB_CDC_DeinitDevice(USB_Device* pDevice) 123 | { 124 | USB_CDC_DriverData* pDriverData = (USB_CDC_DriverData*)pDevice->pDriverData; 125 | free(pDriverData); 126 | pDevice->pDriverData = NULL; 127 | return TRUE; 128 | } 129 | 130 | uint8_t USB_CDC_SyncTransfer(USB_Device* pDevice, HCD_TxDir dir, uint8_t* inoutp pBuffer, uint16_t length, uint16_t* outputp txlen) 131 | { 132 | assert(pDevice->bStatus == DS_Ready); 133 | USB_CDC_DriverData* pDriverData = (USB_CDC_DriverData*)pDevice->pDriverData; 134 | assert(pDriverData); 135 | void* pEndpoint = pDriverData->bDataEP[dir&0x1]; 136 | assert(pEndpoint); 137 | return USB_SyncTransfer(pDevice, pEndpoint, pBuffer, length, txlen); 138 | } 139 | 140 | uint8_t USB_CDC_Transfer(USB_Device* pDevice, HCD_TxDir dir, uint8_t* inoutp pBuffer, uint16_t length, HCD_COMPLETION_CB nullable pCallback, void* nullable pContext) 141 | { 142 | assert(pDevice->bStatus == DS_Ready); 143 | USB_CDC_DriverData* pDriverData = (USB_CDC_DriverData*)pDevice->pDriverData; 144 | assert(pDriverData); 145 | void* pEndpoint = pDriverData->bDataEP[dir&0x1]; 146 | assert(pEndpoint); 147 | //return pDevice->HCDDevice.pHCI->pHCDMethod->BulkTransfer(&pDevice->HCDDevice, endpoint, dir, pBuffer, length, txlen, pCallback, pContext) == 0; //need prepare buffer, or user may free pBuffer 148 | return USB_Transfer(pDevice, pEndpoint, pBuffer, length, pCallback, pContext); 149 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # USBDDOS 2 | USB driver stack for DOS 3 | 4 | USBDDOS was originally named RWDDOS before released to public, which is only a driver for RetroWave OPL3, and later more drviers added (mouse, keyboard, disk) and renamed to USBDDOS. 5 | 6 | USBDDOS is tested working on following PCs/VMs: 7 | * OCHI: VirtualBox, NEC versa s260(p3) 8 | * UHCI: QEMU, Toshiba portege M200(p4), Compaq Evo N600c(p3), Toshiba Satellite 2410(p4) 9 | * EHCI: VirtualBox, NEC versa s260, Lenovo Thinkpad T540p 10 | 11 | There might be bugs for other PCs, test & feedback is appreiated. 12 | 13 | USBDDOS uses DPMI to perform PCI bus master DMA (MMIO), and also save conventional memory for other DOS programs, it uses little conventional memory (USBDDOS uses ~12K, USBDDOSP uses almost 0). 14 | 15 | The Borland++3.1/Open Watcom build (USBDDOS.EXE) can run without a DPMI host, 16 | it has a builtin 16 bit protected mode functions which will enter protected mode directly or with a EMM manager. 17 | ~~It's not compatible with many games. 18 | To play games with a USB mouse, USBDDOSP.EXE is recommended, which also need a DIMI host (i.e. HDPMI.exe).~~ Latest tests with 1.0fix2 shows that USBDDOS is more stable than USBDDOSP. 19 | Like [Bret Johnson's driver](https://bretjohnson.us/), USBDDOSP/USBDDOS need CuteMouse to work for USB mouse. 20 | 21 | # Tips 22 | USBDDOSP doesn't need HDPMI32i unless you want Retrowave support, normal HDPMI32/CWSDPMI is recommended, unless you want it cope with SBEMU. 23 | 24 | If you get problems with the mouse/keyboard driver, make sure those settings in your BIOS settings: 25 | * Disable USB Legacy Support (USB Keyboard/Mouse Support). (some p4 laptop have buggy mouse support in BIOS) 26 | * Disable OnBoard LAN 27 | 28 | If you're using USB boot disk to boot the system, then ```/disk``` parameter is mandatory, because USBDDOS will take over from BIOS and make the BIOS's USB disk emulation unavailable, so the disk support need to be taken over too, otherwise the system drive will not function. 29 | 30 | Do not use ```LH/LOADHIGH``` for USBDDOS - A DPMI (or a DOS Extender) program is executed above 1M, so no need to do that. Actually if ```LH``` is used, then after TSR the PSP segment will resident in high memory with its' real mode data/code freed, which may generate fragmentations. A DPMI TSR also doesn't need to use assembly to strictly control/optimize the memory layout for TSR, as a common real mode program does. 31 | 32 | # Credits 33 | * RetroWaveLib from Sudomaker (folder renamed to RetroWav as 8.3 file name, and tiny code changes, for old compiler) https://github.com/SudoMaker/RetroWave 34 | * This code is somehow based on an old code, usb-driver-under-dos: https://code.google.com/archive/p/usb-driver-under-dos/, with critital changes: 35 | * Multiple compiler support and code refactoring and major bug fixes. 36 | * DPMI support and wrapper added 37 | * IRQ handling added(polling changed to interrupt) 38 | 39 | # How to Build 40 | The build scripts support multiple hosts: Linux, Windows(WSL/MinGW), DOS/FreeDOS. 41 | Three set of toolchians are supported: DJGPP, Borland C++ 3.1, Open Watcom v2. 42 | Basically the Borland C++3.1 built executable has the same features as the Open Watcom build. 43 | Here's a quick comparison of different toolchains and its generated executables: 44 | | | DJGPP | Borland C++3.1 | Open Watcom | 45 | |-------------|:-------------:|:--------------:|:-----------:| 46 | |Linux Host |Yes |No |Yes | 47 | |Windows Host |Yes (WSL/MinGW)|No | Yes | 48 | |DOS Host |Yes |Yes |Yes | 49 | |Makefile |Makefile | Makefile.BC | Makefile.WC | 50 | |Debug Build | ```DEBUG=1``` | ```-DDEBUG``` |```DEBUG=1```| 51 | |Output Name | usbddosp.exe | usbddos.exe | usbddos.exe | 52 | |Executable || 53 | |DPMI Host Required |Yes |No |No | 54 | |Instruction Set |32-bit|16-bit |16-bit | 55 | |Conventional Mem Usage|0K[\[1\]](README.md#note1)|12K[\[2\]](README.md#note2)|12K[\[2\]](README.md#note2) | 56 | 57 | #### Note[1]: 58 | USBDDOSP itself uses almost 0K (around 1K), but it depends on the DPMI host used, for HPDMI it is actually around 1K, and for CWSDPMI, the total usage is about 200K, most of them are used by CWSDPMI itself, after TSR. 59 | #### Note[2]: 60 | USBDDOS uses 4K memory if in real mode (without VCPI/EMM), 12K if in Virtual 8086 mode. 61 | 62 | ## DJGPP setup 63 | * Download DGJPP from here: https://github.com/andrewwutw/build-djgpp 64 | * Setup environment, Run : ```. /djgpp/setenv``` or ```source /djgpp/setenv``` 65 | * Make: ```make``` 66 | 67 | For DOS host, download from here: https://www.delorie.com/djgpp/ and set the envs: ```set PATH=%PATH%;C:\DJGPP\BIN```, ```set DJGPP=C:\DJGPP\DJGPP.ENV``` 68 | The Makefile will try to auto-detect DOS host, but may fail on FreeDOS, use ```make DOS=1``` to force DOS build. 69 | 70 | ## Borland C++ setup 71 | The makefile uses default BC path: ```C:\BORLANDC``` for includes and libs. 72 | * Set exec path: ```set PATH=%PATH%;C:\BORLANDC\BIN``` 73 | * Make: ```make -f Makefile.BC``` 74 | * If Borland C++ is installed on another location, i.e. C:\BC31, 75 | Then ```set PATH=%PATH%;C:\BC31\BIN``` and ```make -f Makefile.BC -DBCDIR=C:\BC31``` 76 | 77 | ## Open Watcom setup 78 | * Download Open Watcom from here: https://github.com/open-watcom/open-watcom-v2 79 | * Set env: ```. /watcom/owsetenv.sh``` or ```source /watcom/owsetenv.sh``` 80 | * Make: ```wmake -f Makefile.WC``` 81 | 82 | DOS setup: ```set PATH=%PATH%;C:\OW2\BINW```, ```set WATCOM=C:\OW2```, 83 | ```set INCLUDE=C:\OW2\H``` 84 | 85 | # How to Debug 86 | Add ```DEBUG=1``` on make commandline, i.e. 87 | ```make DEBUG=1``` for DJGPP, 88 | ```wmake -f Makefile.WC DEBUG=1``` for Open Watcom, 89 | the built executable will have its logs/assertion enabled. 90 | Use ```-DDEBUG``` for Borland C++'s make file. 91 | 92 | # Requirements 93 | * HIMEM.SYS or other XMS manager 94 | * EMM386 4.46+/HDPMI32i(optional, for RetroWave driver) 95 | * 80386 CPU or later 96 | * MS-DOS (FreeDOS support is still in debugging) 97 | 98 | # Features 99 | The following drivers are added/planned: 100 | * - [x] OHCI driver 101 | * - [x] UHCI driver 102 | * - [x] EHCI driver 103 | * - [ ] xHCI driver 104 | * - [x] Hub 105 | * - [x] Keyborad & mouse driver (HID). use `USBDDOSP /hid` to enable 106 | * - [x] Mass storage class driver (MSC). use `USBDDOSP /disk` to enable 107 | * - [x] Simple CDC(ACM) driver and RetroWave OPL3. use `USBDDOSP /RW` to enable 108 | * - [ ] Audio and MIDI 109 | 110 | # Tested games with Retrowave DOS driver 111 | * Skyroads 112 | * Prince of Persia1 & 2 113 | * Heroes of Jinyong (Jinyong Qun Xia Zhuan), DOS4GW Miles Sound 114 | * Chinese Paladin (Xian Jian Qi Xia Zhuan) 115 | * Theme Hospital, Miles Sound 116 | * DOOM (DJGPP build only, need a modified HDPMI with port trapping feature, see https://github.com/crazii/HX) 117 | * The Jungle Book (DJGPP build only) 118 | * Warcraft II (DJGPP build only) 119 | -------------------------------------------------------------------------------- /USBDDOS/pci.h: -------------------------------------------------------------------------------- 1 | #ifndef _PCI_H 2 | #define _PCI_H_ 3 | #include "USBDDOS/platform.h" 4 | 5 | #if defined(__DJ2__) 6 | #include 7 | #elif defined(__WC__) || defined(__BC__) 8 | #include 9 | #endif 10 | 11 | #ifdef __cplusplus 12 | extern "C" 13 | { 14 | #endif 15 | 16 | //32bit extension 17 | #if defined(__DJ2__) 18 | #define inpd inportl 19 | #define outpd outportl 20 | #elif defined(__BC__) || defined(__WC__) 21 | uint32_t inpd(uint16_t port); 22 | void outpd(uint16_t port, uint32_t value); 23 | #endif 24 | 25 | //PCI configuration space access 26 | //https://en.wikipedia.org/wiki/PCI_configuration_space#Software_implementation 27 | //https://wiki.osdev.org/PCI 28 | 29 | #define PCI_MAX_BUS 16 //256 by specs, but.. 30 | #define PCI_MAX_DEV 32 31 | #define PCI_MAX_FUNC 8 32 | 33 | #define PCI_HEADER_DEVICE 0x0 34 | #define PCI_HEADER_PCI_BRIDGE 0x1 35 | #define PCI_HEADER_CARDBUS_BRIDGE 0x2 36 | #define PCI_HEADER_MULTI_FUNCTION 0x80 //multi-function bit (mask) 37 | 38 | //PCI BIOS functions (PCI BIOS specification 2.1) 39 | #define PCI_FUNCTION_ID 0xB1 40 | #define PCI_BIOS_PRESENT 0x01 41 | #define FIND_PCI_DEVICE 0x02 42 | #define READ_CONFIG_BYTE 0x08 43 | #define READ_CONFIG_WORD 0x09 44 | #define READ_CONFIG_DWORD 0x0A 45 | #define WRITE_CONFIG_BYTE 0x0B 46 | #define WRITE_CONFIG_WORD 0x0C 47 | #define WRITE_CONFIG_DWORD 0x0D 48 | #define GET_IRQ_ROUTING_OPTIONS 0x0E 49 | #define SET_PCI_IRQ 0x0F //SET_PCI_HW_INT 50 | #define PCI_INT_NO 0x1A 51 | 52 | #define SUCCESSFUL 0x00 53 | #define FUNC_NOT_SUPPORTED 0x81 54 | #define BAD_VENDOR_ID 0x83 55 | #define DEVICE_NOT_FOUND 0x86 56 | #define BAD_REGISTER_NUMBER 0x87 57 | #define SET_FAILED 0x88 58 | #define BUFFER_TOO_SMALL 0x89 59 | 60 | //BDF 61 | typedef struct _PCIAddress 62 | { 63 | uint8_t Bus; 64 | uint8_t Device; 65 | uint8_t Function; 66 | uint8_t unused; 67 | }PCI_Addr; 68 | 69 | typedef struct 70 | { 71 | uint32_t Base0; // BAR0 (OHCI, EHCI) 72 | uint32_t Base1; 73 | uint32_t Base2; 74 | uint32_t Base3; 75 | uint32_t Base4; // BAR4 (UHCI) 76 | uint32_t Base5; 77 | uint32_t CardbusCIS; //CardBus CIS Pointer 78 | uint16_t SubsystemVendorID; 79 | uint16_t SubsytemID; 80 | uint32_t ROMBase; //Expansion ROM base address 81 | uint8_t Capabilities; 82 | uint8_t Reserved[3]; 83 | uint32_t Reserved2; 84 | uint8_t IRQ; //Interrupt Line (legacy ISA IRQ) 85 | uint8_t INTPIN; //PCI Interrupt PIN (INTA#...INTD#) 86 | uint8_t MinGrant; //(RO) burst period length in 1/4 ms units 87 | uint8_t MaxLatency; //(RO) how often the device needs access to the PCI bus, 1/4ms units 88 | }PCI_DEVICE_HEADER; 89 | 90 | typedef struct 91 | { 92 | uint32_t Base0; 93 | uint32_t Base1; 94 | uint8_t PrimaryBusNO; 95 | uint8_t SeconaryBusNO; 96 | uint8_t SubordinateBusNO; 97 | uint8_t LatencyTimer2; 98 | uint8_t IOBase; 99 | uint8_t IOLimt; 100 | uint16_t Status2; 101 | uint16_t MemoryBase; 102 | uint16_t MemoryLimit; 103 | uint16_t PMemoryBase; //prefetchable memory base 104 | uint16_t PMemoryLimit; //prefetchable memory limit 105 | uint32_t PMemoryBase32; //upper 32 bit 106 | uint32_t PMemoryLimit32; //upper 32 bit 107 | uint16_t IOBase16; //upper 16 bit 108 | uint16_t IOLimt16; //upper 16 bit 109 | uint8_t Capabilities; 110 | uint8_t Reserved[3]; 111 | uint32_t Reserved2; 112 | uint8_t IRQ; 113 | uint8_t INTPIN; 114 | uint16_t BridgeControl; 115 | }PCI_PCI_BRIDGE_HEADER; 116 | 117 | typedef struct 118 | { 119 | uint32_t Base; 120 | uint8_t CapabilityOffset; 121 | uint8_t Reserved; 122 | uint16_t Status2; 123 | uint8_t PCIBusNO; 124 | uint8_t CardBusNO; 125 | uint8_t SubordinateBusNO; 126 | uint8_t CardBusLatencyTimer; 127 | uint32_t Base0; 128 | uint32_t Limit0; 129 | uint32_t Base1; 130 | uint32_t Limit1; 131 | uint32_t IOBase0; 132 | uint32_t IOLimit0; 133 | uint32_t IOBase1; 134 | uint32_t IOLimit1; 135 | uint8_t IRQ; 136 | uint8_t INTPIN; 137 | uint16_t BridgeControl; 138 | uint16_t SubsystemVendorID; 139 | uint16_t SubsytemID; 140 | uint32_t PCCardBase; //legacy 16 bit 141 | }PCI_CARDBUS_BRIDGE_HEADER; 142 | 143 | typedef struct 144 | { 145 | //common header register 0~3 146 | uint16_t VendorID; // Vendor ID (FFFFh invalid) 147 | uint16_t DeviceID; // Device ID 148 | uint16_t Command; // Command (0x04) 149 | uint16_t Status; 150 | uint8_t RevisionID; 151 | uint8_t PInterface; //register-level programming interface 152 | uint8_t SubClass; 153 | uint8_t Class; 154 | uint8_t CacheLineSize; 155 | uint8_t LatencyTimer; 156 | uint8_t HeaderType; //HeaderType: 0: general device, 1: PCI-to-PCI bridge, 2: PCI-to-CardBus bridge 157 | uint8_t BIST; //builtin self tet 158 | // 159 | union 160 | { 161 | PCI_DEVICE_HEADER Device; 162 | PCI_PCI_BRIDGE_HEADER PCIBridge; 163 | PCI_CARDBUS_BRIDGE_HEADER CardBusBridge; 164 | }DevHeader; 165 | 166 | }PCI_HEADER; 167 | 168 | typedef union 169 | { 170 | PCI_HEADER Header; 171 | uint32_t Registers[64]; 172 | uint8_t Offset[256]; 173 | }PCI_DEVICE; 174 | 175 | //command register (word) 176 | #define PCI_REGISTER_CMD 0x04 177 | //status register (word) 178 | #define PCI_REGISTER_STS 0x06 179 | typedef union 180 | { 181 | uint16_t reg16; 182 | struct 183 | { 184 | uint16_t IOSpace : 1; //enable io space 185 | uint16_t MemorySpace : 1; //enable memory space (MMIO) 186 | uint16_t BusMaster : 1; //enable PCI access 187 | uint16_t SpecialCircles : 1; 188 | uint16_t MemoryInvalidate : 1; 189 | uint16_t VGAPaletteSnoop : 1; 190 | uint16_t ParityError : 1; //Parity Error Response 191 | uint16_t Reserved : 1; 192 | uint16_t SERR : 1; 193 | uint16_t FastB2B : 1; //fast bck to back 194 | uint16_t InterruptDisable : 1; //disable interrupt 195 | uint16_t Reserved2 : 5; 196 | }bits; 197 | }PCI_CMD; 198 | 199 | #define PCI_REGISTER_IRQ 0x3C //word: IRQ (low byte) & INTPIN 200 | #define PCI_REGISTER_INTPIN 0x3D 201 | 202 | uint8_t PCI_ReadByte(uint8_t bus, uint8_t dev, uint8_t func, uint8_t reg); 203 | uint16_t PCI_ReadWord(uint8_t bus, uint8_t dev, uint8_t func, uint8_t reg); 204 | uint32_t PCI_ReadDWord(uint8_t bus, uint8_t dev, uint8_t func, uint8_t reg); 205 | 206 | void PCI_WriteByte(uint8_t bus, uint8_t dev, uint8_t func, uint8_t reg, uint8_t value); 207 | void PCI_WriteWord(uint8_t bus, uint8_t dev, uint8_t func, uint8_t reg, uint16_t value); 208 | void PCI_WriteDWord(uint8_t bus, uint8_t dev, uint8_t func, uint8_t reg, uint32_t value); 209 | 210 | void PCI_ReadDevice(uint8_t bus, uint8_t dev, uint8_t func, PCI_DEVICE* device); 211 | 212 | uint32_t PCI_Sizing(uint8_t bus, uint8_t dev, uint8_t func, uint8_t reg); 213 | 214 | uint8_t PCI_AssignIRQ(uint8_t bus, uint8_t dev, uint8_t func, uint8_t INTPIN); 215 | 216 | BOOL PCI_SetIRQ(uint8_t bus, uint8_t dev, uint8_t func, uint8_t INTPIN, uint8_t IRQ); //SET_PCI_IRQ, INTPIN=0x1...4 217 | 218 | #ifdef __cplusplus 219 | } 220 | #endif 221 | 222 | #endif 223 | -------------------------------------------------------------------------------- /USBDDOS/DPMI/dpmi_wc.c: -------------------------------------------------------------------------------- 1 | 2 | //NOTE: this file is deprecated because now 16-bit real mode is used for Wactom C. 3 | 4 | #if defined(__WC__) 5 | #include "USBDDOS/DPMI/dpmi.h" 6 | #include "USBDDOS/DPMI/xms.h" 7 | #include 8 | #include 9 | //#include 10 | //#include 11 | 12 | #define USE_DLMALLOC 1 13 | #if USE_DLMALLOC 14 | 15 | #define ONLY_MSPACES 1 16 | #define NO_MALLOC_STATS 1 17 | #define USE_LOCKS 0 18 | #define HAVE_MMAP 0 19 | #define LACKS_SYS_PARAM_H 20 | #pragma warning * 9 21 | #include "dlmalloc.h" 22 | 23 | static const int32_t DOS_HEAP_SIZE = 1024*16; 24 | static uint32_t DOS_HeapHandle; 25 | static mspace DOS_Space; 26 | 27 | #endif 28 | 29 | int32_t __dpmi_physical_address_mapping(int32_t addr, int32_t size); //TODO: make interface compatible with DJGPP 30 | //int 31h, 0800h, bx:cx(bx:cx, si:di) 31 | #pragma aux __dpmi_physical_address_mapping = \ 32 | "mov ecx, ebx" \ 33 | "shr ebx, 16" \ 34 | "mov di, ax" \ 35 | "shr eax, 16" \ 36 | "mov si, ax" \ 37 | "mov ax, 0800h" \ 38 | "int 31h" \ 39 | "mov ax, cx" \ 40 | "mov cx, bx" \ 41 | "shl ecx, 16" \ 42 | "mov cx, ax" \ 43 | value [ecx] \ 44 | parm [ebx] [eax] \ 45 | modify [eax ecx ebx si di] 46 | 47 | uint16_t _my_cs(); 48 | #pragma aux _my_cs = "mov ax, cs" value[ax] parm[] modify[] 49 | 50 | uint16_t _my_ds(); 51 | #pragma aux _my_ds = "mov ax, ds" value[ax] parm[] modify[] 52 | 53 | uint16_t _my_es(); 54 | #pragma aux _my_es = "mov ax, es" value[ax] parm[] modify[] 55 | 56 | uint16_t _my_ss(); 57 | #pragma aux _my_ss = "mov ax, ss" value[ax] parm[] modify[] 58 | 59 | int32_t __dpmi_get_segment_base_address(uint16_t); 60 | //int 31h, 0006h, cx:dx(bx) 61 | #pragma aux __dpmi_get_segment_base_address = \ 62 | "mov ax, 0006h" \ 63 | "int 31h" \ 64 | "shl ecx, 16" \ 65 | "mov cx, dx" \ 66 | value [ecx] \ 67 | parm [bx] \ 68 | modify [ax dx bx ecx] 69 | 70 | int32_t __dpmi_allocate_dos_memory(uint16_t paragraphs); //TODO: make interface compatible with DJGPP 71 | //int 31h, 0100h, dx:ax(bx) dx=pm selector, ax=rm addr 72 | #pragma aux __dpmi_allocate_dos_memory = \ 73 | "mov ax, 0100h" \ 74 | "int 31h" \ 75 | "shl edx, 16" \ 76 | "mov dx, ax" \ 77 | value [edx] \ 78 | parm [bx] \ 79 | modify [ax edx] 80 | 81 | uint16_t __dpmi_free_dos_memory(uint16_t selector); 82 | //int 31h, 0101h, ax(dx) ax=error code 83 | #pragma aux __dpmi_free_dos_memory = \ 84 | "mov ax, 0101h" \ 85 | "int 31h" \ 86 | value [ax] \ 87 | parm [dx] \ 88 | modify [ax] 89 | 90 | //only supprt by DOS/4GW professional 91 | uint16_t __dpmi_simulate_real_mode_procedure_retf(void* reg); 92 | //int 31h, 0301h, ax(bh=0,cx,es:edi) 93 | #pragma aux __dpmi_simulate_real_mode_procedure_retf = \ 94 | "push es" \ 95 | "xor bx, bx" \ 96 | "xor cx, cx" \ 97 | "mov ax, ds" \ 98 | "mov es, ax" \ 99 | "mov ax, 0301h" \ 100 | "int 31h" \ 101 | "pop es" \ 102 | "sbb ax, ax" \ 103 | value [ax] \ 104 | parm [edi] \ 105 | modify [ax cx bx] 106 | 107 | uint16_t __dpmi_simulate_real_mode_interrupt(uint8_t _int, void* reg); 108 | //int 31h, 0300h ax(bl=i,bh=0,cx,es:edi) 109 | #pragma aux __dpmi_simulate_real_mode_interrupt = \ 110 | "push es" \ 111 | "xor bh, bh" \ 112 | "xor cx, cx" \ 113 | "mov ax, ds" \ 114 | "mov es, ax" \ 115 | "mov ax, 0300h" \ 116 | "int 31h" \ 117 | "pop es" \ 118 | "sbb ax, ax" \ 119 | value [ax] \ 120 | parm [bl] [edi] \ 121 | modify [ax cx bx] 122 | 123 | uint16_t __dpmi_simulate_real_mode_procedure_iret(void* reg); 124 | //int 31h, 0302h ax(bh=0,cx,es:edi) 125 | #pragma aux __dpmi_simulate_real_mode_interrupt = \ 126 | "push es" \ 127 | "xor bh, bh" \ 128 | "xor cx, cx" \ 129 | "mov ax, ds" \ 130 | "mov es, ax" \ 131 | "mov ax, 0302h" \ 132 | "int 31h" \ 133 | "pop es" \ 134 | "sbb ax, ax" \ 135 | value [ax] \ 136 | parm [bl] [edi] \ 137 | modify [ax cx bx] 138 | 139 | uint32_t DPMI_MapMemory(uint32_t physicaladdr, uint32_t size) 140 | { 141 | //DPMI call to map physical memory 142 | //if DOS/4GW starts at real mode, the mapped linear addr 143 | //should be the same as physical addr below 1M. 144 | //if EMM exist, memory always mapped. 145 | return __dpmi_physical_address_mapping(physicaladdr, size); 146 | } 147 | 148 | #if !USE_DLMALLOC 149 | void* DPMI_DMAMalloc(unsigned int size, unsigned int alignment) 150 | { 151 | //don't do malloc as TSR 152 | //temporary: use dos alloc to get physial address which equal linear on DOS/4GW 153 | //http://www.delorie.com/djgpp/v2faq/faq18_13.html option 1 154 | // 155 | //TODO: 156 | //1. DOS/4GW don't have uncommitted memory support, we cannot map XMS to a specific address, but since DOS/4GW 157 | //is pure flat with 0 base, we don't need map it to a specific location as in DJGPP. we map it to any location and it is near pointer already. 158 | //2. if we use dos memory, we can do the data transaction in real(v86) mode TSR directly. 159 | // 160 | //new conclusion: 161 | //DOS/4GW and Causeway don't have "call real mode far ret" support, thus XMS not quite available. 162 | uint32_t sel_seg = __dpmi_allocate_dos_memory((uint16_t)((size + alignment + 2 + 15)>>4)); 163 | uint16_t selector = (uint16_t)((sel_seg>>16)&0xFFFF); 164 | uint16_t physicalseg = (uint16_t)(sel_seg&0xFFFF); 165 | 166 | int8_t* ptr = (int8_t*)(physicalseg<<4) + 2; 167 | void* aligned; 168 | 169 | uint32_t addr = DPMI_PTR2L(ptr); 170 | uint16_t offset = (uint16_t)(align(addr, alignment) - addr); 171 | 172 | aligned = (int8_t*)ptr + offset; 173 | ((uint16_t*)aligned)[-1] = (uint16_t)selector; 174 | 175 | //assert(align((int32_t)aligned, alignment) == (int32_t)aligned); 176 | 177 | return aligned; 178 | } 179 | 180 | void DPMI_DMAFree(void* ptr) 181 | { 182 | uint16_t selector = ((uint16_t*)ptr)[-1]; 183 | __dpmi_free_dos_memory(selector); 184 | } 185 | 186 | #else 187 | 188 | void* DPMI_DMAMalloc(unsigned int size, unsigned int alignment/* = 4*/) 189 | { 190 | return mspace_memalign(DOS_Space, alignment, size); 191 | } 192 | 193 | void DPMI_DMAFree(void* ptr) 194 | { 195 | return mspace_free(DOS_Space, ptr); 196 | } 197 | 198 | #endif 199 | 200 | uint32_t DPMI_DOSMalloc(uint16_t size) 201 | { 202 | return __dpmi_allocate_dos_memory(size); 203 | } 204 | 205 | void DPMI_DOSFree(uint32_t segment) 206 | { 207 | __dpmi_free_dos_memory((uint16_t)(segment>>16)); 208 | } 209 | 210 | uint16_t DPMI_CallRealModeRETF(DPMI_REG* reg) //not supported by DOS/4GW, supported by Causeway or DOS/4GW Professional 211 | { 212 | reg->d._reserved = 0; 213 | return __dpmi_simulate_real_mode_procedure_retf(®); 214 | } 215 | 216 | uint16_t DPMI_CallRealModeINT(uint8_t i, DPMI_REG* reg) 217 | { 218 | reg->d._reserved = 0; 219 | return __dpmi_simulate_real_mode_interrupt(i, reg); 220 | } 221 | 222 | uint16_t DPMI_CallRealModeIRET(DPMI_REG* reg) 223 | { 224 | reg->d._reserved = 0; 225 | return (uint16_t)__dpmi_simulate_real_mode_procedure_iret(i, (__dpmi_regs*)reg); 226 | } 227 | 228 | uint16_t DPMI_InstallISR(int i, void(*ISR)(void), DPMI_ISR_HANDLE* outputp handle) 229 | { 230 | if(!DPMI_PM || i < 0 || i > 255 || handle == NULL) 231 | return -1; 232 | //TODO: 233 | return -1; 234 | } 235 | 236 | uint16_t DPMI_UninstallISR(DPMI_ISR_HANDLE* inputp handle) 237 | { 238 | return -1; 239 | } 240 | 241 | void DPMI_GetPhysicalSpace(DPMI_SPACE* outputp spc) 242 | { 243 | //cs & ds based at 0. 244 | spc->base = 0; 245 | spc->limit = 0xFFFFFFFF; 246 | //TODO: get esp 247 | #error not implemented. 248 | } 249 | 250 | static void DPMI_Shutdown(void); 251 | 252 | void DPMI_Init(void) 253 | { 254 | #if USE_DLMALLOC 255 | DOS_HeapHandle = DPMI_DOSMalloc(DOS_HEAP_SIZE>>4); 256 | 257 | uint32_t DOS_Base = (DOS_HeapHandle&0xFFFF)<<4; 258 | DOS_Space = create_mspace_with_base((void*)DOS_Base, DOS_HEAP_SIZE, 0); 259 | #endif 260 | } 261 | static void DPMI_Shutdown(void) 262 | { 263 | #if USE_DLMALLOC 264 | DPMI_DOSFree(DOS_HeapHandle); 265 | DOS_HeapHandle = 0; 266 | #endif 267 | } 268 | #endif 269 | -------------------------------------------------------------------------------- /USBDDOS/CLASS/hub.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include "USBDDOS/CLASS/hub.h" 9 | #include "USBDDOS/DPMI/dpmi.h" 10 | #include "USBDDOS/dbgutil.h" 11 | 12 | typedef union USB_HUB_PortStatus 13 | { 14 | uint32_t val; 15 | struct 16 | { 17 | uint16_t status; //PS_* 18 | uint16_t change; //PSC_* 19 | }bm; 20 | }USB_HUB_PS; 21 | 22 | static BOOL USB_HUB_SetPortFeature(USB_Device* pDevice, uint8_t port, uint16_t feature) 23 | { 24 | USB_HUB_DriverData* pDriverData = (USB_HUB_DriverData*)pDevice->pDriverData; 25 | if(port > pDriverData->desc.bNbrPorts) 26 | return FALSE; 27 | 28 | USB_Request req = {USB_REQ_WRITE|USB_REQ_TYPE_HUBPORT, USB_REQ_SET_FEATURE, 0, 0, 0}; 29 | req.wValue = feature; 30 | req.wIndex = (uint16_t)(port+1); //1 based port no 31 | return USB_SyncSendRequest(pDevice, &req, NULL) == 0; 32 | } 33 | 34 | static BOOL USB_HUB_ClearPortFeature(USB_Device* pDevice, uint8_t port, uint16_t feature) 35 | { 36 | USB_HUB_DriverData* pDriverData = (USB_HUB_DriverData*)pDevice->pDriverData; 37 | if(port > pDriverData->desc.bNbrPorts) 38 | return FALSE; 39 | USB_Request req = {USB_REQ_WRITE|USB_REQ_TYPE_HUBPORT, USB_REQ_CLEAR_FEATURE, 0, 0, 0}; 40 | req.wValue = feature; 41 | req.wIndex = (uint16_t)(port+1); //1 based port no 42 | return USB_SyncSendRequest(pDevice, &req, NULL) == 0; 43 | } 44 | 45 | //first word: status (PS_*), second word: status changes (PSC_*) 46 | static uint32_t USB_HUB_GetPortStatus(USB_Device* pDevice, uint8_t port) 47 | { 48 | USB_HUB_DriverData* pDriverData = (USB_HUB_DriverData*)pDevice->pDriverData; 49 | if(port > pDriverData->desc.bNbrPorts) 50 | return 0; 51 | 52 | USB_Request req = {USB_REQ_READ|USB_REQ_TYPE_HUBPORT, USB_REQ_GET_STATUS, 0, 0, 4}; 53 | req.wIndex = (uint16_t)(port+1); //1 based port no 54 | uint32_t* status = (uint32_t*)DPMI_DMAMalloc(4, 4); 55 | uint8_t e = USB_SyncSendRequest(pDevice, &req, status); 56 | uint32_t sts = *status; 57 | DPMI_DMAFree(status); 58 | return e == 0 ? sts : 0; 59 | } 60 | 61 | static BOOL HUB_SetPortStatus(HCD_HUB* pHub, uint8_t port, uint16_t status) 62 | { 63 | if(!pHub || !pHub->pDevice || !HC2USB(pHub->pDevice)->pDriverData) 64 | { 65 | assert(FALSE); 66 | return FALSE; 67 | } 68 | USB_HUB_PS ps; ps.val = USB_HUB_GetPortStatus(HC2USB(pHub->pDevice), port); 69 | uint32_t current = ps.bm.status; 70 | BOOL result = TRUE; 71 | 72 | if((status&USB_PORT_RESET)) 73 | { 74 | _LOG("HUB port %d resetting\n", port); 75 | result = USB_HUB_SetPortFeature(HC2USB(pHub->pDevice), port, PORT_RESET) && result; 76 | delay(55); //apply reset signal for 10ms+ 77 | result = USB_HUB_ClearPortFeature(HC2USB(pHub->pDevice), port, PORT_RESET) && result; //release reset signal 78 | do 79 | { 80 | delay(5); 81 | USB_HUB_PS ps; ps.val = USB_HUB_GetPortStatus(HC2USB(pHub->pDevice), port); 82 | current = ps.bm.status; 83 | } while((current&PS_RESET)); //wait until reset is actually done. this also reload the current states 84 | 85 | _LOG("HUB port %d reset %x\n", port, current); 86 | } 87 | 88 | if((status&USB_PORT_ENABLE) && !(current&PS_ENABLE)) 89 | { 90 | //cannot directly enable ports according to the spec. (usb2.0 11.24.2.7.1.2) 91 | //it must be RESET to perform 'reset and enable' 92 | //USBD will issue a port RESET to enable the port 93 | } 94 | 95 | if((status&USB_PORT_DISABLE) && (current&PS_ENABLE)) 96 | { 97 | //_LOG("HUB ClearPortFeature: enable\n"); 98 | result = USB_HUB_ClearPortFeature(HC2USB(pHub->pDevice), port, PORT_ENABLE) && result; 99 | do 100 | { 101 | delay(55); 102 | } while((USB_HUB_GetPortStatus(HC2USB(pHub->pDevice), port)&PS_ENABLE)); 103 | } 104 | 105 | if((status&USB_PORT_SUSPEND) && !(current&PS_SUSPEND)) 106 | result = USB_HUB_SetPortFeature(HC2USB(pHub->pDevice), port, PORT_SUSPEND) && result; 107 | else if(!(status&USB_PORT_SUSPEND) && (current&PS_SUSPEND)) 108 | result = USB_HUB_ClearPortFeature(HC2USB(pHub->pDevice), port, PORT_SUSPEND) && result; 109 | 110 | if((status&USB_PORT_CONNECT_CHANGE)) 111 | result = USB_HUB_ClearPortFeature(HC2USB(pHub->pDevice), port, C_PORT_CONNECTION) && result; 112 | return result; 113 | } 114 | 115 | static uint16_t HUB_GetPortStatus(HCD_HUB* pHub, uint8_t port) 116 | { 117 | if(!pHub || !pHub->pDevice || !HC2USB(pHub->pDevice)->pDriverData) 118 | { 119 | assert(FALSE); 120 | return 0; 121 | } 122 | USB_HUB_PS ps; ps.val = USB_HUB_GetPortStatus(HC2USB(pHub->pDevice), port); 123 | uint32_t statuschange = ps.bm.change; 124 | uint32_t status = ps.bm.status; 125 | uint16_t result = 0; 126 | 127 | //by the spec 128 | if(!(status&PS_LOW_SPEED) && !(status&PS_HIGH_SPEED)) 129 | result |= USB_PORT_Full_Speed_Device; 130 | else if((status&PS_LOW_SPEED) && !(status&PS_HIGH_SPEED)) 131 | result |= USB_PORT_Low_Speed_Device; 132 | else if(!(status&PS_LOW_SPEED) && (status&PS_HIGH_SPEED)) 133 | result |= USB_PORT_High_Speed_Device; 134 | 135 | if(status & PS_CONNECTION) 136 | result |= USB_PORT_ATTACHED; 137 | 138 | if(status & PS_ENABLE) 139 | result |= USB_PORT_ENABLE; 140 | else 141 | result |= USB_PORT_DISABLE; 142 | 143 | if(status & PS_SUSPEND) 144 | result |= USB_PORT_SUSPEND; 145 | if(status & PS_RESET) //in reset 146 | result |= USB_PORT_RESET; 147 | if(statuschange & PSC_CONNECTION) 148 | result |= USB_PORT_CONNECT_CHANGE; 149 | return result; 150 | } 151 | 152 | BOOL USB_HUB_InitDevice(USB_Device* pDevice) 153 | { 154 | _LOG("HUB Endpoint count: %d\n",pDevice->bNumEndpoints); 155 | if(pDevice->bNumEndpoints != 1) //TODO: verify (usb2.0: 11.23.1) 156 | return FALSE; 157 | 158 | USB_HubDesc desc; 159 | USB_Request req = {USB_REQ_READ|USB_REQ_TYPE_HUB, USB_REQ_GET_DESCRIPTOR, USB_DT_HUB<<8, 0, sizeof(desc)}; 160 | void* dma = DPMI_DMAMalloc(sizeof(desc), 4); 161 | uint8_t err = USB_SyncSendRequest(pDevice, &req, dma); 162 | memcpy(&desc, dma, sizeof(desc)); 163 | if(err != 0) 164 | { 165 | _LOG("HUB Failed get hub descriptor. %x\n",err); 166 | return FALSE; 167 | } 168 | _LOG("HUB Port count: %d.\n", desc.bNbrPorts); 169 | 170 | USB_HUB_DriverData* pData = (USB_HUB_DriverData*)malloc(sizeof(USB_HUB_DriverData)); 171 | memset(pData, 0, sizeof(*pData)); 172 | pData->desc = desc; 173 | pData->statusEP = pDevice->pEndpointDesc[0]->bEndpointAddress; 174 | pDevice->pDriverData = pData; 175 | 176 | //powerup & disable all ports: prepare enumeration for USBD 177 | //powerup 178 | {for(uint8_t i = 0; i < desc.bNbrPorts; ++i) 179 | USB_HUB_SetPortFeature(pDevice, i, PORT_POWER);} 180 | delay(55); 181 | 182 | //only after RESEST the high-speed flags is properly set 183 | {for(uint8_t i = 0; i < desc.bNbrPorts; ++i) 184 | USB_HUB_SetPortFeature(pDevice, i, PORT_RESET);} 185 | 186 | delay(55); 187 | 188 | {for(uint8_t i = 0; i < desc.bNbrPorts; ++i) 189 | USB_HUB_ClearPortFeature(pDevice, i, PORT_RESET);} 190 | delay(55); 191 | 192 | //disable 193 | {for(uint8_t i = 0; i < desc.bNbrPorts; ++i) 194 | USB_HUB_ClearPortFeature(pDevice, i, PORT_ENABLE);} 195 | //_LOG("HUB ports powered & disabled.\n"); 196 | #if 0 197 | {for(uint8_t i = 0; i < desc.bNbrPorts; ++i) 198 | _LOG("HUB port %d status: %x\n",i, USB_HUB_GetPortStatus(pDevice,i));} 199 | #endif 200 | delay(55); 201 | 202 | //transfer status ? (we don't support PnP yet) 203 | //USB_Transfer(pDevice, pDevice->pEndpointDesc[0], ) 204 | 205 | HCD_HUB hub = 206 | { 207 | "HUB", 0, 0, 0, 0, 208 | &HUB_GetPortStatus, 209 | &HUB_SetPortStatus, 210 | }; 211 | hub.pHCI = pDevice->HCDDevice.pHCI; 212 | hub.pDevice = &pDevice->HCDDevice; 213 | hub.bHubAddress = pDevice->HCDDevice.bAddress; 214 | hub.bNumPorts = desc.bNbrPorts; 215 | return USB_AddHub(hub); 216 | } 217 | 218 | BOOL USB_HUB_DeinitDevice(USB_Device* pDevice) 219 | { 220 | USB_HUB_DriverData* pData = (USB_HUB_DriverData*)pDevice->pDriverData; 221 | if(pData) 222 | free(pData); 223 | pDevice->pDriverData = NULL; 224 | //TODO: remove hub from usb? 225 | return TRUE; 226 | } 227 | -------------------------------------------------------------------------------- /USBDDOS/DPMI/djgpp/gormcb.c: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2015 DJ Delorie, see COPYING.DJ for details */ 2 | /* Copyright (C) 2007 DJ Delorie, see COPYING.DJ for details */ 3 | /* Copyright (C) 1999 DJ Delorie, see COPYING.DJ for details */ 4 | /* Copyright (C) 1998 DJ Delorie, see COPYING.DJ for details */ 5 | /* Copyright (C) 1996 DJ Delorie, see COPYING.DJ for details */ 6 | /* Copyright (C) 1995 DJ Delorie, see COPYING.DJ for details */ 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | /* This code really can't be nested since the RMCB structure isn't copied, 14 | so the stack check isn't really useful. But someone may fix it someday. 15 | On entry CS is known to be ours, ES is probably ours (since we passed it), 16 | SS:ESP is locked 4K stack. ES:EDI is regs structure, DS:ESI is RM SS:SP. 17 | Do NOT enable interrupts in the user routine. Thanks to ctm@ardi.com for 18 | the improvements. C. Sandmann 3/95 */ 19 | 20 | /* Keeps FLAGS untouched on IRET (new line 83), 21 | useful for HW interrupt handlers. Crazii 12/20/2023 */ 22 | 23 | #define STACK_WAS_MALLOCED (1 << 0) 24 | 25 | #define FILL 0x00 26 | 27 | static unsigned char wrapper_common[] = { 28 | /* 00 */ 0x06, /* push es */ 29 | /* 01 */ 0x1e, /* push ds */ 30 | /* 02 */ 0x06, /* push es */ 31 | /* 03 */ 0x1f, /* pop ds */ 32 | /* 04 */ 0x66, 0xb8, /* mov ax, */ 33 | /* 06 */ FILL, FILL, /* _our_selector */ 34 | /* 08 */ 0x8e, 0xd8, /* mov ds, ax */ 35 | /* 0a */ 0xff, 0x05, /* incl */ 36 | /* 0c */ FILL, FILL, FILL, FILL, /* _call_count */ 37 | /* 10 */ 0x83, 0x3d, /* cmpl */ 38 | /* 12 */ FILL, FILL, FILL, FILL, /* _in_this_handler */ 39 | /* 16 */ 0x00, /* $0 */ 40 | /* 17 */ 0x75, /* jne */ 41 | /* 18 */ 0x33, /* bypass */ 42 | /* 19 */ 0xc6, 0x05, /* movb */ 43 | /* 1b */ FILL, FILL, FILL, FILL, /* _in_this_handler */ 44 | /* 1f */ 0x01, /* $1 */ 45 | /* 20 */ 0x8e, 0xc0, /* mov es, ax */ 46 | /* 22 */ 0x8e, 0xe0, /* mov fs, ax */ 47 | /* 24 */ 0x8e, 0xe8, /* mov gs, ax */ 48 | /* 26 */ 0xbb, /* mov ebx, */ 49 | /* 27 */ FILL, FILL, FILL, FILL, /* _local_stack */ 50 | /* 2b */ 0xfc, /* cld */ 51 | /* 2c */ 0x89, 0xe1, /* mov ecx, esp */ 52 | /* 2e */ 0x8c, 0xd2, /* mov dx, ss */ 53 | /* 30 */ 0x8e, 0xd0, /* mov ss, ax */ 54 | /* 32 */ 0x89, 0xdc, /* mov esp, ebx */ 55 | /* 34 */ 0x52, /* push edx */ 56 | /* 35 */ 0x51, /* push ecx */ 57 | /* 36 */ 0x56, /* push esi */ 58 | /* 37 */ 0x57, /* push edi */ 59 | /* 38 */ 0xe8, /* call */ 60 | /* 39 */ FILL, FILL, FILL, FILL, /* _rmcb */ 61 | /* 3d */ 0x5f, /* pop edi */ 62 | /* 3e */ 0x5e, /* pop esi */ 63 | /* 3f */ 0x58, /* pop eax */ 64 | /* 40 */ 0x5b, /* pop ebx */ 65 | /* 41 */ 0x8e, 0xd3, /* mov ss, bx */ 66 | /* 43 */ 0x89, 0xc4, /* mov esp, eax */ 67 | /* 45 */ 0xc6, 0x05, /* movb */ 68 | /* 47 */ FILL, FILL, FILL, FILL, /* _in_this_handler */ 69 | /* 4b */ 0x00, /* $0 */ 70 | /* 4c */ 0x1f, /* bypass: pop ds */ 71 | /* 4d */ 0x07, /* pop es */ 72 | 73 | /* 4e */ 0x8b, 0x06, /* mov eax,[esi] */ 74 | /* 50 */ 0x26, 0x89, 0x47, 0x2a, /* mov es:[edi+42],eax */ 75 | }; 76 | 77 | static unsigned char wrapper_retf[] = { 78 | 0x66, 0x26, 0x83, 0x47, 0x2e, 0x04, /* add es:[edi+46],0x4 */ 79 | 0xcf /* iret */ 80 | }; 81 | 82 | static unsigned char wrapper_iret[] = { 83 | #if 1 84 | /* This overwrote the FLAGS in the real-mode call structure with 85 | their original value, thus making it impossible for the user's 86 | RMCB to change FLAGS (e.g., to set/reset the carry bit). */ 87 | 0x66, 0x8b, 0x46, 0x04, /* mov ax,[esi+4] */ 88 | 0x66, 0x26, 0x89, 0x47, 0x20, /* mov es:[edi+32],ax */ 89 | #endif 90 | 0x66, 0x26, 0x83, 0x47, 0x2e, 0x06, /* add es:[edi+46],0x6 */ 91 | 0xcf /* iret */ 92 | }; 93 | 94 | unsigned long _go32_rmcb_stack_size = 32256; 95 | 96 | static int setup_rmcb(unsigned char *wrapper, _go32_dpmi_seginfo *info, 97 | __dpmi_regs *regs, unsigned char *stack, unsigned long stack_length) 98 | { 99 | #define MALLOC_STACK() \ 100 | do { \ 101 | if (!stack_length) { \ 102 | stack_length = _go32_rmcb_stack_size; \ 103 | stack = (unsigned char *)malloc(stack_length);\ 104 | if (stack == 0) { \ 105 | free(wrapper); \ 106 | return 0x8015; \ 107 | } \ 108 | if( _go32_dpmi_lock_data( stack, \ 109 | stack_length) ) return 0x8015; \ 110 | ((long *)stack)[0] = STACK_WAS_MALLOCED; \ 111 | } else \ 112 | ((long *)stack)[0] = 0; \ 113 | ((long *)stack)[1] = 0; \ 114 | ((long *)stack)[2] = 0; \ 115 | } while (0) 116 | 117 | MALLOC_STACK(); 118 | if( _go32_dpmi_lock_data(regs, sizeof(__dpmi_regs))) 119 | return 0x8015; 120 | 121 | *(short *)(wrapper+0x06) = __djgpp_ds_alias; 122 | *(long *)(wrapper+0x0c) = (long) stack + 8; 123 | *(long *)(wrapper+0x12) = (long) stack + 4; 124 | *(long *)(wrapper+0x1b) = (long) stack + 4; 125 | *(long *)(wrapper+0x27) = (long) stack + stack_length; 126 | *(long *)(wrapper+0x39) = info->pm_offset - ((long)wrapper + 0x3d); 127 | *(long *)(wrapper+0x47) = (long) stack + 4; 128 | 129 | info->size = (int)wrapper; 130 | 131 | return __dpmi_allocate_real_mode_callback((void *)wrapper, regs, 132 | (__dpmi_raddr *)&info->rm_offset); 133 | } 134 | 135 | 136 | static int _go32_dpmi_allocate_real_mode_callback_retf_with_stack( 137 | _go32_dpmi_seginfo *info, __dpmi_regs *regs, unsigned char *stack, 138 | unsigned long stack_length) 139 | { 140 | unsigned char *wrapper; 141 | 142 | #define CHECK_STACK() \ 143 | if ((stack_length && stack_length < 512) || \ 144 | (!stack_length && _go32_rmcb_stack_size < 512)) \ 145 | return 0x8015 146 | 147 | CHECK_STACK(); 148 | 149 | wrapper = (unsigned char *)malloc(sizeof(wrapper_common) + 150 | sizeof(wrapper_retf)); 151 | if (wrapper == 0) 152 | return 0x8015; 153 | 154 | if( _go32_dpmi_lock_data( wrapper, 155 | sizeof(wrapper_common) + sizeof(wrapper_retf)) ) return 0x8015; 156 | 157 | memcpy(wrapper, wrapper_common, sizeof(wrapper_common)); 158 | memcpy(wrapper+sizeof(wrapper_common), wrapper_retf, sizeof(wrapper_retf)); 159 | 160 | return setup_rmcb(wrapper, info, regs, stack, stack_length); 161 | } 162 | 163 | int _go32_dpmi_allocate_real_mode_callback_retf(_go32_dpmi_seginfo *info, 164 | __dpmi_regs *regs) 165 | { 166 | return _go32_dpmi_allocate_real_mode_callback_retf_with_stack 167 | (info, regs, (unsigned char *) 0, 0); 168 | } 169 | 170 | static int _go32_dpmi_allocate_real_mode_callback_iret_with_stack( 171 | _go32_dpmi_seginfo *info, __dpmi_regs *regs, 172 | unsigned char *stack, unsigned long stack_length) 173 | { 174 | unsigned char *wrapper; 175 | 176 | CHECK_STACK(); 177 | 178 | wrapper = (unsigned char *)malloc(sizeof(wrapper_common) + 179 | sizeof(wrapper_iret)); 180 | if (wrapper == 0) 181 | return 0x8015; 182 | 183 | if( _go32_dpmi_lock_data( wrapper, 184 | sizeof(wrapper_common) + sizeof(wrapper_iret)) ) return 0x8015; 185 | 186 | memcpy(wrapper, wrapper_common, sizeof(wrapper_common)); 187 | memcpy(wrapper+sizeof(wrapper_common), wrapper_iret, sizeof(wrapper_iret)); 188 | 189 | return setup_rmcb(wrapper, info, regs, stack, stack_length); 190 | } 191 | 192 | int _go32_dpmi_allocate_real_mode_callback_iret(_go32_dpmi_seginfo *info, 193 | __dpmi_regs *regs) 194 | { 195 | return _go32_dpmi_allocate_real_mode_callback_iret_with_stack(info, regs, 196 | (unsigned char *) 0, 0); 197 | } 198 | 199 | int _go32_dpmi_free_real_mode_callback(_go32_dpmi_seginfo *info) 200 | { 201 | unsigned char *stack; 202 | 203 | stack = (unsigned char *)(*(long *)((long) info->size+0x12) - 4); 204 | if (*(long *) stack & STACK_WAS_MALLOCED) 205 | free(stack); 206 | 207 | free((char *)info->size); 208 | return __dpmi_free_real_mode_callback((__dpmi_raddr *)&info->rm_offset); 209 | } 210 | -------------------------------------------------------------------------------- /USBDDOS/DPMI/dpmi.h: -------------------------------------------------------------------------------- 1 | #ifndef _DPMI_H_ 2 | #define _DPMI_H_ 3 | #include "USBDDOS/platform.h" 4 | 5 | #ifdef __cplusplus 6 | extern "C" 7 | { 8 | #endif 9 | 10 | //a DPMI wrapper for different compilers. Borland C++, DJGPP, WatCom etc. 11 | //the porpose of this file is to hide all __dpmi* or int 31h calls from outside 12 | typedef union _DPMI_REG { 13 | struct 14 | { 15 | uint16_t di, hdi; 16 | uint16_t si, hsi; 17 | uint16_t bp, hbp; 18 | uint16_t _reservedl, _reservedh; 19 | uint16_t bx, hbx; 20 | uint16_t dx, hdx; 21 | uint16_t cx, hcx; 22 | uint16_t ax, hax; 23 | uint16_t flags; 24 | uint16_t es; 25 | uint16_t ds; 26 | uint16_t fs; 27 | uint16_t gs; 28 | uint16_t ip; 29 | uint16_t cs; 30 | uint16_t sp; 31 | uint16_t ss; 32 | }w; //BC doesn't support unamed struct. 33 | 34 | struct 35 | { 36 | uint32_t edi; 37 | uint32_t esi; 38 | uint32_t ebp; 39 | uint32_t _reserved; 40 | uint32_t ebx; 41 | uint32_t edx; 42 | uint32_t ecx; 43 | uint32_t eax; 44 | }d; 45 | 46 | struct 47 | { 48 | uint8_t edi4b[4]; 49 | uint8_t esi4b[4]; 50 | uint8_t ebp4b[4]; 51 | uint8_t _reserved4b[4]; 52 | uint8_t bl, bh, eb2, eb3; 53 | uint8_t dl, dh, ed2, ed3; 54 | uint8_t cl, ch, ec2, ec3; 55 | uint8_t al, ah, ea2, ea3; 56 | }h; 57 | }DPMI_REG; 58 | 59 | //DPMI_SPACE && DPMI_ADDRESSING usage: get physical addr and setup paging/gdt, then set to DPMI wrapper to use. 60 | 61 | typedef struct//TSR/callback usage 62 | { 63 | uint32_t baseds; //physical base for ds,es, ss 64 | uint32_t limitds; //limit for ds, in bytes 65 | uint32_t basecs; //physical base for cs 66 | uint32_t limitcs; //limit for cs, in bytes 67 | uint32_t stackpointer; //esp 68 | }DPMI_SPACE; 69 | 70 | typedef struct //TSR/callback usage. state for linear DPMI_Load*/DPMI_Store*/DPMI_Mask*/DPMI_CopyLinear functions 71 | { 72 | uint16_t selector; //selector created from outside 73 | uint16_t physical; //1: physical addr instead of virutal. used when not called through DPMI/DPMI, and context unavailable, and no paging 74 | }DPMI_ADDRESSING; 75 | 76 | typedef struct //old interrupt handler info returned by install isr. 77 | { 78 | uint32_t extra; 79 | uint32_t offset; 80 | uint16_t cs; 81 | uint16_t rm_offset; 82 | uint16_t rm_cs; 83 | uint8_t n; //INTn 84 | uint8_t user; //user defined 85 | }DPMI_ISR_HANDLE; 86 | 87 | #if defined(__BC__) || defined(__WC__) 88 | #include 89 | 90 | //convert a linear (virtual) addr to physical addr (current segment) 91 | //only working with memory allocated with DPMI_DMAMalloc, or DPMI_MapMemory 92 | #define DPMI_L2P(addr) (addr) 93 | 94 | //convert a physical addr to linear addr (current segment) 95 | //only working with memory allocated with DPMI_DMAMalloc, or DPMI_MapMemory 96 | #define DPMI_P2L(addr) (addr) 97 | 98 | //convert a DATA ptr to linear (page mapped) addr 99 | //ptr must in data segment, not code, i.e. function address 100 | uint32_t DPMI_PTR2L(void* ptr); 101 | 102 | void* DPMI_L2PTR(uint32_t addr); 103 | 104 | int DPMI_Exit(int c); 105 | 106 | #define exit(c) DPMI_Exit(c) 107 | 108 | extern BOOL DPMI_TSRed; //extra flags for _dos_keep, which calls atexit 109 | 110 | #elif defined(__DJ2__) 111 | 112 | //note: DJGPP use paged flat mode linear address. 113 | 114 | //convert a linear (virtual) addr to physical addr 115 | //only working with memory allocated with DPMI_DMAMalloc, or DPMI_MapMemory 116 | uint32_t DPMI_L2P(uint32_t vaddr); 117 | 118 | //convert a physical addr to linear addr 119 | //only working with memory allocated with DPMI_DMAMalloc, or DPMI_MapMemory 120 | uint32_t DPMI_P2L(uint32_t paddr); 121 | 122 | //convert a ptr to linear (page mapped) addr 123 | uint32_t DPMI_PTR2L(void* ptr); 124 | 125 | void* DPMI_L2PTR(uint32_t addr); 126 | 127 | #define DPMI_Exit(c) (c) 128 | 129 | #define DPMI_TSRed (FALSE) 130 | 131 | #else //stub 132 | 133 | //convert a linear (virtual) addr to physical addr 134 | uint32_t DPMI_L2P(uint32_t addr); 135 | //convert a physical addr to linear addr 136 | uint32_t DPMI_P2L(uint32_t addr); 137 | //convert a ptr to linear (page mapped) addr 138 | uint32_t DPMI_PTR2L(void* ptr); 139 | void* DPMI_L2PTR(uint32_t addr); 140 | int DPMI_Exit(int); 141 | extern BOOL DPMI_TSRed; 142 | 143 | #endif 144 | 145 | //convert ptr to physical addr 146 | #define DPMI_PTR2P(ptr) DPMI_L2P(DPMI_PTR2L(ptr)) 147 | //convert physical addr to ptr 148 | #define DPMI_P2PTR(addr) DPMI_L2PTR(DPMI_P2L(addr)) 149 | 150 | //return virtual mapped memory in linear space, usually for device IO 151 | //get the device base address in physical space and map it to the linear space to access it 152 | //input physical addr must < 1M (0x100000) 153 | //http://www.delorie.com/djgpp/v2faq/faq18_7.html 154 | uint32_t DPMI_MapMemory(uint32_t physicaladdr, uint32_t size); 155 | uint32_t DPMI_UnmapMemory(uint32_t linearaddr); 156 | 157 | //the 'DMA' here doesn't involve DMA controller, but device directly accessing physical RAM, i.e. PCI bus master 158 | //memory allocated with this function is guaranteed to work with DPMI_L2P/DPMI_P2L 159 | //use this function if you want map between virtual addr and physical addr, meant for driver/device MMIO 160 | //malloc is recommended for normal memory allocation. 161 | void* DPMI_DMAMalloc(unsigned int size, unsigned int alignment); 162 | void* DPMI_DMAMallocNCPB(unsigned int size, unsigned int alignment); //no crossing page boundary 163 | void DPMI_DMAFree(void* ptr); 164 | 165 | //allocate DOS conventional memory (below 640K) 166 | //input: size in paragraphs (16 bytes) 167 | //return: high 16: selector, low 16: segment base address. 168 | //allocated memory is 1:1 mapped (physical==linear) 169 | uint32_t DPMI_DOSMalloc(uint16_t size); 170 | void DPMI_DOSFree(uint32_t segment); 171 | 172 | //RM call. return 0 on succeed. 173 | uint16_t DPMI_CallRealModeRETF(DPMI_REG* reg); 174 | uint16_t DPMI_CallRealModeINT(uint8_t i, DPMI_REG* reg); 175 | uint16_t DPMI_CallRealModeIRET(DPMI_REG* reg); 176 | //install interrupt service routine. ISR use normal return, no need to do IRET. 177 | //return 0 if succeed 178 | uint16_t DPMI_InstallISR(uint8_t i, void(*ISR)(void), DPMI_ISR_HANDLE* outputp handle); 179 | uint16_t DPMI_UninstallISR(DPMI_ISR_HANDLE* inputp handle); 180 | //allocate realmode callback. return: hiword: segment, lowword: offset. return 0 if fail 181 | //input: Fn is a common function with normal return. the RMCB will use RETF finally 182 | uint32_t DPMI_AllocateRMCB_RETF(void(*Fn)(void), DPMI_REG* reg); 183 | uint32_t DPMI_AllocateRMCB_IRET(void(*Fn)(void), DPMI_REG* reg); 184 | 185 | //TSR/callback usage 186 | void DPMI_GetPhysicalSpace(DPMI_SPACE* outputp spc); 187 | BOOL DPMI_TSR(void); 188 | //switch addressing mode for linear functions, should use it temporarily and interrupt disabled. 189 | void DPMI_SetAddressing(DPMI_ADDRESSING* inputp newaddr, DPMI_ADDRESSING* outputp oldaddr); 190 | 191 | void DPMI_Init(void); 192 | //void DPMI_Shutdown(void); auto called atexit 193 | 194 | //linear memory access 195 | uint8_t __CDECL DPMI_LoadB(uint32_t addr); 196 | void __CDECL DPMI_StoreB(uint32_t addr, uint8_t val); 197 | void __CDECL DPMI_MaskB(uint32_t addr, uint8_t mand, uint8_t mor); 198 | 199 | uint16_t __CDECL DPMI_LoadW(uint32_t addr); 200 | void __CDECL DPMI_StoreW(uint32_t addr, uint16_t val); 201 | void __CDECL DPMI_MaskW(uint32_t addr, uint16_t mand, uint16_t mor); 202 | 203 | uint32_t __CDECL DPMI_LoadD(uint32_t addr); 204 | void __CDECL DPMI_StoreD(uint32_t addr, uint32_t val); 205 | void __CDECL DPMI_MaskD(uint32_t addr, uint32_t mand, uint32_t mor); 206 | 207 | void __CDECL DPMI_CopyLinear(uint32_t dest, uint32_t src, uint32_t size); 208 | void __CDECL DPMI_SetLinear(uint32_t dest, uint8_t val, uint32_t size); 209 | int32_t __CDECL DPMI_CompareLinear(uint32_t addr1, uint32_t addr2, uint32_t size); 210 | 211 | //topdown allocation of DPMI_DOSMalloc, from high address (640K/1024K downwards). 212 | //input: size in paragraphs (16 bytes) 213 | //UMB: use UMB memory (640K~1024K), memory may not be 1:1 mapped. 214 | //output: segment address in low 16 bit. 215 | //note: only conventional 640K is 1:1 mapped. 216 | //UMB returned addr not essentially equals to physical addr 217 | //do not use UMB if physical addr (DPMI_L2P) is needed. 218 | uint32_t DPMI_HighMalloc(uint16_t size, BOOL UMB); 219 | void DPMI_HighFree(uint32_t segment); 220 | 221 | //convert real mode far pointer to linear addr 222 | #define DPMI_FP2L(f32) ((((f32)>>12)&0xFFFF0)+((f32)&0xFFFF)) 223 | //convert far pointer (seg:off) to linear 224 | #define DPMI_SEGOFF2L(seg, off) ((((uint32_t)((seg)&0xFFFF))<<4) + ((off)&0xFFFF)) 225 | //convert far pointer (seg:off) to 32bit far ptr 226 | #define DPMI_MKFP(seg, off) ((((uint32_t)((seg)&0xFFFF))<<16) | ((off)&0xFFFF)) 227 | 228 | #ifdef __cplusplus 229 | } 230 | #endif 231 | 232 | #endif 233 | -------------------------------------------------------------------------------- /main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include "USBDDOS/DPMI/dpmi.h" 7 | #include "USBDDOS/usb.h" 8 | #include "USBDDOS/CLASS/msc.h" 9 | #include "USBDDOS/CLASS/hid.h" 10 | #include "USBDDOS/dbgutil.h" 11 | 12 | #define USBDDOS_VERSION 0x0200 //BCD 13 | #ifndef USBDDOS_BUILD 14 | #define USBDDOS_BUILD "Local build" 15 | #endif 16 | 17 | #if defined(__BC__) || defined(__WC__) 18 | #define ENABLE_RETROWAVE 0 //code exceed 64K 19 | #else 20 | #define ENABLE_RETROWAVE 1 21 | #endif 22 | 23 | #if ENABLE_RETROWAVE 24 | #include "RetroWav/RetroWav.h" 25 | #include "RetroWav/Platform/dos_cdc.h" 26 | #include "RetroWav/Board/OPL3.h" 27 | #include "emm.h" 28 | #include "hdpmipt.h" 29 | 30 | #define OPL_PRIMARY 0 31 | #define OPL_SECONDARY 1 32 | 33 | RetroWaveContext MAIN_RWContext = {0}; 34 | static uint32_t MAIN_OPLTimerCtrlReg[2]; //if start 1 and 2 seperately we will miss one, so use 2 cache 35 | static uint8_t MAIN_OPLIndexReg[2]; 36 | 37 | //primary index read 38 | #define OPL_TIMER_REG_INDEX 4 39 | #define OPL_TIMER1_MASK 0xC0 40 | #define OPL_TIMER2_MASK 0xA0 41 | #define OPL_TIMER1_START 0x01 42 | #define OPL_TIMER2_START 0x02 43 | #define OPL_TIMER1_TIMEOUT OPL_TIMER1_MASK 44 | #define OPL_TIMER2_TIMEOUT OPL_TIMER2_MASK 45 | 46 | //secondary index read (Adlib Gold). reference: AIL2.0 source code, dosbox 47 | #define ADLG_IOBUSY 0x40UL 48 | #define ADLG_VOLL_REG_INDEX 9 49 | #define ADLG_VOLR_REG_INDEX 10 50 | 51 | //data 52 | #define KEY_ON 0x10 //channel on bit 53 | static uint32_t ADLG_CtrlEnable = 0; //seems not working for Miles Sound, don't use it 54 | static uint32_t ADLG_Volume[2] = {0x08,0x08}; 55 | 56 | static uint32_t MAIN_OPL_Primary_Index(uint32_t port, uint32_t reg, uint32_t out) 57 | { 58 | unused(port); 59 | if(out) 60 | MAIN_OPLIndexReg[OPL_PRIMARY] = (uint8_t)reg; 61 | else 62 | { //in status reg 63 | reg = reg & ~0xFFUL; 64 | if ((MAIN_OPLTimerCtrlReg[0] & (OPL_TIMER1_MASK|OPL_TIMER1_START)) == OPL_TIMER1_START) 65 | reg |= OPL_TIMER1_TIMEOUT; 66 | if ((MAIN_OPLTimerCtrlReg[1] & (OPL_TIMER2_MASK|OPL_TIMER2_START)) == OPL_TIMER2_START) 67 | reg |= OPL_TIMER2_TIMEOUT; 68 | inp((uint16_t)port); //instant delay 69 | } 70 | return reg; 71 | } 72 | 73 | static uint32_t MAIN_OPL_Primary_Data(uint32_t port, uint32_t val, uint32_t out) 74 | { 75 | unused(port); 76 | if(out) 77 | { 78 | if(MAIN_OPLIndexReg[OPL_PRIMARY] == OPL_TIMER_REG_INDEX) 79 | { 80 | if(val&(OPL_TIMER1_START|OPL_TIMER1_MASK)) 81 | MAIN_OPLTimerCtrlReg[0] = val; 82 | if(val&(OPL_TIMER2_START|OPL_TIMER2_MASK)) 83 | MAIN_OPLTimerCtrlReg[1] = val; 84 | } 85 | 86 | retrowave_opl3_emit_port0(&MAIN_RWContext, MAIN_OPLIndexReg[OPL_PRIMARY], (uint8_t)val); 87 | return val; 88 | } 89 | return MAIN_OPL_Primary_Index(port, val, out); 90 | } 91 | 92 | static uint32_t MAIN_OPL_Secondary_Index(uint32_t port, uint32_t reg, uint32_t out) 93 | { 94 | unused(port); 95 | if(out) 96 | { 97 | if(reg == 0xFF) 98 | ADLG_CtrlEnable = TRUE; 99 | else if(reg == 0xFE) 100 | ADLG_CtrlEnable = FALSE; 101 | 102 | MAIN_OPLIndexReg[OPL_SECONDARY] = (uint8_t)reg; 103 | return reg; 104 | } 105 | return ADLG_CtrlEnable ? ~ADLG_IOBUSY : MAIN_OPL_Primary_Index(port, reg, out); 106 | } 107 | 108 | static uint32_t MAIN_OPL_Secondary_Data(uint32_t port, uint32_t val, uint32_t out) 109 | { 110 | unused(port); 111 | if(out) 112 | { 113 | if(/*ADLG_CtrlEnable && */(MAIN_OPLIndexReg[OPL_SECONDARY] == ADLG_VOLL_REG_INDEX || MAIN_OPLIndexReg[OPL_SECONDARY] == ADLG_VOLR_REG_INDEX)) 114 | ADLG_Volume[MAIN_OPLIndexReg[OPL_SECONDARY]-ADLG_VOLL_REG_INDEX] = val; 115 | 116 | retrowave_opl3_emit_port1(&MAIN_RWContext, MAIN_OPLIndexReg[OPL_SECONDARY], (uint8_t)val); 117 | return val; 118 | } 119 | //in 120 | //if(ADLG_CtrlEnable) //adlib gold 121 | { 122 | if(MAIN_OPLIndexReg[OPL_SECONDARY] == ADLG_VOLL_REG_INDEX || MAIN_OPLIndexReg[OPL_SECONDARY] == ADLG_VOLR_REG_INDEX) 123 | return ADLG_Volume[MAIN_OPLIndexReg[OPL_SECONDARY]-ADLG_VOLL_REG_INDEX]; 124 | } 125 | return MAIN_OPL_Primary_Index(port, val, out); 126 | } 127 | 128 | static EMM_IODT MAIN_IODT[4] = 129 | { 130 | 0x388, &MAIN_OPL_Primary_Index, 131 | 0x389, &MAIN_OPL_Primary_Data, 132 | 0x38A, &MAIN_OPL_Secondary_Index, 133 | 0x38B, &MAIN_OPL_Secondary_Data, 134 | }; 135 | static EMM_IOPT MAIN_IOPT; 136 | #if defined(__DJ2__) 137 | static EMM_IOPT MAIN_HDPMI_IOPT; 138 | BOOL MAIN_HDPMI_PortTrapped; 139 | #endif 140 | #endif 141 | 142 | struct 143 | { 144 | const char* option; 145 | const char* desc; 146 | BOOL enable; 147 | }MAIN_Options[] = 148 | { 149 | "/?", "Show help.", FALSE, 150 | #if ENABLE_RETROWAVE 151 | "/RW", "Enable RetroWave OPL3 supprt. EMM386 v4.46+ / HDPMI32i needed.", FALSE, 152 | #endif 153 | "/disk", "Enable USB-disk support", FALSE, 154 | "/hid", "Enable USB keyboard & mouse support", FALSE, 155 | 156 | #if DEBUG 157 | "/test", "debug tests", FALSE, 158 | #endif 159 | NULL, NULL, 0, 160 | }; 161 | enum EOption 162 | { 163 | OPT_Help, 164 | #if ENABLE_RETROWAVE 165 | OPT_RetroWave, 166 | #endif 167 | OPT_Disk, 168 | OPT_HID, 169 | 170 | #if DEBUG 171 | OPT_TEST, 172 | #endif 173 | OPT_COUNT, 174 | }; 175 | 176 | int main(int argc, char* argv[]) 177 | { 178 | if(argc == 1 || (argc == 2 && stricmp(argv[1],"/?") == 0)) 179 | { 180 | printf("USBDDOS: USB driver for DOS. https://github.com/crazii/USBDDOS\n"); 181 | printf("Version: %d.%02d, Build: %s. Usage:\n", USBDDOS_VERSION>>8, USBDDOS_VERSION&0xFF, USBDDOS_BUILD); 182 | int i = 0; 183 | while(MAIN_Options[i].option) 184 | { 185 | printf(" %-8s: %s\n", MAIN_Options[i].option, MAIN_Options[i].desc); 186 | ++i; 187 | } 188 | return 0; 189 | } 190 | else 191 | { 192 | for(int i = 1; i < argc; ++i) 193 | { 194 | for(int j = 0; j < OPT_COUNT; ++j) 195 | { 196 | if(stricmp(argv[i], MAIN_Options[j].option) == 0) 197 | { 198 | MAIN_Options[j].enable = TRUE; 199 | break; 200 | } 201 | } 202 | } 203 | } 204 | 205 | #if DEBUG && 0 206 | if(MAIN_Options[OPT_TEST].enable) 207 | { 208 | extern void DPMI_InitFlat(); 209 | extern void USB_MSC_Test(); 210 | //DPMI_InitFlat(); 211 | //USB_MSC_Test(); 212 | return 0; 213 | } 214 | #endif 215 | 216 | 217 | DPMI_Init(); 218 | 219 | 220 | #if ENABLE_RETROWAVE 221 | if(MAIN_Options[OPT_RetroWave].enable) 222 | { 223 | unsigned short EMMVer = EMM_GetVersion(); 224 | _LOG("EMM386 version: %d.%02d\n", (EMMVer&0xFF), (EMMVer>>8)); 225 | if((EMMVer&0xFF) < 4 || (EMMVer&0xFF) == 4 && (EMMVer&0xFF00) < 46) 226 | { 227 | printf("EMM386 not installed or version not supported: %d.%02d\n", (EMMVer&0xFF), (EMMVer>>8)); 228 | return -1; 229 | } 230 | } 231 | #endif 232 | 233 | 234 | USB_Init(); 235 | 236 | 237 | #if ENABLE_RETROWAVE 238 | if(MAIN_Options[OPT_RetroWave].enable) 239 | { 240 | if(retrowave_init_dos_cdc(&MAIN_RWContext) != 0) 241 | return -1; 242 | retrowave_io_init(&MAIN_RWContext); 243 | retrowave_opl3_reset(&MAIN_RWContext); 244 | 245 | if(!EMM_Install_IOPortTrap(0x388, 0x38B, MAIN_IODT, sizeof(MAIN_IODT)/sizeof(EMM_IODT), &MAIN_IOPT)) 246 | { 247 | puts("IO trap installation failed.\n"); 248 | return 1; 249 | } 250 | 251 | #if defined(__DJ2__) 252 | if(!(MAIN_HDPMI_PortTrapped=HDPMIPT_Install_IOPortTrap(0x388, 0x38B, MAIN_IODT, sizeof(MAIN_IODT)/sizeof(EMM_IODT), &MAIN_HDPMI_IOPT))) 253 | puts("Protected mode IO trap installation failed, make sure an HDPMI that supporting port trap is used.\n"); 254 | #endif 255 | } 256 | BOOL TSR = MAIN_Options[OPT_RetroWave].enable; 257 | #else 258 | BOOL TSR = FALSE; 259 | #endif 260 | TSR = (MAIN_Options[OPT_Disk].enable && USB_MSC_DOS_Install()) || TSR; //note: TSR must be put in the back 261 | TSR = (MAIN_Options[OPT_HID].enable && USB_HID_DOS_Install()) || TSR; 262 | #if DEBUG && 0 263 | TSR = MAIN_Options[OPT_TEST].enable || TSR; 264 | #endif 265 | if(TSR) 266 | { 267 | if(!DPMI_TSR()) 268 | puts("TSR Installation failed.\n"); 269 | } 270 | else 271 | puts("No USB device found, exit.\n"); 272 | 273 | //TSR failure 274 | #if ENABLE_RETROWAVE 275 | if(MAIN_Options[OPT_RetroWave].enable) 276 | { 277 | BOOL uninstalled; 278 | 279 | uninstalled = EMM_Uninstall_IOPortTrap(&MAIN_IOPT); 280 | assert(uninstalled); 281 | 282 | #if defined(__DJ2__) 283 | if(MAIN_HDPMI_PortTrapped) 284 | { 285 | uninstalled = HDPMIPT_Uninstall_IOPortTrap(&MAIN_IOPT); 286 | assert(uninstalled); 287 | } 288 | #endif 289 | unused(uninstalled); 290 | } 291 | #endif 292 | return DPMI_Exit(0); 293 | } 294 | -------------------------------------------------------------------------------- /USBDDOS/HCD/uhci.h: -------------------------------------------------------------------------------- 1 | #ifndef _UHCI_H_ 2 | #define _UHCI_H_ 3 | #include "USBDDOS/HCD/hcd.h" 4 | 5 | //PCI configuration sapce 6 | #define USBBASE 0x20 //0x20~0x23, IO Space Base Address register (PCI BAR4) 7 | #define LEGSUP 0xC0 //0xC0~0xC1, legacy support register 8 | #define USBSMIEN BIT4 //usb smi enable 9 | #define USBPIRQDEN BIT13 10 | 11 | ///PID 12 | #define OUTPID 0xe1 13 | #define INPID 0x69 14 | #define SOFPID 0xa5 15 | #define SETUPPID 0x2d 16 | 17 | #define DATA0PID 0xc3 18 | #define DATA1PID 0x4b 19 | #define DATA2PID 0x87 20 | #define MDATAPID 0x0f 21 | 22 | #define ACKPID 0xd2 23 | #define NAKPID 0x5a 24 | #define STALLPID 0x1e 25 | #define NYETPID 0x96 26 | 27 | #define PREPID 0x3c 28 | #define ERRPID 0x3c 29 | #define SPLITPID 0x78 30 | #define PINGPID 0xb4 31 | #define RESERVEDPID 0xF0 32 | 33 | // invalid QH, TD; means last QH, TD 34 | #define TerminateFlag 0x01 35 | #define QHFlag 0x02 36 | #define DepthSelect 0x04 //Depth/Breath Select, continue element link. 37 | 38 | //control and status, matches ControlStatusBits 39 | #define CS_C_ERR (BIT27|BIT28) //error count 00b: no limit, ... 11b: interrupt after 3 error 40 | #define CS_LowSpeed BIT26 41 | #define CS_IOS BIT25 //isochronous select 42 | #define CS_IOC BIT24 //interrupt on complete 43 | #define CS_ActiveStatus BIT23 44 | #define CS_StalledStatus BIT22 45 | #define CS_DataBufferError BIT21 46 | #define CS_BabbleDetected BIT20 47 | #define CS_NAKReceived BIT19 48 | #define CS_CRCTimeOutError BIT18 49 | #define CS_BitstuffError BIT17 50 | #define CS_ErrorMask (BIT17|BIT18|BIT19|BIT20|BIT21|BIT22) 51 | #define CS_ErrorShift 17L 52 | 53 | #define CS_C_ERR_NOLIMIT (0L<<27) 54 | #define CS_C_ERR1 (1L<<27) //error count 1 55 | #define CS_C_ERR2 (2L<<27) 56 | #define CS_C_ERR3 (3L<<27) 57 | 58 | //token 59 | #define TK_DataToggle BIT19 60 | #define TK_NullLength 0x7FF 61 | 62 | // UHCI register 63 | #define USBCMD 0x00 //command, 16bit 64 | #define USBSTS 0x02 //status, 16bit 65 | #define USBINTR 0x04 //interrupt enable,16bit 66 | #define FRNUM 0x06 //frame number, 16bit (10bit used, 0~1024) 67 | #define FLBASEADD 0x08 //frame list base addr, 32bit 68 | #define SOF 0x0c //start of frame modify, 8bit 69 | #define PORTSC 0x10 70 | #define PORT1 0x10 71 | #define PORT2 0x12 72 | 73 | //USBCMD 74 | #define RS BIT0 //run/stop 75 | #define HCRESET BIT1 76 | #define GRESET BIT2 //global reset 77 | #define EGSM BIT3 //enter global suspend 78 | #define FGR BIT4 //force global resume 79 | #define SWDBG BIT5 //software debug 80 | #define CF BIT6 //configure flag(HCD only, last action) 81 | #define MAXP BIT7 //max packet 0:32bytes, 1:64bytes 82 | 83 | //USBSTS 84 | #define USBINT BIT0 //USBSTS bit 0 85 | #define USBERRORINT BIT1 86 | #define USBRESUMEDETECT BIT2 87 | #define USBHSERROR BIT3 //host system error 88 | #define USBHCERROR BIT4 //host controller error 89 | #define USBHCHALTED BIT5 //HCHalted 90 | #define USBINTMASK (BIT0|BIT1|BIT2|BIT3|BIT4) 91 | 92 | //PORT1 PORT2 93 | 94 | //Current Connect Status RO. 95 | #define CCS BIT0 96 | //Connect Status Change R/WC. 97 | #define CSC BIT1 98 | //Port Enabled/Disabled R/W. 99 | #define PED BIT2 100 | //Port Enable/Disable Change R/WC. 101 | #define PEDC BIT3 102 | //Low Speed Device Attached RO. 103 | #define LSDA BIT8 104 | //Port Reset R/W. 105 | #define PR BIT9 106 | //Suspend R/W 107 | #define SUSPEND BIT12 108 | 109 | #ifdef __cplusplus 110 | extern "C" { 111 | #endif 112 | 113 | struct UHCI_TransferDescriptor; 114 | typedef struct UHCI_TransferDescriptor UHCI_TD; 115 | 116 | /* 117 | 3 2 1 0 118 | ----------------------------------------------------------- 119 | | Link Pointer |0|Vf|Q|T| 120 | ----------------------------------------------------------- 121 | 122 | 3130 23 16 15 11 10 0 123 | ----------------------------------------------------------- 124 | |R | | | Status | R | ActLen | 125 | ----------------------------------------------------------- 126 | 127 | 31 2120 1918 1514 8 7 0 128 | ----------------------------------------------------------- 129 | | MaxLen |R|D| EndPt | Dev Addr | PID | 130 | ----------------------------------------------------------- 131 | 132 | 31 0 133 | ----------------------------------------------------------- 134 | | Buffer Pointer | 135 | ----------------------------------------------------------- 136 | */ 137 | typedef struct UHCI_TransferDescriptor 138 | { 139 | uint32_t LinkPointer; 140 | union 141 | { 142 | uint32_t ControlStatus; 143 | struct 144 | { 145 | uint16_t ActualLen : 11; 146 | uint16_t Reserved0 : 5; 147 | uint16_t Reserved1 : 1; 148 | uint16_t E_Bitstuff : 1; //error bits 149 | uint16_t E_CRC_Timeout : 1; 150 | uint16_t E_NAK : 1; 151 | uint16_t E_Babble : 1; 152 | uint16_t E_DataBuffer : 1; 153 | uint16_t E_Stalled : 1; 154 | uint16_t Active : 1; 155 | uint16_t Interrupt : 1; //IOC 156 | uint16_t Isochronous : 1; //IOS 157 | uint16_t LowSpeed : 1; //CS_LowSpeed 158 | uint16_t ErrorLimit : 2; //CS_C_ERR. 0: no limit 159 | uint16_t ShortPacketDetect : 1; //SPD 160 | uint16_t Reserved2 : 2; 161 | }ControlStatusBits; 162 | }; 163 | union 164 | { 165 | uint32_t Token; 166 | struct 167 | { 168 | #if defined(__BC__) 169 | uint16_t PID : 8; 170 | uint16_t DeviceAddress : 7; 171 | uint16_t Endpoint : 4; 172 | uint16_t DataToggle : 1; 173 | uint16_t Reserved : 1; 174 | uint16_t MaxLen : 11; //0x7FF=NULL 175 | #else 176 | uint32_t PID : 8; 177 | uint32_t DeviceAddress : 7; 178 | uint32_t Endpoint : 4; 179 | uint32_t DataToggle : 1; 180 | uint32_t Reserved : 1; 181 | uint32_t MaxLen : 11; //0x7FF=NULL 182 | #endif 183 | }TokenBits; 184 | }; 185 | uint32_t BufferPointer; 186 | 187 | //extension 188 | uint32_t PAddr; //physical addr 189 | HCD_Request* pRequest; 190 | UHCI_TD* pNext; 191 | UHCI_TD* pPrev; 192 | #if defined(__BC__) || defined(__WC__) 193 | uint16_t padding[3]; 194 | #endif 195 | }UHCI_TD; 196 | static_assert(sizeof(UHCI_TD)%16 == 0, "size alignment error"); 197 | 198 | /* 199 | 3 2 1 0 200 | ----------------------------------------------------------- 201 | | Queue Head Link Pointer |0|0|Q|T| 202 | ----------------------------------------------------------- 203 | 204 | 3 2 1 0 205 | ----------------------------------------------------------- 206 | | Queue Element Link Pointer |0|R|Q|T| 207 | ----------------------------------------------------------- 208 | */ 209 | typedef struct 210 | { // QH must keep 16-byte align. 211 | uint32_t HeadLink; 212 | uint32_t ElementLink; 213 | 214 | //externsion 215 | struct 216 | { 217 | uint16_t wMaxPacketSize : 11; 218 | uint16_t Type : 2; 219 | uint16_t Dir : 1; 220 | uint16_t Interval : 2; 221 | uint16_t DataToggle : 1; 222 | uint16_t Reserved0 : 15; 223 | }Flags; 224 | UHCI_TD* pTail; 225 | #if defined(__BC__) || defined(__WC__) 226 | uint16_t padding[1]; 227 | #endif 228 | }UHCI_QH; 229 | static_assert(sizeof(UHCI_QH)%16 == 0, "size alignment error"); 230 | 231 | typedef struct UHCI_HostControllerDriverData 232 | { 233 | UHCI_QH QH1ms; 234 | UHCI_QH QH2ms; 235 | UHCI_QH QH8ms; 236 | 237 | UHCI_QH ControlQH; 238 | UHCI_QH BulkQH; 239 | 240 | UHCI_QH* InteruptTail[3]; 241 | UHCI_QH* ControlTail; 242 | UHCI_QH* BulkTail; 243 | uint32_t dwFrameListBase;// memory address. 244 | uint16_t wFrameListHandle; //xms handle 245 | }UHCI_HCData; 246 | 247 | typedef struct UHCI_HostControllerDeviceData 248 | { 249 | UHCI_QH ControlQH; 250 | }UHCI_HCDeviceData; 251 | 252 | BOOL UHCI_InitController(HCD_Interface* pHCI, PCI_DEVICE* pPCIDev); 253 | BOOL UHCI_DeinitController(HCD_Interface* pHCI); 254 | BOOL UHCI_ISR(HCD_Interface* pHCI); 255 | 256 | uint8_t UHCI_ControlTransfer(HCD_Device* pDevice, void* pEndpoint, HCD_TxDir dir, uint8_t inputp setup8[8], 257 | void* nullable pSetupData, uint16_t length, HCD_COMPLETION_CB pCB, void* nullable pCBData); 258 | 259 | uint8_t UHCI_DataTransfer(HCD_Device* pDevice, void* pEndpoint, HCD_TxDir dir, uint8_t* inoutp pBuffer, 260 | uint16_t length, HCD_COMPLETION_CB pCB, void* nullable pCBData); 261 | 262 | #ifdef __cplusplus 263 | } 264 | #endif 265 | 266 | #endif 267 | -------------------------------------------------------------------------------- /USBDDOS/CLASS/msc.h: -------------------------------------------------------------------------------- 1 | #ifndef _MSC_H_ 2 | #define _MSC_H_ 3 | //Mass Storage Class 4 | //ref: https://www.usb.org/document-library/mass-storage-class-specification-overview-14 5 | // https://www.usb.org/sites/default/files/usbmassbulk_10.pdf 6 | // https://www.usb.org/sites/default/files/usb_msc_boot_1.0.pdf 7 | 8 | //the mass storage class support 2 modes: CBI(control/bulk/interrupt) and BBB(bulk only transport, BOT). 9 | //CBI is for floppy disk only. and here it is not intended to support. 10 | 11 | //Tested devices: 12 | //Kingston DataTraveller 2G, FAT16, BPB in boot sector 13 | //Toshiba Transmemory 8G, FAT32, BPB in FAT32 VBR 14 | //USB2.0 disk (unknown vendor) 64G,FAT32, BPB in FAT32 VBR 15 | //HP x306w 64G,FAT32, BPB in FAT32 VBR 16 | 17 | #include "USBDDOS/usb.h" 18 | 19 | #define USB_REQ_TYPE_MSC (USB_REQTYPE_CLASS | USB_REQREC_INTERFACE) 20 | 21 | //bInterfaceProtocol 22 | #define USB_MSC_PROTOCOL_CBI_I 0x0 //with command complettion interrupt 23 | #define USB_MSC_PROTOCOL_CBI 1 24 | #define USB_MSC_PROTOCOL_BBB 0x50 25 | 26 | //bInterfaceSubClass 27 | #define USB_MSC_CB_RBC 0x01 //www.t10.org/scsi-3.htm 28 | #define USB_MSC_CB_ATAPI 0x02 //MMC-5, ftp.seagate.com/sff/INF-8070.PDF 29 | #define USB_MSC_CB_UFI 0x04 30 | #define USB_MSC_CB_SCSI 0x06 //www.t10.org/scsi-3.htm, www.t10.org/scsi-3.htm 31 | #define USB_MSC_CB_LSDFS 0x07 32 | #define USB_MSC_CB_IEEE1667 0x08 33 | 34 | //bRequest 35 | #define USB_REQ_MSC_RESET 0xFF //bulk only rest (out) 36 | #define USB_REQ_MSC_GET_MAX_LUN 0xFE //get max lun (in) 37 | 38 | //signature 39 | #define USB_MSC_CBW_SIGNATURE 0x43425355 40 | #define USB_MSC_CSW_SIGNATURE 0x53425355 41 | 42 | //CSW status 43 | #define USB_MSC_CSW_STATUS_PASSED 0 44 | #define USB_MSC_CSW_STATUS_FAILED 1 45 | #define USB_MSC_CSW_STATUS_PHASE_ERROR 2 46 | 47 | 48 | //CBW & CSW are transported via data (bulk) transfer. CBW(OUT) -> data(IN/OUT) -> CSW(IN) 49 | 50 | #if defined(__DJ2__) || defined(__WC__) 51 | #pragma pack(1) 52 | #endif 53 | 54 | //CBW 55 | typedef struct USB_MSC_CommandBlockWrapper 56 | { 57 | uint32_t dCBWSignature; //USB_MSC_CBW_SIGNATURE 58 | uint32_t dCBWTag; 59 | uint32_t dCBWDataTransferLength; 60 | uint8_t bmCBWFlags; //bit 7: 0: out, 1: in. other bits obsolete or reserved and must be 0 61 | 62 | uint8_t bCBWLUN : 4; 63 | uint8_t reserved0 : 4; 64 | 65 | uint8_t bCBWCBLength : 5; //valid length of CBWCB 66 | uint8_t reserved1 : 3; 67 | 68 | uint8_t CBWCB[16]; //command block. significant bytes first 69 | }USB_MSC_CBW; 70 | static_assert(sizeof(USB_MSC_CBW) == 31, "incorrect size"); 71 | 72 | //CSW 73 | typedef struct USB_MSC_CommandStatusWrapper 74 | { 75 | uint32_t dCSWSignature; //USB_MSC_CSW_SIGNATURE 76 | uint32_t dCSWTag; 77 | uint32_t dCSWDataResidue; 78 | uint8_t bCSWStatus; //USB_MSC_CSW_STATUS_* 79 | }USB_MSC_CSW; 80 | 81 | //below are SCSI commands used by CBW (the CBWCB field) 82 | //not all commands, but essential for a usb booting device 83 | 84 | //NCITS 306-1998 SCSI Block Commands (SBC), www.t10.org/scsi-3.htm 85 | #define USB_MSC_SBC_INQUIRY 0x12 86 | #define USB_MSC_SBC_READ10 0x28 87 | #define USB_MSC_SBC_REQSENSE 0x03 //request sense 88 | #define USB_MSC_SBC_TESTUNITREADY 0x00 //test unity ready 89 | #define USB_MSC_SBC_MODESENSE 0x5A 90 | #define USB_MSC_SBC_READ_CAP 0x25 //read capacity 91 | #define USB_MSC_SBC_READ_TOC 0x43 //read TOC for CDROM 92 | #define USB_MSC_SBC_FORMAT_UNIT 0x04 93 | #define USB_MSC_SBC_VERIFY 0x2F 94 | #define USB_MSC_SBC_WRITE10 0x2A 95 | 96 | ///INQUIRY 97 | //Peripheral Device Type for INQUIRY 98 | #define USB_MSC_PDT_SBC_DAD 0x00 //SBC Direct-access device 99 | #define USB_MSC_PDT_CDROM 0x05 100 | #define USB_MSC_PDT_OPTICAL 0x07 //non-CD optical 101 | #define USB_MSC_PDT_RBC_DAD 0x0E //RBC Direct-access device 102 | 103 | typedef struct USB_MSC_InquiryCommand 104 | { 105 | uint8_t opcode; //USB_MSC_SBC_INQUIRY 106 | uint8_t reserved0 : 5; //zero 107 | uint8_t LUN : 3; 108 | uint8_t reserved1[2]; 109 | uint8_t AllocationLength; //24h=sizeof(USB_MSC_INQUIRY_DATA) 110 | uint8_t reserved2; 111 | uint8_t PAD[6]; //zero 112 | }USB_MSC_INQUIRY_CMD; 113 | static_assert(sizeof(USB_MSC_INQUIRY_CMD) == 12, "incorrect size"); 114 | 115 | typedef struct USB_MSC_InquiryData 116 | { 117 | uint8_t PDT : 5; //USB_MSC_PDT_*, byte 0, bit 0~4 118 | uint8_t reserved0 : 3; 119 | uint8_t reserved1 : 7; 120 | uint8_t RMB : 1; //removable media bit 121 | uint8_t reserved2[2]; 122 | uint8_t AdditionalLength; 123 | uint8_t reserved3[3]; //byte 5~7 124 | uint8_t VendorID[8]; 125 | uint8_t ProductID[16]; 126 | uint8_t ProductRevisionLevel[4]; 127 | }USB_MSC_INQUIRY_DATA; 128 | static_assert(sizeof(USB_MSC_INQUIRY_DATA) == 36, "incorrect size"); 129 | 130 | ///READ(10) 131 | typedef struct USB_MSC_ReadCommand //read(10) command 132 | { 133 | uint8_t opcode; //USB_MSC_SBC_READ10 134 | uint8_t reserved0 : 5; 135 | uint8_t LUN : 3; 136 | uint32_t LBA; //need reverse endian 137 | uint8_t reserved1; 138 | uint16_t TransferLength; //length in logical blocks //need reverse endian 139 | uint8_t reserved2; 140 | uint8_t PAD[2]; //padding, need set to 0 141 | }USB_MSC_READ_CMD; 142 | static_assert(sizeof(USB_MSC_READ_CMD) == 12, "incorrect size"); 143 | 144 | ///REQUEST SENSE 145 | typedef USB_MSC_INQUIRY_CMD USB_MSC_REQSENSE_CMD; //opcode = USB_MSC_SBC_REQSENSE 146 | typedef struct USB_MSC_ReqSenseData 147 | { 148 | uint8_t ErrorCode : 7; //0x70~0x71 149 | uint8_t Valid : 1; 150 | uint8_t SenseKey : 4; 151 | uint8_t Reserved0 : 1; 152 | uint8_t ILI : 1; 153 | uint8_t Reserved : 2; 154 | uint32_t Information; 155 | uint8_t AdditionalSenseLength; //n-7 156 | uint32_t CommandSpecificInformation; 157 | uint8_t AdditionalSenseCode; 158 | uint8_t AdditionalSenseCodeQualifierOPT; 159 | }USB_MSC_REQSENSE_DATA; 160 | 161 | 162 | ///TEST UNIT READY 163 | typedef USB_MSC_INQUIRY_CMD USB_MSC_TESTUNITREADY_CMD; //opcode = USB_MSC_SBC_TESTUNITREADY, AllocationLength = 0 164 | 165 | ///MODE SENSE 166 | typedef struct USB_MSC_ModeSenseCommand 167 | { 168 | uint8_t opcode; //USB_MSC_SBC_MODESENSE 169 | uint8_t reserved0 : 3; 170 | uint8_t DBD : 1; 171 | uint8_t reserved1 : 1; 172 | uint8_t LUN : 3; 173 | uint8_t PageCode : 6; 174 | uint8_t reserved2 : 2; 175 | uint8_t reserved3[4]; 176 | uint16_t ParamListLen; //need swap endian 177 | uint8_t reserved; 178 | uint8_t PAD[2]; 179 | }USB_MSC_MODESENSE_CMD; 180 | static_assert(sizeof(USB_MSC_MODESENSE_CMD) == 12, "incorrect size"); 181 | 182 | ///READ CAPACITY 183 | typedef USB_MSC_INQUIRY_CMD USB_MSC_READCAP_CMD; //opcode = USB_MSC_SBC_READ_CAP, AllocationLength = 0 184 | typedef struct USB_MSC_ReadCapData 185 | { 186 | uint32_t LastLBA; //last LBA address.need swap endian 187 | uint32_t BlockSize; //need swap endian 188 | }USB_MSC_READCAP_DATA; 189 | 190 | ///READ TOC 191 | typedef struct USB_MSC_ReadTOCCommand 192 | { 193 | uint8_t opcode; //USB_MSC_SBC_READ_TOC 194 | uint8_t reserved0 : 1; 195 | uint8_t MSF : 1; 196 | uint8_t reserved1 : 6; 197 | uint8_t FormatA : 4; 198 | uint8_t reserved2 : 4; 199 | uint8_t reserved3[4]; 200 | uint16_t AllocationLength; //need swap endian 201 | uint8_t reserved4 : 6; 202 | uint8_t FormatB : 2; 203 | uint8_t PAD[2]; 204 | }USB_MSC_READTOC_CMD; 205 | static_assert(sizeof(USB_MSC_READTOC_CMD) == 12, "incorrect size"); 206 | 207 | typedef struct USB_MSC_ReadTOCData 208 | { 209 | uint16_t TOCDataLen; //need swap endian = 0Ah, TOCDataLen itself excluded 210 | uint8_t FirstCompleteSN; //first complete session number 211 | uint8_t LastCompleteSN; 212 | uint8_t reserved0; 213 | uint8_t reserved1; 214 | uint8_t FirstTNInLastSession; //first track number in last complete session 215 | uint8_t reserved2; 216 | uint32_t LBA; //LBA of FirstTNInLastSession 217 | }USB_MSC_READTOC_DATA; 218 | static_assert(sizeof(USB_MSC_READTOC_DATA) == 12, "incorrect size"); 219 | 220 | ///FORMAT UNIT 221 | typedef struct USB_MSC_FormatUnitCommand 222 | { 223 | uint8_t opcode; //USB_MSC_SBC_FORMAT_UNIT 224 | uint8_t DefectListFormat : 3; //7 225 | uint8_t CmpList : 1; //0 226 | uint8_t FmtData : 1; //1 227 | uint8_t LUN : 3; 228 | uint8_t VendorSpecific; 229 | uint16_t Interleave; //need swap endian 230 | uint8_t reserved0; 231 | uint8_t PAD[6]; 232 | }USB_MSC_FORMATUNIT_CMD; 233 | static_assert(sizeof(USB_MSC_FORMATUNIT_CMD) == 12, "incorrect size"); 234 | 235 | ///VERIFY 236 | typedef struct USB_MSC_VerifyCommand 237 | { 238 | uint8_t opcode; //USB_MSC_SBC_VERIFY 239 | uint8_t reserved0 : 1; 240 | uint8_t ByteChk : 1; 241 | uint8_t reserved1 : 3; 242 | uint8_t LUN : 3; 243 | uint32_t LBA; //need swap endian 244 | uint8_t reserved2; 245 | uint16_t VerificationLen; 246 | uint8_t reserved3; 247 | uint8_t PAD[2]; 248 | }USB_MSC_VERIFY_CMD; 249 | static_assert(sizeof(USB_MSC_VERIFY_CMD) == 12, "incorrect size"); 250 | 251 | ///WRITE(10) 252 | typedef USB_MSC_READ_CMD USB_MSC_WRITE_CMD; //opcode = USB_MSC_SBC_WRITE10 253 | 254 | #if defined(__DJ2__) 255 | #pragma pack() 256 | #endif 257 | 258 | typedef struct 259 | { 260 | uint8_t bInterface; 261 | uint8_t MaxLUN; 262 | uint32_t MaxLBA; 263 | uint32_t BlockSize; 264 | uint16_t SizeGB; 265 | void* pDataEP[2]; //bulk in/out 266 | uint8_t bEPAddr[2]; 267 | uint32_t DOSDriverMem; 268 | }USB_MSC_DriverData; 269 | 270 | #ifdef __cplusplus 271 | extern "C" 272 | { 273 | #endif 274 | 275 | BOOL USB_MSC_InitDevice(USB_Device* pDevice); 276 | 277 | BOOL USB_MSC_DeinitDevice(USB_Device* pDevice); 278 | 279 | BOOL USB_MSC_BulkReset(USB_Device* pDevice); 280 | 281 | BOOL USB_MSC_IssueCommand(USB_Device* pDevice, void* inputp cmd, uint32_t CmdSize, uint32_t LinearData, uint32_t DataSize, HCD_TxDir dir); 282 | 283 | //separate dos installation routine, might be called delayed 284 | BOOL USB_MSC_DOS_Install(); 285 | BOOL USB_MSC_DOS_Uninstall(); 286 | 287 | void USB_MSC_PreInit(); 288 | void USB_MSC_PostDeInit(); 289 | 290 | #ifdef __cplusplus 291 | } 292 | #endif 293 | 294 | #endif //_MSC_H_ 295 | -------------------------------------------------------------------------------- /USBDDOS/HCD/ohci.h: -------------------------------------------------------------------------------- 1 | #ifndef _OHCI_H_ 2 | #define _OHCI_H_ 3 | #include "USBDDOS/HCD/hcd.h" 4 | 5 | //pci configuration space 6 | #define OHCI_REGISTER_BAR 0x10 //BAR_OHCI (BAR0) 7 | 8 | #define HcRevision 0L 9 | 10 | #define HcControl 4L //HcControl Register 11 | #define ControlBulkServiceRatio (BIT0 | BIT1) //HcControl bits 12 | #define PeriodicListEnable BIT2 13 | #define IsochronousEnable BIT3 14 | #define ControlListEnable BIT4 15 | #define BulkListEnable BIT5 16 | 17 | #define HcCommandStatus 8L 18 | #define HostControllerReset BIT0 19 | #define ControlListFilled BIT1 20 | #define BulkListFilled BIT2 21 | #define OwnershipChangeRequest BIT3 22 | #define InterruptRouting BIT8 23 | #define HostControllerFunctionalState (BIT6 | BIT7) 24 | #define HostControllerFunctionalState_SHIFT 6 25 | #define USBRESET 0UL 26 | #define USBRESUME 1UL 27 | #define USBOPERATIONAL 2UL 28 | #define USBSUSPEND 3UL 29 | 30 | #define HcInterruptStatus 0x0CL 31 | #define ScheduleOverrun BIT0 32 | #define WriteBackDoneHead BIT1 33 | #define StartofFrame BIT2 34 | #define ResumeDetected BIT3 35 | #define UnrecoverableError BIT4 36 | #define FrameNumberOverflow BIT5 37 | #define RootHubStatusChange BIT6 38 | #define OwnershipChange BIT30 39 | 40 | #define HcInterruptEnable 0x10L //bits as HcInterruptStatus, plus MasterInterruptEnable 41 | #define HcInterruptDisable 0x14L //bits as HcInterruptStatus, plus MasterInterruptEnable 42 | #define MasterInterruptEnable BIT31 43 | 44 | #define HcHCCA 0x18L 45 | #define HcPeriodCurrentED 0x1CL 46 | #define HcControlHeadED 0x20L 47 | #define HcControlCurrentED 0x24L 48 | #define HcBulkHeadED 0x28L 49 | #define HcBulkCurrentED 0x2CL 50 | #define HcDoneHead 0x30L 51 | #define HcFmInterval 0x34L 52 | #define HcFmRemaining 0x38L 53 | #define HcFmNumber 0x3CL 54 | #define HcPeriodicStart 0x40L 55 | #define HcLSThreshold 0x44L 56 | 57 | #define HcRhDescriptorA 0x48L 58 | #define PowerSwitchingMode BIT8 59 | 60 | #define HcRhDescriptorB 0x4CL 61 | 62 | #define HcRhStatus 0x50L 63 | #define SetGlobalPower BIT16 64 | 65 | #define HcRhPort1Status 0x54L 66 | #define CurrentConnectStatus BIT0 67 | #define ClearPortEnable BIT0 68 | #define PortEnableStatus BIT1 69 | #define SetPortEnable BIT1 70 | #define PortSuspendStatus BIT2 71 | #define SetPortSuspend BIT2 72 | #define PortOverCurrentIndicator BIT3 73 | #define ClearSuspendStatus BIT3 74 | #define PortResetStatus BIT4 75 | #define SetPortReset BIT4 76 | #define PortPowerStatus BIT8 77 | #define SetPortPower BIT8 78 | #define LowSpeedDeviceAttached BIT9 79 | #define ClearPortPower BIT9 80 | #define ConnectStatusChange BIT16 81 | #define PortEnableStatusChange BIT17 82 | #define PortSuspendStatusChange BIT18 83 | #define PortOverCurrentIndicatorChange BIT19 84 | #define PortResetStatusChange BIT20 85 | 86 | #define PIDFROMTD 0 //for control ED PID 87 | #define PIDSETUP 0 88 | #define PIDOUT 1 89 | #define PIDIN 2 90 | #define PIDINVERT(pid) (3-pid) 91 | 92 | //control words 93 | #define OHCI_CW_NO_INTERRUPT 7 //delay counter, 111 means disable donehead interrupt 94 | #define OHCI_CW_DATATOGGLE_CARRY 0 95 | #define OHCI_CW_DATATOGGLE_DATA0 2 //10b 96 | #define OHCI_CW_DATATOGGLE_DATA1 3 //11b 97 | 98 | //codition code 99 | #define OHCI_CC_NO_ERROR 0L 100 | #define OHCI_CC_ERROR_CRC 0x1L 101 | #define OHCI_CC_ERROR_STALL 0x4L 102 | #define OHCI_CC_ERROR_DEVICE_NOT_RESPONDING 0x5L 103 | #define OHCI_CC_ERROR_PID_CHECK_FAILURE 0x6L 104 | #define OHCI_CC_NOT_ACCESSED 0xEL //'untouched'mark. both E,F are OK, inited by host driver 105 | 106 | //0~8192 according to the spec (max 1 page crossing, need aligned to 4K if large than 4K) for each TD. 107 | #define OHCI_MAX_TD_BUFFER_SIZE 4096 108 | #define OHCI_NULL_TD_PHYSICAL_ADDR 0 109 | //magic to distinguish TD from ISO_TD. make sure LSB 1 bits is 1, so that it won't conflict with Offset field of ISO_TD. 110 | //#define OHCI_TD_MAGIC (((uint32_t)('O')<<24) | ((uint32_t)('H' | 0x1)<<16) | (('C')<<8) | ('I') | 0x1) 111 | 112 | #ifdef __cplusplus 113 | extern "C" 114 | { 115 | #endif 116 | struct OHCI_TransferDescriptor; 117 | typedef struct OHCI_TransferDescriptor OHCI_TD; 118 | struct OHCI_IsochronousTransferDescriptor; 119 | typedef struct OHCI_IsochronousTransferDescriptor OHCI_ISO_TD; 120 | struct OHCI_EndpointDescriptor; 121 | typedef struct OHCI_EndpointDescriptor OHCI_ED; 122 | 123 | typedef struct OHCI_TransferDescriptor 124 | { 125 | union 126 | { 127 | uint32_t ControlFlags; 128 | struct //use 16bit bitfield for 16bit compiler compatibility i.e. Borland C 129 | { 130 | uint16_t Reserved1; //aviable to HCD (but not modifiable during processing) 131 | uint16_t Reserved2 : 2; //aviable to HCD (but not modifiable during processing) 132 | uint16_t BufferRounding : 1; 133 | uint16_t PID : 2; 134 | uint16_t DelayInterrupt : 3; 135 | uint16_t DataToggle : 2; 136 | uint16_t ErrorCount : 2; 137 | uint16_t ConditionCode : 4; 138 | }ControlBits; 139 | }; 140 | uint32_t CurrentBufferP; 141 | uint32_t NextTD; 142 | uint32_t BufferEnd; 143 | 144 | //extension. the OHCI spec only need the alignment as 16 145 | void* Unused[2]; 146 | #if defined(__BC__) || defined(__WC__) 147 | uint16_t padding[4]; 148 | #endif 149 | OHCI_TD* pNext; //Match the location of ISO TD 150 | HCD_Request* pRequest; 151 | }OHCI_TD; 152 | 153 | #define OHCI_MAX_ISO_FRAME 4 //max frame for a ISO TD. 8 by spec, reserve last 4 for custom information 154 | typedef struct OHCI_IsochronousTransferDescriptor 155 | { 156 | union 157 | { 158 | uint32_t ControlFlags; //condition code in it will be updated by hc 159 | struct 160 | { 161 | uint16_t StartFrame; 162 | uint16_t Reserved1 : 5; 163 | 164 | uint16_t DelayInterrupt : 3; 165 | uint16_t FrameCount : 3; 166 | uint16_t Reserved2 : 1; 167 | uint16_t ConditionCode : 4; 168 | }ControlBits; 169 | }; 170 | uint32_t BufferPage; 171 | uint32_t NextTD; 172 | uint32_t BufferEnd; 173 | 174 | uint16_t Offset[OHCI_MAX_ISO_FRAME]; //max frames data by the spec 175 | #if defined(__BC__) || defined(__WC__) 176 | uint16_t padding[2]; 177 | #endif 178 | OHCI_TD* pNext; 179 | HCD_Request* pRequest; 180 | }OHCI_ISO_TD; 181 | 182 | typedef struct OHCI_EndpointDescriptor 183 | { 184 | union 185 | { 186 | uint32_t ControlFlags; 187 | struct 188 | { 189 | uint16_t FunctionAddress : 7; 190 | uint16_t EndPoint : 4; 191 | uint16_t Direction : 2; 192 | uint16_t LowSpeed : 1; 193 | uint16_t Skip : 1; //Skip: don't process 194 | uint16_t Format : 1; //Format: Isochronous mode ED 195 | uint16_t MaxPacketSize : 11; 196 | //uint16_t Reserved : 5; //reserved for HCD 197 | uint16_t TransferType : 2; //HCD 198 | uint16_t Unsued : 3; //HCD 199 | }ControlBits; 200 | }; 201 | uint32_t TailP; 202 | uint32_t HeadP; 203 | uint32_t NextED; 204 | 205 | //extension 206 | OHCI_ED* pPrev; 207 | union 208 | { 209 | OHCI_TD* pTail; //tail TD 210 | OHCI_ISO_TD* pISOTail; //tail ISO TD 211 | }; 212 | void* Unused[2]; 213 | #if defined(__BC__) || defined(__WC__) 214 | uint16_t padding[4]; 215 | #endif 216 | }OHCI_ED; 217 | 218 | static_assert(sizeof(OHCI_ED) == 32, "size missmatch"); 219 | static_assert(sizeof(OHCI_TD) == 32, "size missmatch"); 220 | static_assert(sizeof(OHCI_ISO_TD) == 32, "size missmatch"); 221 | 222 | typedef struct 223 | { 224 | uint32_t InterruptTable[32]; //HccaInterrruptTable 225 | uint16_t wFrameNumber; 226 | uint16_t wPadding; 227 | uint32_t dwDoneHead; 228 | uint32_t Reserved[29]; 229 | uint32_t dwPadding; //extra custom padding to 256 230 | }OHCI_HCCA_BLOCK; 231 | 232 | typedef struct OHCI_HostControllerData //per hc data 233 | { 234 | OHCI_HCCA_BLOCK HCCA; //hcca, 256-aligned 235 | OHCI_ED ControlHead; 236 | OHCI_ED BulkHead; 237 | 238 | //periodic data, isochronous and interrupt 239 | //interval frames, 1ms~32ms for full speed (1frame=1ms), 0.125ms~4ms for high speed (1frame=0.125ms) 240 | OHCI_ED ED32ms; 241 | OHCI_ED ED16ms; 242 | OHCI_ED ED8ms; 243 | OHCI_ED ED4ms; 244 | OHCI_ED ED2ms; 245 | OHCI_ED ED1ms; 246 | 247 | OHCI_ED* ControlTail; 248 | OHCI_ED* BulkTail; 249 | OHCI_ED* ED32msTail; 250 | OHCI_ED* ED16msTail; 251 | OHCI_ED* ED8msTail; 252 | OHCI_ED* ED4msTail; 253 | OHCI_ED* ED2msTail; 254 | OHCI_ED* ED1msTail; 255 | 256 | uint32_t FrameNumberHigh; 257 | }OHCI_HCData; 258 | 259 | typedef struct OHCI_HostControllerDeviceData //per device data 260 | { 261 | //default control pipe (ed0), used before/after addressed. 262 | OHCI_ED ControlED; 263 | 264 | }OHCI_HCDeviceData; 265 | 266 | BOOL OHCI_InitController(HCD_Interface* pHCI, PCI_DEVICE* pPCIDev); 267 | BOOL OHCI_DeinitController(HCD_Interface* pHCI); 268 | BOOL OHCI_ISR(HCD_Interface* pHCI); 269 | 270 | uint8_t OHCI_ControlTransfer(HCD_Device* pDevice, void* pEndPoint, HCD_TxDir dir, uint8_t inputp setup8[8], 271 | void* nullable pSetupData, uint16_t length, HCD_COMPLETION_CB pCB, void* nullable pCBData); 272 | 273 | uint8_t OHCI_IsochronousTransfer(HCD_Device* pDevice, void* pEndPoint, HCD_TxDir dir, uint8_t* inoutp pBuffer, 274 | uint16_t length, HCD_COMPLETION_CB nullable pCB, void* nullable pCBData); 275 | 276 | uint8_t OHCI_DataTransfer(HCD_Device* pDevice, void* pEndPoint, HCD_TxDir dir, uint8_t* inoutp pBuffer, 277 | uint16_t length, HCD_COMPLETION_CB nullable pCB, void* nullable pCBData); 278 | 279 | #ifdef __cplusplus 280 | } 281 | #endif 282 | 283 | #endif 284 | -------------------------------------------------------------------------------- /USBDDOS/usballoc.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "USBDDOS/usballoc.h" 3 | #include "USBDDOS/dbgutil.h" 4 | 5 | #if USBALLOC_ENABLE 6 | 7 | #define USBALLOC_FLAG_USED 0x01 8 | #define USBALLOC_FLAG_32 0x02 9 | 10 | #define USBALLOC_MEMORY_SIZE (1*1024) 11 | 12 | //the code need more test, not enabled for now. the way of pooling waste memory and may cause problem 13 | #define USBALLOC_DEBUG 1 //use DPMI_DMAMalloc directly (probably with more debug info) 14 | 15 | #if defined(__BC__) 16 | #define USBALLOC_MEMORY_COUNT 16 17 | #undef USBALLOC_DEBUG 18 | #define USBALLOC_DEBUG 1 19 | #else 20 | #define USBALLOC_MEMORY_COUNT 64 21 | #endif 22 | 23 | #define USBALLOC_PREALLOC (0 && !USBALLOC_DEBUG) 24 | 25 | typedef struct 26 | { 27 | uint8_t* arena; 28 | union 29 | { 30 | uint32_t mask; 31 | struct 32 | { 33 | uint16_t offset; 34 | uint16_t left; 35 | }buff; 36 | }; 37 | uint16_t flags; 38 | uint16_t index; 39 | }USBALLOC_Memory; 40 | 41 | static USBALLOC_Memory USBALLOC_Pool[USBALLOC_MEMORY_COUNT]; 42 | static USBALLOC_Memory* USBALLOC_CurrentBuf = NULL; 43 | static USBALLOC_Memory* USBALLOC_Current32 = NULL; 44 | 45 | static USBALLOC_Memory* USBALLOC_GetMemory(void) 46 | { 47 | int i; 48 | for(i = 0; ; ++i) //will wait for interrupt to release finished memory in dead loop 49 | { //if alreay in interrupt, it'll be dead. i.e. EMM386 IO port trap with interrupt disabled. 50 | USBALLOC_Memory* memory = &USBALLOC_Pool[i%USBALLOC_MEMORY_COUNT]; 51 | if(!(memory->flags&USBALLOC_FLAG_USED)) 52 | { 53 | #if USBALLOC_PREALLOC 54 | assert(memory->arena != NULL); 55 | #else 56 | assert(memory->arena == NULL); 57 | memory->arena = (uint8_t*)DPMI_DMAMalloc(USBALLOC_MEMORY_SIZE, 32); //alignment to 32 for EHCI 58 | #endif 59 | //_LOG("memory arena: %08lx\n", ((uint32_t)(memory->arena))); 60 | assert((((uint32_t)(memory->arena))&0x1F) == 0); 61 | memory->flags = USBALLOC_FLAG_USED; 62 | memory->index = (uint16_t)(i%USBALLOC_MEMORY_COUNT); 63 | return memory; 64 | } 65 | } 66 | return NULL; 67 | } 68 | 69 | static void USBALLOC_ReturnMemory(USBALLOC_Memory* memory) 70 | { 71 | assert(memory->arena); 72 | #if !USBALLOC_PREALLOC 73 | DPMI_DMAFree(memory->arena); 74 | memory->arena = NULL; 75 | #endif 76 | memory->mask = 0; 77 | memory->flags = 0; 78 | } 79 | 80 | void USBALLOC_Init(void) 81 | { 82 | assert(USBALLOC_CurrentBuf == NULL); 83 | assert(USBALLOC_Current32 == NULL); 84 | //USBALLOC_CurrentBuf = USBALLOC_GetMemoryBuf(); 85 | //USBALLOC_Current32 = USBALLOC_GetMemory32(); 86 | #if USBALLOC_PREALLOC 87 | for(int i = 0; i < USBALLOC_MEMORY_COUNT; ++i) 88 | { 89 | USBALLOC_Pool[i].arena = (uint8_t*)DPMI_DMAMalloc(USBALLOC_MEMORY_SIZE, 32); 90 | assert(USBALLOC_Pool[i].arena); 91 | } 92 | #endif 93 | } 94 | 95 | void USBALLOC_Shutdown(void) 96 | { 97 | //assert(USBALLOC_CurrentBuf != NULL); 98 | //assert(USBALLOC_Current32 != NULL); 99 | USBALLOC_CurrentBuf = NULL; 100 | USBALLOC_Current32 = NULL; 101 | int i; 102 | for(i = 0; i < USBALLOC_MEMORY_COUNT; ++i) 103 | { 104 | USBALLOC_Memory* memory = &USBALLOC_Pool[i]; 105 | #if USBALLOC_PREALLOC 106 | DPMI_DMAFree(memory->arena); 107 | #else 108 | if((memory->flags&USBALLOC_FLAG_USED)) 109 | USBALLOC_ReturnMemory(memory); 110 | #endif 111 | } 112 | } 113 | 114 | 115 | void* USBALLOC_TransientAlloc(uint16_t size, uint16_t alignment) 116 | { 117 | #if USBALLOC_DEBUG 118 | { 119 | CLIS(); 120 | void* ptr = DPMI_DMAMalloc(size, alignment); 121 | STIL(); 122 | return ptr; 123 | } 124 | #endif 125 | 126 | CLIS(); 127 | alignment = max(alignment, 4); 128 | uint16_t actual = (uint16_t)(size + alignment + 4); 129 | uint16_t index = USBALLOC_CurrentBuf->index; 130 | uint8_t* ptr = NULL; 131 | if(!USBALLOC_CurrentBuf || USBALLOC_MEMORY_SIZE - USBALLOC_CurrentBuf->buff.offset < actual) 132 | { 133 | if(actual > USBALLOC_MEMORY_SIZE/2) 134 | { 135 | ptr = (uint8_t*)DPMI_DMAMalloc(actual, 1) + 4; 136 | index = 0xFFFF; 137 | } 138 | else 139 | { 140 | USBALLOC_CurrentBuf = USBALLOC_GetMemory(); 141 | USBALLOC_CurrentBuf->buff.offset = 0; 142 | USBALLOC_CurrentBuf->buff.left = USBALLOC_MEMORY_SIZE; 143 | index = USBALLOC_CurrentBuf->index; 144 | } 145 | } 146 | if(!ptr) 147 | { 148 | ptr = USBALLOC_CurrentBuf->arena + USBALLOC_CurrentBuf->buff.offset + 4; 149 | USBALLOC_CurrentBuf->buff.offset = (uint16_t)(USBALLOC_CurrentBuf->buff.offset + actual); 150 | assert(USBALLOC_CurrentBuf->buff.offset <= USBALLOC_MEMORY_SIZE); 151 | assert(USBALLOC_CurrentBuf->buff.left >= actual); 152 | USBALLOC_CurrentBuf->buff.left = (uint16_t)(USBALLOC_CurrentBuf->buff.left - actual); 153 | } 154 | uint32_t addr = DPMI_PTR2L(ptr); 155 | uint32_t offset = align(addr, alignment) - addr; 156 | uint16_t* aptr = (uint16_t*)(ptr + offset); 157 | aptr[-1] = index; 158 | aptr[-2] = (index != 0xFFFF) ? actual : (uint16_t)(offset + 4); 159 | STIL(); 160 | return aptr; 161 | } 162 | 163 | void USBALLOC_TransientFree(void* ptr) 164 | { 165 | #if USBALLOC_DEBUG 166 | { 167 | CLIS(); 168 | DPMI_DMAFree(ptr); 169 | STIL(); 170 | return; 171 | } 172 | #endif 173 | 174 | uint16_t index = ((uint16_t*)ptr)[-1]; 175 | uint16_t actual = ((uint16_t*)ptr)[-2]; 176 | if(index == 0xFFFF) 177 | { 178 | CLIS(); 179 | DPMI_DMAFree((uint8_t*)ptr - actual); 180 | STIL(); 181 | return; 182 | } 183 | CLIS(); 184 | assert(index < USBALLOC_MEMORY_COUNT); 185 | USBALLOC_Memory* memory = &USBALLOC_Pool[index]; 186 | memory->buff.left = (uint16_t)(memory->buff.left + actual); 187 | assert(USBALLOC_CurrentBuf->buff.left <= USBALLOC_MEMORY_SIZE); 188 | 189 | if(memory->buff.left == USBALLOC_MEMORY_SIZE) 190 | { 191 | memory->buff.offset = 0; 192 | if(memory != USBALLOC_CurrentBuf) 193 | USBALLOC_ReturnMemory(memory); 194 | else 195 | { 196 | int i; 197 | for(i = 0; i < USBALLOC_MEMORY_COUNT; ++i) 198 | { 199 | USBALLOC_Memory* memory = &USBALLOC_Pool[i]; 200 | if(memory != USBALLOC_CurrentBuf && (memory->flags&(USBALLOC_FLAG_USED)) && !(memory->flags&(USBALLOC_FLAG_32)) && (USBALLOC_MEMORY_SIZE-memory->buff.offset) >= USBALLOC_MEMORY_SIZE/4) 201 | { 202 | assert(memory->arena); 203 | USBALLOC_ReturnMemory(USBALLOC_CurrentBuf); 204 | USBALLOC_CurrentBuf = memory; 205 | break; 206 | } 207 | } 208 | } 209 | } 210 | STIL(); 211 | } 212 | 213 | void* USBALLOC_TransientAlloc32(uint16_t sizeverify) 214 | { 215 | if(sizeverify > 32) 216 | { 217 | assert(FALSE); 218 | return NULL; 219 | } 220 | 221 | #if USBALLOC_DEBUG 222 | { 223 | CLIS(); 224 | sizeverify = max(32, sizeverify); 225 | void* ptr = DPMI_DMAMalloc(sizeverify, 32); 226 | for(int i = 0; i < 8; ++i) 227 | ((int32_t*)ptr)[i] = 0x0BAD0ACE; 228 | STIL(); 229 | return ptr; 230 | } 231 | #endif 232 | 233 | CLIS(); 234 | if(USBALLOC_Current32 == NULL || USBALLOC_Current32->mask == 0) 235 | { 236 | USBALLOC_Current32 = USBALLOC_GetMemory(); 237 | assert(USBALLOC_Current32->arena); 238 | assert((((uint32_t)(USBALLOC_Current32->arena))&0x1F) == 0); 239 | assert(USBALLOC_Current32->flags&USBALLOC_FLAG_USED); 240 | USBALLOC_Current32->mask = 0xFFFFFFFFL; 241 | USBALLOC_Current32->flags |= USBALLOC_FLAG_32; 242 | } 243 | register uint16_t index = (uint16_t)BSF(USBALLOC_Current32->mask); 244 | //_LOG("M32 Mask %08lx ", USBALLOC_Current32->mask); 245 | USBALLOC_Current32->mask &= ~(1UL << index); 246 | //_LOG("%08lx\n", USBALLOC_Current32->mask); 247 | STIL(); 248 | return USBALLOC_Current32->arena + (index << 5); 249 | } 250 | 251 | void USBALLOC_TransientFree32(void* ptr) 252 | { 253 | #if USBALLOC_DEBUG 254 | { 255 | CLIS(); 256 | for(int i = 0; i < 8; ++i) 257 | ((uint32_t*)ptr)[i] = 0xF00DFEEDU; 258 | DPMI_DMAFree(ptr); 259 | STIL(); 260 | return; 261 | } 262 | #endif 263 | 264 | CLIS(); 265 | assert((((uint32_t)ptr)&0x1F) == 0); 266 | if(USBALLOC_Current32 && ((uint8_t*)ptr) >= USBALLOC_Current32->arena && ((uint8_t*)ptr) < USBALLOC_Current32->arena + USBALLOC_MEMORY_SIZE) 267 | { 268 | assert(USBALLOC_Current32->flags&(USBALLOC_FLAG_USED|USBALLOC_FLAG_32)); 269 | assert(USBALLOC_Current32->arena); 270 | uint16_t index = (uint16_t)((uint8_t*)ptr - USBALLOC_Current32->arena)>>5; 271 | assert(index < 32); 272 | //_LOG("FreeM32 Mask %08lx ", USBALLOC_Current32->mask); 273 | assert(USBALLOC_Current32->mask | (1UL << index) > USBALLOC_Current32->mask); 274 | USBALLOC_Current32->mask |= (1UL << index); 275 | //_LOG("%08lx\n", USBALLOC_Current32->mask); 276 | if(USBALLOC_Current32->mask != 0xFFFFFFFFL) 277 | { 278 | STIL(); 279 | return; 280 | } 281 | 282 | int i; 283 | for(i = 0; i < USBALLOC_MEMORY_COUNT; ++i) 284 | { 285 | USBALLOC_Memory* memory = &USBALLOC_Pool[i]; 286 | if(memory != USBALLOC_Current32 && (memory->flags&(USBALLOC_FLAG_USED|USBALLOC_FLAG_32)) && memory->mask != 0) 287 | { 288 | USBALLOC_ReturnMemory(USBALLOC_Current32); 289 | USBALLOC_Current32 = memory; 290 | break; 291 | } 292 | } 293 | STIL(); 294 | return; 295 | } 296 | 297 | int i; 298 | for(i = 0; i < USBALLOC_MEMORY_COUNT; ++i) 299 | { 300 | USBALLOC_Memory* memory = &USBALLOC_Pool[i]; 301 | if(memory != USBALLOC_Current32 && (memory->flags&(USBALLOC_FLAG_USED|USBALLOC_FLAG_32))) 302 | { 303 | assert(memory->arena); 304 | if(((uint8_t*)ptr) >= memory->arena && ((uint8_t*)ptr) < memory->arena + USBALLOC_MEMORY_SIZE) 305 | { 306 | uint16_t index = (uint16_t)(((uint8_t*)ptr - memory->arena)>>5); 307 | memory->mask |= 1U << index; 308 | if(memory->mask == 0xFFFFFFFFL) 309 | USBALLOC_ReturnMemory(memory); 310 | STIL(); 311 | return; 312 | } 313 | } 314 | } 315 | STIL(); 316 | assert(FALSE); 317 | } 318 | 319 | #endif //USBALLOC_ENABLE 320 | -------------------------------------------------------------------------------- /USBDDOS/dbgutil.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include "USBDDOS/DPMI/dpmi.h" 10 | #include "USBDDOS/usb.h" 11 | #include "USBDDOS/dbgutil.h" 12 | #include "USBDDOS/pic.h" 13 | 14 | #if _LOG_ENABLE 15 | 16 | #if defined(__BC__) //BC always uses C++ to compile 17 | extern "C" 18 | #endif 19 | BOOL DPMI_IsInProtectedMode(); 20 | 21 | //https://dev.to/frosnerd/writing-my-own-vga-driver-22nn 22 | #define VGA_CTRL_REGISTER 0x3d4 23 | #define VGA_DATA_REGISTER 0x3d5 24 | #define VGA_OFFSET_LOW 0x0f 25 | #define VGA_OFFSET_HIGH 0x0e 26 | #define VGA_VIDEO_ADDRESS 0xB8000 27 | #define VGA_MAX_ROWS 25 //TODO: read VGA mode in BIOS data area and decide rows/cols 28 | #define VGA_MAX_COLS 80 29 | static void VGA_SetCursor(uint32_t offset) 30 | { 31 | outp(VGA_CTRL_REGISTER, VGA_OFFSET_HIGH); 32 | outp(VGA_DATA_REGISTER, (unsigned char) (offset >> 8)); 33 | outp(VGA_CTRL_REGISTER, VGA_OFFSET_LOW); 34 | outp(VGA_DATA_REGISTER, (unsigned char) (offset & 0xff)); 35 | } 36 | 37 | static uint32_t VGA_GetCursor() 38 | { 39 | outp(VGA_CTRL_REGISTER, VGA_OFFSET_HIGH); 40 | uint32_t offset = (uint32_t)inp(VGA_DATA_REGISTER) << 8; 41 | outp(VGA_CTRL_REGISTER, VGA_OFFSET_LOW); 42 | offset += inp(VGA_DATA_REGISTER); 43 | return offset; 44 | } 45 | 46 | static void VGA_SetChar(char character, uint32_t offset) 47 | { 48 | #if defined(__BC__) || defined(__WC__) 49 | if(!DPMI_IsInProtectedMode()) 50 | *(char far*)MK_FP(0xB800, offset*2) = character; 51 | else 52 | #endif 53 | { 54 | DPMI_StoreB(VGA_VIDEO_ADDRESS + offset*2, (uint8_t)character); 55 | } 56 | } 57 | 58 | static uint32_t VGA_GetOffset(uint32_t col, uint32_t row) 59 | { 60 | return (uint32_t)(row * VGA_MAX_COLS + col); 61 | } 62 | 63 | static uint32_t VGA_NewLine(uint32_t offset) 64 | { 65 | uint32_t row = offset / VGA_MAX_COLS; 66 | return VGA_GetOffset(0, row+1); 67 | } 68 | 69 | static uint32_t VGA_Scroll(uint32_t offset) 70 | { 71 | #if defined(__BC__) || defined(__WC__) 72 | if(!DPMI_IsInProtectedMode()) 73 | { 74 | char far* line0 = (char far*)MK_FP(0xB800, VGA_GetOffset(0, 0)*2); 75 | char far* line1 = (char far*)MK_FP(0xB800, VGA_GetOffset(0, 1)*2); 76 | _fmemcpy(line0, line1, VGA_MAX_COLS * (VGA_MAX_ROWS - 1)*2); 77 | } 78 | else 79 | #endif 80 | { 81 | DPMI_CopyLinear(VGA_VIDEO_ADDRESS + VGA_GetOffset(0, 0)*2, VGA_VIDEO_ADDRESS + VGA_GetOffset(0, 1)*2, VGA_MAX_COLS * (VGA_MAX_ROWS - 1)*2); 82 | } 83 | 84 | for(uint32_t i = 0; i < VGA_MAX_COLS; ++i) 85 | VGA_SetChar(' ', VGA_MAX_COLS * (VGA_MAX_ROWS - 1) + i); 86 | 87 | return offset - VGA_MAX_COLS; 88 | } 89 | 90 | #if defined(__WC__) 91 | #pragma disable_message (202) //W202: Symbol 'VGA_Print' has been defined, but not referenced 92 | #endif 93 | static void VGA_Print(const char *string) 94 | { 95 | uint32_t offset = VGA_GetCursor(); 96 | int i = 0; 97 | while (string[i] != 0) 98 | { 99 | char ch = string[i++]; 100 | if (ch == '\n') 101 | offset = VGA_NewLine(offset); 102 | else 103 | VGA_SetChar(ch, offset++); 104 | 105 | if(offset >= VGA_MAX_ROWS * VGA_MAX_COLS) 106 | offset = VGA_Scroll(offset); 107 | } 108 | VGA_SetCursor(offset); 109 | //update cursor in BIOS data area (40:50) 110 | //https://stanislavs.org/helppc/bios_data_area.html 111 | #if defined(__BC__) || defined(__WC__) 112 | if(!DPMI_IsInProtectedMode()) 113 | { 114 | *(char far*)MK_FP(0x40, 0x50) = (uint8_t)(offset % VGA_MAX_COLS); 115 | *(char far*)MK_FP(0x40, 0x51) = (uint8_t)(offset / VGA_MAX_COLS); 116 | } 117 | else 118 | #endif 119 | { 120 | DPMI_StoreB((0x40UL<<4)+0x50, (uint8_t)(offset % VGA_MAX_COLS)); 121 | DPMI_StoreB((0x40UL<<4)+0x50+1, (uint8_t)(offset / VGA_MAX_COLS)); 122 | } 123 | } 124 | //#if defined(__WC__) //NOT WORKING 125 | //#pragma enable_message (202) //W202: Symbol 'VGA_Print' has been defined, but not referenced 126 | //#endif 127 | 128 | //needs to work in interrupt handler. now use IN/OUT controls VGA directly. 129 | void DBG_Logv(const char* fmt, va_list aptr) 130 | { 131 | #define SIZE (int)(DUMP_BUFF_SIZE*2) 132 | char buf[SIZE]; 133 | #if defined(__BC__) 134 | int len = vsprintf(buf, fmt, aptr); 135 | #else 136 | int len = vsnprintf(buf, SIZE, fmt, aptr); 137 | #endif 138 | assert(len < SIZE); 139 | len = min(len, SIZE-1); 140 | buf[len] = '\0'; 141 | 142 | #if 0 143 | outp(0x3F8+3, 0x03); 144 | for(int i = 0; i < len; ++i) 145 | { 146 | while((inp(0x3F8+5)&0x20)==0); 147 | outp(0x3F8, (uint8_t)buf[i]); 148 | } 149 | return; 150 | #endif 151 | 152 | #if 1 153 | if(!(CPU_FLAGS()&CPU_IFLAG)) 154 | { //use VGA when in interrupt 155 | VGA_Print(buf); 156 | } 157 | else 158 | #endif 159 | { //note: int 10h also support graphics mode 160 | uint16_t mask = PIC_GetIRQMask(); 161 | PIC_SetIRQMask(0xFFFF); //mask all interrupts in case we're in interrupt and int10h will enable interrupts 162 | DPMI_REG r = {0}; 163 | for(int i = 0; i < len; ++i) 164 | { 165 | r.h.ah = 0x0E; 166 | r.h.al = (uint8_t)buf[i]; 167 | r.h.bl = 0x07; //graphics mode only: foreground clolor 168 | DPMI_CallRealModeINT(0x10,&r); 169 | if(buf[i] =='\n') 170 | { 171 | r.h.ah = 0x0E; 172 | r.h.al = '\r'; 173 | DPMI_CallRealModeINT(0x10,&r); 174 | } 175 | } 176 | PIC_SetIRQMask(mask); 177 | } 178 | #undef SIZE 179 | } 180 | 181 | void DBG_Log(const char* fmt, ...) 182 | { 183 | va_list aptr; 184 | va_start(aptr, fmt); 185 | DBG_Logv(fmt, aptr); 186 | va_end(aptr); 187 | } 188 | #endif //_LOG_ENABLE 189 | 190 | #if defined(__BC__) 191 | int DBG_Nolog(const char* fmt, ...) {unused(fmt);return 0;} 192 | #endif 193 | 194 | #if DEBUG 195 | static DBG_DBuff dbuff; 196 | 197 | static inline DBG_DBuff* db() {dbuff.cur = 0; return &dbuff;} 198 | 199 | void DBG_DumpB(uint8_t* StartPtr, unsigned n, DBG_DBuff* buff/* = NULL*/) 200 | { 201 | buff = buff && buff->enable ? buff : db(); 202 | char* p = buff->buff + buff->cur; 203 | char* end = buff->buff + DUMP_BUFF_SIZE - 1; 204 | 205 | for(unsigned i = 0; i < n; i++) 206 | { 207 | sprintf(p, "%02x", StartPtr[i]); 208 | p+=2; 209 | *(p++) = ' '; 210 | if(i && (i+1)%8 == 0 && (i+1)%16) { sprintf(p, "| "); p+=2;} 211 | if(i && (i+1)%16 ==0 && i != n-1) {*(p++) = '\n';} 212 | if( p + 7 >= end) 213 | break; 214 | } 215 | *(p++) = '\n'; 216 | buff->cur = (uint16_t)(p - buff->buff); 217 | assert(buff->cur < DUMP_BUFF_SIZE); 218 | *p = '\0'; 219 | 220 | if(buff == &dbuff) 221 | DBG_Log("%s", buff->buff); 222 | return; 223 | } 224 | 225 | void DBG_DumpD(uint32_t* StartPtr, unsigned n, DBG_DBuff* buff/* = NULL*/) 226 | { 227 | buff = buff && buff->enable ? buff : db(); 228 | char* p = buff->buff + buff->cur; 229 | char* end = buff->buff + DUMP_BUFF_SIZE - 1; 230 | 231 | for(unsigned i = 0; i < n; i++) 232 | { 233 | sprintf(p, "%08lx", StartPtr[i]); 234 | p += 8; 235 | *(p++) = ' '; 236 | if(i && (i+1)%4 == 0 && i != n-1) *(p++) = '\n'; 237 | if(p + 11 >= end) 238 | break; 239 | } 240 | *(p++) = '\n'; 241 | buff->cur = (uint16_t)(p - buff->buff); 242 | assert(buff->cur < DUMP_BUFF_SIZE); 243 | *p = '\0'; 244 | 245 | if(buff == &dbuff) 246 | DBG_Log("%s", buff->buff); 247 | return; 248 | } 249 | 250 | void DBG_DumpReq8(uint8_t* req, DBG_DBuff* buff/* = NULL*/) 251 | { 252 | USB_Request* q = (USB_Request*)req; 253 | DBG_Printf(buff, "Request: %x, %d, %d, %d, %d\n", q->bmRequestType, q->bRequest, q->wValue, q->wIndex, q->wLength); 254 | } 255 | 256 | void DBG_DumpLB(uint32_t addr, unsigned n, DBG_DBuff* buff/* = NULL*/) 257 | { 258 | uint8_t* b8 = (uint8_t*)alloca(n * sizeof(uint8_t)); 259 | for(unsigned i = 0; i < n; ++i) 260 | b8[i] = DPMI_LoadB(addr+i); 261 | DBG_DumpB(b8, n, buff); 262 | } 263 | 264 | void DBG_DumpLD(uint32_t addr, unsigned n, DBG_DBuff* buff/* = NULL*/) 265 | { 266 | uint32_t* d32 = (uint32_t*)alloca(n * sizeof(uint32_t)); 267 | for(unsigned i = 0; i < n; ++i) 268 | d32[i] = DPMI_LoadD(addr+i*4); 269 | DBG_DumpD(d32, n, buff); 270 | } 271 | 272 | void DBG_DumpPB(uint32_t addr, unsigned n, DBG_DBuff* buff/* = NULL*/) 273 | { 274 | #if defined(__BC__) && 0//disable paging to make sure paing is correct 275 | DBG_DBuff bf = {1}; 276 | buff = buff == NULL ? &bf : buff; 277 | __asm {cli; mov eax, cr3; push eax; mov eax, cr0; and eax, 0x7FFFFFFF; mov cr0, eax; xor eax, eax; mov cr3, eax} 278 | #endif 279 | 280 | DBG_DumpLB(DPMI_P2L(addr), n, buff); 281 | 282 | #if defined(__BC__) && 0 283 | __asm {pop eax; mov cr3, eax; mov eax, cr0; or eax, 0x80000000; mov cr0, eax; sti;} 284 | if(buff == &bf) 285 | DBG_Flush(&bf); 286 | #endif 287 | } 288 | 289 | void DBG_DumpPD(uint32_t addr, unsigned n, DBG_DBuff* buff/* = NULL*/) 290 | { 291 | #if defined(__BC__) && 0//disable paging to make sure paing is correct 292 | DBG_DBuff bf = {1}; 293 | buff = buff == NULL ? &bf : buff; 294 | __asm {cli; mov eax, cr3; push eax; mov eax, cr0; and eax, 0x7FFFFFFF; mov cr0, eax; xor eax, eax; mov cr3, eax} 295 | #endif 296 | 297 | DBG_DumpLD(DPMI_P2L(addr), n, buff); 298 | 299 | #if defined(__BC__) && 0 300 | __asm {pop eax; mov cr3, eax; mov eax, cr0; or eax, 0x80000000; mov cr0, eax; sti;} 301 | if(buff == &bf) 302 | DBG_Flush(&bf); 303 | #endif 304 | } 305 | 306 | void DBG_Printf(DBG_DBuff* nullable buff, const char* fmt, ...) 307 | { 308 | va_list aptr; 309 | va_start(aptr, fmt); 310 | if(!buff || !buff->enable) 311 | { 312 | DBG_Logv(fmt, aptr); 313 | va_end(aptr); 314 | return; 315 | } 316 | 317 | dbuff.cur = (uint16_t)vsprintf(dbuff.buff, fmt, aptr); 318 | va_end(aptr); 319 | 320 | uint32_t count = dbuff.cur; 321 | count = count < DUMP_BUFF_SIZE - buff->cur - 1u ? count : DUMP_BUFF_SIZE - buff->cur - 1u; 322 | memcpy(buff->buff + buff->cur, dbuff.buff, count); 323 | buff->cur = (uint16_t)(buff->cur + count); 324 | *(buff->buff + buff->cur) = 0; 325 | } 326 | 327 | void DBG_Flush(DBG_DBuff* buff) 328 | { 329 | if(buff->enable) 330 | { 331 | *(buff->buff+buff->cur) = 0; 332 | DBG_Log("%s", buff->buff); 333 | buff->cur = 0; 334 | *(buff->buff+buff->cur) = 0; 335 | } 336 | } 337 | 338 | void DBG_DumpREG(DPMI_REG* reg) 339 | { 340 | DBG_Log("EAX:%08lx EBX:%08lx ECX:%08lx EDX:%08lx ESI:%08lx EDI:%08lx\n", reg->d.eax, reg->d.ebx, reg->d.ecx, reg->d.edx, reg->d.esi, reg->d.edi); 341 | DBG_Log("DS:%04x ES:%04x EBP:%08lx ", reg->w.ds, reg->w.es, reg->d.ebp); 342 | DBG_Log("SS:SP:%04x:%04x CS:IP:%04x:%04x FLAGS:%04x\n", reg->w.ss, reg->w.sp, reg->w.cs, reg->w.ip, reg->w.flags); 343 | } 344 | 345 | #endif //DEBUG 346 | --------------------------------------------------------------------------------