diff --git a/CHANGELOG.md b/CHANGELOG.md
new file mode 100644
--- /dev/null
+++ b/CHANGELOG.md
@@ -0,0 +1,22 @@
+# Revision history for cufft
+
+Notable changes to the project will be documented in this file.
+
+The format is based on [Keep a Changelog](http://keepachangelog.com/) and the
+project adheres to the [Haskell Package Versioning
+Policy (PVP)](https://pvp.haskell.org)
+
+
+## [0.9.0.0] - 2018-03-12
+### Changed
+  * Updated API
+
+### Fixed
+  * Build fix for Cabal-2.2 (ghc-8.4)
+
+## 0.8.0.0 - 2017-08-24
+  * _No change log recorded at this point_
+
+
+[0.9.0.0]:          https://github.com/tmcdonell/cufft/compare/release/0.8.0.0...0.9.0.0
+
diff --git a/Foreign/CUDA/FFT.hs b/Foreign/CUDA/FFT.hs
--- a/Foreign/CUDA/FFT.hs
+++ b/Foreign/CUDA/FFT.hs
@@ -1,15 +1,54 @@
+-- |
+-- Module      : Foreign.CUDA.FFT
+-- Copyright   : [2013..2018] Robert Clifton-Everest, Trevor L. McDonell
+-- License     : BSD
+--
+-- Maintainer  : Trevor L. McDonell <tmcdonell@cse.unsw.edu.au>
+-- Stability   : experimental
+-- Portability : non-portable (GHC extensions)
+--
+-- The cuFFT library is an implementation of Fast Fourier Transform (FFT)
+-- operations for NVIDIA GPUs.
+--
+-- The FFT is a divide-and-conquer algorithm for efficiently computing discrete
+-- Fourier transforms of real- or complex-valued data sets. It is one of the
+-- most important and widely used numerical algorithms in computational physics
+-- and general signals processing. The cuFFT library provides a simple interface
+-- for computing FFTs on a NVIDIA GPU.
+--
+-- To use operations from the cuFFT library, the user must allocate the required
+-- arrays in the GPU memory space, fill them with data, call the desired
+-- sequence of cuFFT library functions, then copy the results from the GPU
+-- memory back to the host.
+--
+-- The <http://hackage.haskell.org/package/cuda cuda> package can be used for
+-- writing to and retrieving data from the GPU.
+--
+-- [/Example/]
+--
+-- _TODO_
+--
+-- [/Additional information/]
+--
+-- For more information, see the NVIDIA cuFFT documentation:
+--
+-- <http://docs.nvidia.com/cuda/cufft/index.html>
+--
 
 module Foreign.CUDA.FFT (
 
+  -- * Control
+  module Foreign.CUDA.FFT.Plan,
+  module Foreign.CUDA.FFT.Stream,
   module Foreign.CUDA.FFT.Error,
+
+  -- * Operations
   module Foreign.CUDA.FFT.Execute,
-  module Foreign.CUDA.FFT.Plan,
-  module Foreign.CUDA.FFT.Stream
 
 ) where
 
-import Foreign.CUDA.FFT.Error
+import Foreign.CUDA.FFT.Error                                       ( CUFFTException(..) )
 import Foreign.CUDA.FFT.Execute
-import Foreign.CUDA.FFT.Plan
+import Foreign.CUDA.FFT.Plan                                        hiding ( useHandle )
 import Foreign.CUDA.FFT.Stream
 
diff --git a/Foreign/CUDA/FFT/Error.chs b/Foreign/CUDA/FFT/Error.chs
--- a/Foreign/CUDA/FFT/Error.chs
+++ b/Foreign/CUDA/FFT/Error.chs
@@ -1,25 +1,40 @@
 {-# LANGUAGE CPP                      #-}
 {-# LANGUAGE DeriveDataTypeable       #-}
 {-# LANGUAGE ForeignFunctionInterface #-}
+-- |
+-- Module      : Foreign.CUDA.FFT.Error
+-- Copyright   : [2013..2018] Robert Clifton-Everest, Trevor L. McDonell
+-- License     : BSD3
+--
+-- Maintainer  : Trevor L. McDonell <tmcdonell@cse.unsw.edu.au>
+-- Stability   : experimental
+-- Portability : non-portable (GHC extensions)
+--
 
 module Foreign.CUDA.FFT.Error
   where
 
--- System
-import Data.Typeable
+-- friends
+import Foreign.CUDA.FFT.Internal.C2HS
+
+-- system
 import Control.Exception
+import Data.Typeable
+import Foreign.C.Types
 
 #include <cbits/wrap.h>
 {# context lib="cufft" #}
 
 
--- Error codes -----------------------------------------------------------------
+-- | Error codes used by cuFFT library functions
 --
+-- <http://docs.nvidia.com/cuda/cufft/index.html#cufftresult>
+--
 {# enum cufftResult as Result
   { underscoreToCase }
   with prefix="CUFFT" deriving (Eq, Show) #}
 
--- Describe each error code
+-- | Describe an error code
 --
 describe :: Result -> String
 describe Success                 = "success"
@@ -70,6 +85,7 @@
 -- | Return the results of a function on successful execution, otherwise throw
 -- an exception with an error string associated with the return code
 --
+{-# INLINE resultIfOk #-}
 resultIfOk :: (Result, a) -> IO a
 resultIfOk (status,result) =
     case status of
@@ -80,9 +96,14 @@
 -- | Throw an exception with an error string associated with an unsuccessful
 -- return code, otherwise return unit.
 --
+{-# INLINE nothingIfOk #-}
 nothingIfOk :: Result -> IO ()
 nothingIfOk status =
     case status of
         Success -> return  ()
         _       -> throwIO (ExitCode status)
+
+{-# INLINE checkStatus #-}
+checkStatus :: CInt -> IO ()
+checkStatus = nothingIfOk . cToEnum
 
diff --git a/Foreign/CUDA/FFT/Execute.chs b/Foreign/CUDA/FFT/Execute.chs
--- a/Foreign/CUDA/FFT/Execute.chs
+++ b/Foreign/CUDA/FFT/Execute.chs
@@ -1,102 +1,172 @@
 {-# LANGUAGE CPP                      #-}
 {-# LANGUAGE ForeignFunctionInterface #-}
+-- |
+-- Module      : Foreign.CUDA.FFT.Execute
+-- Copyright   : [2013..2018] Robert Clifton-Everest, Trevor L. McDonell
+-- License     : BSD3
+--
+-- Maintainer  : Trevor L. McDonell <tmcdonell@cse.unsw.edu.au>
+-- Stability   : experimental
+-- Portability : non-portable (GHC extensions)
+--
 
 module Foreign.CUDA.FFT.Execute (
-  execC2C,execZ2Z,
-  execR2C,execD2Z,
-  execC2R,execZ2D,
+
+  Mode(..),
+
+  execC2C, execZ2Z,
+  execR2C, execD2Z,
+  execC2R, execZ2D,
+
 ) where
 
--- Friends
+-- friends
 import Foreign.CUDA.FFT.Error
 import Foreign.CUDA.FFT.Plan
 import Foreign.CUDA.FFT.Internal.C2HS
 
 import Foreign.CUDA.Ptr
 
--- System
+-- system
 import Foreign
 import Foreign.C
+import Data.Complex
 
 #include <cbits/wrap.h>
 {# context lib="cufft" #}
 
--- | Executes a single-precision complex-to-complex transform plan in the
--- transform direction specified by the fourth argument
+#c
+typedef enum cufftMode_enum {
+    CUFFT_MODE_FORWARD = CUFFT_FORWARD,
+    CUFFT_MODE_INVERSE = CUFFT_INVERSE
+} cufftMode;
+#endc
+
+-- | FFT transform direction
 --
-execC2C :: Handle -> DevicePtr Float -> DevicePtr Float -> Int -> IO ()
-execC2C ctx i o dir = nothingIfOk =<< cufftExecC2C ctx i o dir
+{# enum cufftMode as Mode
+  { underscoreToCase }
+  with prefix="CUFFT_MODE" deriving (Eq, Show, Bounded) #}
 
-{# fun unsafe cufftExecC2C
-  { useHandle  `Handle'
-  , useDev     `DevicePtr Float'
-  , useDev     `DevicePtr Float'
-  ,            `Int'             } -> `Result' cToEnum #}
-  where
-    useDev      = useDevicePtr . castDevPtr
 
--- | Executes a double-precision complex-to-complex transform plan in the
--- transform direction specified by the fourth argument
+-- | Executes a single-precision complex-to-complex transform.
 --
-execZ2Z :: Handle -> DevicePtr Double -> DevicePtr Double -> Int -> IO ()
-execZ2Z ctx i o dir = nothingIfOk =<< cufftExecZ2Z ctx i o dir
+-- If the input and output device pointers are the same, an in-place transform
+-- is executed.
+--
+-- <http://docs.nvidia.com/cuda/cufft/index.html#function-cufftexecc2c-cufftexecz2z>
+--
+{-# INLINEABLE execC2C #-}
+execC2C
+    :: Handle                     -- ^ plan handle, of type 'C2C'
+    -> Mode                       -- ^ transform direction
+    -> DevicePtr (Complex Float)  -- ^ input data
+    -> DevicePtr (Complex Float)  -- ^ output data
+    -> IO ()
+execC2C hdl dir i o = cufftExecC2C hdl i o dir
+  where
+    {# fun unsafe cufftExecC2C
+      { useHandle     `Handle'
+      , useDevicePtr' `DevicePtr (Complex Float)'
+      , useDevicePtr' `DevicePtr (Complex Float)'
+      , cFromEnum     `Mode'
+      }
+      -> `()' checkStatus*- #}
 
-{# fun unsafe cufftExecZ2Z
-  { useHandle  `Handle'
-  , useDev     `DevicePtr Double'
-  , useDev     `DevicePtr Double'
-  ,            `Int'             } -> `Result' cToEnum #}
+
+-- | Executes a double-precision complex-to-complex transform.
+--
+-- If the input and output device pointers are the same, an in-place transform
+-- is executed.
+--
+-- <http://docs.nvidia.com/cuda/cufft/index.html#function-cufftexecc2c-cufftexecz2z>
+--
+{-# INLINEABLE execZ2Z #-}
+execZ2Z
+    :: Handle                     -- ^ plan handle, of type 'Z2Z'
+    -> Mode                       -- ^ transform direction
+    -> DevicePtr (Complex Double) -- ^ input data
+    -> DevicePtr (Complex Double) -- ^ output data
+    -> IO ()
+execZ2Z hdl dir i o = cufftExecZ2Z hdl i o dir
   where
-    useDev      = useDevicePtr . castDevPtr
+    {# fun unsafe cufftExecZ2Z
+      { useHandle     `Handle'
+      , useDevicePtr' `DevicePtr (Complex Double)'
+      , useDevicePtr' `DevicePtr (Complex Double)'
+      , cFromEnum     `Mode'
+      }
+      -> `()' checkStatus*- #}
 
--- | Executes a single-precision real-to-complex (implicitly forward)
--- transform plan
+
+-- | Executes a single-precision real-to-complex, implicitly forward, transform.
 --
-execR2C :: Handle -> DevicePtr Float -> DevicePtr Float -> IO ()
-execR2C ctx i o = nothingIfOk =<< cufftExecR2C ctx i o
+-- If the input and output device pointers refer to the same address, an
+-- in-place transform is executed.
+--
+-- <http://docs.nvidia.com/cuda/cufft/index.html#function-cufftexecr2c-cufftexecd2z>
+--
+{-# INLINEABLE execR2C #-}
+{# fun unsafe cufftExecR2C as execR2C
+  { useHandle     `Handle'                      -- ^ plan handle, of type 'R2C'
+  , useDevicePtr' `DevicePtr Float'             -- ^ input data
+  , useDevicePtr' `DevicePtr (Complex Float)'   -- ^ output data
+  }
+  -> `()' checkStatus*- #}
 
-{# fun unsafe cufftExecR2C
-  { useHandle  `Handle'
-  , useDev     `DevicePtr Float'
-  , useDev     `DevicePtr Float' } -> `Result' cToEnum #}
-  where
-    useDev      = useDevicePtr . castDevPtr
 
--- | Executes a double-precision real-to-complex (implicitly forward)
--- transform plan
+-- | Executes a double-precision real-to-complex, implicitly forward, transform.
 --
-execD2Z :: Handle -> DevicePtr Double -> DevicePtr Double -> IO ()
-execD2Z ctx i o = nothingIfOk =<< cufftExecD2Z ctx i o
+-- If the input and output device pointers refer to the same address, an
+-- in-place transform is executed.
+--
+-- <http://docs.nvidia.com/cuda/cufft/index.html#function-cufftexecr2c-cufftexecd2z>
+--
+{-# INLINEABLE execD2Z #-}
+{# fun unsafe cufftExecD2Z as execD2Z
+  { useHandle     `Handle'                      -- ^ plan handle, of type 'D2Z'
+  , useDevicePtr' `DevicePtr Double'            -- ^ input data
+  , useDevicePtr' `DevicePtr (Complex Double)'  -- ^ output data
+  }
+  -> `()' checkStatus*- #}
 
-{# fun unsafe cufftExecD2Z
-  { useHandle  `Handle'
-  , useDev     `DevicePtr Double'
-  , useDev     `DevicePtr Double' } -> `Result' cToEnum #}
-  where
-    useDev      = useDevicePtr . castDevPtr
 
--- | Executes a single-precision complex-to-real (implicitly forward)
--- transform plan
+-- | Executes a single-precision complex-to-real, implicitly forward, transform.
 --
-execC2R :: Handle -> DevicePtr Float -> DevicePtr Float -> IO ()
-execC2R ctx i o = nothingIfOk =<< cufftExecC2R ctx i o
+-- If the input and output device pointers refer to the same address, an
+-- in-place transform is executed.
+--
+-- <http://docs.nvidia.com/cuda/cufft/index.html#function-cufftexecc2r-cufftexecz2d>
+--
+{-# INLINEABLE execC2R #-}
+{# fun unsafe cufftExecC2R as execC2R
+  { useHandle     `Handle'                      -- ^ plan handle, of type 'C2R'
+  , useDevicePtr' `DevicePtr (Complex Float)'   -- ^ input data
+  , useDevicePtr' `DevicePtr Float'             -- ^ output data
+  }
+  -> `()' checkStatus*- #}
 
-{# fun unsafe cufftExecC2R
-  { useHandle  `Handle'
-  , useDev     `DevicePtr Float'
-  , useDev     `DevicePtr Float' } -> `Result' cToEnum #}
-  where
-    useDev      = useDevicePtr . castDevPtr
 
--- | Executes a double-precision complex-to-real (implicitly forward)
--- transform plan
+-- | Executes a double-precision complex-to-real, implicitly forward, transform.
 --
-execZ2D :: Handle -> DevicePtr Double -> DevicePtr Double -> IO ()
-execZ2D ctx i o = nothingIfOk =<< cufftExecZ2D ctx i o
+-- If the input and output device pointers refer to the same address, an
+-- in-place transform is executed.
+--
+-- <http://docs.nvidia.com/cuda/cufft/index.html#function-cufftexecc2r-cufftexecz2d>
+--
+{-# INLINEABLE execZ2D #-}
+{# fun unsafe cufftExecZ2D as execZ2D
+  { useHandle     `Handle'                      -- ^ plan handle, of type 'Z2D'
+  , useDevicePtr' `DevicePtr (Complex Double)'  -- ^ input data
+  , useDevicePtr' `DevicePtr Double'            -- ^ output data
+  }
+  -> `()' checkStatus*- #}
 
-{# fun unsafe cufftExecZ2D
-  { useHandle  `Handle'
-  , useDev     `DevicePtr Double'
-  , useDev     `DevicePtr Double' } -> `Result' cToEnum #}
-  where
-    useDev      = useDevicePtr . castDevPtr
+
+-- c2hs treats pointers to complex values as 'Ptr ()' (they are structs on the
+-- C side) and uses 'CFloat' instead of 'Float', etc.
+--
+{-# INLINE useDevicePtr' #-}
+useDevicePtr' :: DevicePtr a -> Ptr b
+useDevicePtr' = castPtr . useDevicePtr
+
diff --git a/Foreign/CUDA/FFT/Internal/C2HS.hs b/Foreign/CUDA/FFT/Internal/C2HS.hs
--- a/Foreign/CUDA/FFT/Internal/C2HS.hs
+++ b/Foreign/CUDA/FFT/Internal/C2HS.hs
@@ -1,3 +1,12 @@
+-- |
+-- Module      : Foreign.CUDA.FFT.Internal.C2HS
+-- Copyright   : [2013..2018] Robert Clifton-Everest, Trevor L. McDonell
+-- License     : BSD3
+--
+-- Maintainer  : Trevor L. McDonell <tmcdonell@cse.unsw.edu.au>
+-- Stability   : experimental
+-- Portability : non-portable (GHC extensions)
+--
 
 module Foreign.CUDA.FFT.Internal.C2HS (
 
diff --git a/Foreign/CUDA/FFT/Plan.chs b/Foreign/CUDA/FFT/Plan.chs
--- a/Foreign/CUDA/FFT/Plan.chs
+++ b/Foreign/CUDA/FFT/Plan.chs
@@ -1,9 +1,17 @@
 {-# LANGUAGE CPP                      #-}
 {-# LANGUAGE ForeignFunctionInterface #-}
+-- |
+-- Module      : Foreign.CUDA.FFT.Plan
+-- Copyright   : [2013..2018] Robert Clifton-Everest, Trevor L. McDonell
+-- License     : BSD3
+--
+-- Maintainer  : Trevor L. McDonell <tmcdonell@cse.unsw.edu.au>
+-- Stability   : experimental
+-- Portability : non-portable (GHC extensions)
+--
 
 module Foreign.CUDA.FFT.Plan (
 
-  -- * Context
   Handle(..),
   Type(..),
   plan1D,
@@ -28,10 +36,27 @@
 {# context lib="cufft" #}
 
 
--- | Operations handle
+-- | A handle used to store and access cuFFT plans.
 --
+-- A handle is created by the FFT planning functions (e.g. 'plan1D') and used
+-- during execution of the transforms (e.g. 'Foreign.CUDA.FFT.Execute.execC2C').
+--
+-- The handle may be reused, but should be 'destroy'ed once it is no longer
+-- required, in order to release associated GPU memory and other resources.
+--
 newtype Handle = Handle { useHandle :: {# type cufftHandle #}}
 
+
+-- | The cuFFT library supports complex- and real-valued transforms. This data
+-- type enumerates the kind of transform a plan will execute.
+--
+-- Key:
+--
+--   * __R__: real (32-bit float)
+--   * __D__: double (64-bit float)
+--   * __C__: single-precision complex numbers (32-bit, interleaved)
+--   * __Z__: double-precision complex numbers (64-bit, interleaved)
+--
 {# enum cufftType as Type
   {}
   with prefix="CUFFT" deriving (Eq, Show) #}
@@ -39,89 +64,115 @@
 -- Context management ----------------------------------------------------------
 --
 
--- | Creates a 1D FFT plan configuration for a specified signal size and data type.
--- The third argument tells CUFFT how many 1D transforms to configure.
---
-plan1D :: Int -> Type -> Int -> IO Handle
-plan1D nx t batch = resultIfOk =<< cufftPlan1d nx t batch
+-- |
 
-{# fun unsafe cufftPlan1d
+-- | Creates a 1D FFT plan configured for a specified signal size and data type.
+--
+-- The third argument tells cuFFT how many 1D transforms, of size given by the
+-- first argument, to configure. Consider using 'planMany' for multiple
+-- transforms instead.
+--
+-- <http://docs.nvidia.com/cuda/cufft/index.html#function-cufftplan1d>
+--
+{-# INLINEABLE plan1D #-}
+{# fun unsafe cufftPlan1d as plan1D
   { alloca-   `Handle' peekHdl*
-  ,           `Int'
-  , cFromEnum `Type'
-  ,           `Int'             } -> `Result' cToEnum #}
+  ,           `Int'               -- ^ Size of the transformation
+  , cFromEnum `Type'              -- ^ Transformation data type
+  ,           `Int'               -- ^ Number of one-dimensional transforms to configure
+  }
+  -> `()' checkStatus*- #}
   where
     peekHdl = liftM Handle . peek
 
+
 -- | Creates a 2D FFT plan configuration for a specified signal size and data type.
 --
-plan2D :: Int -> Int -> Type -> IO Handle
-plan2D nx ny t = resultIfOk =<< cufftPlan2d nx ny t
-
-{# fun unsafe cufftPlan2d
+-- <http://docs.nvidia.com/cuda/cufft/index.html#function-cufftplan2d>
+--
+{-# INLINEABLE plan2D #-}
+{# fun unsafe cufftPlan2d as plan2D
   { alloca-   `Handle' peekHdl*
-  ,           `Int'
-  ,           `Int'
-  , cFromEnum `Type'            } -> `Result' cToEnum #}
+  ,           `Int'               -- ^ The transform size in the /x/-dimension. This is the slowest changing dimension of a transform (strided in memory)
+  ,           `Int'               -- ^ The transform size in the /y/-dimension. This is the fastest changing dimension of a transform (contiguous in memory)
+  , cFromEnum `Type'              -- ^ Transformation data type
+  }
+  -> `()' checkStatus*- #}
   where
     peekHdl = liftM Handle . peek
 
+
 -- | Creates a 3D FFT plan configuration for a specified signal size and data type.
 --
-plan3D :: Int -> Int -> Int -> Type -> IO Handle
-plan3D nx ny nz t = resultIfOk =<< cufftPlan3d nx ny nz t
-
-{# fun unsafe cufftPlan3d
+-- <http://docs.nvidia.com/cuda/cufft/index.html#function-cufftplan3d>
+--
+{-# INLINEABLE plan3D #-}
+{# fun unsafe cufftPlan3d as plan3D
   { alloca-   `Handle' peekHdl*
-  ,           `Int'
-  ,           `Int'
-  ,           `Int'
-  , cFromEnum `Type'            } -> `Result' cToEnum #}
+  ,           `Int'               -- ^ The transform size in the /x/-dimension. This is the slowest changing dimension of the transform (strided in memory)
+  ,           `Int'               -- ^ The transform size in the /y/-dimension.
+  ,           `Int'               -- ^ The transform size in the /z/-dimension. This is the fastest changing dimension of the transform (contiguous in memory)
+  , cFromEnum `Type'              -- ^ Transformation data type
+  }
+  -> `()' checkStatus*- #}
   where
     peekHdl = liftM Handle . peek
 
--- | Creates a batched plan configuration for many signals of a specified size in
--- either 1, 2 or 3 dimensions, and of the specified data type.
+
+-- | Creates a batched plan configuration for many signals of a specified size
+-- and data type in either 1, 2 or 3 dimensions.
 --
-planMany :: [Int]                   -- ^ The size of each dimension
-         -> Maybe ([Int], Int, Int) -- ^ Storage dimensions of the output data,
-                                    -- the stride, and the distance between
-                                    -- signals for the input data
-         -> Maybe ([Int], Int, Int) -- ^ As above but for the output data
-         -> Type                    -- ^ The type of the transformation.
-         -> Int                     -- ^ The batch size (either 1, 2 or 3)
+-- This function supports more complicated input and output data layouts. If not
+-- specified (that is, 'Nothing' is passed for either of the second or third
+-- parameters), contiguous data arrays are assumed.
+--
+-- Data layout configuration consists of three fields, respectively:
+--
+--   * storage dimensions of the input data in memory
+--   * the distance between two successive input elements in the innermost (least significant) dimension
+--   * the distance between the first element of two consecutive signals in a batch of the input data
+--
+-- <http://docs.nvidia.com/cuda/cufft/index.html#function-cufftplanmany>
+--
+planMany :: [Int]                   -- ^ The size of the transform in each dimension, where @(n !! 0)@ is the size of the outermost dimension, and @(n !! rank-1)@ the size of the innermost (contiguous) dimension of the transform.
+         -> Maybe ([Int], Int, Int) -- ^ Input data layout. If 'Nothing', the data is assumed to be contiguous.
+         -> Maybe ([Int], Int, Int) -- ^ Output data layout. If 'Nothing', the data is stored contiguously.
+         -> Type                    -- ^ Transformation type
+         -> Int                     -- ^ Batch size for this transform
          -> IO Handle
-planMany n ilayout olayout t batch
-  = do
-      let (inembed, istride, idist) = fromMaybe ([], 0, 0) ilayout
-      let (onembed, ostride, odist) = fromMaybe ([], 0, 0) olayout
-      resultIfOk =<< cufftPlanMany (length n) n inembed istride idist onembed ostride odist t batch
-
-{# fun unsafe cufftPlanMany
-  { alloca-   `Handle' peekHdl*
-  ,           `Int'
-  , asArray *  `[Int]'
-  , asArray *  `[Int]'
-  ,           `Int'
-  ,           `Int'
-  , asArray *  `[Int]'
-  ,           `Int'
-  ,           `Int'
-  , cFromEnum `Type'
-  ,           `Int'} -> `Result' cToEnum #}
+planMany n ilayout olayout t batch =
+  cufftPlanMany (length n) n inembed istride idist onembed ostride odist t batch
   where
+    (inembed, istride, idist) = fromMaybe ([], 0, 0) ilayout
+    (onembed, ostride, odist) = fromMaybe ([], 0, 0) olayout
+
     peekHdl = liftM Handle . peek
+
     asArray [] f = f nullPtr
     asArray xs f = withArray (map fromIntegral xs) f
 
--- | This function releases hardware resources used by the CUFFT plan. The
--- release of GPU resources may be deferred until the application exits. This
--- function is usually the last call with a particular handle to the CUFFT
--- plan.
---
-destroy :: Handle -> IO ()
-destroy ctx = nothingIfOk =<< cufftDestroy ctx
+    {# fun unsafe cufftPlanMany
+      { alloca-   `Handle' peekHdl*
+      ,           `Int'
+      , asArray*  `[Int]'
+      , asArray*  `[Int]'
+      ,           `Int'
+      ,           `Int'
+      , asArray*  `[Int]'
+      ,           `Int'
+      ,           `Int'
+      , cFromEnum `Type'
+      ,           `Int'
+      }
+      -> `()' checkStatus*- #}
 
-{# fun unsafe cufftDestroy
-  { useHandle `Handle' } -> `Result' cToEnum #}
+
+-- | Release resources associated with the given plan. This function should be
+-- called once a plan is no longer needed, to avoid wasting GPU memory.
+--
+-- <http://docs.nvidia.com/cuda/cufft/index.html#function-cufftdestroy>
+--
+{-# INLINEABLE destroy #-}
+{# fun unsafe cufftDestroy as destroy
+  { useHandle `Handle' } -> `()' checkStatus*- #}
 
diff --git a/Foreign/CUDA/FFT/Stream.chs b/Foreign/CUDA/FFT/Stream.chs
--- a/Foreign/CUDA/FFT/Stream.chs
+++ b/Foreign/CUDA/FFT/Stream.chs
@@ -1,9 +1,18 @@
 {-# LANGUAGE CPP                      #-}
 {-# LANGUAGE ForeignFunctionInterface #-}
+-- |
+-- Module      : Foreign.CUDA.FFT.Stream
+-- Copyright   : [2013..2018] Robert Clifton-Everest, Trevor L. McDonell
+-- License     : BSD3
+--
+-- Maintainer  : Trevor L. McDonell <tmcdonell@cse.unsw.edu.au>
+-- Stability   : experimental
+-- Portability : non-portable (GHC extensions)
+--
 
 module Foreign.CUDA.FFT.Stream (
 
-  -- * Streamed transforms
+  Stream,
   setStream,
 
 ) where
@@ -21,15 +30,22 @@
 #include <cbits/wrap.h>
 {# context lib="cufft" #}
 
--- | Associates a CUDA stream with a CUFFT plan. All kernel launches made during
--- plan execution are now done through the associated stream, enabling overlap
--- with activity in other streams (e.g. data copying). The association remains
--- until the plan is destroyed or the stream is changed.
---
-setStream :: Handle -> Stream -> IO ()
-setStream ctx st = nothingIfOk =<< cufftSetStream ctx st
 
-{# fun unsafe cufftSetStream
+-- | Set the execution stream which all subsequent cuFFT library functions will
+-- execute with. This enables the activity in this execution stream (e.g. kernel
+-- launches and data transfer) to overlap with activity in other execution
+-- streams. The association remains until the plan is destroyed or the stream is
+-- changed.
+--
+-- If not set, functions execute in the default stream, which never overlaps
+-- with any other operation.
+--
+-- <http://docs.nvidia.com/cuda/cufft/index.html#function-cufftsetstream>
+--
+{-# INLINEABLE setStream #-}
+{# fun unsafe cufftSetStream as setStream
   { useHandle `Handle'
-  , useStream `Stream' } -> `Result' cToEnum #}
+  , useStream `Stream'
+  }
+  -> `()' checkStatus*- #}
 
diff --git a/README.md b/README.md
--- a/README.md
+++ b/README.md
@@ -1,18 +1,19 @@
 Haskell FFI Bindings to CUDA FFT
 ================================
 
-[![Build Status](https://travis-ci.org/robeverest/cufft.svg)](https://travis-ci.org/robeverest/cufft)
+[![Travis build status](https://img.shields.io/travis/tmcdonell/cufft/master.svg?label=linux)](https://travis-ci.org/tmcdonell/cufft)
+[![AppVeyor build status](https://img.shields.io/appveyor/ci/tmcdonell/cufft/master.svg?label=windows)](https://ci.appveyor.com/project/tmcdonell/cufft)
+[![Stackage LTS](https://stackage.org/package/cufft/badge/lts)](https://stackage.org/lts/package/cufft)
+[![Stackage Nightly](https://stackage.org/package/cufft/badge/nightly)](https://stackage.org/nightly/package/cufft)
+[![Hackage](https://img.shields.io/hackage/v/cufft.svg)](https://hackage.haskell.org/package/cufft)
 
-The CUFFT library provides high performance implementations of Fast Fourier
+The cuFFT library provides high performance implementations of Fast Fourier
 Transform (FFT) operations on NVIDIA GPUs. This is a collection of bindings to
 allow you to call those functions from Haskell. You will need to install the
 CUDA driver and developer toolkit.
 
-[http://developer.nvidia.com/cuda-downloads][cuda]
+  <https://developer.nvidia.com/cuda-toolkit>
 
 The configure script will look for your CUDA installation in the standard
 places, and if the `nvcc` compiler is found in your `PATH`, relative to that.
-
-[cuda]: http://developer.nvidia.com/object/cuda.html
-
 
diff --git a/Setup.hs b/Setup.hs
--- a/Setup.hs
+++ b/Setup.hs
@@ -9,7 +9,6 @@
 #endif
 
 import Distribution.PackageDescription
-import Distribution.PackageDescription.Parse
 import Distribution.Simple
 import Distribution.Simple.BuildPaths
 import Distribution.Simple.Command
@@ -27,6 +26,11 @@
 import Distribution.PackageDescription.PrettyPrint
 import Distribution.Version
 #endif
+#if MIN_VERSION_Cabal(2,2,0)
+import Distribution.PackageDescription.Parsec
+#else
+import Distribution.PackageDescription.Parse
+#endif
 
 import Control.Applicative
 import Control.Exception
@@ -172,7 +176,7 @@
 updateLibraryRPATHs verbosity (Platform _ os) sharedLib extraLibDirs' =
   when (os == OSX) $ do
     exists <- doesFileExist sharedLib
-    unless exists $ die $ printf "Unexpected failure: library does not exist: %s" sharedLib
+    unless exists $ die' verbosity $ printf "Unexpected failure: library does not exist: %s" sharedLib
     --
     mint   <- findProgram verbosity "install_name_tool"
     case mint of
@@ -213,7 +217,7 @@
           notice verbosity $ printf "Provide a '%s' file to override this behaviour" customBuildInfoFilePath
           readHookedBuildInfo verbosity generatedBuildInfoFilePath
         else
-          die $ printf "Unexpected failure: neither the default '%s' nor custom '%s' exist" generatedBuildInfoFilePath customBuildInfoFilePath
+          die' verbosity $ printf "Unexpected failure: neither the default '%s' nor custom '%s' exist" generatedBuildInfoFilePath customBuildInfoFilePath
 
 
 findProgram :: Verbosity -> FilePath -> IO (Maybe FilePath)
@@ -301,7 +305,7 @@
         Nothing        -> warn verbosity $ say "Unknown ld.exe version"
         Just ldVersion -> do
           debug verbosity $ "Found ld.exe version: " ++ show ldVersion
-          when (ldVersion < [2,25,1]) $ die (windowsLinkerBugMsg ldPath)
+          when (ldVersion < [2,25,1]) $ die' verbosity (windowsLinkerBugMsg ldPath)
 validateLinker _ _ _ = return () -- The linker bug is present only on Win64 platform
 
 
@@ -405,7 +409,7 @@
       { platformIndependent = False
       , runPreProcessor     = \(inBaseDir, inRelativeFile)
                                (outBaseDir, outRelativeFile) verbosity ->
-          rawSystemProgramConf verbosity c2hsProgram (withPrograms lbi) . filter (not . null) $
+          runDbProgram verbosity c2hsProgram (withPrograms lbi) . filter (not . null) $
             maybe [] words (lookup "x-extra-c2hs-options" (customFieldsBI bi))
             ++ ["--include=" ++ outBaseDir]
             ++ ["--cppopts=" ++ opt | opt <- getCppOptions bi lbi]
@@ -444,5 +448,10 @@
 #if MIN_VERSION_Cabal(1,25,0)
 versionBranch :: Version -> [Int]
 versionBranch = versionNumbers
+#endif
+
+#if !MIN_VERSION_Cabal(2,0,0)
+die' :: Verbosity -> String -> IO a
+die' _ = die
 #endif
 
diff --git a/cufft.cabal b/cufft.cabal
--- a/cufft.cabal
+++ b/cufft.cabal
@@ -1,10 +1,10 @@
 name:                   cufft
-version:                0.8.0.0
+version:                0.9.0.0
 synopsis:               Haskell bindings for the CUFFT library
 description:
     This library contains FFI bindings to the CUFFT library, which provides
     highly optimised, FFTW compatible, Fast-Fourier Transform (FFT)
-    implementations for NVIDIA GPUs. The CUFFT library is part of the CUDA
+    implementations for NVIDIA GPUs. The cuFFT library is part of the CUDA
     developer toolkit.
     .
     <http://developer.nvidia.com/cuda-downloads>
@@ -12,7 +12,6 @@
     See the <https://travis-ci.org/tmcdonell/cublas travis-ci.org> build matrix
     for tested CUDA library versions.
 
-homepage:               http://github.com/robeverest/cufft
 license:                BSD3
 license-file:           LICENSE
 author:                 Robert Clifton-Everest, Trevor L. McDonell
@@ -21,7 +20,7 @@
 bug-reports:            https://github.com/robeverest/cufft/issues
 category:               Foreign
 build-type:             Custom
-cabal-version:          >= 1.22
+cabal-version:          >= 1.24
 tested-with:            GHC >= 7.6
 
 Extra-tmp-files:
@@ -29,12 +28,13 @@
 
 Extra-source-files:
     cbits/wrap.h
+    CHANGELOG.md
     README.md
 
 custom-setup
   setup-depends:
       base              >= 4.6
-    , Cabal             >= 1.22
+    , Cabal             >= 1.24
     , cuda              >= 0.8
     , directory         >= 1.0
     , filepath          >= 1.0
@@ -47,17 +47,17 @@
 
   exposed-modules:
       Foreign.CUDA.FFT
-
-  other-modules:
       Foreign.CUDA.FFT.Error
       Foreign.CUDA.FFT.Execute
       Foreign.CUDA.FFT.Plan
       Foreign.CUDA.FFT.Stream
+
+  other-modules:
       Foreign.CUDA.FFT.Internal.C2HS
 
   build-depends:
       base                              == 4.*
-    , cuda                              >= 0.6.6
+    , cuda                              >= 0.8
 
   build-tools:
       c2hs                              >= 0.21
@@ -75,6 +75,6 @@
 source-repository this
     type:               git
     location:           https://github.com/robeverest/cufft
-    tag:                0.8.0.0
+    tag:                0.9.0.0
 
 -- vim: nospell
