From 6d65cb0461c8ae43edb9d6afce62cce5571bb636 Mon Sep 17 00:00:00 2001 From: Vasily Suvorov Date: Sun, 16 Dec 2018 11:48:13 +0300 Subject: [PATCH] Initial Commit --- LICENSE | 24 ++ README.md | 14 + gcutil.xcodeproj/project.pbxproj | 284 ++++++++++++++++++ .../contents.xcworkspacedata | 7 + .../xcshareddata/IDEWorkspaceChecks.plist | 8 + .../xcdebugger/Breakpoints_v2.xcbkptlist | 5 + .../xcschemes/xcschememanagement.plist | 19 ++ gcutil/GSMux.h | 43 +++ gcutil/GSMux.m | 271 +++++++++++++++++ gcutil/main.m | 56 ++++ 10 files changed, 731 insertions(+) create mode 100644 LICENSE create mode 100644 README.md create mode 100644 gcutil.xcodeproj/project.pbxproj create mode 100644 gcutil.xcodeproj/project.xcworkspace/contents.xcworkspacedata create mode 100644 gcutil.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist create mode 100644 gcutil.xcodeproj/xcuserdata/bazil.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist create mode 100644 gcutil.xcodeproj/xcuserdata/bazil.xcuserdatad/xcschemes/xcschememanagement.plist create mode 100644 gcutil/GSMux.h create mode 100644 gcutil/GSMux.m create mode 100644 gcutil/main.m diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..a2e2d6e --- /dev/null +++ b/LICENSE @@ -0,0 +1,24 @@ +Copyright (c) 2010-2012, Cody Krieger +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of gfxCardStatus nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL CODY KRIEGER BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..6a42ffc --- /dev/null +++ b/README.md @@ -0,0 +1,14 @@ +# gcutil +Graphic cards utility for mac is using to switch discrete or integrated GPU or auto switching mode from CLI of your mac. + +``` +$ gcutil +gcutil - graphic card utility +Usage: gcutil [-d|-i|-a] + -d Force Discrete card + -i Force Integrated card + -a Dynamic switching +Current state: integrated card, dynamic switching mode +``` + +The utility was created on base GUI application [gfxCardStatus](https://github.com/codykrieger/gfxCardStatus) by Cody Krieger. diff --git a/gcutil.xcodeproj/project.pbxproj b/gcutil.xcodeproj/project.pbxproj new file mode 100644 index 0000000..23e944e --- /dev/null +++ b/gcutil.xcodeproj/project.pbxproj @@ -0,0 +1,284 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 48; + objects = { + +/* Begin PBXBuildFile section */ + D1AA848A203EA44D005B720F /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = D1AA8489203EA44D005B720F /* main.m */; }; + D1AA8492203EA49F005B720F /* GSMux.m in Sources */ = {isa = PBXBuildFile; fileRef = D1AA8490203EA49F005B720F /* GSMux.m */; }; +/* End PBXBuildFile section */ + +/* Begin PBXCopyFilesBuildPhase section */ + D1AA8484203EA44D005B720F /* CopyFiles */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = /usr/share/man/man1/; + dstSubfolderSpec = 0; + files = ( + ); + runOnlyForDeploymentPostprocessing = 1; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + D1AA8486203EA44D005B720F /* gcutil */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = gcutil; sourceTree = BUILT_PRODUCTS_DIR; }; + D1AA8489203EA44D005B720F /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; + D1AA8490203EA49F005B720F /* GSMux.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GSMux.m; sourceTree = ""; }; + D1AA8491203EA49F005B720F /* GSMux.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GSMux.h; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + D1AA8483203EA44D005B720F /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + D1AA847D203EA44D005B720F = { + isa = PBXGroup; + children = ( + D1AA8488203EA44D005B720F /* gcutil */, + D1AA8487203EA44D005B720F /* Products */, + ); + sourceTree = ""; + }; + D1AA8487203EA44D005B720F /* Products */ = { + isa = PBXGroup; + children = ( + D1AA8486203EA44D005B720F /* gcutil */, + ); + name = Products; + sourceTree = ""; + }; + D1AA8488203EA44D005B720F /* gcutil */ = { + isa = PBXGroup; + children = ( + D1AA8491203EA49F005B720F /* GSMux.h */, + D1AA8490203EA49F005B720F /* GSMux.m */, + D1AA8489203EA44D005B720F /* main.m */, + ); + path = gcutil; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + D1AA8485203EA44D005B720F /* gcutil */ = { + isa = PBXNativeTarget; + buildConfigurationList = D1AA848D203EA44D005B720F /* Build configuration list for PBXNativeTarget "gcutil" */; + buildPhases = ( + D1AA8482203EA44D005B720F /* Sources */, + D1AA8483203EA44D005B720F /* Frameworks */, + D1AA8484203EA44D005B720F /* CopyFiles */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = gcutil; + productName = gcutil; + productReference = D1AA8486203EA44D005B720F /* gcutil */; + productType = "com.apple.product-type.tool"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + D1AA847E203EA44D005B720F /* Project object */ = { + isa = PBXProject; + attributes = { + LastUpgradeCheck = 0940; + ORGANIZATIONNAME = "Vasily Suvorov"; + TargetAttributes = { + D1AA8485203EA44D005B720F = { + CreatedOnToolsVersion = 9.2; + ProvisioningStyle = Automatic; + }; + }; + }; + buildConfigurationList = D1AA8481203EA44D005B720F /* Build configuration list for PBXProject "gcutil" */; + compatibilityVersion = "Xcode 8.0"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + ); + mainGroup = D1AA847D203EA44D005B720F; + productRefGroup = D1AA8487203EA44D005B720F /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + D1AA8485203EA44D005B720F /* gcutil */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXSourcesBuildPhase section */ + D1AA8482203EA44D005B720F /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + D1AA8492203EA49F005B720F /* GSMux.m in Sources */, + D1AA848A203EA44D005B720F /* main.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin XCBuildConfiguration section */ + D1AA848B203EA44D005B720F /* 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_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = 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_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + CODE_SIGN_IDENTITY = "Mac Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.13; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = macosx; + }; + name = Debug; + }; + D1AA848C203EA44D005B720F /* 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_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = 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_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + CODE_SIGN_IDENTITY = "Mac Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.13; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = macosx; + }; + name = Release; + }; + D1AA848E203EA44D005B720F /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_STYLE = Automatic; + DEVELOPMENT_TEAM = PN29ZGL6D7; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Debug; + }; + D1AA848F203EA44D005B720F /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_STYLE = Automatic; + DEVELOPMENT_TEAM = PN29ZGL6D7; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + D1AA8481203EA44D005B720F /* Build configuration list for PBXProject "gcutil" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + D1AA848B203EA44D005B720F /* Debug */, + D1AA848C203EA44D005B720F /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + D1AA848D203EA44D005B720F /* Build configuration list for PBXNativeTarget "gcutil" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + D1AA848E203EA44D005B720F /* Debug */, + D1AA848F203EA44D005B720F /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = D1AA847E203EA44D005B720F /* Project object */; +} diff --git a/gcutil.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/gcutil.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..e9add9b --- /dev/null +++ b/gcutil.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/gcutil.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/gcutil.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 0000000..18d9810 --- /dev/null +++ b/gcutil.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/gcutil.xcodeproj/xcuserdata/bazil.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist b/gcutil.xcodeproj/xcuserdata/bazil.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist new file mode 100644 index 0000000..fe2b454 --- /dev/null +++ b/gcutil.xcodeproj/xcuserdata/bazil.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist @@ -0,0 +1,5 @@ + + + diff --git a/gcutil.xcodeproj/xcuserdata/bazil.xcuserdatad/xcschemes/xcschememanagement.plist b/gcutil.xcodeproj/xcuserdata/bazil.xcuserdatad/xcschemes/xcschememanagement.plist new file mode 100644 index 0000000..a778dec --- /dev/null +++ b/gcutil.xcodeproj/xcuserdata/bazil.xcuserdatad/xcschemes/xcschememanagement.plist @@ -0,0 +1,19 @@ + + + + + SchemeUserState + + gcutil.xcscheme + + orderHint + 0 + + gcutil.xcscheme_^#shared#^_ + + orderHint + 0 + + + + diff --git a/gcutil/GSMux.h b/gcutil/GSMux.h new file mode 100644 index 0000000..36a3a07 --- /dev/null +++ b/gcutil/GSMux.h @@ -0,0 +1,43 @@ +// +// GSMux.h +// gfxCardStatus +// +// Created by Cody Krieger on 6/21/11. +// Copyright 2011 Cody Krieger. All rights reserved. +// +// Changed for use in a CLI application on 2/22/18 +// by Vasily Suvorov (gbazil@gmail.com) +// + +#import + +#define kDriverClassName "AppleGraphicsControl" + +typedef enum { + GSSwitcherModeForceIntegrated, + GSSwitcherModeForceDiscrete, + GSSwitcherModeDynamicSwitching, + GSSwitcherModeToggleGPU +} GSSwitcherMode; + +@interface GSMux : NSObject + +// Switching driver initialization and cleanup routines. ++ (BOOL)switcherOpen; ++ (void)switcherClose; + ++ (BOOL)setMode:(GSSwitcherMode)mode; + ++ (BOOL)isUsingIntegratedGPU; ++ (BOOL)isUsingDiscreteGPU; ++ (BOOL)isUsingDynamicSwitching; + +// Whether or not a machine is using the old-style "you must log out first" +// switching policy or not. We kick machines into said policy when we switch to +// Integrated Only or Discrete Only for reliability and consistency purposes. ++ (BOOL)isUsingOldStyleSwitchPolicy; + ++ (BOOL)isOnIntegratedOnlyMode; ++ (BOOL)isOnDiscreteOnlyMode; + +@end diff --git a/gcutil/GSMux.m b/gcutil/GSMux.m new file mode 100644 index 0000000..1fc228e --- /dev/null +++ b/gcutil/GSMux.m @@ -0,0 +1,271 @@ +// +// GSMux.m +// gfxCardStatus +// +// Created by Cody Krieger on 6/21/11. +// Copyright 2011 Cody Krieger. All rights reserved. +// +// The following code has been adapted from ah's original version +// (from the MacRumors forums). See switcher.h/m early on in repo history +// for original logic. +// +// Changed for use in a CLI application on 2/22/18 +// by Vasily Suvorov (gbazil@gmail.com) +// + +#import "GSMux.h" + +#define kNewStyleSwitchPolicyValue 0 // dynamic switching +#define kOldStyleSwitchPolicyValue 2 // log out before switching + +static io_connect_t _switcherConnect = IO_OBJECT_NULL; + +// Stuff to look at: +// nvram -p -> gpu_policy +// bootargs: agc=0/1: flags in dmesg +// Compile: gcc -o switcher switcher.c -framework IOKit +// Enable logging to kernel.log: +// Add agclog=10000 agcdebug=4294967295 to com.apple.Boot.plist + +// User client method dispatch selectors. +typedef enum { + kOpen, + kClose, + kSetMuxState, + kGetMuxState, + kSetExclusive, + kDumpState, + kUploadEDID, + kGetAGCData, + kGetAGCData_log1, + kGetAGCData_log2, + kNumberOfMethods +} dispatchSelectors; + +typedef enum { + muxDisableFeature = 0, // set only + muxEnableFeature = 1, // set only + + muxFeatureInfo = 0, // get: returns a uint64_t with bits set according to FeatureInfos, 1=enabled + muxFeatureInfo2 = 1, // get: same as MuxFeatureInfo + + muxForceSwitch = 2, // set: force Graphics Switch regardless of switching mode + // get: always returns 0xdeadbeef + + muxPowerGPU = 3, // set: power down a gpu, pretty useless since you can't power down the igp and the dedicated gpu is powered down automatically + // get: maybe returns powered on graphics cards, 0x8 = integrated, 0x88 = discrete (or probably both, since integrated never gets powered down?) + + muxGpuSelect = 4, // set/get: Dynamic Switching on/off with [2] = 0/1 (the same as if you click the checkbox in systemsettings.app) + + // TODO: Test what happens on older mbps when switchpolicy = 0 + // Changes if you're able to switch in systemsettings.app without logout + muxSwitchPolicy = 5, // set: 0 = dynamic switching, 2 = no dynamic switching, exactly like older mbp switching, 3 = no dynamic stuck, others unsupported + // get: possibly inverted? + + muxUnknown = 6, // get: always 0xdeadbeef + + muxGraphicsCard = 7, // get: returns active graphics card + muxUnknown2 = 8, // get: sometimes 0xffffffff, TODO: figure out what that means +} muxState; + +typedef enum { + Policy, + Auto_PowerDown_GPU, + Dynamic_Switching, + GPU_Powerpolling, // Inverted: Disable Feature enables it and vice versa + Defer_Policy, + Synchronous_Launch, + Backlight_Control=8, + Recovery_Timeouts, + Power_Switch_Debounce, + Logging=16, + Display_Capture_Switch, + No_GL_HDA_busy_idle_registration, + muxFeaturesCount +} muxFeature; + +static BOOL getMuxState(io_connect_t connect, uint64_t input, uint64_t *output) +{ + kern_return_t kernResult; + uint32_t outputCount = 1; + uint64_t scalarI_64[2] = { 1 /* Always 1 (kMuxControl?) */, input /* Feature Info */ }; + + kernResult = IOConnectCallScalarMethod(connect, // an io_connect_t returned from IOServiceOpen(). + kGetMuxState, // selector of the function to be called via the user client. + scalarI_64, // array of scalar (64-bit) input values. + 2, // the number of scalar input values. + output, // array of scalar (64-bit) output values. + &outputCount); // pointer to the number of scalar output values. + + return kernResult == KERN_SUCCESS; +} + +static BOOL setMuxState(io_connect_t connect, muxState state, uint64_t arg) +{ + kern_return_t kernResult; + uint64_t scalarI_64[3] = { 1 /* always? */, (uint64_t) state, arg }; + + kernResult = IOConnectCallScalarMethod(connect, // an io_connect_t returned from IOServiceOpen(). + kSetMuxState, // selector of the function to be called via the user client. + scalarI_64, // array of scalar (64-bit) input values. + 3, // the number of scalar input values. + NULL, // array of scalar (64-bit) output values. + 0); // pointer to the number of scalar output values. + + return kernResult == KERN_SUCCESS; +} + +static BOOL setFeatureInfo(io_connect_t connect, muxFeature feature, BOOL enabled) +{ + return setMuxState(connect, enabled ? muxEnableFeature : muxDisableFeature, 1< +#import "GSMux.h" + +#define HELP "gcutil - graphic card utility\n" \ +"Version 18.02, Vasily Suvorov (gbazil@gmail.com)\n" \ +"Usage: gcutil [-d|-i|-a]\n" \ +"\t-d\tForce Discrete card\n" \ +"\t-i\tForce Integrated card\n" \ +"\t-a\tDynamic switching\n" + +int main(int argc, const char * argv[]) { + @autoreleasepool { + [GSMux switcherOpen]; + + if (argc == 1) { + printf(HELP); + + char *state = ""; + if ([GSMux isUsingIntegratedGPU]) + state = "integrated card"; + if ([GSMux isUsingDiscreteGPU]) + state = "discrete card"; + + char *mode = ", dynamic switching is off"; + if ([GSMux isUsingDynamicSwitching]) + mode = ", dynamic switching mode"; + + printf("Current state: %s%s\n", state, mode); + } else { + if (strcmp(argv[1], "-i") == 0) { + if ([GSMux setMode:GSSwitcherModeForceIntegrated]) + printf("integrated card switched on\n"); + } else if (strcmp(argv[1], "-d") == 0) { + if ([GSMux setMode:GSSwitcherModeForceDiscrete]) + printf("discrete card switched on\n"); + } else if (strcmp(argv[1], "-a") == 0) { + if ([GSMux setMode:GSSwitcherModeDynamicSwitching]) + printf("dynamic switching is on\n"); + } else { + printf(HELP); + } + } + + [GSMux switcherClose]; + } + + return 0; +}