diff --git a/ChangeLog b/ChangeLog
new file mode 100644
--- /dev/null
+++ b/ChangeLog
@@ -0,0 +1,13 @@
+Changes in 0.1.0.2
+
+* Minor cabal file fixes.
+* Documentation fixes.
+* Remove references to 'bladerf_set_tx_gain()' missing symbol.
+* Moved from malloc to alloca usage, resolves memory leaks.
+* Provide bladeRF{Get,Set}Loopback actions and BladeRFLoopback type.
+
+Changes in 0.1.0.1
+
+* Add a change log.
+* LibBladeRF/Flash.hs: Provide untested bladeRFWriteFlash action.
+* hlibBladeRF.cabal: Move Bindings.X.Y into other-modules.
diff --git a/hlibBladeRF.cabal b/hlibBladeRF.cabal
--- a/hlibBladeRF.cabal
+++ b/hlibBladeRF.cabal
@@ -2,7 +2,7 @@
 -- documentation, see http://haskell.org/cabal/users-guide/
 
 name:                hlibBladeRF
-version:             0.1.0.1
+version:             0.1.0.2
 synopsis:            Haskell binding to libBladeRF SDR library
 description:         IO Monadic binding for libbladeRF software defined radio.
 homepage:            https://victoredwardocallaghan.github.io/hlibBladeRF
@@ -14,7 +14,7 @@
 copyright:           (c) Edward O'Callaghan, 2015
 category:            FFI
 build-type:          Simple
--- extra-source-files:  
+extra-source-files:  ChangeLog
 cabal-version:       >=1.10
 
 --------------------------------------------
@@ -73,3 +73,4 @@
   type:                git
   location:            git://github.com/victoredwardocallaghan/hlibBladeRF
   branch:              master
+  tag:                 v0.1.0.2
diff --git a/src/Bindings/LibBladeRF/Gain.hsc b/src/Bindings/LibBladeRF/Gain.hsc
--- a/src/Bindings/LibBladeRF/Gain.hsc
+++ b/src/Bindings/LibBladeRF/Gain.hsc
@@ -15,9 +15,6 @@
 #ccall bladerf_set_txvga1 , Ptr (<bladerf>) -> CInt -> IO CInt
 #ccall bladerf_get_txvga1 , Ptr (<bladerf>) -> Ptr (CInt) -> IO CInt
 
--- symb not found
--- #ccall bladerf_set_tx_gain , Ptr (<bladerf>) -> CInt -> IO CInt
-
 #ccall bladerf_set_lna_gain , Ptr (<bladerf>) -> <bladerf_lna_gain> -> IO CInt
 #ccall bladerf_get_lna_gain , Ptr (<bladerf>) -> Ptr (<bladerf_lna_gain>) -> IO CInt
 
diff --git a/src/Bindings/LibBladeRF/LibBladeRF.hsc b/src/Bindings/LibBladeRF/LibBladeRF.hsc
--- a/src/Bindings/LibBladeRF/LibBladeRF.hsc
+++ b/src/Bindings/LibBladeRF/LibBladeRF.hsc
@@ -39,8 +39,8 @@
 
 #ccall bladerf_enable_module , Ptr (<bladerf>) -> <bladerf_module> -> Bool -> IO CInt
 
-#ccall bladerf_set_loopback , Ptr (<bladerf>) -> <bladerf_loopback> -> CInt
-#ccall bladerf_get_loopback , Ptr (<bladerf>) -> Ptr (<bladerf_loopback>) -> CInt
+#ccall bladerf_set_loopback , Ptr (<bladerf>) -> <bladerf_loopback> -> IO CInt
+#ccall bladerf_get_loopback , Ptr (<bladerf>) -> Ptr (<bladerf_loopback>) -> IO CInt
 
 -- #ccall bladerf_set_sample_rate , Ptr (<bladerf>) -> <bladerf_module> -> CUInt -> Ptr (CUInt) -> CInt
 
diff --git a/src/LibBladeRF/Flash.hs b/src/LibBladeRF/Flash.hs
--- a/src/LibBladeRF/Flash.hs
+++ b/src/LibBladeRF/Flash.hs
@@ -25,37 +25,35 @@
 import LibBladeRF.LibBladeRF
 
 
--- | Erase regions of the bladeRF's SPI flash
+-- | Erase regions of the bladeRF's SPI flash.
 --
--- This function operates in units of 64KiB erase blocks
+-- This function operates in units of 64KiB erase blocks.
 bladeRFEraseFlash :: DeviceHandle  -- ^ Device handle
                   -> Word32        -- ^ Erase block to start erasing at
                   -> Word32        -- ^ Number of blocks to erase.
                   -> IO CInt
 bladeRFEraseFlash dev b c = c'bladerf_erase_flash (unDeviceHandle dev) b c
 
--- | Read data from the bladeRF's SPI flash
+-- | Read data from the bladeRF's SPI flash.
 --
 -- This function operates in units of 256-byte pages.
 bladeRFReadFlash :: DeviceHandle -- ^ Device handle
                  -> Word32       -- ^ Page to begin reading from
                  -> Word32       -- ^ Number of pages to read
                  -> IO (CInt, Word8)
-bladeRFReadFlash dev p c = do
-  bptr <- malloc :: IO (Ptr Word8)
+bladeRFReadFlash dev p c = alloca $ \bptr -> do
   ret <- c'bladerf_read_flash (unDeviceHandle dev) bptr p c
   buffer <- peek bptr
-  free bptr
   return (ret, buffer)
 
