diff --git a/CREDITS.txt b/CREDITS.txt
index a681e5d9e5d2f8c7e2012ec394f1380d2d550f66..dff5142547a5e5e30d15cacb7b49bae6ba79c305 100644
--- a/CREDITS.txt
+++ b/CREDITS.txt
@@ -11,4 +11,5 @@ Ryan LaMothe provided patch for issue #3 (Support of char - mapped to unsigned s
 Ryan LaMothe provided patch for issue #22 (Integrate FindBugs into the Ant build scripts) Feb 18th 2012.
 Ryan LaMothe provided patch for issue #37 (Add Kernel and JNI build support for Applets and JNLP JWS) Feb 18th 2012.
 Oliver Coleman provided patch for issue #64 (Support explicit boolean put and get) Aug 15th 2012
+Steven Libby provided patch for #6 (Allow finer control over fallback mode selection) Aug 21th 2012
 
diff --git a/com.amd.aparapi/src/java/com/amd/aparapi/Kernel.java b/com.amd.aparapi/src/java/com/amd/aparapi/Kernel.java
index 1db1dac020536a03641cbb786b1b55aa88ef82f1..b93a4d7b1a9607f736666c22bae8e165a9d39af9 100644
--- a/com.amd.aparapi/src/java/com/amd/aparapi/Kernel.java
+++ b/com.amd.aparapi/src/java/com/amd/aparapi/Kernel.java
@@ -42,6 +42,9 @@ import java.lang.annotation.RetentionPolicy;
 import java.lang.reflect.Method;
 import java.util.HashMap;
 import java.util.List;
+import java.util.LinkedHashSet;
+import java.util.Arrays;
+import java.util.Iterator;
 import java.util.Map;
 import java.util.concurrent.BrokenBarrierException;
 import java.util.concurrent.CyclicBarrier;
@@ -335,13 +338,15 @@ public abstract class Kernel implements Cloneable{
           }
        }
       */
