From dadbef34c4313eedc0adb118e7664b2952991319 Mon Sep 17 00:00:00 2001 From: Matthias Melcher Date: Thu, 10 May 2018 16:04:55 +0200 Subject: [PATCH] Adds BasiliskII specific serial port emulation for Einstein under MacOS. NTK and NCU were tested and work well. Simply set Serial Port Emulation to BasiliskII in the Einstein Preferences, and set the BasiliskII modem port to "/tmp/pty.BasiliskII" in Basilisk II settings. Removed attempts to write a driver and bridge app which is now part of Einstein. --- Drivers/MacOS Serial Driver/Info.plist | 47 - Drivers/MacOS Serial Driver/README.txt | 138 --- Drivers/MacOS Serial Driver/SerialDriver.cpp | 827 ------------------ Drivers/MacOS Serial Driver/SerialDriver.h | 50 -- .../Serial/TBasiliskIISerialPortManager.cp | 242 +++-- .../Serial/TBasiliskIISerialPortManager.h | 34 +- _Build_/Xcode/BasiliskBridge/main.cpp | 549 ------------ .../Xcode/Einstein.xcodeproj/project.pbxproj | 407 --------- 8 files changed, 202 insertions(+), 2092 deletions(-) delete mode 100644 Drivers/MacOS Serial Driver/Info.plist delete mode 100644 Drivers/MacOS Serial Driver/README.txt delete mode 100644 Drivers/MacOS Serial Driver/SerialDriver.cpp delete mode 100644 Drivers/MacOS Serial Driver/SerialDriver.h delete mode 100644 _Build_/Xcode/BasiliskBridge/main.cpp diff --git a/Drivers/MacOS Serial Driver/Info.plist b/Drivers/MacOS Serial Driver/Info.plist deleted file mode 100644 index ba431fc9b..000000000 --- a/Drivers/MacOS Serial Driver/Info.plist +++ /dev/null @@ -1,47 +0,0 @@ - - - - - CFBundleDevelopmentRegion - $(DEVELOPMENT_LANGUAGE) - CFBundleExecutable - $(EXECUTABLE_NAME) - CFBundleIdentifier - $(PRODUCT_BUNDLE_IDENTIFIER) - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - $(PRODUCT_NAME) - CFBundlePackageType - KEXT - CFBundleShortVersionString - 1.0 - CFBundleVersion - 1 - IOKitPersonalities - - SerialDriver - - CFBundleIdentifier - com.matthiasm.elektriktrick.SerialDriver - IOClass - com_matthiasm_elektriktrick_SerialDriver - IOKitDebug - 65535 - IOProviderClass - IOResources - IOMatchCategory - com_matthiasm_elektriktrick_SerialDriver - - - OSBundleLibraries - - com.apple.iokit.IOSerialFamily - 11.0 - com.apple.kpi.iokit - 17.5 - com.apple.kpi.libkern - 17.5 - - - diff --git a/Drivers/MacOS Serial Driver/README.txt b/Drivers/MacOS Serial Driver/README.txt deleted file mode 100644 index 4d74d7c4e..000000000 --- a/Drivers/MacOS Serial Driver/README.txt +++ /dev/null @@ -1,138 +0,0 @@ - -Einstein Serial Driver -====================== - -The Einstein Serial driver is a macOS kernel extension (KEXT) that will help -the Einstein emulator to present its serial port to the host machine. Apps -running on the host machine will not see a difference to a MessagePad connected -via a serial cable and a USB-to-serail converter. - -This allows existing apps like NCX, or NCU or NTK via BasiliskII, to use -Einstein emulation just as if a physical machine was connected. - -Note: the KEXT makes Einstein look like a physical device to the host machine. -This is different from making the host look like an actual MessagePad to the -outside world (for example, running Einstein on an Android device with a serial -cable plugged into it), which is not implemented either, but much easier to do. - - -Prerequisites -------------- - -The Einstein Serial Driver is implemented as a KEXT on macOS. Other platforms -can use much simpler BSD dirvers, 'socat' port redirection, or 'com0com' to -emulate a serial port. MacOS is quite a bit more demanding, requiring a rather -complex driver, signed with a special certificate that Apple may or may not -grant us. - -The KEXT s based on a collection of USB-to-serial KEXTs found all over the net, -and the "AppleUSBCDCC" source code, also available on the net. At the time -of development, MacOS High Sierra is the current OS. Unfortunatley, High Sierra -is much more demanding to KEXT, plus a lot of the header files used in the -sample code vanished and was replaced by new concepts. - -Since KEXTs run as part of the BSD kernel, any bug or error in the KEXT will -crash the entire system into a kernel panic. A second machine, preferably an -emulated virtual machine, for testing is an absolute must have. The emulated -machine must mave all security features disabled. - - -Implementation Concept ----------------------- - -The Serial Driver is a KEXT that forwards Einstein serial port communication -from a sytem socket to a BSD style device file that appears as a serial port -to the host machine. - - emulated native -MessagePad <--------> Einstein - HW emualation - - user space kernel space /dev/cu.Einstein - Einstein <--------> KEXT <--------> BSD device - systems socket serial port Nub - - native emulated - BSD device <--------> BasiliskII <--------> NTK, NCU, etc. - BSD read/write/ioctl HW emulation - -Even though this looks like a quite complicated way to acheive this line of -communication, it seems the only fully compatible way to do this. A virtual -Null-Modem cable ("com0com") or a working "socat" would make this simpler, but -the current safety concept of macOS don;t seem to allow that. Even this -implementation is not yet sanctioned by Apple. - - -Development Status ------------------- - -The driver skeleton is launching as a driver in an unprotected machine. It -creates the BSD device files for a durect serial connection and a terminal -connection. It receives commands to set the baud rate and other serial port -settings via "ioctl" to "/dev/cu.Einstein", and it tries to receive serial -data sent from an external app, - -FIXME: but is not received by the KEXT yet. - -TODO: before continuing the KEXT, I want to implement a little tool that -simulates communication on the BSD side, so I can trace the exact reaction of -the KEXT. - -TODO: I want to implement the Einstein <--> KEXT path of communication next, so -I can reliably follow the KEXT communication: - -https://developer.apple.com/documentation/kernel/1809176-ctl_register - -This will also require a little tool that simulates the socket part of the -communication the the KEXT. This shall also replace the system level logging -which is rather complex and unneccessary. - - -Resources ---------- - -Why we must do this, and why there is no shortcut: -https://forums.developer.apple.com/thread/89944 - -How to disable System Integrity Protection (SIP) on a Parallels VM? -https://forum.parallels.com/threads/how-to-disable-system-integrity-protection-sip.339840/ - -Serial Drivers: -https://developer.apple.com/library/content/documentation/DeviceDrivers/Conceptual/IOKitFundamentals/Features/Features.html#//apple_ref/doc/uid/TP0000012-TPXREF101 -https://developer.apple.com/library/content/documentation/DeviceDrivers/Conceptual/WritingDeviceDriver/DebuggingDrivers/DebuggingDrivers.html -https://www.alauda.ro/2014/09/writing-serial-drivers-for-os-x-1/ - -Creating a Kernel Extension: -https://developer.apple.com/library/content/documentation/Darwin/Conceptual/KEXTConcept/KEXTConceptIOKit/iokit_tutorial.html#//apple_ref/doc/uid/20002366-SW6 - -Base Class for the KEXT -https://developer.apple.com/documentation/kernel/ioserialdriversync?language=objc - -System Sockets -https://developer.apple.com/library/content/documentation/Darwin/Conceptual/NKEConceptual/control/control.html - -Sample code: -https://opensource.apple.com/source/AppleUSBCDCDriver/ -https://github.com/landonf/mac-cp210x -https://github.com/sideeffect42/osx-pl2303 -https://github.com/pablomarx/BelkinF5U103Driver/tree/master/BelkinF5U103Driver - -We are not alone: -https://stackoverflow.com/questions/10388889/mac-virtual-serial-port - -Relaunching the KEXT on the virtual machine: - sudo bash - kextunload -v 6 /tmp/SerialDriver.kext/ - rm -R /tmp/SerialDriver.kext - cp -R /Volumes/Shared\ Folders/Home/Library/Developer/Xcode/.../Debug/SerialDriver.kext /tmp/ - chmod -R a-rw /tmp/SerialDriver.kext - chown -R root:wheel /tmp/SerialDriver.kext - kextutil -tn /tmp/SerialDriver.kext/ || { echo 'FAILED' ; exit 1; } - kextload -v 6 /tmp/SerialDriver.kext/ || { echo 'FAILED' ; exit 1; } - ioreg -bl || { echo 'FAILED' ; exit 1; } - log show --predicate 'eventMessage contains "matthiasm"' --last 5m --info --debug - - - - - diff --git a/Drivers/MacOS Serial Driver/SerialDriver.cpp b/Drivers/MacOS Serial Driver/SerialDriver.cpp deleted file mode 100644 index ad8db4e16..000000000 --- a/Drivers/MacOS Serial Driver/SerialDriver.cpp +++ /dev/null @@ -1,827 +0,0 @@ - -#include "SerialDriver.h" - -#include -#include -#include -#include - -#include - - -// This required macro defines the class's constructors, destructors, -// and several other methods I/O Kit requires. -OSDefineMetaClassAndStructors(com_matthiasm_elektriktrick_SerialDriver, IOSerialDriverSync); - -// Define the driver's superclass. -#define super IOSerialDriverSync - -#define STATE_ALL (PD_RS232_S_MASK | PD_S_MASK) -#define STATE_EXTERNAL (PD_S_MASK | (PD_RS232_S_MASK & ~PD_RS232_S_LOOP)) - - -bool com_matthiasm_elektriktrick_SerialDriver::init(OSDictionary *dict) -{ - bool result = super::init(dict); - IOLog("matthiasm: Initializing\n"); - - pNub = nullptr; - pWorkLoop = nullptr; - pState = 0; - pWatchState = 0; - pLock = IOLockAlloc(); - - return result; -} - -void com_matthiasm_elektriktrick_SerialDriver::free(void) -{ - IOLog("matthiasm: Freeing\n"); - IOLockFree(pLock); - super::free(); -} - -IOService *com_matthiasm_elektriktrick_SerialDriver::probe(IOService *provider, - SInt32 *score) -{ - IOService *result = super::probe(provider, score); - IOLog("matthiasm: Probing (%p)\n", result); - return result; -} - -bool com_matthiasm_elektriktrick_SerialDriver::start(IOService *provider) -{ - IOLog("matthiasm: Starting...\n"); - - // start the super class - bool ret = super::start(provider); - if (ret==false) { - IOLog("matthiasm: ERROR: super won't start\n"); - return false; - } - - // create and initialise the link to the BSD file system - if (!pNub) { - pNub = new IORS232SerialStreamSync; - if (!pNub) { - IOLog("matthiasm: ERROR: IORS232SerialStreamSync ctor failed\n"); - return false; - } - } - - ret = pNub->init(nullptr, nullptr); // ?? optional dictionary and user pointer - if (ret==false) { - IOLog("matthiasm: ERROR: won't init nub\n"); - return false; - } - - ret = pNub->attach(this); - if (ret==false) { - IOLog("matthiasm: ERROR: won't attach nub to driver\n"); - return false; - } - - pNub->setProperty(kIOTTYBaseNameKey, "Einstein"); - pNub->setProperty(kIOTTYSuffixKey, ""); - - pNub->registerService(); - - // create and initialize our event loop - if (!pWorkLoop) { - pWorkLoop = IOWorkLoop::workLoop(); - if (!pWorkLoop) { - IOLog("matthiasm: ERROR: can't find Work Loop\n"); - return false; - } - pWorkLoop->retain(); - } - - - IOLog("matthiasm: Starting: success\n"); - return true; -} - - -void com_matthiasm_elektriktrick_SerialDriver::stop(IOService *provider) -{ - IOLog("matthiasm: Stopping\n"); - - if (pWorkLoop) { - pWorkLoop->release(); - pWorkLoop = nullptr; - } - - if (pNub) { - // pNub->getResourceService()->release(); - pNub->removeProperty(kIOTTYSuffixKey); - pNub->removeProperty(kIOTTYBaseNameKey); - pNub->detach(this); - pNub->release(); - pNub = nullptr; - } - - super::stop(provider); - IOLog("matthiasm: Stopping: ok\n"); -} - - -/* acquire tests and sets the state of the port object. If the port was - * available, then the state is set to busy, and kIOReturnSuccess is returned. - * If the port was already busy and sleep is YES, then the thread will sleep - * until the port is freed, then re-attempts the acquire. If the port was - * already busy and sleep in NO, then kIOReturnExclusiveAccess is returned. - */ -IOReturn com_matthiasm_elektriktrick_SerialDriver::acquirePort(bool sleep, void *refCon) { - IOLog("matthiasm: acquirePort\n"); - - IOReturn ret = kIOReturnExclusiveAccess; - IOLockLock(pLock); - - if (sleep && (pState&PD_S_ACQUIRED)) { - IOLog("matthiasm: NOT SUPPORTED: sleep=true\n"); - /* - while (sleep) { - // FIXME: - UInt32 reqState = 0; - IOReturn rtn = watchState(&reqState, PD_S_ACQUIRED, refCon, true); - if (rtn != kIOReturnSuccess) { - IOLockUnlock(_lock); - return rtn; - } - } - */ - } - if ((pState&PD_S_ACQUIRED)==0) { - setState(PD_S_ACQUIRED, STATE_ALL, refCon, true); - // FIXME: startReceive(nullptr); - ret = kIOReturnSuccess; - } - - IOLockUnlock(pLock); - - if (ret==kIOReturnExclusiveAccess) { - IOLog("matthiasm: acquirePort: busy\n"); - } - if (ret==kIOReturnSuccess) { - IOLog("matthiasm: acquirePort: ok\n"); - } - return ret; -} - - -/* release sets the state of the port object to available and wakes up any - *threads sleeping for access to this port. It will return kIOReturnSuccess - *if the port was in a busy state, and kIOReturnNotOpen if it was available. - */ -IOReturn com_matthiasm_elektriktrick_SerialDriver::releasePort(void *refCon) { - IOLog("matthiasm: releasePort\n"); - return kIOReturnIOError; -} - - -/* - *Set the state for the port device. - */ -IOReturn com_matthiasm_elektriktrick_SerialDriver::setState(UInt32 state, UInt32 mask, void *refCon) { - return setState(state, mask, refCon, false); -} - - -IOReturn com_matthiasm_elektriktrick_SerialDriver::setState(UInt32 state, UInt32 mask, void *refCon, bool haveLock) { - IOLog("matthiasm: setState (0x%08x, 0x%08x)\n", state, mask); - IOReturn ret = kIOReturnSuccess; - - if (!haveLock) { - IOLockLock(pLock); - } - - /* If the port has neither been acquired, nor is it being acquired, then inform the caller that - * the port is not open. */ - if ((pState & PD_S_ACQUIRED) == 0 && ((state & mask) & PD_S_ACQUIRED) == 0) { - IOLog("matthiasm: setState: not open\n"); - ret = kIOReturnNotOpen; - } else { - UInt32 newState = (pState & ~mask) | (state & mask); - UInt32 deltaState = newState ^ pState; - pState = newState; - if (deltaState & pWatchState) { - pWatchState = 0; - IOLockWakeup(pLock, &pStateEvent, false); - } - } - - if (!haveLock) { - IOLockUnlock(pLock); - } - - IOLog("matthiasm: setState: done (0x%08x)\n", pState); - return ret; -} - - -/* - *Get the state for the port device. - */ -UInt32 com_matthiasm_elektriktrick_SerialDriver::getState(void *refCon) { - IOLog("matthiasm: getState (0x%08lx)\n", pState & STATE_EXTERNAL); - return pState & STATE_EXTERNAL; -} - -/* - *The variables below make up the bits returned - *by the State methods:- getState, setState, watchState - - #define PD_S_MASK 0xffff0000UL - #define PD_S_RX_OFFSET 7 - - #define PD_S_ACQUIRED 0x80000000UL - #define PD_S_ACTIVE 0x40000000UL - - #define PD_S_TX_ENABLE 0x20000000UL - #define PD_S_TX_BUSY 0x10000000UL - #define PD_S_TX_EVENT 0x08000000UL - #define PD_S_TXQ_EMPTY 0x04000000UL - #define PD_S_TXQ_LOW_WATER 0x02000000UL - #define PD_S_TXQ_HIGH_WATER 0x01000000UL - #define PD_S_TXQ_FULL 0x00800000UL - #define PD_S_TXQ_MASK 0x07800000UL - - #define PD_S_RX_ENABLE 0x00400000UL - #define PD_S_RX_BUSY 0x00200000UL - #define PD_S_RX_EVENT 0x00100000UL - #define PD_S_RXQ_EMPTY 0x00080000UL - #define PD_S_RXQ_LOW_WATER 0x00040000UL - #define PD_S_RXQ_HIGH_WATER 0x00020000UL - #define PD_S_RXQ_FULL 0x00010000UL - #define PD_S_RXQ_MASK 0x000F0000UL - */ - -/* - *Wait for the at least one of the state bits defined in mask to be equal - *to the value defined in state. - *Check on entry then sleep until necessary. - */ -IOReturn com_matthiasm_elektriktrick_SerialDriver::watchState(UInt32 *state, UInt32 mask, void *refCon) { - // matthiasm: watchState (0x0e000040, 0x18000040) - // Mask: PD_S_TX_BUSY turns 0 - // PD_S_TX_EVENT turns 1 - // watchState(0xe000040, 0x18000040 - return watchState(state, mask, refCon, false); -} - -/** - * Block until the backing state matches @a state, masked by @a mask has changed. - * - * @param state The required state values to wait for. - * @param mask The mask to use when evaluating @a state - * @param refCon Reference constant. - * @param haveLock If true, the method will assume that _lock is held. If false, the lock will be acquired - * automatically. - */ -IOReturn com_matthiasm_elektriktrick_SerialDriver::watchState (UInt32 *state, UInt32 mask, void *refCon, bool haveLock) { - IOLog("matthiasm: watchState (state: 0x%08x, mask: 0x%08x, is: 0x%08x)\n", state ? *state : 0, mask, pState); - - /* Ensure that state is non-NULL */ - if (state == NULL) { - IOLog("matthiasm: Watch request with NULL state"); - return kIOReturnBadArgument; - } - - if (mask == 0) { - IOLog("matthiasm: Watch request with 0 mask"); - return kIOReturnSuccess; - } - - /* Acquire our lock */ - if (!haveLock) { - IOLockLock(pLock); - - // /* Verify that the driver has not been stopped while the lock was not held */ - // if (_stopping) { - // LOG_DEBUG("watchState() - offline (stopping)"); - // IOLockUnlock(_lock); - // return kIOReturnOffline; - // } - } - - /* Limit mask to EXTERNAL_MASK. There are no comments or documentation describing why this is - * necessary, but this matches Apple's USBCDCDMM driver implementation. */ - mask &= STATE_EXTERNAL; - - /* There's nothing left to watch if the port has not been opened. */ - if ((pState & PD_S_ACQUIRED) == 0) { - if (!haveLock) - IOLockUnlock(pLock); - return kIOReturnNotOpen; - } - - UInt32 watchState = *state; - - /* To properly handle closure of the serial port, we must always track the PD_S_ACTIVE or PD_S_ACQUIRED state. - * If the caller is not already doing so, we register our interest here. */ - bool autoActive = false; - if ((mask & (PD_S_ACQUIRED | PD_S_ACTIVE)) == 0) { - /* Watch for low on PD_S_ACTIVE bit */ - mask |= PD_S_ACTIVE; - watchState &= ~PD_S_ACTIVE; - - /* Record that we enabled PD_S_ACTIVE monitoring */ - autoActive = true; - } - - /* Loop (and block) until one of our watched state values is achieved */ - while (true) { - /* Determine the currently matching states. We invert the current state mask with ~, and then use ^ to implement - * XNOR. Truth table: - * - * X Y O - * 1 0 = 0 - * 0 0 = 1 - * 0 1 = 0 - * 1 1 = 1 - */ - UInt32 matched = (watchState ^ pState) & mask; - if (matched != 0) { - *state = pState & STATE_EXTERNAL; - - /* Ensure that we drop our lock before returning. No further access to internal - * mutable state is required after this. */ - if (!haveLock) - IOLockUnlock(pLock); - - /* If the port has been closed (and the caller was not tracking PD_S_ACTIVE), - * return an error. Otherwise we're just informing the caller that PD_S_ACTIVE was set low, - * closing the port. This must necessarily differ from success, as the caller's state changes - * of interest have not been detected. - */ - if (autoActive && (matched & PD_S_ACTIVE)) { - return kIOReturnIOError; - } else { - return kIOReturnSuccess; - } - } - - /* Update the watched bits. This will reset the watchState on every loop -- it is reset to 0 when threads - * are signaled. */ - pWatchState |= mask; - - /* Wait to be signaled on a state change */ - int rtn = IOLockSleep(pLock, &pStateEvent, THREAD_ABORTSAFE); - if (rtn == THREAD_TIMED_OUT) { - if (!haveLock) - IOLockUnlock(pLock); - return kIOReturnTimeout; - } else if (rtn == THREAD_INTERRUPTED) { - if (!haveLock) - IOLockUnlock(pLock); - return kIOReturnAborted; - } - - /* Check if we've been stopped while the lock was relinquished. */ - // if (_stopping) { - // LOG_DEBUG("watchState() - offline (stopping) after IOLockSleep"); - // if (!haveLock) - // IOLockUnlock(_lock); - // return kIOReturnOffline; - // } - } - - if (!haveLock) - IOLockUnlock(pLock); - - /* Should not be reachable */ - IOLog("matthiasm: Reached unreachable end of watchState()"); - return kIOReturnOffline; -} - - - -/* nextEvent returns the type of the next event on the RX queue. If no - *events are present on the RX queue, then EOQ is returned. - */ -UInt32 com_matthiasm_elektriktrick_SerialDriver::nextEvent(void *refCon) { - IOLog("matthiasm: nextEvent\n"); - // FIXME: - return PD_E_EOQ; // no event in queue -} - - -// /Applications/Xcode.app//Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/System/Library/Frameworks/Kernel.framework/Versions/A/Headers/IOKit//serial/IOSerialStreamSync.h - -/* executeEvent causes the specified event to be processed immediately. - *This is primarily used for channel control commands like START & STOP - */ -IOReturn com_matthiasm_elektriktrick_SerialDriver::executeEvent(UInt32 event, UInt32 data, void *refCon) { - IOLog("matthiasm: executeEvent %d %d\n", event, data); - IOReturn ret = kIOReturnSuccess; - UInt32 stateUpdate; - UInt32 stateMask; - - IOLockLock(pLock); - - /* Verify that the driver has not been stopped */ - // if (_stopping) { - // IOLog("matthiasm:executeEvent() - offline (stopping)"); - // IOLockUnlock(_lock); - // return kIOReturnOffline; - // } - - switch (event) { - case PD_E_ACTIVE: { // matt: called first - IOLog("matthiasm:executeEvent(PD_E_ACTIVE, %u, %p)", data, refCon); - - /* Start or stop the UART */ - bool starting = data; - - /* Skip if already started, already stopped */ - if (starting && (pState & PD_S_ACTIVE) != 0) { - break; - } else if (!starting && (pState & PD_S_ACTIVE) == 0) { - break; - } - - // /* Set up the UART request */ - // IOUSBDevRequest req; - // req.bmRequestType = USLCOM_WRITE; - // req.bRequest = USLCOM_IFC_ENABLE; - // req.wIndex = USLCOM_PORT_NO; - // req.wLength = 0; - // req.pData = NULL; - // - stateMask = PD_S_ACTIVE; - if (starting) { - IOLog("matthiasm:Enabling UART"); - stateUpdate = PD_S_ACTIVE; - // req.wValue = USLCOM_IFC_ENABLE_EN; - } else { - IOLog("matthiasm:Disabling UART"); - stateUpdate = 0; - // req.wValue = USLCOM_IFC_ENABLE_DIS; - } - // - // /* Issue request */ - // ret = this->sendUSBDeviceRequest(&req); - // if (ret != kIOReturnSuccess) { - // /* Only return an error on start. At stop time, the device - // * may have simply disappeared. */ - // if (starting) { - // LOG_ERR("Set PD_E_ACTIVE (data=%u) failed: %u", data, ret); - // break; - // } else { - // IOLog("matthiasm:Ignoring PD_E_ACTIVE error %u on stop. The device was likely unplugged.", ret); - // ret = kIOReturnSuccess; - // break; - // } - // } - // - /* Update state */ - setState(stateUpdate, stateMask, refCon, true); - - if (starting) { - setState(PD_S_TX_ENABLE|PD_S_TXQ_EMPTY|PD_S_TXQ_LOW_WATER, PD_S_TX_ENABLE|PD_S_TX_BUSY|PD_S_TXQ_MASK, refCon, true); - setState(PD_S_RX_ENABLE|PD_S_RXQ_EMPTY|PD_S_RXQ_LOW_WATER, PD_S_RX_ENABLE|PD_S_RX_BUSY|PD_S_RXQ_MASK, refCon, true); - } - - //#define PD_S_TX_ENABLE 0x20000000UL - //#define PD_S_TX_BUSY 0x10000000UL - //#define PD_S_TX_EVENT 0x08000000UL - //#define PD_S_TXQ_EMPTY 0x04000000UL - //#define PD_S_TXQ_LOW_WATER 0x02000000UL - //#define PD_S_TXQ_HIGH_WATER 0x01000000UL - //#define PD_S_TXQ_FULL 0x00800000UL - //#define PD_S_TXQ_MASK 0x07800000UL - // - //#define PD_S_RX_ENABLE 0x00400000UL - //#define PD_S_RX_BUSY 0x00200000UL - //#define PD_S_RX_EVENT 0x00100000UL - //#define PD_S_RXQ_EMPTY 0x00080000UL - //#define PD_S_RXQ_LOW_WATER 0x00040000UL - //#define PD_S_RXQ_HIGH_WATER 0x00020000UL - //#define PD_S_RXQ_FULL 0x00010000UL - //#define PD_S_RXQ_MASK 0x000F0000UL - - // - // // TODO - Restore any line state? - // - break; - } - - - case PD_E_RXQ_SIZE: - /* Adjust receive queue size. We're not required to support this. */ - IOLog("matthiasm:executeEvent(PD_E_RXQ_SIZE, %u, %p)", data, refCon); - break; - case PD_E_TXQ_SIZE: - /* Adjust send queue size. We're not required to support this. */ - IOLog("matthiasm:executeEvent(PD_E_TXQ_SIZE, %u, %p)", data, refCon); - break; - - case PD_E_RXQ_HIGH_WATER: - /* Optional */ - IOLog("matthiasm:executeEvent(PD_E_RXQ_HIGH_WATER, %u, %p)", data, refCon); - break; - - case PD_E_RXQ_LOW_WATER: - /* Optional */ - IOLog("matthiasm:executeEvent(PD_E_RXQ_HIGH_WATER, %u, %p)", data, refCon); - break; - - case PD_E_TXQ_HIGH_WATER: - /* Optional */ - IOLog("matthiasm:executeEvent(PD_E_TXQ_HIGH_WATER, %u, %p)", data, refCon); - break; - - case PD_E_TXQ_LOW_WATER: - /* Optional */ - IOLog("matthiasm:executeEvent(PD_E_TXQ_LOW_WATER, %u, %p)", data, refCon); - break; - - case PD_E_TXQ_FLUSH: // matt: called 2nd, - /* No-op. */ - IOLog("matthiasm:executeEvent(PD_E_TXQ_FLUSH, %u, %p)", data, refCon); - break; - - case PD_E_RXQ_FLUSH: // matt: called 3rd - /* No-op. */ - IOLog("matthiasm:executeEvent(PD_E_RXQ_FLUSH, %u, %p)", data, refCon); - break; - - case PD_E_DATA_RATE: { // matt: - /* Set the baud rate. */ - IOLog("matthiasm:executeEvent(PD_E_DATA_RATE, %u>>1, %p)", data, refCon); - - /* - * IOSerialBSDClient shifts the speed << 1 before issuing a PD_E_DATA_RATE, - * claiming that the speed is stored in half-bits, but this does not appear - * to be the case. Comments in Apple's serial drivers' PD_E_DATA_RATE merely - * state 'For API compatiblilty with Intel' before reversing the shift. - * - * Summary: This is necessary to keep IOSerialBSDClient happy, and why - * IOSerialBSDClient requires this is lost to the history of whatever - * Apple engineer is responsible. - */ - // UInt32 baud = data >> 1; - // - // /* Set up the UART request */ - // IOUSBDevRequest req; - // uint32_t reqBuad = OSSwapHostToLittleInt32(baud); - // req.bmRequestType = USLCOM_WRITE; - // req.bRequest = USLCOM_SET_BAUDRATE; - // req.wValue = 0; - // req.wIndex = USLCOM_PORT_NO; - // req.wLength = sizeof(reqBuad); - // req.pData = &reqBuad; - // - // /* Issue request */ - // ret = this->sendUSBDeviceRequest(&req); - // if (ret == kIOReturnSuccess) { - // _baudRate = baud; - // } else { - // LOG_ERR("Set USLCOM_BAUD_RATE failed: %u", ret); - // break; - // } - - break; - } - - case PD_E_RX_DATA_RATE: - /* We don't support setting an independent RX data rate to anything but 0. It's unclear - * why we need to support a value of zero, but this matches Apple's USBCDCDMM implementation. */ - IOLog("matthiasm:executeEvent(PD_E_RX_DATA_RATE, %u>>1, %p)", data, refCon); - // if (data != 0) - // ret = kIOReturnBadArgument; - break; - - case PD_E_DATA_INTEGRITY: // matt: - // Fall-through - case PD_E_RX_DATA_INTEGRITY: - if (event == PD_E_DATA_INTEGRITY) { - IOLog("matthiasm:executeEvent(PD_E_DATA_INTEGRITY, %u, %p)", data, refCon); - } else { - IOLog("matthiasm:executeEvent(PD_E_RX_DATA_INTEGRITY, %u, %p)", data, refCon); - } - - // switch (data) { - // case PD_RS232_PARITY_NONE: - // case PD_RS232_PARITY_ODD: - // case PD_RS232_PARITY_EVEN: - // /* Set TX+RX vs. RX-only parity */ - // if (event == PD_E_DATA_INTEGRITY) { - // /* Attempt to write the new configuration */ - // ret = writeCP210xDataConfig(data, _twoStopBits, _characterLength); - // if (ret == kIOReturnSuccess) { - // /* Update internal state on success */ - // _txParity = data; - // _rxParity = PD_RS232_PARITY_DEFAULT; - // } - // - // } else { - // _rxParity = data; - // } - // - // break; - // - // default: - // /* Unsupported parity setting */ - // ret = kIOReturnBadArgument; - // break; - // } - // - break; - - case PD_RS232_E_STOP_BITS: // matt: - /* Set the stop bits */ - IOLog("matthiasm:executeEvent(PD_RS232_E_STOP_BITS, %u>>1, %p)", data, refCon); - - // /* Provided as half bits */ - // data >>= 1; - // bool newTwoStopBits; - // - // if (data == 1) { - // newTwoStopBits = false; - // } else if (data == 2) { - // newTwoStopBits = true; - // } else { - // LOG_ERR("PD_RS232_E_STOP_BITS with invalid data=%u", data); - // ret = kIOReturnBadArgument; - // break; - // } - // - // /* Attempt to write the new configuration */ - // ret = writeCP210xDataConfig(_txParity, newTwoStopBits, _characterLength); - // if (ret == kIOReturnSuccess) { - // _twoStopBits = newTwoStopBits; - // } - - break; - - case PD_RS232_E_RX_STOP_BITS: - /* We don't support setting an independent RX stop bit value to anything but 0. It's unclear - * why we need to support a value of zero, but this matches Apple's USBCDCDMM implementation. */ - IOLog("matthiasm:executeEvent(PD_RS232_E_RX_STOP_BITS, %u>>1, %p)", data, refCon); - // if (data != 0) - // ret = kIOReturnBadArgument; - break; - - case PD_E_DATA_SIZE: { // matt: - /* Set the character bit size */ - IOLog("matthiasm:executeEvent(PD_E_DATA_SIZE, %u>>1, %p)", data, refCon); - - // /* Provided as half bits */ - // data >>= 1; - // - // if (data < 5 || data > 8) { - // ret = kIOReturnBadArgument; - // break; - // } - // - // /* Attempt to write the new configuration */ - // ret = writeCP210xDataConfig(_txParity, _twoStopBits, data); - // if (ret == kIOReturnSuccess) { - // _characterLength = data; - // } - // - break; - } - - case PD_E_RX_DATA_SIZE: - /* We don't support setting an independent RX data size to anything but 0. It's unclear - * why we need to support a value of zero, but this matches Apple's USBCDCDMM implementation. */ - IOLog("matthiasm:executeEvent(PD_E_RX_DATA_SIZE, %u>>1, %p)", data, refCon); - // if (data != 0) - // ret = kIOReturnBadArgument; - break; - - case PD_E_FLOW_CONTROL: // matt: called 4th - IOLog("matthiasm:executeEvent(PD_E_FLOW_CONTROL, %x, %p)", data, refCon); - - /* Validate the data */ - // if (data & ~PL_A_FLOWCONTROL_MASK) { - // LOG_ERR("PD_E_FLOW_CONTROL called with invalid data"); - // ret = kIOReturnBadArgument; - // } - - /* Shift to PD_RS232_S_ */ - data >>= PD_RS232_A_SHIFT; - - /* Update state */ - setState(data, PD_RS232_S_MASK, refCon, true); - break; - - case PD_RS232_E_XON_BYTE: // matt: - IOLog("matthiasm:executeEvent(PD_RS232_E_XON_BYTE, %u, %p)", data, refCon); - // _xonChar = data; - break; - - case PD_RS232_E_XOFF_BYTE: // matt: - IOLog("matthiasm:executeEvent(PD_RS232_E_XOFF_BYTE, %u, %p)", data, refCon); - // _xoffChar = data; - break; - - case PD_E_SPECIAL_BYTE: - IOLog("matthiasm:executeEvent(PD_E_SPECIAL_BYTE, %u, %p)", data, refCon); - /** - * 'Special' bytes are an optional optimization, used to implement - * wake up of waiting threads if a 'special' character is received. This - * is only used by the PPP and SLIP line disciplines. We do not support - * this feature. - */ - break; - - case PD_E_VALID_DATA_BYTE: - IOLog("matthiasm:executeEvent(PD_E_VALID_DATA_BYTE, %u, %p)", data, refCon); - /** - * Reset a 'special' byte set in PD_E_SPECIAL_BYTE. - */ - break; - - default: - IOLog("matthiasm:Unsupported executeEvent(%x, %u, %p)", event, data, refCon); - ret = kIOReturnBadArgument; - break; - } - - IOLockUnlock(pLock); - return ret; -} - - -/* requestEvent processes the specified event as an immediate request and - *returns the results in data. This is primarily used for getting link - *status information and verifying baud rate and such. - */ -IOReturn com_matthiasm_elektriktrick_SerialDriver::requestEvent(UInt32 event, UInt32 *data, void *refCon) { - IOLog("matthiasm: requestEvent\n"); - return kIOReturnIOError; -} - - -/* enqueueEvent will place the specified event into the TX queue. The - *sleep argument allows the caller to specify the enqueueEvent's - *behaviour when the TX queue is full. If sleep is true, then this - *method will sleep until the event is enqueued. If sleep is false, - *then enqueueEvent will immediatly return kIOReturnNoResources. - */ -IOReturn com_matthiasm_elektriktrick_SerialDriver::enqueueEvent(UInt32 event, UInt32 data, - bool sleep, void *refCon) { - IOLog("matthiasm: enqueueEvent\n"); - return kIOReturnIOError; -} - - -/* dequeueEvent will remove the oldest event from the RX queue and return - *it in event & data. The sleep argument defines the behaviour if the RX - *queue is empty. If sleep is true, then this method will sleep until an - *event is available. If sleep is false, then an EOQ event will be - *returned. In either case kIOReturnSuccess is returned. - */ -IOReturn com_matthiasm_elektriktrick_SerialDriver::dequeueEvent(UInt32 *event, UInt32 *data, - bool sleep, void *refCon) { - IOLog("matthiasm: dequeueEvent\n"); - return kIOReturnIOError; -} - - -/* enqueueData will attempt to copy data from the specified buffer to the - *TX queue as a sequence of VALID_DATA events. The argument bufferSize - *specifies the number of bytes to be sent. The actual number of bytes - *transferred is returned in transferCount. If sleep is true, then this - *method will sleep until all bytes can be transferred. If sleep is - *false, then as many bytes as possible will be copied to the TX queue. - */ -IOReturn com_matthiasm_elektriktrick_SerialDriver::enqueueData(UInt8 *buffer, UInt32 size, UInt32 *count, - bool sleep, void *refCon) { - IOLog("matthiasm: enqueueData\n"); - return kIOReturnIOError; -} - - -/* dequeueData will attempt to copy data from the RX queue to the specified - *buffer. No more than bufferSize VALID_DATA events will be transferred. - *In other words, copying will continue until either a non-data event is - *encountered or the transfer buffer is full. The actual number of bytes - *transferred is returned in transferCount. - * - *The sleep semantics of this method are slightly more complicated than - *other methods in this API: Basically, this method will continue to - *sleep until either minCount characters have been received or a non - *data event is next in the RX queue. If minCount is zero, then this - *method never sleeps and will return immediatly if the queue is empty. - * - *The latency parameter specifies the maximum amount of time that should - *pass after the first character is available before the routine returns. - *This allows the caller to specify a 'packet' timeout. The unit of the - *latency parameter is microseconds, though the exact delay may vary - *depending on the granularity of the timeout services available to the - *driver. - */ -IOReturn com_matthiasm_elektriktrick_SerialDriver::dequeueData(UInt8 *buffer, UInt32 size, UInt32 *count, - UInt32 min, void *refCon) { - IOLog("matthiasm: dequeueData (%d:%.*s)\n", size, size, buffer); - *count = size; - // FIXME: - return kIOReturnSuccess; - return kIOReturnIOError; -} - - diff --git a/Drivers/MacOS Serial Driver/SerialDriver.h b/Drivers/MacOS Serial Driver/SerialDriver.h deleted file mode 100644 index cc9d443a6..000000000 --- a/Drivers/MacOS Serial Driver/SerialDriver.h +++ /dev/null @@ -1,50 +0,0 @@ - -#include - -// Driver implementation -#include - -// representation in user space ("/dev/tty.Whatever") -#include - -class com_matthiasm_elektriktrick_SerialDriver: public IOSerialDriverSync -{ - OSDeclareDefaultStructors(com_matthiasm_elektriktrick_SerialDriver) - - IORS232SerialStreamSync *pNub; - IOWorkLoop *pWorkLoop; - UInt32 pState; - UInt32 pWatchState; - IOLock *pLock; - void *pStateEvent; - -public: - virtual bool init(OSDictionary *dictionary = 0) override; - virtual void free(void) override; - virtual IOService *probe(IOService *provider, SInt32 *score) override; - virtual bool start(IOService *provider) override; - virtual void stop(IOService *provider) override; - - virtual IOReturn acquirePort(bool sleep, void *refCon) override; - virtual IOReturn releasePort(void *refCon) override; - virtual IOReturn setState(UInt32 state, UInt32 mask, void *refCon) override; - IOReturn setState(UInt32 state, UInt32 mask, void *refCon, bool haveLock); - virtual UInt32 getState(void *refCon) override; - virtual IOReturn watchState(UInt32 *state, UInt32 mask, void *refCon) override; - IOReturn watchState(UInt32 *state, UInt32 mask, void *refCon, bool haveLock); - virtual UInt32 nextEvent(void *refCon) override; - virtual IOReturn executeEvent(UInt32 event, UInt32 data, void *refCon) override; - virtual IOReturn requestEvent(UInt32 event, UInt32 *data, void *refCon) override; - virtual IOReturn enqueueEvent(UInt32 event, UInt32 data, - bool sleep, void *refCon) override; - virtual IOReturn dequeueEvent(UInt32 *event, UInt32 *data, - bool sleep, void *refCon) override; - virtual IOReturn enqueueData(UInt8 *buffer, UInt32 size, UInt32 *count, - bool sleep, void *refCon) override; - virtual IOReturn dequeueData(UInt8 *buffer, UInt32 size, UInt32 *count, - UInt32 min, void *refCon) override; -}; - - - - diff --git a/Emulator/Serial/TBasiliskIISerialPortManager.cp b/Emulator/Serial/TBasiliskIISerialPortManager.cp index 450e4bb5f..1f712f6b7 100644 --- a/Emulator/Serial/TBasiliskIISerialPortManager.cp +++ b/Emulator/Serial/TBasiliskIISerialPortManager.cp @@ -48,11 +48,26 @@ #include "Emulator/TARMProcessor.h" +const char *TBasiliskIISerialPortManager::kBasiliskPipe = "/tmp/pty.BasiliskII"; + + // -------------------------------------------------------------------------- // // * TBasiliskIISerialPortManager() -// Emulate a serial port via a pseudo terminal. -// For example, opening /dev/ptyp0 as a master will give access to the -// corresponding slave port /dev/ttyp0. +// +// Emulate a serial port via a pseudo terminal (pty) in MacOS +// +// This driver works around a bug in BasiliskII, where Basilisk will hang +// forever when closing a serial port. +// +// This driver provides a PTY via /tmp/pty.BasiliskII . It will try to +// determine when an app inside Basilisk closes the serial port. The Einstein +// driver will then remove the PTY, which will in turn break the endless +// loop in Basilisk. +// +// This workaround functions well for NTK and NCU, running inside BasiliskII. +// +// \author Matthias Melcher +// // -------------------------------------------------------------------------- // TBasiliskIISerialPortManager::TBasiliskIISerialPortManager( TLog* inLog, @@ -60,10 +75,12 @@ TBasiliskIISerialPortManager::TBasiliskIISerialPortManager( : TBasicSerialPortManager(inLog, inLocationID), mPipe{-1,-1}, - mPtyPort(-1), mDMAIsRunning(false), mDMAThread(0L), - mPtyName(0L) + pBasiliskSlaveName(nullptr), + pBasiliskMaster(-1), + pBasiliskSlave(-1), + pComState(kStateInit) { } @@ -75,10 +92,11 @@ TBasiliskIISerialPortManager::TBasiliskIISerialPortManager( // -------------------------------------------------------------------------- // TBasiliskIISerialPortManager::~TBasiliskIISerialPortManager() { - if (mPtyName) - free(mPtyName); + if (mDMAIsRunning) + TriggerEvent('Q'); } + // -------------------------------------------------------------------------- // // * run( TInterruptManager*, TDMAManager*, TMemory* ) // -------------------------------------------------------------------------- // @@ -93,6 +111,7 @@ void TBasiliskIISerialPortManager::run(TInterruptManager* inInterruptManager, RunDMA(); } + // -------------------------------------------------------------------------- // // DMA or interrupts were triggered // -------------------------------------------------------------------------- // @@ -105,27 +124,105 @@ void TBasiliskIISerialPortManager::TriggerEvent(KUInt8 cmd) // -------------------------------------------------------------------------- // -// * FindPtyName() +// * OpenPTY // -------------------------------------------------------------------------- // -void -TBasiliskIISerialPortManager::FindBasiliskIIName() +bool +TBasiliskIISerialPortManager::OpenPTY() { - if (mPtyName) - return; - // TODO: hardcode the name for now -// mPtyName = strdup("/dev/ttyp0"); - mPtyName = strdup("/tmp/BBridge.Einstein"); + int ret = -1; + + // TODO: if we ever decide to suppirt more than the internal serial port, we + // will have to generate diffwerent names for different ports. + ret = unlink(kBasiliskPipe); + if (ret==-1 && errno!=2) { + perror("TBasiliskIISerialPortManager: Can't unlink Basilisk Pipe"); +// return false; + } + + pBasiliskMaster = posix_openpt(O_RDWR | O_NOCTTY); + if (pBasiliskMaster==-1) { + perror("TBasiliskIISerialPortManager: Can't open Basilisk Master"); + return false; + } + + ret = grantpt(pBasiliskMaster); + if (ret==-1) { + perror("TBasiliskIISerialPortManager: Can't grant Basilisk Master pseudo terminal"); + return false; + } + + ret = unlockpt(pBasiliskMaster); + if (ret==-1) { + perror("TBasiliskIISerialPortManager: Can't unlock Basilisk Master pseudo terminal"); + return false; + } + + const char *slaveName = ptsname(pBasiliskMaster); + if (slaveName==nullptr) { + perror("TBasiliskIISerialPortManager: Can't get name of Basilisk Slave pseudo terminal"); + return false; + } + pBasiliskSlaveName = strdup(slaveName); + + pBasiliskSlave = open(slaveName, O_RDWR | O_NOCTTY); + if (pBasiliskSlave==-1) { + perror("TBasiliskIISerialPortManager: Can't open Basilisk Slave pseudo terminal"); + return false; + } + + ret = symlink(slaveName, kBasiliskPipe); + if (ret==-1) { + perror("TBasiliskIISerialPortManager: Can't link Basilisk pipe"); + return false; + } + + // tcgetattr(fd, &struct termios) + struct termios tios; + + ret = tcgetattr(pBasiliskMaster, &tios); + if (ret==-1) { perror("TBasiliskIISerialPortManager: tcgetattr"); return false; } + cfmakeraw(&tios); + tios.c_cflag |= (HUPCL | CLOCAL); + ret = tcsetattr(pBasiliskMaster, TCSANOW, &tios); + if (ret==-1) { perror("TBasiliskIISerialPortManager: tcsetattr"); return false; } + + ret = tcgetattr(pBasiliskSlave, &tios); + if (ret==-1) { perror("TBasiliskIISerialPortManager: tcgetattr"); return false; } + cfmakeraw(&tios); + tios.c_cflag |= (HUPCL | CLOCAL); + ret = tcsetattr(pBasiliskSlave, TCSANOW, &tios); + if (ret==-1) { perror("TBasiliskIISerialPortManager: tcsetattr"); return false; } + + int pkt = 1; + ret = ioctl(pBasiliskMaster, TIOCPKT, &pkt); + if (ret==-1) { perror("TBasiliskIISerialPortManager: TIOCPKT"); return false; } + + return true; } // -------------------------------------------------------------------------- // -// * CreatePty +// * ClosePTY // -------------------------------------------------------------------------- // -bool -TBasiliskIISerialPortManager::CreateBasiliskII() +void +TBasiliskIISerialPortManager::ClosePTY() { - // TODO: Remove this function. There is nothing to create. - return true; + unlink(kBasiliskPipe); + + if (pBasiliskMaster!=-1) { + close(pBasiliskMaster); + pBasiliskMaster = -1; + } + + if (pBasiliskSlave!=-1) { + close(pBasiliskSlave); + pBasiliskSlave = -1; + } + + if (pBasiliskSlaveName!=nullptr) { + free(pBasiliskSlaveName); + pBasiliskSlaveName = nullptr; + } } @@ -144,31 +241,24 @@ TBasiliskIISerialPortManager::CreateBasiliskII() void TBasiliskIISerialPortManager::RunDMA() { - // create named pipe nodes - FindBasiliskIIName(); - if (!CreateBasiliskII()) { - return; - } - - // open the named pipes - mPtyPort = open(mPtyName, O_RDWR | O_NOCTTY | O_NONBLOCK); - if (mPtyPort==-1) { - printf("***** Error opening pseudo terminal %s - %s (%d).\n", mPtyName, strerror(errno), errno); + // create PTY and named pipe + bool hasPty = OpenPTY(); + if (!hasPty) { + printf("***** TBasiliskIISerialPortManager::RunDMA: Error creating pseudo terminal %s.\n", kBasiliskPipe); return; } - tcflush(mPtyPort, TCIOFLUSH); // open the thread communication pipe int err = pipe(mPipe); if (err==-1) { - printf("***** Error opening pipe - %s (%d).\n", strerror(errno), errno); + printf("***** TBasiliskIISerialPortManager::RunDMA: Error opening pipe - %s (%d).\n", strerror(errno), errno); return; } // create the actual thread and let it run forever int ptErr = ::pthread_create( &mDMAThread, NULL, &SHandleDMA, this ); if (ptErr==-1) { - printf("***** Error creating pthread - %s (%d).\n", strerror(errno), errno); + printf("***** TBasiliskIISerialPortManager::RunDMA: Error creating pthread - %s (%d).\n", strerror(errno), errno); return; } pthread_detach( mDMAThread ); @@ -184,15 +274,19 @@ TBasiliskIISerialPortManager::RunDMA() void TBasiliskIISerialPortManager::HandleDMA() { + bool shutdownThread = false; + pComState = kStateInit; static int maxFD = -1; - if (mPtyPort>maxFD) maxFD = mPtyPort; + if (pBasiliskMaster>maxFD) maxFD = pBasiliskMaster; + if (pBasiliskSlave>maxFD) maxFD = pBasiliskSlave; if (mPipe[0]>maxFD) maxFD = mPipe[0]; // thread loops and handles pipe, port, and DMA fd_set readSet; struct timeval timeout; - for (;;) { + + while (!shutdownThread) { bool needTimer = false; if (mTxDMAControl&0x00000002) { // DMA is enabled @@ -204,7 +298,7 @@ TBasiliskIISerialPortManager::HandleDMA() // wait for the next event FD_ZERO(&readSet); FD_SET(mPipe[0], &readSet); - FD_SET(mPtyPort, &readSet); + FD_SET(pBasiliskMaster, &readSet); if (needTimer) { timeout.tv_sec = 0; timeout.tv_usec = 260; // one byte at 38400bps serial port speed @@ -218,8 +312,7 @@ TBasiliskIISerialPortManager::HandleDMA() // write a byte KUInt8 data = 0; mMemory->ReadBP(mTxDMAPhysicalData, data); - //printf(":::::>> TX: 0x%02X '%c'\n", data, isprint(data)?data:'.'); - write(mPtyPort, &data, 1); + write(pBasiliskMaster, &data, 1); mTxDMAPhysicalData++; mTxDMABufferSize--; if (mTxDMABufferSize==0) { @@ -228,8 +321,6 @@ TBasiliskIISerialPortManager::HandleDMA() mTxDMADataCountdown--; if (mTxDMADataCountdown==0) { // trigger a "send buffer empty" interrupt - //mDMAManager->WriteChannel2Register(1, 1, 0x00000080); // 0x80 = TxBufEmpty, 0x00000180 - //printf(":::::>> buffer is now empty\n"); mTxDMAEvent = 0x00000080; mInterruptManager->RaiseInterrupt(0x00000100); } @@ -238,41 +329,54 @@ TBasiliskIISerialPortManager::HandleDMA() // handle receiving DMA - // FIXME: This routine is currently a mess. it needs to be rewritten - // and retested. Note though that the original Newton hardware and OS - // did have timing issues whan the server PC communicated faster as - // expected in the year 1996, which lead to CPU cycle burning software - // like "slowdown.exe". - - if (FD_ISSET(mPtyPort, &readSet)) { + if (FD_ISSET(pBasiliskMaster, &readSet)) { // read bytes that come in through the serial port KUInt8 buf[1026]; int n = -1; usleep(100000); // 1/10th of a second - for (int j=2; j>0; j--) { - // FIXME: reading 1024 bytes will overflow the buffer - // FIXME: reading less bytes must make sure that the next select() call triggers on data left in the buffer - n = (int)read(mPtyPort, buf, 1024); -// n = read(mRxPort, buf, 1); - if (n<=0) - usleep(100000); // 1/10th of a second - else - break; - } - if (n==-1) { - printf("***** Error reading from serial port %s - %s (%d).\n", mPtyName, strerror(errno), errno); - } else if (n==0) { - // printf("***** No data yet\n"); + n = (int)read(pBasiliskMaster, buf, 1024); + if (n<=0) { + usleep(100000); // 1/10th of a second + } else if (n==1) { + const uint8_t FLUSHRW = TIOCPKT_FLUSHREAD|TIOCPKT_FLUSHWRITE; + uint8_t c = buf[0]; + switch (pComState) { + case kStateInit: + // Initial state. Wait for Basilisk to open and setup its COM port + if ((c&TIOCPKT_NOSTOP) == TIOCPKT_NOSTOP) pComState = kStateOpen; + break; + case kStateOpen: + // The port is open. Wait for Basilisk to flush the COM port after initialising + if ((c&FLUSHRW) == FLUSHRW) pComState = kStateFlushRW; + break; + case kStateFlushRW: + // wait for a second flushing of the COM port. This indicates to us that Basilisk + // is very likely trying to close the port, but may be deadloking. Help Basilisk + // out by closing and reopening the pipe. + if ((c&FLUSHRW) == FLUSHRW) { + ClosePTY(); + usleep(500000); // half a second + OpenPTY(); + pComState = kStateInit; + } + break; + } + // handle control command in buf[0] +// printf("BasiliskII sent control code (%d):", pComState); +// if (c&TIOCPKT_FLUSHREAD) puts(" - TIOCPKT_FLUSHREAD"); +// if (c&TIOCPKT_FLUSHWRITE) puts(" - TIOCPKT_FLUSHWRITE"); +// if (c&TIOCPKT_STOP) puts(" - TIOCPKT_STOP"); +// if (c&TIOCPKT_START) puts(" - TIOCPKT_START"); +// if (c&TIOCPKT_DOSTOP) puts(" - TIOCPKT_DOSTOP"); +// if (c&TIOCPKT_NOSTOP) puts(" - TIOCPKT_NOSTOP"); } else { - //printf("----> Received %d bytes data from NCX\n", n); - for (KUInt32 i=0; iWriteBP(mRxDMAPhysicalData, data); - //printf(" rx[%.3d] -> %02X '%c'\n", i, data, isprint(data)?data:'.'); mRxDMAPhysicalData++; mRxDMABufferSize--; if (mRxDMABufferSize==0) { // or mRxDMADataCountdown? -// if (mRxDMADataCountdown==0) { // or mRxDMADataCountdown does not work! mRxDMAPhysicalData = mRxDMAPhysicalBufferStart; } mRxDMADataCountdown--; @@ -280,10 +384,8 @@ TBasiliskIISerialPortManager::HandleDMA() // buffer overflow? } } - //printf("===> Start Rx DMA\n"); mRxDMAEvent = 0x00000040; mInterruptManager->RaiseInterrupt(0x00000080); // 0x00000180 - //printf("===> End Rx DMA\n"); } } @@ -301,13 +403,17 @@ TBasiliskIISerialPortManager::HandleDMA() if (n==-1) { printf("***** Error reading pipe - %s (%d).\n", strerror(errno), errno); } else if (n) { - //printf(":::::>> pipe commend '%c'\n", cmd); + if (cmd=='Q') { + shutdownThread = true; + } } } } } } + ClosePTY(); + mDMAIsRunning = false; } diff --git a/Emulator/Serial/TBasiliskIISerialPortManager.h b/Emulator/Serial/TBasiliskIISerialPortManager.h index 9f9bcf9c9..d664df3bc 100644 --- a/Emulator/Serial/TBasiliskIISerialPortManager.h +++ b/Emulator/Serial/TBasiliskIISerialPortManager.h @@ -36,10 +36,26 @@ class TMemory; /// /// Emulate a serial port via a pseudo terminal (pty) in MacOS /// +/// This driver works around a bug in BasiliskII, where Basilisk will hang +/// forever when closing a serial port. +/// +/// This driver provides a PTY via /tmp/pty.BasiliskII . It will try to +/// determine when an app inside Basilisk closes the serial port. The Einstein +/// driver will then remove the PTY, which will in turn break the endless +/// loop in Basilisk. +/// +/// This workaround functions well for NTK and NCU, running inside BasiliskII. +/// /// \author Matthias Melcher /// class TBasiliskIISerialPortManager : public TBasicSerialPortManager { + typedef enum { + kStateInit = 0, + kStateOpen, + kStateFlushRW + } ComState; + public: /// @@ -83,20 +99,26 @@ class TBasiliskIISerialPortManager : public TBasicSerialPortManager static void *SHandleDMA(void *This) { ((TBasiliskIISerialPortManager*)This)->HandleDMA(); return 0L; } /// - /// Find good names for the named pipes + /// Open a PTY that is linked to /tmp/pty.BasiliskII /// - void FindBasiliskIIName(); + bool OpenPTY(); /// - /// Create the named pipes as nodes in the file system + /// Close the BasiliskII special PTY, breaking Basilisks endless loop. /// - bool CreateBasiliskII(); + void ClosePTY(); int mPipe[2]; ///< communication between emulator and DMA thread - int mPtyPort; ///< pseudo terminal file id +// int mPtyPort; ///< pseudo terminal file id bool mDMAIsRunning; ///< set if DMA thread is active pthread_t mDMAThread; - char *mPtyName; ///< named of pseudo terminal +// char *mPtyName; ///< named of pseudo terminal + + static const char *kBasiliskPipe; ///< Base name of the pasilisk pty + char *pBasiliskSlaveName; ///< PTY slave filename + int pBasiliskMaster; ///< PTY master file id + int pBasiliskSlave; ///< PTY slave file id + ComState pComState; ///< state of the connection to Basilisk }; #endif diff --git a/_Build_/Xcode/BasiliskBridge/main.cpp b/_Build_/Xcode/BasiliskBridge/main.cpp deleted file mode 100644 index 61c610ced..000000000 --- a/_Build_/Xcode/BasiliskBridge/main.cpp +++ /dev/null @@ -1,549 +0,0 @@ -// -// main.cpp -// BasiliskBridge -// -// Created by Matthias Melcher on 5/2/18. -// - -/* - This tool creates a link between the EInstein serial port emulation and the - BasiliskII serial port emulation without blocking either app. Make sure that - BasiliskBridge runs before BasiliskII or EInstein is launched. - - To the outside, BBridge create two Unix files that act like a pseudo terminal, - connecting Einstein and BasiliskII. Einstein should emulate its serial port - through "/tmp/BBridge.Einstein", which it does automatically if the serial - option is set to BBridge. BasiliskII should set "/tmp/BBridge.BasiliskII" - for the Modem port emulation. - - Under the hood, BBridge generates two pseudo terminal connactions via pty. - Those terminals are linked to the files in "/tmp" whic are then accessible - form those apps. BBridge then manages the other ends of those terminals so - that neithe rprogram blocks (BasiliskII will block when using standard - pseudo terminals). - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - - -const char *gBasiliskPipe = "/tmp/BBridge.BasiliskII"; -const char *gBasiliskSlaveName = nullptr; -int gBasiliskMaster = -1; -int gBasiliskSlave = -1; - -const char *gEinsteinPipe = "/tmp/BBridge.Einstein"; -int gEinsteinMaster = -1; -int gEinsteinSlave = -1; - - -void dumpRead(const char *pre, int fd, int fdOut) -{ - int nAvail = 0; - int ret = ioctl(fd, FIONREAD, &nAvail); - nAvail = 1024; - if (nAvail) { - printf(" reading %d bytes\n", nAvail); - uint8_t *buf = (uint8_t*)malloc(nAvail); - nAvail = ::read(fd, buf, nAvail); - printf(" %s ", pre); - int i; - for (i=0; i' '&&c<127 ? c : '.'); - } - printf("\n"); - if (fdOut!=-1) { - ::write(fdOut, buf, nAvail); - } - free(buf); - } -} - - -void dumpPacketRead(const char *pre, int fd, int fdOut) -{ - int nAvail = 0; - int ret = ioctl(fd, FIONREAD, &nAvail); - nAvail = 1024; - if (nAvail) { - printf(" reading %d bytes\n", nAvail); - uint8_t *buf = (uint8_t*)malloc(nAvail); - nAvail = ::read(fd, buf, nAvail); - printf(" %s ", pre); - int i; - for (i=0; i' '&&c<127 ? c : '.'); - } - printf("\n"); - if (nAvail==1) { - uint8_t c = buf[0]; - if (c&TIOCPKT_FLUSHREAD) puts(" - TIOCPKT_FLUSHREAD"); - if (c&TIOCPKT_FLUSHWRITE) puts(" - TIOCPKT_FLUSHWRITE"); - if (c&TIOCPKT_STOP) puts(" - TIOCPKT_STOP"); - if (c&TIOCPKT_START) puts(" - TIOCPKT_START"); - if (c&TIOCPKT_DOSTOP) puts(" - TIOCPKT_DOSTOP"); - if (c&TIOCPKT_NOSTOP) puts(" - TIOCPKT_NOSTOP"); - /* - Basilisk app starts: - TIOCPKT_NOSTOP - then - TIOCPKT_FLUSHREAD - then - TIOCPKT_FLUSHREAD - TIOCPKT_FLUSHWRITE - - Basilisk app stops: - TIOCPKT_FLUSHREAD - TIOCPKT_FLUSHWRITE - then locked, close and open pty, then - TIOCPKT_NOSTOP - - */ - } else if (nAvail>1) { - if (fdOut!=-1) { - ::write(fdOut, buf+1, nAvail-1); - } - } - free(buf); - } -} - - -int setupBasiliskPipe() -{ - int ret = -1; - - ret = unlink(gBasiliskPipe); - //ret = remove(gBasiliskPipe); - if (ret==-1 && errno!=2) { - perror("Can't unlink Basilisk Pipe"); - return -1; - } - // } - - gBasiliskMaster = posix_openpt(O_RDWR | O_NOCTTY); - if (gBasiliskMaster==-1) { - perror("Can't open Basilisk Master"); - return -1; - } - - ret = grantpt(gBasiliskMaster); - if (ret==-1) { - perror("Can't grant Basilisk Master pseudo terminal"); - return -1; - } - - ret = unlockpt(gBasiliskMaster); - if (ret==-1) { - perror("Can't unlock Basilisk Master pseudo terminal"); - return -1; - } - - // ptsname_r(int fildes, char *buffer, size_t buflen); - const char *slaveName = ptsname(gBasiliskMaster); - if (slaveName==nullptr) { - perror("Can't get name of Basilisk Slave pseudo terminal"); - return -1; - } - gBasiliskSlaveName = strdup(slaveName); - - gBasiliskSlave = open(slaveName, O_RDWR | O_NOCTTY); - if (gBasiliskSlave==-1) { - perror("Can't open Basilisk Slave pseudo terminal"); - return -1; - } - - ret = symlink(slaveName, gBasiliskPipe); - if (ret==-1) { - perror("Can't link Basilisk pipe"); - return -1; - } - - // tcgetattr(fd, &struct termios) - struct termios tios; - - ret = tcgetattr(gBasiliskMaster, &tios); - if (ret==-1) { perror("tcgetattr"); return -1; } - cfmakeraw(&tios); - tios.c_cflag |= (HUPCL | CLOCAL); - ret = tcsetattr(gBasiliskMaster, TCSANOW, &tios); - if (ret==-1) { perror("tcsetattr"); return -1; } - - ret = tcgetattr(gBasiliskSlave, &tios); - if (ret==-1) { perror("tcgetattr"); return -1; } - cfmakeraw(&tios); - tios.c_cflag |= (HUPCL | CLOCAL); - ret = tcsetattr(gBasiliskSlave, TCSANOW, &tios); - if (ret==-1) { perror("tcsetattr"); return -1; } - - int pkt = 1; - ret = ioctl(gBasiliskMaster, TIOCPKT, &pkt); - if (ret==-1) { perror("TIOCPKT"); return -1; } - - return 0; -} - -int setupEinsteinPipe() -{ - int ret = -1; - - ret = unlink(gEinsteinPipe); - //ret = remove(gEinsteinPipe); - if (ret==-1 && errno!=2) { - perror("Can't unlink Einstein Pipe"); - return -1; - } - // } - - gEinsteinMaster = posix_openpt(O_RDWR | O_NOCTTY); - if (gEinsteinMaster==-1) { - perror("Can't open Einstein Master"); - return -1; - } - - ret = grantpt(gEinsteinMaster); - if (ret==-1) { - perror("Can't grant Einstein Master pseudo terminal"); - return -1; - } - - ret = unlockpt(gEinsteinMaster); - if (ret==-1) { - perror("Can't unlock Einstein Master pseudo terminal"); - return -1; - } - - // ptsname_r(int fildes, char *buffer, size_t buflen); - const char *slaveName = ptsname(gEinsteinMaster); - if (slaveName==nullptr) { - perror("Can't get name of Einstein Slave pseudo terminal"); - return -1; - } - slaveName = strdup(slaveName); - - gEinsteinSlave = open(slaveName, O_RDWR | O_NOCTTY); - if (gEinsteinSlave==-1) { - perror("Can't open Einstein Slave pseudo terminal"); - return -1; - } - - ret = symlink(slaveName, gEinsteinPipe); - if (ret==-1) { - perror("Can't link Einstein pipe"); - return -1; - } - - // tcgetattr(fd, &struct termios) - struct termios tios; - - ret = tcgetattr(gEinsteinMaster, &tios); - if (ret==-1) { perror("tcgetattr"); return -1; } - cfmakeraw(&tios); - ret = tcsetattr(gEinsteinMaster, TCSANOW, &tios); - if (ret==-1) { perror("tcsetattr"); return -1; } - - ret = tcgetattr(gEinsteinSlave, &tios); - if (ret==-1) { perror("tcgetattr"); return -1; } - cfmakeraw(&tios); - ret = tcsetattr(gEinsteinSlave, TCSANOW, &tios); - if (ret==-1) { perror("tcsetattr"); return -1; } - - return 0; -} - -// getpt(3), grantpt(3), ptsname(3), unlockpt(3), pty(7) - -int main(int argc, const char * argv[]) -{ - int ret; - - ret = setupBasiliskPipe(); - if (ret!=0) - return ret; - - ret = setupEinsteinPipe(); - if (ret!=0) - return ret; - -// struct termios tios; -// tcgetattr(STDIN_FILENO, &tios); -// tios.c_cflag &= ~ICANON; -// tios.c_cflag &= ~ECHO; -// tios.c_cc[VMIN] = 1; -// tios.c_cc[VTIME] = 0; -// tcsetattr(STDIN_FILENO, TCSANOW, &tios); -// setbuf(stdin, nullptr); -// int flags; -// fcntl(STDIN_FILENO, F_GETFL, &flags); -// flags |= O_NONBLOCK; -// fcntl(STDIN_FILENO, F_SETFL, &flags); - int flags = 1; - fcntl(STDIN_FILENO, F_NOCACHE, &flags); - - -// signal(SIGQUIT, slirp_exit); -// signal(SIGHUP, slirp_exit); -// signal(SIGINT, slirp_exit); -// signal(SIGTERM, slirp_exit); - - int maxFD = -1; - - printf("Basilisk Master (%d) is %s\n", gBasiliskMaster, ttyname(gBasiliskMaster)); - printf("Basilisk Slave (%d) is %s\n", gBasiliskSlave, ttyname(gBasiliskSlave)); - - if (gBasiliskMaster>maxFD) maxFD = gBasiliskMaster; - if (gBasiliskSlave>maxFD) maxFD = gBasiliskSlave; - if (gEinsteinMaster>maxFD) maxFD = gEinsteinMaster; - if (gEinsteinSlave>maxFD) maxFD = gEinsteinSlave; - - fd_set readSet; - fd_set writeSet; - fd_set errorSet; - struct timeval timeout; - for (;;) { - // wait for the next event - FD_ZERO(&readSet); - FD_SET(gBasiliskMaster, &readSet); -// FD_SET(gBasiliskSlave, &readSet); - FD_SET(gEinsteinMaster, &readSet); -// FD_SET(gEinsteinSlave, &readSet); - FD_SET(STDIN_FILENO, &readSet); - - FD_ZERO(&writeSet); - - FD_ZERO(&errorSet); - FD_SET(gBasiliskMaster, &errorSet); - FD_SET(gBasiliskSlave, &errorSet); - FD_SET(gEinsteinMaster, &errorSet); - FD_SET(gEinsteinSlave, &errorSet); - - // if (needTimer) { - timeout.tv_sec = 1; - timeout.tv_usec = 0; // one byte at 38400bps serial port speed - // } - ret = select(maxFD+1, &readSet, &writeSet, &errorSet, 0L /* &timeout */); - if (ret==-1) { - perror("\"slect\" failed"); - return 30; - } - printf("+++ select() returned %d fd's\n", ret); - - if (ret==0) { -#if 0 - int flags = 0; - ret = ioctl(gBasiliskMaster, TIOCMGET, &flags); - if (ret==-1) perror("Can't get state"); - printf("%s ", flags&TIOCM_LE ? "DSR" : "dsr"); - printf("%s ", flags&TIOCM_DTR ? "DTR" : "dtr"); - printf("%s ", flags&TIOCM_RTS ? "RTS" : "rts"); - printf("%s ", flags&TIOCM_CTS ? "CTS" : "cts"); - printf("%s ", flags&TIOCM_CAR ? "DCD" : "dcd"); - printf("%s\n", flags&TIOCM_DSR ? "DSR" : "dsr"); - int ldisc = 0; - ret = ioctl(gBasiliskMaster, TIOCGETD, &ldisc); - if (ret==-1) perror("Can't get ldisc"); - printf("%d ", ldisc); - ret = ioctl(gBasiliskSlave, TIOCGETD, &ldisc); - if (ret==-1) perror("Can't get ldisc"); - printf("%d \n", ldisc); - int fd = open(gBasiliskSlaveName, O_RDWR|O_EXCL|O_NONBLOCK); - printf("Open pipe returned %d\n", fd); - if (fd==-1) { - perror("Pipe"); - } else { - printf("Pipe is %s\n", ttyname(fd)); - close(fd); - } - int fd2 = access(gBasiliskPipe, W_OK|R_OK); - if (fd2==-1) { - perror("Pipe"); - } -#endif - struct stat s; - ret = stat(gBasiliskPipe, &s); - if (ret==-1) { - perror("stat"); - } else { - printf("%d %d %d %d\n", s.st_dev, s.st_mode, s.st_flags, s.st_nlink); - } - } - - if (FD_ISSET(STDIN_FILENO, &readSet)) { - char buf[16]; - ssize_t n = read(STDIN_FILENO, buf, 15); - buf[n] = 0; - printf("--- stdin: '%s'\n", buf); - switch (buf[0]) { - case '0': write(gBasiliskSlave, "\0", 1); break; - case '1': - close(gBasiliskSlave); - open(gBasiliskSlaveName, O_RDWR | O_NOCTTY); - break; - case '2': - unlink(gBasiliskPipe); - symlink(gBasiliskPipe, ttyname(gBasiliskMaster)); - break; - case '3': - unlink(gBasiliskPipe); - close(gBasiliskMaster); - close(gBasiliskSlave); - setupBasiliskPipe(); - break; - case '4': - ret = ioctl(gBasiliskMaster, TIOCSTART, 0); - if (ret==-1) perror("ERR1"); - ret = ioctl(gBasiliskSlave, TIOCSTART, 0); - if (ret==-1) perror("ERR1"); - break; - } - } - - if (FD_ISSET(gBasiliskMaster, &readSet)) { - printf("--- gBasiliskMaster readSet\n"); - dumpPacketRead(">", gBasiliskMaster, gEinsteinMaster); - } - - if (FD_ISSET(gBasiliskMaster, &errorSet)) { - printf("--- gBasiliskMaster errorSet\n"); - } - - if (FD_ISSET(gBasiliskSlave, &readSet)) { - printf("--- gBasiliskSlave readSet\n"); - dumpRead("<", gBasiliskSlave, gEinsteinSlave); - } - - if (FD_ISSET(gBasiliskSlave, &errorSet)) { - printf("--- gBasiliskSlave errorSet\n"); - } - - if (FD_ISSET(gEinsteinMaster, &readSet)) { - printf("--- gEinsteinMaster readSet\n"); - dumpRead(">", gEinsteinMaster, gBasiliskMaster); - } - - if (FD_ISSET(gEinsteinMaster, &errorSet)) { - printf("--- gEinsteinMaster errorSet\n"); - } - - if (FD_ISSET(gEinsteinSlave, &readSet)) { - printf("--- gEinsteinSlave readSet\n"); - dumpRead("<", gEinsteinSlave, gBasiliskSlave); - } - - if (FD_ISSET(gEinsteinSlave, &errorSet)) { - printf("--- gEinsteinSlave errorSet\n"); - } - - - } - -#if 0 - int - remove(const char *path); - // insert code here... - - int fd = -1; - - getpt() opens a pseudoterminal master and returns its file descriptor. It is equivalent to - open(/dev/ptmx, O_RDWR | O_NOCTTY); - int posix_openpt(int flags); - // /dev/ptmx , ptm masster, pts slave in /dev/pts/* - char *ptsname(int fd); - int ptsname_r(int fd, char *buf, size_t buflen); - int ret = grantpt(fd); - int unlockpt(int fd); - - int - ttyname_r(int fd, char *buf, size_t len); - /* - #include - - void (*signal(int sig, void (*func)(int)))(int); - - or in the equivalent but easier to read typedef'd version: - - typedef void (*sig_t) (int); - - sig_t - signal(int sig, sig_t func); - - */ - - - int - link(const char *path1, const char *path2); - int - symlink(const char *path1, const char *path2); - int - unlink(const char *path); - - - int - atexit(void (*function)(void)); - - -BasiliskII: - - static int cfmakeraw(struct termios *termios_p) - { - termios_p->c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP|INLCR|IGNCR|ICRNL|IXON); - termios_p->c_oflag &= ~OPOST; - termios_p->c_lflag &= ~(ECHO|ECHONL|ICANON|ISIG|IEXTEN); - termios_p->c_cflag &= ~(CSIZE|PARENB); - termios_p->c_cflag |= CS8; - return 0; - } - - fd = ::open(device_name, O_RDWR); - if (protocol == serial || protocol == pty) { - if (tcgetattr(fd, &mode) < 0) - goto open_error; - cfmakeraw(&mode); - mode.c_cflag |= HUPCL; - mode.c_cc[VMIN] = 1; - mode.c_cc[VTIME] = 0; - tcsetattr(fd, TCSAFLUSH, &mode); - } - - mode.c_cflag &= ~CRTSCTS; - - ?? tcsendbreak(fd, 0); - unsigned int status = TIOCM_DTR; - ioctl(fd, TIOCMBIS, &status); - - unsigned int status = TIOCM_RTS; - ioctl(fd, TIOCMBIS, &status); - - - - switch (code) { - case 1: // KillIO - io_killed = true; - if (protocol == serial) - tcflush(fd, TCIOFLUSH); - while (read_pending || write_pending) <<--- This is where we hang! - usleep(10000); - io_killed = false; - return noErr; - - -#endif - - return 0; -} diff --git a/_Build_/Xcode/Einstein.xcodeproj/project.pbxproj b/_Build_/Xcode/Einstein.xcodeproj/project.pbxproj index d5b0224eb..2035ec9c5 100644 --- a/_Build_/Xcode/Einstein.xcodeproj/project.pbxproj +++ b/_Build_/Xcode/Einstein.xcodeproj/project.pbxproj @@ -105,14 +105,11 @@ C901E52E1326566D0074513E /* TIOException.cp in Sources */ = {isa = PBXBuildFile; fileRef = C99E32BD111B7570002165EC /* TIOException.cp */; }; C901E52F1326566F0074513E /* TMemError.cp in Sources */ = {isa = PBXBuildFile; fileRef = C99E32B8111B7570002165EC /* TMemError.cp */; }; C901E530132656710074513E /* TEOFException.cp in Sources */ = {isa = PBXBuildFile; fileRef = C99E32BB111B7570002165EC /* TEOFException.cp */; }; - C92FC6F5208CDD3600EF4BB1 /* SerialDriver.h in Headers */ = {isa = PBXBuildFile; fileRef = C92FC6F4208CDD3600EF4BB1 /* SerialDriver.h */; }; - C92FC6F7208CDD3600EF4BB1 /* SerialDriver.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C92FC6F6208CDD3600EF4BB1 /* SerialDriver.cpp */; }; C92FC71E209374B600EF4BB1 /* TPipesSerialPortManager.cp in Sources */ = {isa = PBXBuildFile; fileRef = C92FC71B209374B600EF4BB1 /* TPipesSerialPortManager.cp */; }; C92FC71F209374B600EF4BB1 /* TPipesSerialPortManager.cp in Sources */ = {isa = PBXBuildFile; fileRef = C92FC71B209374B600EF4BB1 /* TPipesSerialPortManager.cp */; }; C932824711D0CF0A003B93C3 /* button_network_in.png in Resources */ = {isa = PBXBuildFile; fileRef = C932824511D0CF0A003B93C3 /* button_network_in.png */; }; C932824811D0CF0A003B93C3 /* button_network.png in Resources */ = {isa = PBXBuildFile; fileRef = C932824611D0CF0A003B93C3 /* button_network.png */; }; C932C4C211A1AB5D00F6A7E4 /* TNE2000Card.cp in Sources */ = {isa = PBXBuildFile; fileRef = C932C4C011A1AB5D00F6A7E4 /* TNE2000Card.cp */; }; - C935F77C2099F5F200351905 /* main.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C935F77B2099F5F200351905 /* main.cpp */; }; C935F783209CD68900351905 /* TBasiliskIISerialPortManager.cp in Sources */ = {isa = PBXBuildFile; fileRef = C935F782209CD68900351905 /* TBasiliskIISerialPortManager.cp */; }; C935F784209CD68900351905 /* TBasiliskIISerialPortManager.cp in Sources */ = {isa = PBXBuildFile; fileRef = C935F782209CD68900351905 /* TBasiliskIISerialPortManager.cp */; }; C945F6731E53180C002505E9 /* TBasicSerialPortManager.cp in Sources */ = {isa = PBXBuildFile; fileRef = C945F6711E53180C002505E9 /* TBasicSerialPortManager.cp */; }; @@ -645,15 +642,6 @@ /* End PBXContainerItemProxy section */ /* Begin PBXCopyFilesBuildPhase section */ - C935F7772099F5F200351905 /* CopyFiles */ = { - isa = PBXCopyFilesBuildPhase; - buildActionMask = 2147483647; - dstPath = /usr/share/man/man1/; - dstSubfolderSpec = 0; - files = ( - ); - runOnlyForDeploymentPostprocessing = 1; - }; C98AB2351A351D20001BB1CD /* CopyFiles */ = { isa = PBXCopyFilesBuildPhase; buildActionMask = 2147483647; @@ -683,19 +671,12 @@ 29B97324FDCFA39411CA2CEA /* AppKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AppKit.framework; path = /System/Library/Frameworks/AppKit.framework; sourceTree = ""; }; 29B97325FDCFA39411CA2CEA /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = /System/Library/Frameworks/Foundation.framework; sourceTree = ""; }; 8D1107320486CEB800E47090 /* Einstein.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Einstein.app; sourceTree = BUILT_PRODUCTS_DIR; }; - C92FC6F2208CDD3600EF4BB1 /* SerialDriver.kext */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = SerialDriver.kext; sourceTree = BUILT_PRODUCTS_DIR; }; - C92FC6F4208CDD3600EF4BB1 /* SerialDriver.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SerialDriver.h; sourceTree = ""; }; - C92FC6F6208CDD3600EF4BB1 /* SerialDriver.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = SerialDriver.cpp; sourceTree = ""; }; - C92FC6F8208CDD3600EF4BB1 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; - C92FC71620932ADD00EF4BB1 /* README.txt */ = {isa = PBXFileReference; lastKnownFileType = text; path = README.txt; sourceTree = ""; }; C92FC717209374B500EF4BB1 /* TPipesSerialPortManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TPipesSerialPortManager.h; sourceTree = ""; }; C92FC71B209374B600EF4BB1 /* TPipesSerialPortManager.cp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = TPipesSerialPortManager.cp; sourceTree = ""; }; C932824511D0CF0A003B93C3 /* button_network_in.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = button_network_in.png; sourceTree = ""; }; C932824611D0CF0A003B93C3 /* button_network.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = button_network.png; sourceTree = ""; }; C932C4C011A1AB5D00F6A7E4 /* TNE2000Card.cp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.cpp.cpp; path = TNE2000Card.cp; sourceTree = ""; tabWidth = 4; usesTabs = 1; }; C932C4C111A1AB5D00F6A7E4 /* TNE2000Card.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TNE2000Card.h; sourceTree = ""; }; - C935F7792099F5F200351905 /* BasiliskBridge */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = BasiliskBridge; sourceTree = BUILT_PRODUCTS_DIR; }; - C935F77B2099F5F200351905 /* main.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = main.cpp; sourceTree = ""; }; C935F781209CD67300351905 /* TBasiliskIISerialPortManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TBasiliskIISerialPortManager.h; sourceTree = ""; }; C935F782209CD68900351905 /* TBasiliskIISerialPortManager.cp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = TBasiliskIISerialPortManager.cp; sourceTree = ""; }; C945F6711E53180C002505E9 /* TBasicSerialPortManager.cp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = TBasicSerialPortManager.cp; sourceTree = ""; }; @@ -1145,20 +1126,6 @@ ); runOnlyForDeploymentPostprocessing = 0; }; - C92FC6EE208CDD3600EF4BB1 /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; - C935F7762099F5F200351905 /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; C95E60AC198B76DC004C6CEF /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; @@ -1237,8 +1204,6 @@ C98AB2371A351D20001BB1CD /* retarget */, DA4FF0691A35E73900092B5A /* EinsteinTests.xctest */, DA4BA4051A3A0153002BDB80 /* CLITest */, - C92FC6F2208CDD3600EF4BB1 /* SerialDriver.kext */, - C935F7792099F5F200351905 /* BasiliskBridge */, ); name = Products; sourceTree = ""; @@ -1259,7 +1224,6 @@ C98AB23F1A351D61001BB1CD /* Tools */, C99E3156111B72CC002165EC /* Libraries */, 29B97317FDCFA39411CA2CEA /* Resources */, - C935F77A2099F5F200351905 /* BasiliskBridge */, 29B97323FDCFA39411CA2CEA /* Frameworks */, 19C28FACFE9D520D11CA2CBB /* Products */, ); @@ -1292,31 +1256,11 @@ C92FC686208CDCD800EF4BB1 /* Drivers */ = { isa = PBXGroup; children = ( - C92FC6D8208CDCD800EF4BB1 /* MacOS Serial Driver */, ); name = Drivers; path = ../../Drivers; sourceTree = ""; }; - C92FC6D8208CDCD800EF4BB1 /* MacOS Serial Driver */ = { - isa = PBXGroup; - children = ( - C92FC71620932ADD00EF4BB1 /* README.txt */, - C92FC6F4208CDD3600EF4BB1 /* SerialDriver.h */, - C92FC6F6208CDD3600EF4BB1 /* SerialDriver.cpp */, - C92FC6F8208CDD3600EF4BB1 /* Info.plist */, - ); - path = "MacOS Serial Driver"; - sourceTree = ""; - }; - C935F77A2099F5F200351905 /* BasiliskBridge */ = { - isa = PBXGroup; - children = ( - C935F77B2099F5F200351905 /* main.cpp */, - ); - path = BasiliskBridge; - sourceTree = ""; - }; C962429411B69A6E00EE66F3 /* Network */ = { isa = PBXGroup; children = ( @@ -2082,17 +2026,6 @@ }; /* End PBXGroup section */ -/* Begin PBXHeadersBuildPhase section */ - C92FC6EF208CDD3600EF4BB1 /* Headers */ = { - isa = PBXHeadersBuildPhase; - buildActionMask = 2147483647; - files = ( - C92FC6F5208CDD3600EF4BB1 /* SerialDriver.h in Headers */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXHeadersBuildPhase section */ - /* Begin PBXNativeTarget section */ 2389E9371A1E4D4A0001A8C5 /* iOSEinstein */ = { isa = PBXNativeTarget; @@ -2129,41 +2062,6 @@ productReference = 8D1107320486CEB800E47090 /* Einstein.app */; productType = "com.apple.product-type.application"; }; - C92FC6F1208CDD3600EF4BB1 /* SerialDriver */ = { - isa = PBXNativeTarget; - buildConfigurationList = C92FC6F9208CDD3600EF4BB1 /* Build configuration list for PBXNativeTarget "SerialDriver" */; - buildPhases = ( - C92FC6ED208CDD3600EF4BB1 /* Sources */, - C92FC6EE208CDD3600EF4BB1 /* Frameworks */, - C92FC6EF208CDD3600EF4BB1 /* Headers */, - C92FC6F0208CDD3600EF4BB1 /* Resources */, - ); - buildRules = ( - ); - dependencies = ( - ); - name = SerialDriver; - productName = SerialDriver; - productReference = C92FC6F2208CDD3600EF4BB1 /* SerialDriver.kext */; - productType = "com.apple.product-type.kernel-extension"; - }; - C935F7782099F5F200351905 /* BasiliskBridge */ = { - isa = PBXNativeTarget; - buildConfigurationList = C935F7802099F5F200351905 /* Build configuration list for PBXNativeTarget "BasiliskBridge" */; - buildPhases = ( - C935F7752099F5F200351905 /* Sources */, - C935F7762099F5F200351905 /* Frameworks */, - C935F7772099F5F200351905 /* CopyFiles */, - ); - buildRules = ( - ); - dependencies = ( - ); - name = BasiliskBridge; - productName = BasiliskBridge; - productReference = C935F7792099F5F200351905 /* BasiliskBridge */; - productType = "com.apple.product-type.tool"; - }; C95E603C198B76DC004C6CEF /* EinsteinDev (Matthias) */ = { isa = PBXNativeTarget; buildConfigurationList = C95E60B3198B76DC004C6CEF /* Build configuration list for PBXNativeTarget "EinsteinDev (Matthias)" */; @@ -2244,16 +2142,6 @@ attributes = { LastUpgradeCheck = 0830; TargetAttributes = { - C92FC6F1208CDD3600EF4BB1 = { - CreatedOnToolsVersion = 9.3; - DevelopmentTeam = BK4ST6N599; - ProvisioningStyle = Manual; - }; - C935F7782099F5F200351905 = { - CreatedOnToolsVersion = 9.3; - DevelopmentTeam = BK4ST6N599; - ProvisioningStyle = Automatic; - }; C98AB2361A351D20001BB1CD = { CreatedOnToolsVersion = 6.1.1; }; @@ -2283,8 +2171,6 @@ C98AB2361A351D20001BB1CD /* retarget */, DA4FF0681A35E73900092B5A /* EinsteinTests */, DA4BA4041A3A0153002BDB80 /* CLITest */, - C92FC6F1208CDD3600EF4BB1 /* SerialDriver */, - C935F7782099F5F200351905 /* BasiliskBridge */, ); }; /* End PBXProject section */ @@ -2327,13 +2213,6 @@ ); runOnlyForDeploymentPostprocessing = 0; }; - C92FC6F0208CDD3600EF4BB1 /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; C95E603D198B76DC004C6CEF /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; @@ -2653,22 +2532,6 @@ ); runOnlyForDeploymentPostprocessing = 0; }; - C92FC6ED208CDD3600EF4BB1 /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - C92FC6F7208CDD3600EF4BB1 /* SerialDriver.cpp in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - C935F7752099F5F200351905 /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - C935F77C2099F5F200351905 /* main.cpp in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; C95E604A198B76DC004C6CEF /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; @@ -3265,256 +3128,6 @@ }; name = Release; }; - C92FC6FA208CDD3600EF4BB1 /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - CLANG_ANALYZER_NONNULL = YES; - CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; - CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_ENABLE_OBJC_WEAK = YES; - CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; - CLANG_WARN_COMMA = YES; - CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_DOCUMENTATION_COMMENTS = NO; - CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; - CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; - CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; - CLANG_WARN_STRICT_PROTOTYPES = YES; - CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; - CODE_SIGN_IDENTITY = "Developer ID Application"; - CODE_SIGN_STYLE = Manual; - COMBINE_HIDPI_IMAGES = YES; - COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 1.0.0d1; - DEBUG_INFORMATION_FORMAT = dwarf; - DEVELOPMENT_TEAM = BK4ST6N599; - GCC_C_LANGUAGE_STANDARD = gnu11; - GCC_DYNAMIC_NO_PIC = NO; - GCC_PREPROCESSOR_DEFINITIONS = ( - "DEBUG=1", - "$(inherited)", - ); - GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; - GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - INFOPLIST_FILE = "$(SRCROOT)/../../Drivers/MacOS Serial Driver/Info.plist"; - MACOSX_DEPLOYMENT_TARGET = 10.13; - MODULE_NAME = com.matthiasm.elektriktrick.SerialDriver; - MODULE_VERSION = 1.0.0d1; - MTL_ENABLE_DEBUG_INFO = YES; - PRODUCT_BUNDLE_IDENTIFIER = com.matthiasm.elektriktrick.SerialDriver; - PRODUCT_NAME = "$(TARGET_NAME)"; - PROVISIONING_PROFILE_SPECIFIER = ""; - WRAPPER_EXTENSION = kext; - }; - name = Debug; - }; - C92FC6FB208CDD3600EF4BB1 /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - CLANG_ANALYZER_NONNULL = YES; - CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; - CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_ENABLE_OBJC_WEAK = YES; - CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; - CLANG_WARN_COMMA = YES; - CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_DOCUMENTATION_COMMENTS = NO; - CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; - CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; - CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; - CLANG_WARN_STRICT_PROTOTYPES = YES; - CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; - CODE_SIGN_IDENTITY = "Developer ID Application"; - CODE_SIGN_STYLE = Manual; - COMBINE_HIDPI_IMAGES = YES; - COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 1.0.0d1; - DEVELOPMENT_TEAM = BK4ST6N599; - ENABLE_NS_ASSERTIONS = NO; - GCC_C_LANGUAGE_STANDARD = gnu11; - GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; - GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - INFOPLIST_FILE = "$(SRCROOT)/../../Drivers/MacOS Serial Driver/Info.plist"; - MACOSX_DEPLOYMENT_TARGET = 10.13; - MODULE_NAME = com.matthiasm.elektriktrick.SerialDriver; - MODULE_VERSION = 1.0.0d1; - MTL_ENABLE_DEBUG_INFO = NO; - PRODUCT_BUNDLE_IDENTIFIER = com.matthiasm.elektriktrick.SerialDriver; - PRODUCT_NAME = "$(TARGET_NAME)"; - PROVISIONING_PROFILE_SPECIFIER = ""; - WRAPPER_EXTENSION = kext; - }; - name = Release; - }; - C92FC6FC208CDD3600EF4BB1 /* Distribution */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - CLANG_ANALYZER_NONNULL = YES; - CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; - CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_ENABLE_OBJC_WEAK = YES; - CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; - CLANG_WARN_COMMA = YES; - CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_DOCUMENTATION_COMMENTS = NO; - CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; - CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; - CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; - CLANG_WARN_STRICT_PROTOTYPES = YES; - CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; - CODE_SIGN_IDENTITY = "Developer ID Application"; - CODE_SIGN_STYLE = Manual; - COMBINE_HIDPI_IMAGES = YES; - COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 1.0.0d1; - DEVELOPMENT_TEAM = BK4ST6N599; - ENABLE_NS_ASSERTIONS = NO; - GCC_C_LANGUAGE_STANDARD = gnu11; - GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; - GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - INFOPLIST_FILE = "$(SRCROOT)/../../Drivers/MacOS Serial Driver/Info.plist"; - MACOSX_DEPLOYMENT_TARGET = 10.13; - MODULE_NAME = com.matthiasm.elektriktrick.SerialDriver; - MODULE_VERSION = 1.0.0d1; - MTL_ENABLE_DEBUG_INFO = NO; - PRODUCT_BUNDLE_IDENTIFIER = com.matthiasm.elektriktrick.SerialDriver; - PRODUCT_NAME = "$(TARGET_NAME)"; - PROVISIONING_PROFILE_SPECIFIER = ""; - WRAPPER_EXTENSION = kext; - }; - name = Distribution; - }; - C935F77D2099F5F200351905 /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - CLANG_ANALYZER_NONNULL = YES; - CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; - CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_ENABLE_OBJC_WEAK = YES; - CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; - CLANG_WARN_COMMA = YES; - CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_DOCUMENTATION_COMMENTS = YES; - CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; - CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; - CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; - CLANG_WARN_STRICT_PROTOTYPES = YES; - CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; - CODE_SIGN_IDENTITY = "Mac Developer"; - CODE_SIGN_STYLE = Automatic; - COPY_PHASE_STRIP = NO; - DEBUG_INFORMATION_FORMAT = dwarf; - DEVELOPMENT_TEAM = BK4ST6N599; - GCC_C_LANGUAGE_STANDARD = gnu11; - GCC_DYNAMIC_NO_PIC = NO; - GCC_PREPROCESSOR_DEFINITIONS = ( - "DEBUG=1", - "$(inherited)", - ); - GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; - GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - MACOSX_DEPLOYMENT_TARGET = 10.13; - MTL_ENABLE_DEBUG_INFO = YES; - PRODUCT_NAME = "$(TARGET_NAME)"; - }; - name = Debug; - }; - C935F77E2099F5F200351905 /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - CLANG_ANALYZER_NONNULL = YES; - CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; - CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_ENABLE_OBJC_WEAK = YES; - CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; - CLANG_WARN_COMMA = YES; - CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_DOCUMENTATION_COMMENTS = YES; - CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; - CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; - CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; - CLANG_WARN_STRICT_PROTOTYPES = YES; - CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; - CODE_SIGN_IDENTITY = "Mac Developer"; - CODE_SIGN_STYLE = Automatic; - COPY_PHASE_STRIP = NO; - DEVELOPMENT_TEAM = BK4ST6N599; - ENABLE_NS_ASSERTIONS = NO; - GCC_C_LANGUAGE_STANDARD = gnu11; - GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; - GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - MACOSX_DEPLOYMENT_TARGET = 10.13; - MTL_ENABLE_DEBUG_INFO = NO; - PRODUCT_NAME = "$(TARGET_NAME)"; - }; - name = Release; - }; - C935F77F2099F5F200351905 /* Distribution */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - CLANG_ANALYZER_NONNULL = YES; - CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; - CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_ENABLE_OBJC_WEAK = YES; - CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; - CLANG_WARN_COMMA = YES; - CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_DOCUMENTATION_COMMENTS = YES; - CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; - CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; - CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; - CLANG_WARN_STRICT_PROTOTYPES = YES; - CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; - CODE_SIGN_IDENTITY = "Mac Developer"; - CODE_SIGN_STYLE = Automatic; - COPY_PHASE_STRIP = NO; - DEVELOPMENT_TEAM = BK4ST6N599; - ENABLE_NS_ASSERTIONS = NO; - GCC_C_LANGUAGE_STANDARD = gnu11; - GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; - GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - MACOSX_DEPLOYMENT_TARGET = 10.13; - MTL_ENABLE_DEBUG_INFO = NO; - PRODUCT_NAME = "$(TARGET_NAME)"; - }; - name = Distribution; - }; C95E60B4198B76DC004C6CEF /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { @@ -4124,26 +3737,6 @@ defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; - C92FC6F9208CDD3600EF4BB1 /* Build configuration list for PBXNativeTarget "SerialDriver" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - C92FC6FA208CDD3600EF4BB1 /* Debug */, - C92FC6FB208CDD3600EF4BB1 /* Release */, - C92FC6FC208CDD3600EF4BB1 /* Distribution */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - C935F7802099F5F200351905 /* Build configuration list for PBXNativeTarget "BasiliskBridge" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - C935F77D2099F5F200351905 /* Debug */, - C935F77E2099F5F200351905 /* Release */, - C935F77F2099F5F200351905 /* Distribution */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; C95E60B3198B76DC004C6CEF /* Build configuration list for PBXNativeTarget "EinsteinDev (Matthias)" */ = { isa = XCConfigurationList; buildConfigurations = (