--- | Write data from the bladeRF's SPI flash
--- XXX - Buffer allocation size must be `page` * BLADERF_FLASH_PAGE_SIZE bytes or larger.
+-- | Write data from the bladeRF's SPI flash.
 bladeRFWriteFlash :: DeviceHandle     -- ^ Device handle
                   -> BS.ByteString    -- ^ Data to write to flash
                   -> Word32           -- ^ page  Page to begin writing at
                   -> Word32           -- ^ count
                   -> IO ()
 bladeRFWriteFlash dev b p c = allocaBytes (fromIntegral $ p * c'BLADERF_FLASH_PAGE_SIZE) $ \bptr -> do
+  -- XXX - Buffer allocation size must be `page` * BLADERF_FLASH_PAGE_SIZE bytes or larger.
   pokeArray bptr (BS.unpack b) -- XXX can we overflow here??
   _ <- c'bladerf_write_flash (unDeviceHandle dev) bptr p c
   return () -- ignore ret
diff --git a/src/LibBladeRF/Frequency.hs b/src/LibBladeRF/Frequency.hs
--- a/src/LibBladeRF/Frequency.hs
+++ b/src/LibBladeRF/Frequency.hs
@@ -25,7 +25,7 @@
 import LibBladeRF.Types
 
 
--- | Write value to VCTCXO DAC
+-- | Write value to VCTCXO DAC.
 bladeRFDACWrite :: DeviceHandle -- ^ Device handle
                 -> Word16       -- ^ Data to write to DAC register
                 -> IO ()
@@ -33,15 +33,14 @@
   c'bladerf_dac_write (unDeviceHandle dev) v
   return () -- ignores ret
 
--- | Get module's current frequency in Hz
+-- | Get module's current frequency in Hz.
 bladeRFGetFrequency :: DeviceHandle  -- ^ Device handle
                     -> BladeRFModule -- ^ Module to configure
                     -> IO Int        -- ^ Returned frequency
 bladeRFGetFrequency dev m = do
-  pf <- malloc :: IO (Ptr CUInt)
-  c'bladerf_get_frequency (unDeviceHandle dev) ((fromIntegral . fromEnum) m) pf
-  f <- peek pf
-  free pf
+  f <- alloca $ \pf -> do
+    c'bladerf_get_frequency (unDeviceHandle dev) ((fromIntegral . fromEnum) m) pf
+    peek pf
   return $ fromIntegral f
 
 -- | Set module's frequency in Hz.
@@ -53,19 +52,16 @@
   c'bladerf_set_frequency (unDeviceHandle dev) ((fromIntegral . fromEnum) m) (fromIntegral f)
   return () -- ignores ret
 
--- | Obtain the current value of the specified configuration parameter
+-- | Obtain the current value of the specified configuration parameter.
 bladeRFGetCorrection :: DeviceHandle       -- ^ Device handle
                      -> BladeRFModule      -- ^ Module to retrieve correction information from
                      -> BladeRFCorrection  -- ^ Correction type
                      -> IO Word16          -- ^ Current value
-bladeRFGetCorrection dev m c = do
-  pc <- malloc :: IO (Ptr Word16)
+bladeRFGetCorrection dev m c = alloca $ \pc -> do
   c'bladerf_get_correction (unDeviceHandle dev) ((fromIntegral . fromEnum) m) ((fromIntegral . fromEnum) c) pc
-  c <- peek pc
-  free pc
-  return c
+  peek pc
 
--- | Set the value of the specified configuration parameter
+-- | Set the value of the specified configuration parameter.
 bladeRFSetCorrection :: DeviceHandle      -- ^ Device handle
                      -> BladeRFModule     -- ^ Module to apply correction to
                      -> BladeRFCorrection -- ^ Correction type
diff --git a/src/LibBladeRF/Gain.hs b/src/LibBladeRF/Gain.hs
--- a/src/LibBladeRF/Gain.hs
+++ b/src/LibBladeRF/Gain.hs
@@ -6,7 +6,7 @@
   Stability   : provisional
   Portability : portable
 
-  This module deals with Gain control
+  This module deals with Gain control.
 -}
 
 module LibBladeRF.Gain ( -- * set,get TxVGA2
@@ -25,8 +25,6 @@
                        , bladeRFSetLNAGain
                        , bladeRFGetLNAGain
                        -- * Optimal gain control
--- XXX symb not found!!!
---                       , bladeRFSetTXGain
                        , bladeRFSetGain
                        ) where
 
@@ -39,7 +37,7 @@
 import LibBladeRF.Types
 
 
--- | Set the PA gain in dB
+-- | Set the PA gain in dB.
 bladeRFSetTXVGA2 :: DeviceHandle -- ^ Device handle
                  -> Int          -- ^ Desired gain
                  -> IO ()
@@ -47,17 +45,16 @@
   c'bladerf_set_txvga2 (unDeviceHandle dev) (fromIntegral g)
   return () -- ignores ret
 
--- | Get the PA gain in dB
+-- | Get the PA gain in dB.
 bladeRFGetTXVGA2 :: DeviceHandle -- ^ Device handle
                  -> IO Int       -- ^ Returned gain
 bladeRFGetTXVGA2 dev = do
-  p <- malloc :: IO (Ptr CInt)
-  c'bladerf_get_txvga2 (unDeviceHandle dev) p
-  g <-  peek p
-  free p
+  g <- alloca $ \p -> do
+    c'bladerf_get_txvga2 (unDeviceHandle dev) p
+    peek p
   return $ fromIntegral g
 