+
       static EXECUTION_MODE getDefaultExecutionMode() {
          EXECUTION_MODE defaultExecutionMode = OpenCLJNI.getJNI().isOpenCLAvailable() ? GPU : JTP;
          String executionMode = Config.executionMode;
          if (executionMode != null) {
             try {
-               EXECUTION_MODE requestedExecutionMode = valueOf(executionMode.toUpperCase());
-               logger.fine("requested execution mode = " + requestedExecutionMode);
+               EXECUTION_MODE requestedExecutionMode;
+               requestedExecutionMode = getExecutionModeFromString(executionMode).iterator().next();
+               logger.fine("requested execution mode =");
                if ((OpenCLJNI.getJNI().isOpenCLAvailable() && requestedExecutionMode.isOpenCL())
                      || !requestedExecutionMode.isOpenCL()) {
                   defaultExecutionMode = requestedExecutionMode;
@@ -351,24 +356,78 @@ public abstract class Kernel implements Cloneable{
             }
          }
 
-         logger.fine("default execution mode = " + defaultExecutionMode);
+         logger.fine("default execution modes = " + defaultExecutionMode);
 
          return (defaultExecutionMode);
       }
 
+      static LinkedHashSet<EXECUTION_MODE> getDefaultExecutionModes() {
+         LinkedHashSet<EXECUTION_MODE> defaultExecutionModes = new LinkedHashSet<EXECUTION_MODE>();
+         if(OpenCLJNI.getJNI().isOpenCLAvailable()) {
+             defaultExecutionModes.add(GPU);
+             defaultExecutionModes.add(JTP);
+         } else {
+             defaultExecutionModes.add(JTP);
+         }
+         String executionMode = Config.executionMode;
+         if (executionMode != null) {
+            try {
+               LinkedHashSet<EXECUTION_MODE> requestedExecutionModes;
+               requestedExecutionModes = EXECUTION_MODE.getExecutionModeFromString(executionMode);
+               logger.fine("requested execution mode =");
+               for(EXECUTION_MODE mode : requestedExecutionModes) {
+                   logger.fine(" " + mode);
+               }
+               if ((OpenCLJNI.getJNI().isOpenCLAvailable() 
+                     && EXECUTION_MODE.anyOpenCL(requestedExecutionModes))
+                     || !EXECUTION_MODE.anyOpenCL(requestedExecutionModes)) {
+                  defaultExecutionModes = requestedExecutionModes;
+               }
+            } catch (Throwable t) {
+               // we will take the default
+            }
+         }
+
+         logger.fine("default execution modes = " + defaultExecutionModes);
+
+         for(EXECUTION_MODE e : defaultExecutionModes)
+         {
+             logger.warning("SETTING DEFAULT MODE: " + e.toString());
+         }
+
+         return (defaultExecutionModes);
+      }
+
+      static LinkedHashSet<EXECUTION_MODE> getExecutionModeFromString(String executionMode) {
+         LinkedHashSet<EXECUTION_MODE> executionModes = new LinkedHashSet<EXECUTION_MODE>();
+         for(String mode : executionMode.split(",")) {
+             executionModes.add(valueOf(mode.toUpperCase()));
+         }
+         return executionModes;
+      }
+
       static EXECUTION_MODE getFallbackExecutionMode() {
          EXECUTION_MODE defaultFallbackExecutionMode = JTP;
          logger.info("fallback execution mode = " + defaultFallbackExecutionMode);
          return (defaultFallbackExecutionMode);
       }
 
+
+      static boolean anyOpenCL(LinkedHashSet<EXECUTION_MODE> _executionModes) {
+         for(EXECUTION_MODE mode : _executionModes) {
+            if(mode == GPU || mode== CPU) {
+               return true;
+            }
+         }
+         return false;
+      }
+
       boolean isOpenCL() {
          return this == GPU || this == CPU;
       }
 
    };
 
-   private EXECUTION_MODE executionMode = EXECUTION_MODE.getDefaultExecutionMode();
 
    int[] globalId = new int[] {
          0,
@@ -2126,4 +2185,35 @@ public abstract class Kernel implements Cloneable{
       return (kernelRunner.getProfileInfo());
    }
 
+   private LinkedHashSet<EXECUTION_MODE> executionModes = EXECUTION_MODE.getDefaultExecutionModes();
+   private Iterator<EXECUTION_MODE> currentMode = executionModes.iterator();
+   private EXECUTION_MODE executionMode = currentMode.next();
+
+   /**
+    * set possible fallback path for execution modes.
+    * for example setExecutionFallbackPath(GPU,CPU,JTP) will try to use the GPU
+    * if it fails it will fall back to OpenCL CPU and finally it will try JTP.
+    */
+   public void addExecutionModes(EXECUTION_MODE... platforms) {
+      executionModes.addAll(Arrays.asList(platforms));
+      currentMode = executionModes.iterator();
+      executionMode = currentMode.next();
+   }
+
+   /**
+    * @return is there another execution path we can try
+    */
+   public boolean hasNextExecutionMode() {
+      return currentMode.hasNext();
+   }
+
+   /**
+    * try the next execution path in the list if there aren't any more than give up
+    */
+   public void tryNextExecutionMode() {
+      if(currentMode.hasNext()) {
+         executionMode = currentMode.next();
+      }
+   }
+
 }
diff --git a/com.amd.aparapi/src/java/com/amd/aparapi/KernelRunner.java b/com.amd.aparapi/src/java/com/amd/aparapi/KernelRunner.java
index 75e5a9731f7c2c9e0eafe0cb07eb393c8b5d936c..62ac74df1650e42c038f203a5ba8975a71673e7d 100644
--- a/com.amd.aparapi/src/java/com/amd/aparapi/KernelRunner.java
+++ b/com.amd.aparapi/src/java/com/amd/aparapi/KernelRunner.java
@@ -1332,8 +1332,12 @@ class KernelRunner{
    }
 
    synchronized private Kernel fallBackAndExecute(String _entrypointName, final Range _range, final int _passes) {
+      if(kernel.hasNextExecutionMode()) {
+         kernel.tryNextExecutionMode();
+      } else {
+         kernel.setFallbackExecutionMode();
+      }
 
-      kernel.setFallbackExecutionMode();
       return execute(_entrypointName, _range, _passes);
    }