--- | Set the post-LPF gain in dB
+-- | Set the post-LPF gain in dB.
 bladeRFSetTXVGA1 :: DeviceHandle         -- ^ Device handle
                  -> BladeRFVGAGainBounds -- ^ Desired gain
                  -> IO ()
@@ -65,17 +62,16 @@
   c'bladerf_set_txvga1 (unDeviceHandle dev) ((fromIntegral . fromEnum) g)
   return () -- ignores ret
 
--- | Get the post-LPF gain in dB
+-- | Get the post-LPF gain in dB.
 bladeRFGetTXVGA1 :: DeviceHandle -- ^ Device handle
                  -> IO Int       -- ^ Returned gain
 bladeRFGetTXVGA1 dev = do
-  p <- malloc :: IO (Ptr CInt)
-  c'bladerf_get_txvga1 (unDeviceHandle dev) p
-  g <-  peek p
-  free p
+  g <- alloca $ \p -> do
+    c'bladerf_get_txvga1 (unDeviceHandle dev) p
+    peek p
   return $ fromIntegral g
 
--- | Set the post-LPF VGA gain
+-- | Set the post-LPF VGA gain.
 bladeRFSetRXVGA2 :: DeviceHandle         -- ^ Device handle
                  -> BladeRFVGAGainBounds -- ^ Desired gain
                  -> IO ()
@@ -83,17 +79,16 @@
   c'bladerf_set_rxvga2 (unDeviceHandle dev) ((fromIntegral . fromEnum) g)
   return () -- ignores ret
 
--- | Get the post-LPF VGA gain
+-- | Get the post-LPF VGA gain.
 bladeRFGetRXVGA2 :: DeviceHandle -- ^ Device handle
                  -> IO Int       -- ^ Returned set gain level
 bladeRFGetRXVGA2 dev = do
-  p <- malloc :: IO (Ptr CInt)
-  c'bladerf_get_rxvga2 (unDeviceHandle dev) p
-  g <-  peek p
-  free p
+  g <- alloca $ \p -> do
+    c'bladerf_get_rxvga2 (unDeviceHandle dev) p
+    peek p
   return $ fromIntegral g
 
--- | Set the pre-LPF VGA gain
+-- | Set the pre-LPF VGA gain.
 bladeRFSetRXVGA1 :: DeviceHandle         -- ^ Device handle
                  -> BladeRFVGAGainBounds -- ^ Desired gain
                  -> IO ()
@@ -101,17 +96,16 @@
   c'bladerf_set_rxvga1 (unDeviceHandle dev) ((fromIntegral . fromEnum) g)
   return () -- ignores ret
 
--- | Get the pre-LPF VGA gain
+-- | Get the pre-LPF VGA gain.
 bladeRFGetRXVGA1 :: DeviceHandle -- ^ Device handle
                  -> IO Int       -- ^ Returned set gain level
 bladeRFGetRXVGA1 dev = do
-  p <- malloc :: IO (Ptr CInt)
-  c'bladerf_get_rxvga1 (unDeviceHandle dev) p
-  g <-  peek p
-  free p
+  g <- alloca $ \p -> do
+    c'bladerf_get_rxvga1 (unDeviceHandle dev) p
+    peek p
   return $ fromIntegral g
 
--- | Set LNA Gain
+-- | Set LNA Gain.
 bladeRFSetLNAGain :: DeviceHandle   -- ^ Device handle
                   -> BladeRFLNAGain -- ^ Desired gain level
                   -> IO ()
@@ -119,30 +113,20 @@
   c'bladerf_set_lna_gain (unDeviceHandle dev) ((fromIntegral . fromEnum) g)
   return () -- ignores ret
 
--- | Get LNA Gain
+-- | Get LNA Gain.
 bladeRFGetLNAGain :: DeviceHandle      -- ^ Device handle
                   -> IO BladeRFLNAGain -- ^ Returned set gain level
 bladeRFGetLNAGain dev = do
-  p <- malloc :: IO (Ptr C'bladerf_lna_gain)
-  c'bladerf_get_lna_gain (unDeviceHandle dev) p
-  g <-  peek p
-  free p
+  g <- alloca $ \p -> do
+    c'bladerf_get_lna_gain (unDeviceHandle dev) p
+    peek p
   return $ (toEnum . fromIntegral) g
 
+-- | Set a combined pre and post LPF RX gain.
 --
--- | Set a combined VGA TX gain
---   This function computes the optimal TXVGA1 and TXVGA2 gains for a requested
---   amount of gain
--- XXX symb not found!!!
---bladeRFSetTXGain :: DeviceHandle -> Int -> IO ()
---bladeRFSetTXGain dev g = do
---  c'bladerf_set_tx_gain (unDeviceHandle dev) (fromIntegral g)
---  return () -- ignores ret
-
--- | Set a combined pre and post LPF RX gain
---   This function computes the optimal LNA, RXVGA1, and RVGA2 gains for a
---   requested amount of RX gain, and computes the optimal TXVGA1 and TXVGA2 gains
---   for a requested amount of TX gain
+-- This action computes the optimal LNA, RXVGA1, and RVGA2 gains for a
+-- requested amount of RX gain, and computes the optimal TXVGA1 and TXVGA2
+-- gains for a requested amount of TX gain
 bladeRFSetGain :: DeviceHandle  -- ^ Device handle
                -> BladeRFModule -- ^ Module
                -> Int           -- ^ Desired gain
diff --git a/src/LibBladeRF/Gpio.hs b/src/LibBladeRF/Gpio.hs
--- a/src/LibBladeRF/Gpio.hs
+++ b/src/LibBladeRF/Gpio.hs
@@ -6,7 +6,7 @@
   Stability   : provisional
   Portability : portable
 
-  This module GPIO configuration handling
+  This module GPIO configuration handling.
 -}
 
 module LibBladeRF.Gpio ( bladeRFConfigGPIORead
@@ -22,20 +22,17 @@
 import LibBladeRF.Types
 
 
--- | Read a configuration GPIO register
+-- | Read a configuration GPIO register.
 bladeRFConfigGPIORead :: DeviceHandle -- ^ Device handle
                       -> IO Word32    -- ^ Read data
-bladeRFConfigGPIORead dev = do
-  pv <- malloc :: IO (Ptr Word32)
+bladeRFConfigGPIORead dev = alloca $ \pv -> do
   c'bladerf_config_gpio_read (unDeviceHandle dev) pv
-  v <- peek pv
-  free pv
-  return v
+  peek pv
 
--- | Write a configuration GPIO register. Callers should be sure to perform a
+-- | Write a configuration GPIO register.
 --
---   read-modify-write sequence to avoid accidentally clearing other
---   GPIO bits that may be set by the library internally.
+-- Callers should be sure to perform a read-modify-write sequence to avoid
+-- accidentally clearing other GPIO bits that may be set by the library internally.
 bladeRFConfigGPIOWrite :: DeviceHandle -- ^ Device handle
                        -> Word32       -- ^ Data to write to GPIO register
                        -> IO ()
diff --git a/src/LibBladeRF/Sampling.hs b/src/LibBladeRF/Sampling.hs
--- a/src/LibBladeRF/Sampling.hs
+++ b/src/LibBladeRF/Sampling.hs
@@ -23,52 +23,50 @@
 import LibBladeRF.Types
 
 
--- | Configure the device's sample rate, in Hz.  Note this requires the sample
---   rate is an integer value of Hz.  Use bladeRFSetRationalSampleRate
---   for more arbitrary values.
+-- | Configure the device's sample rate, in Hz.
+--
+-- Note this requires the sample rate is an integer value of Hz.
+-- Use 'bladeRFSetRationalSampleRate' for more arbitrary values.
 bladeRFSetSampleRate :: DeviceHandle  -- ^ Device handle
                      -> BladeRFModule -- ^ Module to change
                      -> Int           -- ^ Sample rate
                      -> IO Int        -- ^ Actual sample rate achieved.
 bladeRFSetSampleRate dev m r = do
-  par <- malloc :: IO (Ptr CUInt)
-  c'bladerf_set_sample_rate (unDeviceHandle dev) ((fromIntegral . fromEnum) m) (fromIntegral r) par
-  actual <- peek par
-  free par
+  actual <- alloca $ \par -> do
+         c'bladerf_set_sample_rate (unDeviceHandle dev) ((fromIntegral . fromEnum) m) (fromIntegral r) par
+         peek par
   return $ fromIntegral actual
 
 -- | Configure the device's sample rate as a rational fraction of Hz.
---   Sample rates are in the form of integer + num/denom.
+--
+-- Sample rates are in the form of integer + num/denom.
 bladeRFSetRationalSampleRate :: DeviceHandle           -- ^ Device handle
                              -> BladeRFModule          -- ^ Module to change
                              -> BladeRFRationalRate    -- ^ Rational sample rate
                              -> IO BladeRFRationalRate -- ^ Actual rational sample rate achieved.
 bladeRFSetRationalSampleRate dev m r = do
-  pr <- malloc :: IO (Ptr C'bladerf_rational_rate)
-  par <- malloc :: IO (Ptr C'bladerf_rational_rate)
   let rate = C'bladerf_rational_rate { c'bladerf_rational_rate'integer = integer r
                                      , c'bladerf_rational_rate'num     = num r
                                      , c'bladerf_rational_rate'den     = den r
                                      }
-  poke pr rate
-  c'bladerf_set_rational_sample_rate (unDeviceHandle dev) ((fromIntegral . fromEnum) m) pr par
-  ar <- peek par
+  ar <- alloca $ \pr -> do
+     poke pr rate
+     alloca $ \par -> do
+       c'bladerf_set_rational_sample_rate (unDeviceHandle dev) ((fromIntegral . fromEnum) m) pr par
+       peek par
   let actual = BladeRFRationalRate { integer = c'bladerf_rational_rate'integer ar
                                    , num     = c'bladerf_rational_rate'num ar
                                    , den     = c'bladerf_rational_rate'den ar
                                    }
-  free pr
-  free par
   return actual
 
--- | Set the bandwidth of the LMS LPF to specified value in Hz
+-- | Set the bandwidth of the LMS LPF to specified value in Hz.
 bladeRFSetBandwidth :: DeviceHandle  -- ^ Device handle
                     -> BladeRFModule -- ^ Module for bandwidth request
                     -> Int           -- ^ Desired bandwidth
                     -> IO Int        -- ^ Actual bandwidth that the device was able to achieve.
 bladeRFSetBandwidth dev m b = do
-  ab <- malloc :: IO (Ptr CUInt)
-  c'bladerf_set_bandwidth (unDeviceHandle dev) ((fromIntegral . fromEnum) m) (fromIntegral b) ab
-  actual <- peek ab
-  free ab
+  actual <- alloca $ \ab -> do
+         c'bladerf_set_bandwidth (unDeviceHandle dev) ((fromIntegral . fromEnum) m) (fromIntegral b) ab
+         peek ab
   return $ fromIntegral actual
diff --git a/src/LibBladeRF/Sync.hs b/src/LibBladeRF/Sync.hs
--- a/src/LibBladeRF/Sync.hs
+++ b/src/LibBladeRF/Sync.hs
@@ -54,22 +54,21 @@
 --
 -- Under the hood, this call starts up an underlying asynchronous stream as
 -- needed. This stream can be stopped by disabling the TX module. (See
--- bladeRFEnableModule for more details.)
+-- 'LibBladeRF.Utils.bladeRFEnableModule' for more details.)
 --
 -- Samples will only be sent to the FPGA when a buffer have been filled. The
 -- number of samples required to fill a buffer corresponds to the `buffer_size`
--- parameter passed to bladeRFSyncConfig.
+-- parameter passed to 'bladeRFSyncConfig'.
 bladeRFSyncTx :: DeviceHandle    -- ^ Device handle
               -> BS.ByteString   -- ^ Array of samples
               -> Int             -- ^ Number of samples to write
               -> BladeRFMetadata -- ^ Sample metadata. This must be provided when using
-                                 --   the ::BLADERF_FORMAT_SC16_Q11_META format, but may
+                                 --   the 'FORMAT_SC16_Q11_META' format, but may
                                  --   be NULL when the interface is configured for
-                                 --   the ::BLADERF_FORMAT_SC16_Q11 format.
+                                 --   the 'FORMAT_SC16_Q11' format.
               -> Int             -- ^ Timeout (milliseconds) for this call to complete. Zero implies infinite.
               -> IO ()
 bladeRFSyncTx dev s n md t = do
-  pmd <- malloc :: IO (Ptr C'bladerf_metadata)
 -- Use the following instead when switching to ghc7.8 later..
 -- bladeRFMetadataToCBladeRFMetadata :: BladeRFMetadata -> C'bladerf_metadata
   let meta = C'bladerf_metadata { c'bladerf_metadata'timestamp    = timestamp md
@@ -78,25 +77,25 @@
                                 , c'bladerf_metadata'actual_count = (fromIntegral . count) md
                                 , c'bladerf_metadata'reserved     = [0]
                                 }
-  poke pmd meta
-  BS.useAsCStringLen s $
-    \(p, _len) -> c'bladerf_sync_tx (unDeviceHandle dev) p (fromIntegral n) pmd (fromIntegral t)
-  free pmd
+  alloca $ \pmd -> do
+    poke pmd meta
+    BS.useAsCStringLen s $
+      \(p, _len) -> c'bladerf_sync_tx (unDeviceHandle dev) p (fromIntegral n) pmd (fromIntegral t)
+  return () -- XXX ignores ret
 
 -- | Receive IQ samples.
 --
 -- Underthe hood, this call starts up an underlying asynchronous stream as
 -- needed. This stream can be stopped by disabling the RX module. (See
--- bladeRFEnableModule for more details.)
+-- 'LibBladeRF.Utils.bladeRFEnableModule' for more details.)
 bladeRFSyncRx :: DeviceHandle    -- ^ Device handle
               -> Int             -- ^ Number of samples to read
               -> Int             -- ^ Timeout (milliseconds) for this call to complete. Zero implies infinite.
               -> IO (BS.ByteString, BladeRFMetadata)
-bladeRFSyncRx dev n t = do
-  pmd <- malloc :: IO (Ptr C'bladerf_metadata)
-  ptr <- mallocBytes (4 * n)
-  c'bladerf_sync_rx (unDeviceHandle dev) ptr (fromIntegral n) pmd (fromIntegral t)
-  par <- peekArray (4 * n) ptr
+bladeRFSyncRx dev n t = alloca $ \pmd -> do
+  par <- allocaBytes (4 * n) $ \ptr -> do
+      c'bladerf_sync_rx (unDeviceHandle dev) ptr (fromIntegral n) pmd (fromIntegral t)
+      peekArray (4 * n) ptr
   let bs = BS.pack par
   cmd <- peek pmd
  -- Use the following instead when switching to ghc7.8 later..
@@ -106,5 +105,4 @@
                              , status    = c'bladerf_metadata'status       cmd
                              , count     = fromIntegral $ c'bladerf_metadata'actual_count cmd
                              }
-  free pmd
   return (bs, meta)
diff --git a/src/LibBladeRF/Types.hs b/src/LibBladeRF/Types.hs
--- a/src/LibBladeRF/Types.hs
+++ b/src/LibBladeRF/Types.hs
@@ -26,6 +26,7 @@
 --                        needs ghc >= 7.8
 --                        , bladeRFMetadataToCBladeRFMetadata
 --                        , bladeRFMetadataFromCBladeRFMetadata
+                        , BladeRFLoopback(..)
                         ) where
 
 
@@ -38,8 +39,7 @@
 --import Data.Coerce
 --import GHC.Generics
 
---
--- | Version structure for FPGA, firmware, libbladeRF, and associated utilities
+-- | Version structure for FPGA, firmware, libbladeRF, and associated utilities.
 data BladeRFVersion = BladeRFVersion { major :: Word16 -- ^ Major version
                                      , minor :: Word16 -- ^ Minor version
                                      , patch :: Word16 -- ^ Patch version
@@ -52,8 +52,7 @@
            show (patch a) ++ " (" ++
                 descr a ++ ")"
 
---
--- | Information about a bladeRF attached to the system
+-- | Information about a bladeRF attached to the system.
 data BladeRFDeviceInfo = BladeRFDeviceInfo { backend :: BladeRFBackend -- ^ Backend to use when connecting to device
                                            , serial  :: String         -- ^ Device serial number string
                                            , usbBus  :: Word8          -- ^ Bus number device is attached to
@@ -68,8 +67,7 @@
            " USB address: " ++ show (usbAddr a) ++ "\n" ++
            " Instance: " ++ show (inst a)
 
---
--- | FPGA device variant (size)
+-- | FPGA device variant (size).
 data BladeRFFPGASize = FPGA_UNKNOWN -- ^ Unable to determine FPGA variant
                      | FPGA_40KLE   -- ^ 40 kLE FPGA
                      | FPGA_115KLE  -- ^ 115 kLE FPGA
@@ -89,7 +87,7 @@
         , (FPGA_115KLE, c'BLADERF_FPGA_115KLE)
         ]
 
--- | Backend by which the host communicates with the device
+-- | Backend by which the host communicates with the device.
 data BladeRFBackend = BACKEND_ANY     -- ^ Don't Care, use any available backend
                     | BACKEND_LINUX   -- ^ Linux kernel driver
                     | BACKEND_LIBUSB  -- ^ libusb
@@ -115,14 +113,14 @@
            , (BACKEND_DUMMY, c'BLADERF_BACKEND_DUMMY)
            ]
 
--- | Rational sample rate representation
+-- | Rational sample rate representation.
 data BladeRFRationalRate = BladeRFRationalRate { integer :: Word64 -- ^ Integer portion
                                                , num     :: Word64 -- ^ Numerator in fractional portion
                                                , den     :: Word64 -- ^ Denominator in fractional portion. This must be > 0.
                                                } deriving (Eq, Show)
 
 
--- | Module selection for those which have both RX and TX constituents
+-- | Module selection for those which have both RX and TX constituents.
 data BladeRFModule = MODULE_RX -- ^ Receive Module
                    | MODULE_TX -- ^ Transmit Module
                    deriving (Eq)
@@ -136,7 +134,7 @@
           ]
 
 
--- | Sample format
+-- | Sample format.
 data BladeRFFormat
   {-| Signed, Complex 16-bit Q11. This is the native format of the DAC data.
 
@@ -168,10 +166,10 @@
      0x0c [uint32_t:  BLADERF_META_FLAG_* flags]
     @
 
-    When using the 'bladeRFSyncRx' and 'bladeRFSyncTx' actions,
-    this detail is transparent to caller. These functions take care of
-    packing/unpacking the metadata into/from the data, via the
-    bladerf_metadata structure.
+    When using the 'LibBladeRF.Sync.bladeRFSyncRx' and
+    'LibBladeRF.Sync.bladeRFSyncTx' actions, this detail is transparent to
+    caller. These functions take care of packing/unpacking the metadata
+    into/from the data, via the 'LibBladeRF.Types.BladeRFMetadata' structure.
 
     Currently, when using the asynchronous data transfer interface, the user
     is responsible for manually packing/unpacking this metadata into/from
@@ -190,7 +188,7 @@
           ]
 
 
--- | LNA gain options
+-- | LNA gain options.
 data BladeRFLNAGain = LNA_GAIN_UNKNOWN -- ^ Invalid LNA gain
                     | LNA_GAIN_BYPASS  -- ^ LNA bypassed - 0dB gain
                     | LNA_GAIN_MID     -- ^ LNA Mid Gain (MAX-6dB)
@@ -207,7 +205,7 @@
          , (LNA_GAIN_MAX, c'BLADERF_LNA_GAIN_MAX)
          ]
 
--- | Device control and configuration
+-- | Device control and configuration.
 --
 -- This section provides functions pertaining to accessing, controlling, and
 -- configuring various device options and parameters.
@@ -235,10 +233,11 @@
          , (TXVGA2_GAIN_MAX, c'BLADERF_TXVGA2_GAIN_MAX)
          ]
 
--- | Correction parameter selection
+-- | Correction parameter selection.
 --
 -- These values specify the correction parameter to modify or query when
--- calling bladerf_set_correction() or bladerf_get_correction(). Note that the
+-- calling 'LibBladeRF.Frequency.bladeRFSetCorrection' or
+-- 'LibBladeRF.Frequency.bladeRFGetCorrection'. Note that the
 -- meaning of the `value` parameter to these functions depends upon the
 -- correction parameter.
 data BladeRFCorrection = CORR_LMS_DCOFF_I -- ^ Adjusts the in-phase DC offset via controls provided by the LMS6002D
@@ -288,7 +287,7 @@
          ]
 
 
--- | Sample metadata
+-- | Sample metadata.
 --
 -- This structure is used in conjunction with the 'FORMAT_SC16_Q11_META'
 -- format to TX scheduled bursts or retrieve timestamp information about
@@ -301,8 +300,40 @@
                                                              --   transmissions/receptions.
                                        , count     :: Int    -- ^ This output parameter is updated to reflect the actual
                                                              --   number of contiguous samples that have been populated
-                                                             --   in an RX buffer during a 'bladeRFSyncRx' call.
+                                                             --   in an RX buffer during a 'LibBladeRF.Sync.bladeRFSyncRx' call.
                                        }
+
+
+-- | Loopback options.
+data BladeRFLoopback = LB_FIRMWARE         -- ^ Firmware loopback inside of the FX3
+                     | LB_BB_TXLPF_RXVGA2  -- ^ Baseband loopback. TXLPF output is connected to the RXVGA2 input.
+                     | LB_BB_TXVGA1_RXVGA2 -- ^ Baseband loopback. TXVGA1 output is connected to the RXVGA2 input.
+                     | LB_BB_TXLPF_RXLPF   -- ^ Baseband loopback. TXLPF output is connected to the RXLPF input.
+                     | LB_BB_TXVGA1_RXLPF  -- ^ Baseband loopback. TXVGA1 output is connected to RXLPF input.
+                     | LB_RF_LNA1          -- ^ RF loopback. The TXMIX output, through the AUX PA, is connected to the
+                                           --   output of LNA1.
+                     | LB_RF_LNA2          -- ^ RF loopback. The TXMIX output, through the AUX PA, is connected to the
+                                           --   output of LNA2.
+                     | LB_RF_LNA3          -- ^ RF loopback. The TXMIX output, through the AUX PA, is connected to the
+                                           --   output of LNA3.
+                     | LB_NONE             -- ^ Disables loopback and returns to normal operation.
+                     deriving (Eq)
+
+instance Enum BladeRFLoopback where
+  fromEnum = fromJust . flip lookup loopbacks
+  toEnum   = fromJust . flip lookup (map swap loopbacks)
+
+loopbacks = [ (LB_FIRMWARE, c'BLADERF_LB_FIRMWARE)
+            , (LB_BB_TXLPF_RXVGA2, c'BLADERF_LB_BB_TXLPF_RXVGA2)
+            , (LB_BB_TXVGA1_RXVGA2, c'BLADERF_LB_BB_TXVGA1_RXVGA2)
+            , (LB_BB_TXLPF_RXLPF, c'BLADERF_LB_BB_TXLPF_RXLPF)
+            , (LB_BB_TXVGA1_RXLPF, c'BLADERF_LB_BB_TXVGA1_RXLPF)
+            , (LB_RF_LNA1, c'BLADERF_LB_RF_LNA1)
+            , (LB_RF_LNA2, c'BLADERF_LB_RF_LNA2)
+            , (LB_RF_LNA3, c'BLADERF_LB_RF_LNA3)
+            , (LB_NONE, c'BLADERF_LB_NONE)
+            ]
+
 
 
 -- | Isomorpishms
diff --git a/src/LibBladeRF/Utils.hs b/src/LibBladeRF/Utils.hs
--- a/src/LibBladeRF/Utils.hs
+++ b/src/LibBladeRF/Utils.hs
@@ -18,6 +18,8 @@
                         , bladeRFGetSerial
                         , bladeRFGetFPGASize
                         , bladeRFEnableModule
+                        , bladeRFSetLoopback
+                        , bladeRFGetLoopback
                         ) where
 
 import Foreign
@@ -29,53 +31,50 @@
 import LibBladeRF.Types
 
 
--- | Get libbladeRF version information
--- bladeRFLibVersion :: IO BladeRFVersion
+-- | Get libbladeRF version information.
+bladeRFLibVersion :: IO BladeRFVersion
 bladeRFLibVersion = do
-  p <- malloc :: IO (Ptr C'bladerf_version)
-  c'bladerf_version p
-  brfv <- peek p
+  brfv <- alloca $ \p -> do
+       c'bladerf_version p
+       peek p
   desc <- peekCString $ c'bladerf_version'describe brfv
   let ver = BladeRFVersion { major = c'bladerf_version'major brfv
                            , minor = c'bladerf_version'minor brfv
                            , patch = c'bladerf_version'patch brfv
                            , descr = desc
                            }
-  free p
   return ver
 
--- | Query firmware version
+-- | Query firmware version.
 bladeRFFwVersion :: DeviceHandle      -- ^ Device handle
                  -> IO BladeRFVersion -- ^ Returned firmware version
 bladeRFFwVersion dev = do
-  p <- malloc :: IO (Ptr C'bladerf_version)
-  c'bladerf_fw_version (unDeviceHandle dev) p
-  brfv <- peek p
+  brfv <- alloca $ \p -> do
+       c'bladerf_fw_version (unDeviceHandle dev) p
+       peek p
   desc <- peekCString $ c'bladerf_version'describe brfv
   let ver = BladeRFVersion { major = c'bladerf_version'major brfv
                            , minor = c'bladerf_version'minor brfv
                            , patch = c'bladerf_version'patch brfv
                            , descr = desc
                            }
-  free p
   return ver
 
--- | Query FPGA version
+-- | Query FPGA version.
 bladeRFFPGAVersion :: DeviceHandle      -- ^ Device handle
                    -> IO BladeRFVersion -- ^ Returned firmware version
 bladeRFFPGAVersion dev = do
   status <- c'bladerf_is_fpga_configured (unDeviceHandle dev)
   if status > 0 then do
-    p <- malloc :: IO (Ptr C'bladerf_version)
-    c'bladerf_fpga_version (unDeviceHandle dev) p
-    brfv <- peek p
+    brfv <- alloca $ \p -> do
+         c'bladerf_fpga_version (unDeviceHandle dev) p
+         peek p
     desc <- peekCString $ c'bladerf_version'describe brfv
     let ver = BladeRFVersion { major = c'bladerf_version'major brfv
                              , minor = c'bladerf_version'minor brfv
                              , patch = c'bladerf_version'patch brfv
                              , descr = desc
                              }
-    free p
     return ver
   else
     return    BladeRFVersion { major = 0
@@ -85,9 +84,10 @@
                              }
 
 
--- | Load device's FPGA. Note that this FPGA configuration will be reset
---   at the next power cycle.
--- pass Full path to FPGA bitstream
+-- | Load device's FPGA.
+--
+-- Note that this FPGA configuration will be reset at the next
+-- power cycle. Pass Full path to FPGA bitstream.
 bladeRFLoadFPGA :: DeviceHandle -- ^ Device handle
                 -> String       -- ^ Full path to FPGA bitstream
                 -> IO ()
@@ -96,59 +96,78 @@
   _ <- c'bladerf_load_fpga (unDeviceHandle dev) p
   return ()
 
--- | Obtain the bus speed at which the device is operating
+-- | Obtain the bus speed at which the device is operating.
 bladeRFDeviceSpeed :: DeviceHandle    -- ^ Device handle
                    -> IO BladeRFSpeed -- ^ Device speed
 bladeRFDeviceSpeed dev = do
   speed <- c'bladerf_device_speed (unDeviceHandle dev)
   return $ (toEnum . fromEnum) speed
 
--- | Fill out a provided bladerf_devinfo structure, given an open device handle.
+-- | Fill out a provided 'LibBladeRF.Types.BladeRFDevInfo' structure, given an open device handle.
 bladeRFGetDevInfo :: DeviceHandle         -- ^ Device handle
                   -> IO BladeRFDeviceInfo -- ^ Device information populated by this function
 bladeRFGetDevInfo dev = do
-  p <- malloc :: IO (Ptr C'bladerf_devinfo)
-  c'bladerf_get_devinfo (unDeviceHandle dev) p
--- XXX ^ handle status return error with Maybe monad???
-  brfv <- peek p
+  brfv <- alloca $ \p -> do
+       c'bladerf_get_devinfo (unDeviceHandle dev) p
+       -- XXX ^ handle status return error with Maybe monad???
+       peek p
   let info = BladeRFDeviceInfo { backend = toEnum . fromEnum . c'bladerf_devinfo'backend $ brfv
                                , serial  = map castCCharToChar . c'bladerf_devinfo'serial $ brfv
                                , usbBus  = c'bladerf_devinfo'usb_bus brfv
                                , usbAddr = c'bladerf_devinfo'usb_addr brfv
                                , inst    = c'bladerf_devinfo'instance brfv
                                }
-  free p
   return info
 
--- | Query a device's serial number
+-- | Query a device's serial number.
 bladeRFGetSerial :: DeviceHandle -- ^ Device handle
                  -> IO String    -- ^ Returned serial number.
-bladeRFGetSerial dev = do
-  cstring <- mallocBytes 34 -- device serial is 33 bytes long + null terminating byte.
+bladeRFGetSerial dev = allocaBytes 34 $ \cstring -> do
   -- API bug bladerf_get_serial() should be allocating the buffer itself, not the call site!
+  -- See upstream report: https://github.com/Nuand/bladeRF/issues/382
+  -- device serial is 33 bytes long + null terminating byte.
   c'bladerf_get_serial (unDeviceHandle dev) cstring
-  serial <- peekCString cstring
-  free cstring
-  return serial
+  peekCString cstring
 
--- | Query a device's FPGA size
+-- | Query a device's FPGA size.
 bladeRFGetFPGASize :: DeviceHandle       -- ^ Device handle
                    -> IO BladeRFFPGASize -- ^ Returned on-board FPGA's size.
 bladeRFGetFPGASize dev = do
-  p <- malloc :: IO (Ptr C'bladerf_fpga_size)
-  c'bladerf_get_fpga_size (unDeviceHandle dev) p
-  sz <- peek p
-  free p
+  sz <- alloca $ \p -> do
+     c'bladerf_get_fpga_size (unDeviceHandle dev) p
+     peek p
   return $ (toEnum . fromEnum) sz
 
-
 -- | Enable or disable the specified RX/TX module.
---   When a synchronous stream is associated with the specified module, this
---   will shut down the underlying asynchronous stream when `enable` = false.
+--
+-- When a synchronous stream is associated with the specified module, this
+-- will shut down the underlying asynchronous stream when `enable` = 'False'.
 bladeRFEnableModule :: DeviceHandle  -- ^ Device handle
                     -> BladeRFModule -- ^ Device module
-                    -> Bool          -- ^ true to enable, false to disable
+                    -> Bool          -- ^ 'True' to enable, 'False' to disable
                     -> IO ()
 bladeRFEnableModule dev m t = do
   c'bladerf_enable_module (unDeviceHandle dev) ((fromIntegral . fromEnum) m) t
   return () -- XXX ignore ret
+
+-- | Apply specified loopback mode.
+--
+-- Loopback modes should only be enabled or disabled while the RX and TX
+-- modules are both disabled (and therefore, when no samples are being
+-- actively streamed). Otherwise, unexpected behavior may occur.
+bladeRFSetLoopback :: DeviceHandle    -- ^ Device handle
+                   -> BladeRFLoopback -- ^ Loopback mode. Note that 'LB_NONE'
+                                      --   disables the use of loopback functionality.
+                   -> IO ()
+bladeRFSetLoopback dev l = do
+  c'bladerf_set_loopback (unDeviceHandle dev) ((fromIntegral . fromEnum) l)
+  return () -- XXX ignore ret
+
+-- | Get current loopback mode.
+bladeRFGetLoopback :: DeviceHandle       -- ^ Device handle
+                   -> IO BladeRFLoopback -- ^ Current loopback mode
+bladeRFGetLoopback dev = do
+  l <- alloca $ \lp -> do
+    c'bladerf_get_loopback (unDeviceHandle dev) lp
+    peek lp
+  return $ (toEnum . fromEnum) l
