diff --git a/cbits/hs_i2c.c b/cbits/hs_i2c.c
--- a/cbits/hs_i2c.c
+++ b/cbits/hs_i2c.c
@@ -1,7 +1,6 @@
 #include "hs_i2c.h"
 
 #include <sys/ioctl.h>
-#include <linux/types.h>
 #include <linux/i2c-dev.h>
 
 
diff --git a/cbits/hs_spi.c b/cbits/hs_spi.c
--- a/cbits/hs_spi.c
+++ b/cbits/hs_spi.c
@@ -1,8 +1,8 @@
 #include "hs_spi.h"
 
 #include <sys/ioctl.h>
-#include <linux/types.h>
 #include <linux/spi/spidev.h>
+#include <string.h>
 
 
 unsigned char spi_mode_0() {
@@ -19,45 +19,105 @@
 }
 
 
-int spi_transfer_message_1(int fd, void* buff, __u32 buff_len, __u32 speed, __u8 bits) {
 
-  struct spi_ioc_transfer spi;
-  spi.tx_buf        = (__u64) buff;
-  spi.rx_buf        = (__u64) buff;
-  spi.len           = buff_len;
-  spi.speed_hz      = speed;
-  spi.bits_per_word = bits;
-  spi.delay_usecs   = 0;
-  spi.cs_change     = 0;
+int spi_transfer_tx_rx_1(int fd, void *buff, __u32 buff_len, __u8 bits, __u32 speed, __u16 delay, __u8 cs_change) {
 
-  return ioctl(fd,SPI_IOC_MESSAGE(1),&spi);
+  struct spi_ioc_transfer tran;
+  memset(&tran,0,sizeof(struct spi_ioc_transfer));
+  
+  tran.tx_buf        = (__u64) buff;
+  tran.rx_buf        = (__u64) buff;
+  tran.len           = buff_len;
+  tran.bits_per_word = bits;
+  tran.speed_hz      = speed;
+  tran.delay_usecs   = delay;
+  tran.cs_change     = cs_change;
+
+  return ioctl(fd,SPI_IOC_MESSAGE(1),&tran);
+  
 }
+int spi_transfer_tx_rx_2(int fd,
+			 void *tx_buff, __u32 tx_buff_len,
+			 void *rx_buff, __u32 rx_buff_len,
+			 __u8 bits, __u32 speed, __u16 delay, __u8 cs_change) {
 
-int spi_set_rd_mode(int fd, __u8 mode) {
-  return ioctl(fd,SPI_IOC_RD_MODE,&mode);
+  struct spi_ioc_transfer tran[2];
+  memset(tran,0,sizeof(tran));
+  
+  tran[0].tx_buf        = (__u64) tx_buff;
+  tran[0].len           = tx_buff_len;
+  tran[0].bits_per_word = bits;
+  tran[0].speed_hz      = speed;
+  tran[0].delay_usecs   = delay;
+  tran[0].cs_change     = cs_change;
+
+  tran[1].rx_buf        = (__u64) rx_buff;
+  tran[1].len           = rx_buff_len;
+  tran[1].bits_per_word = bits;
+  tran[1].speed_hz      = speed;
+  tran[1].delay_usecs   = delay;
+  tran[1].cs_change     = cs_change;
+
+  return ioctl(fd,SPI_IOC_MESSAGE(2),tran);
+  
 }
-int spi_set_wr_mode(int fd, __u8 mode) {
+int spi_transfer_tx_1(int fd, void *buff, __u32 buff_len, __u8 bits, __u32 speed, __u16 delay, __u8 cs_change) {
+  
+  struct spi_ioc_transfer tran;
+  memset(&tran,0,sizeof(struct spi_ioc_transfer));
+  
+  tran.tx_buf        = (__u64) buff;
+  tran.len           = buff_len;
+  tran.bits_per_word = bits;
+  tran.speed_hz      = speed;
+  tran.delay_usecs   = delay;
+  tran.cs_change     = cs_change;
+
+  return ioctl(fd,SPI_IOC_MESSAGE(1),&tran);
+
+}
+int spi_transfer_rx_1(int fd, void *buff, __u32 buff_len, __u8 bits, __u32 speed, __u16 delay, __u8 cs_change) {
+  
+  struct spi_ioc_transfer tran;
+  memset(&tran,0,sizeof(struct spi_ioc_transfer));
+  
+  tran.rx_buf        = (__u64) buff;
+  tran.len           = buff_len;
+  tran.bits_per_word = bits;
+  tran.speed_hz      = speed;
+  tran.delay_usecs   = delay;
+  tran.cs_change     = cs_change;
+
+  return ioctl(fd,SPI_IOC_MESSAGE(1),&tran);
+
+}
+
+
+int spi_get_mode(int fd, __u8 *pmode) {
+  return ioctl(fd,SPI_IOC_RD_MODE,pmode);
+}
+int spi_set_mode(int fd, __u8 mode) {
   return ioctl(fd,SPI_IOC_WR_MODE,&mode);
 }
 
-int spi_set_rd_lbs_first(int fd, __u8 lbs) {
-  return ioctl(fd,SPI_IOC_RD_LSB_FIRST,&lbs);
+int spi_get_lsb_first(int fd, __u8 *plsb) {
+  return ioctl(fd,SPI_IOC_RD_LSB_FIRST,plsb);
 }
-int spi_set_wr_lbs_first(int fd, __u8 lbs) {
-  return ioctl(fd,SPI_IOC_WR_LSB_FIRST,&lbs);
+int spi_set_lsb_first(int fd, __u8 lsb) {
+  return ioctl(fd,SPI_IOC_WR_LSB_FIRST,&lsb);
 }
 
-int spi_set_rd_bits_per_word(int fd, __u8 bits) {
-  return ioctl(fd,SPI_IOC_RD_BITS_PER_WORD,&bits);
+int spi_get_bits_per_word(int fd, __u8 *pbits) {
+  return ioctl(fd,SPI_IOC_RD_BITS_PER_WORD,pbits);
 }
-int spi_set_wr_bits_per_word(int fd, __u8 bits) {
+int spi_set_bits_per_word(int fd, __u8 bits) {
   return ioctl(fd,SPI_IOC_WR_BITS_PER_WORD,&bits);
 }
 
-int spi_set_rd_max_speed_hz(int fd, __u32 speed) {
-  return ioctl(fd,SPI_IOC_RD_MAX_SPEED_HZ,&speed);
+int spi_get_max_speed_hz(int fd, __u32 *pspeed) {
+  return ioctl(fd,SPI_IOC_RD_MAX_SPEED_HZ,pspeed);
 }
-int spi_set_wr_max_speed_hz(int fd, __u32 speed) {
+int spi_set_max_speed_hz(int fd, __u32 speed) {
   return ioctl(fd,SPI_IOC_WR_MAX_SPEED_HZ,&speed);
 }
 
diff --git a/huckleberry.cabal b/huckleberry.cabal
--- a/huckleberry.cabal
+++ b/huckleberry.cabal
@@ -1,5 +1,5 @@
 name:                huckleberry
-version:             0.9.1.1
+version:             0.10.0.0
 synopsis:            Haskell IOT on Intel Edison and other Linux computers.
 description:         Please see README.md
 homepage:            https://github.com/mitsuji/huckleberry#readme
@@ -24,6 +24,8 @@
                      , System.PIO.Linux.PWM
                      , System.PIO.Linux.I2C
                      , System.PIO.Linux.SPI
+                     , System.PIO.Linux.I2C.Raw
+                     , System.PIO.Linux.SPI.Raw
   build-depends:       base >= 4.7 && < 5
   default-language:    Haskell2010
   c-sources:           cbits/hs_fcntl.c
diff --git a/include/hs_fcntl.h b/include/hs_fcntl.h
--- a/include/hs_fcntl.h
+++ b/include/hs_fcntl.h
@@ -1,8 +1,6 @@
 #ifndef HS_FCNTL_H
 #define HS_FCNTL_H
 
-#include <linux/types.h>
-
 int o_rdonly();
 int o_wronly();
 int o_rdwr();
diff --git a/include/hs_spi.h b/include/hs_spi.h
--- a/include/hs_spi.h
+++ b/include/hs_spi.h
@@ -2,27 +2,31 @@
 #define HS_SPI_H
 
 #include <linux/types.h>
-#include <stddef.h>
-#include <stdio.h>
 
 unsigned char spi_mode_0();
 unsigned char spi_mode_1();
 unsigned char spi_mode_2();
 unsigned char spi_mode_3();
 
-int spi_transfer_message_1(int fd, void* buff, __u32 buff_len, __u32 speed, __u8 bits);
+int spi_transfer_tx_rx_1(int fd, void *buff, __u32 buff_len, __u8 bits, __u32 speed, __u16 delay, __u8 cs_change);
+int spi_transfer_tx_rx_2(int fd,
+			 void *tx_buff, __u32 tx_buff_len,
+			 void *rx_buff, __u32 rx_buff_len,
+			 __u8 bits, __u32 speed, __u16 delay, __u8 cs_change);
+int spi_transfer_tx_1(int fd, void *buff, __u32 buff_len, __u8 bits, __u32 speed, __u16 delay, __u8 cs_change);
+int spi_transfer_rx_1(int fd, void *buff, __u32 buff_len, __u8 bits, __u32 speed, __u16 delay, __u8 cs_change);
 
-int spi_set_rd_mode(int fd, __u8 mode);
-int spi_set_wr_mode(int fd, __u8 mode);
+int spi_get_mode(int fd, __u8 *pmode);
+int spi_set_mode(int fd, __u8 mode);
 
-int spi_set_rd_lbs_first(int fd, __u8 lbs);
-int spi_set_wr_lbs_first(int fd, __u8 lbs);
+int spi_get_lsb_first(int fd, __u8 *plsb);
+int spi_set_lsb_first(int fd, __u8 lsb);
 
-int spi_set_rd_bits_per_word(int fd, __u8 bits);
-int spi_set_wr_bits_per_word(int fd, __u8 bits);
+int spi_get_bits_per_word(int fd, __u8 *pbits);
+int spi_set_bits_per_word(int fd, __u8 bits);
 
-int spi_set_rd_max_speed_hz(int fd, __u32 speed);
-int spi_set_wr_max_speed_hz(int fd, __u32 speed);
+int spi_get_max_speed_hz(int fd, __u32 *pspeed);
+int spi_set_max_speed_hz(int fd, __u32 speed);
 
 
 #endif
diff --git a/src/System/PIO.hs b/src/System/PIO.hs
--- a/src/System/PIO.hs
+++ b/src/System/PIO.hs
@@ -14,18 +14,22 @@
     f2 '1' = 1
 
 
+-- | an unsigned number in binary notation.
 binToNum :: (Eq a, Num a) => String -> a
 binToNum s = case readBin s of
   (x,""):_  -> x
   _         -> error "binToNum: parse error" 
 
 
+-- | an unsigned number in octal notation.
 octToNum :: (Eq a, Num a) => String -> a
 octToNum s = case readOct s of
   (x,""):_  -> x
   _         -> error "octToNum: parse error" 
 
 
+-- | an unsigned number in hexadecimal notation.
+-- Both upper or lower case letters are allowed.
 hexToNum :: (Eq a, Num a) => String -> a
 hexToNum s = case readHex s of
   (x,""):_  -> x
diff --git a/src/System/PIO/Linux.hs b/src/System/PIO/Linux.hs
--- a/src/System/PIO/Linux.hs
+++ b/src/System/PIO/Linux.hs
@@ -1,29 +1,82 @@
 {-# LANGUAGE ForeignFunctionInterface #-}
 
 module System.PIO.Linux (
+  FilePath,
+  FileDescriptor,
+  IOMode(..),
   fdOpen,
   fdClose,
   fdPutBuf,
   fdGetBuf,
-  oRdOnly,
-  oWrOnly,
-  oRdWr
   ) where
 
 import Foreign.Ptr(Ptr)
 import Foreign.C.String(CString,withCString)
-  
-foreign import ccall "open" open :: CString -> Int -> IO Int
-foreign import ccall "close" fdClose :: Int -> IO Int
-                                        
-foreign import ccall "write" fdPutBuf :: Int -> Ptr a -> Int -> IO Int
-foreign import ccall "read" fdGetBuf :: Int -> Ptr a -> Int -> IO Int
-                                        
-foreign import ccall "o_rdonly" oRdOnly :: Int
-foreign import ccall "o_wronly" oWrOnly :: Int
-foreign import ccall "o_rdwr" oRdWr :: Int
+import Prelude hiding (FilePath)
+import Foreign.C.Error(throwErrno)
+
+-- | File and directory names are values of type String
+type FilePath = String
+
+-- | File descriptor numbers are values of type Int
+type FileDescriptor = Int
+                
+
+foreign import ccall "o_rdonly" o_rdonly :: Int
+foreign import ccall "o_wronly" o_wronly :: Int
+foreign import ccall "o_rdwr" o_rdwr :: Int
                                         
-fdOpen :: String -> Int -> IO Int
-fdOpen path flags = withCString path $ \cs -> open cs flags
-                                              
+foreign import ccall "open" linux_open :: CString -> Int -> IO Int
+foreign import ccall "close" linux_close :: Int -> IO Int
+foreign import ccall "write" linux_write :: Int -> Ptr a -> Int -> IO Int
+foreign import ccall "read" linux_read :: Int -> Ptr a -> Int -> IO Int
+
+                
+data IOMode = ReadMode
+            | WriteMode
+            | ReadWriteMode
+              
+instance Enum IOMode where
+  
+  toEnum n | n == o_rdonly = ReadMode
+           | n == o_wronly = WriteMode
+           | n == o_rdwr = ReadWriteMode
+           | otherwise = error "toEnum: convert error"
+
+  fromEnum ReadMode = o_rdonly
+  fromEnum WriteMode = o_wronly
+  fromEnum ReadWriteMode = o_rdwr
+
+
+
+-- | Computation 'fdOpen' @file@ @mode@ allocates and returns a new, open
+-- descriptor to manage the file @file@. It manages input if @mode@
+-- is 'ReadMode', output if @mode@ is 'WriteMode',
+-- and both input and output if mode is 'ReadWriteMode'.
+fdOpen :: FilePath -> IOMode -> IO FileDescriptor
+fdOpen path mode = withCString path $
+  \cpath -> linux_open cpath (fromEnum mode) >>= \fd -> case fd of
+    -1 -> throwErrno "fdOpen"
+    otherwise -> return fd
+
+-- | Computation 'fdClose' @fd@ makes descriptor @fd@ closed.
+fdClose :: FileDescriptor -> IO ()
+fdClose fd = linux_close fd >>= \rc -> case rc of
+  -1 -> throwErrno "fdClose"
+  otherwise -> return ()
+
+-- | 'fdPutBuf' @fd@ @buf@ @count@ writes @count@ 8-bit bytes from the
+-- buffer @buf@ to the descriptor @fd@.
+fdPutBuf :: FileDescriptor -> Ptr a -> Int -> IO ()
+fdPutBuf fd buf bufLen = linux_write fd buf bufLen >>= \rc -> case rc of
+  -1 -> throwErrno "fdPutBuf"
+  otherwise -> return ()
+
+-- | 'fdGetBuf' @fd@ @buf@ @count@ reads data from the descriptor @fd@
+-- into the buffer @buf@ until either EOF is reached or
+-- @count@ 8-bit bytes have been read.
+fdGetBuf :: FileDescriptor -> Ptr a -> Int -> IO ()
+fdGetBuf fd buf bufLen = linux_read fd buf bufLen >>= \rc -> case rc of
+  -1 -> throwErrno "fdGetBuf"
+  otherwise -> return ()
 
diff --git a/src/System/PIO/Linux/GPIO.hs b/src/System/PIO/Linux/GPIO.hs
--- a/src/System/PIO/Linux/GPIO.hs
+++ b/src/System/PIO/Linux/GPIO.hs
@@ -1,21 +1,27 @@
 module System.PIO.Linux.GPIO (
+  PinNumber,
   setValue,
   getValue
   ) where
 
 import System.IO (writeFile, readFile)
 
-  
+-- | GPIO pin numbers are values of type Int
+type PinNumber = Int
+
 valueFilePath :: Int -> String
 valueFilePath n = "/sys/class/gpio/gpio" ++ (show n) ++ "/value"
 
 
-setValue :: Int -> Bool -> IO ()
+-- | Computation 'setValue' @pinnum@ @True@ makes corresponding pin high.
+-- Computation 'setValue' @pinnum@ @False@ makes corresponding pin low.
+setValue :: PinNumber -> Bool -> IO ()
 setValue n flag =
   writeFile (valueFilePath n) $ show $ fromEnum flag
 
 
-getValue :: Int -> IO Bool
+-- | Computation 'getValue' @pinnum@ obtain status of corresponding pin.
+getValue :: PinNumber -> IO Bool
 getValue n =
   (\flag -> toEnum $ read flag) <$> readFile (valueFilePath n)
 
diff --git a/src/System/PIO/Linux/I2C.hs b/src/System/PIO/Linux/I2C.hs
--- a/src/System/PIO/Linux/I2C.hs
+++ b/src/System/PIO/Linux/I2C.hs
@@ -1,10 +1,5 @@
-{-# LANGUAGE ForeignFunctionInterface #-}
 
+
 module System.PIO.Linux.I2C (
-  setSlave
   ) where
-
-import Data.Word(Word8)
-
-foreign import ccall "i2c_set_slave" setSlave :: Int -> Word8 -> IO Int
 
diff --git a/src/System/PIO/Linux/I2C/Raw.hs b/src/System/PIO/Linux/I2C/Raw.hs
new file mode 100644
--- /dev/null
+++ b/src/System/PIO/Linux/I2C/Raw.hs
@@ -0,0 +1,23 @@
+{-# LANGUAGE ForeignFunctionInterface #-}
+
+module System.PIO.Linux.I2C.Raw (
+  SlaveAddress,
+  setSlave
+  ) where
+
+import Data.Word(Word8)
+import System.PIO.Linux(FileDescriptor)
+import Foreign.C.Error(throwErrno)
+
+type SlaveAddress = Word8
+
+foreign import ccall "i2c_set_slave" i2c_set_slave :: Int -> Word8 -> IO Int
+
+
+-- | Computation 'setSlave' @fd@ @address@ sets the slave address for
+-- descriptor @fd@ on I2C.
+setSlave :: FileDescriptor -> SlaveAddress -> IO ()
+setSlave fd addr = i2c_set_slave fd addr >>= \rc -> case rc of
+  -1 -> throwErrno "setSlave"
+  otherwize -> return ()
+
diff --git a/src/System/PIO/Linux/PWM.hs b/src/System/PIO/Linux/PWM.hs
--- a/src/System/PIO/Linux/PWM.hs
+++ b/src/System/PIO/Linux/PWM.hs
@@ -1,4 +1,7 @@
 module System.PIO.Linux.PWM (
+  Channel,
+  Period,
+  DutyCycle,
   setEnable,
   getEnable,
   setValue,
@@ -7,7 +10,16 @@
 
 import System.IO (writeFile, readFile)
 
+-- | PWM channel numbers are values of type Int
+type Channel = Int
 
+-- | PWM period is a value of type Int
+type Period = Int
+
+-- | PWM duty cycle is a value of type Int
+type DutyCycle = Int
+
+
 interfaceFilePath :: Int -> String -> String
 interfaceFilePath n file = "/sys/class/pwm/pwmchip0/pwm" ++ (show n) ++ file
 
@@ -21,17 +33,21 @@
 dutyCycleFilePath n = interfaceFilePath n "/duty_cycle"
 
 
-setEnable :: Int -> Bool -> IO ()
+-- | Computation 'setEnable' @channel@ @True@ makes corresponding PWM channel enabled.
+-- Computation 'setEnable' @channel@ @False@ makes corresponding PWM channel disabled.
+setEnable :: Channel -> Bool -> IO ()
 setEnable n flag =
   writeFile (enableFilePath n) $ show $ fromEnum flag
 
 
-getEnable :: Int -> IO Bool
+-- | Computation 'getEnable' @channel@ obtain status of corresponding PWM channel.
+getEnable :: Channel -> IO Bool
 getEnable n =
   (\flag -> toEnum $ read flag) <$> readFile (enableFilePath n)
 
 
-setValue :: Int -> Int -> Int -> IO ()
+-- | 'setValue' @channel@ @period@ @dutyCycle@ generates PWM signal on corresponding PWM channel. @period@ and @dutyCycle@ are value of nanoseconds.
+setValue :: Channel -> Period -> DutyCycle -> IO ()
 setValue n period dutyCycle = do
   let dutyCycleFilePath' = dutyCycleFilePath n
   writeFile dutyCycleFilePath' $ show 0
@@ -39,7 +55,8 @@
   writeFile dutyCycleFilePath' $ show dutyCycle
 
 
-getValue :: Int -> IO (Int, Int)
+-- | 'getValue' @channel@ obtain status of current PWM signal on corresponding PWM channel.
+getValue :: Channel -> IO (Period, DutyCycle)
 getValue n =
   (\p dc -> (read p, read dc)) <$> readFile (periodFilePath n) <*> readFile (dutyCycleFilePath n)
 
diff --git a/src/System/PIO/Linux/SPI.hs b/src/System/PIO/Linux/SPI.hs
--- a/src/System/PIO/Linux/SPI.hs
+++ b/src/System/PIO/Linux/SPI.hs
@@ -1,40 +1,5 @@
-{-# LANGUAGE ForeignFunctionInterface #-}
 
+
 module System.PIO.Linux.SPI (
-  mode0,
-  mode1,
-  mode2,
-  mode3,
-  transferMessage1,
-  setRdMode,
-  setWrMode,
-  setRdLbsFirst,
-  setWrLbsFirst,
-  setRdBitsPerWord,
-  setWrBitsPerWord,
-  setRdMaxSpeedHz,
-  setWrMaxSpeedHz,
   ) where
-
-import Foreign.Ptr(Ptr)
-import Data.Word(Word8,Word32)
-
-foreign import ccall "spi_mode_0" mode0 :: Word8
-foreign import ccall "spi_mode_1" mode1 :: Word8
-foreign import ccall "spi_mode_2" mode2 :: Word8
-foreign import ccall "spi_mode_3" mode3 :: Word8
-
-foreign import ccall "spi_transfer_message_1" transferMessage1 :: Int -> Ptr a -> Int -> Word32 -> Word8 -> IO Int
-
-foreign import ccall "spi_set_rd_mode" setRdMode :: Int -> Word8 -> IO Int
-foreign import ccall "spi_set_wr_mode" setWrMode :: Int -> Word8 -> IO Int
-
-foreign import ccall "spi_set_rd_lbs_first" setRdLbsFirst :: Int -> Word8 -> IO Int
-foreign import ccall "spi_set_wr_lbs_first" setWrLbsFirst :: Int -> Word8 -> IO Int
-
-foreign import ccall "spi_set_rd_bits_per_word" setRdBitsPerWord :: Int -> Word8 -> IO Int
-foreign import ccall "spi_set_wr_bits_per_word" setWrBitsPerWord :: Int -> Word8 -> IO Int
-
-foreign import ccall "spi_set_rd_max_speed_hz" setRdMaxSpeedHz :: Int -> Word32 -> IO Int
-foreign import ccall "spi_set_wr_max_speed_hz" setWrMaxSpeedHz :: Int -> Word32 -> IO Int
 
diff --git a/src/System/PIO/Linux/SPI/Raw.hs b/src/System/PIO/Linux/SPI/Raw.hs
new file mode 100644
--- /dev/null
+++ b/src/System/PIO/Linux/SPI/Raw.hs
@@ -0,0 +1,200 @@
+{-# LANGUAGE ForeignFunctionInterface #-}
+
+module System.PIO.Linux.SPI.Raw (
+  SPIMode(..),
+  Bits,
+  Speed,
+  transferTxRx1,
+  transferTxRx2,
+  transferTx,
+  transferRx,
+  getMode,
+  setMode,
+  getLsbFirst,
+  setLsbFirst,
+  getBitsPerWord,
+  setBitsPerWord,
+  getMaxSpeedHz,
+  setMaxSpeedHz,
+  ) where
+
+import Foreign.Ptr(Ptr)
+import Data.Word(Word8,Word16,Word32)
+import System.PIO.Linux(FileDescriptor)
+import Foreign.Marshal.Alloc(alloca)
+import Foreign.Storable(peek)
+import Foreign.C.Error(throwErrno)
+
+
+type Bits  = Word8
+type Speed = Word32
+type Delay = Word16
+type CSChange = Bool
+
+
+foreign import ccall "spi_mode_0" spi_mode0 :: Word8
+foreign import ccall "spi_mode_1" spi_mode1 :: Word8
+foreign import ccall "spi_mode_2" spi_mode2 :: Word8
+foreign import ccall "spi_mode_3" spi_mode3 :: Word8
+
+foreign import ccall "spi_transfer_tx_rx_1" spi_transfer_tx_rx_1
+  :: Int -> Ptr a -> Int -> Word8 -> Word32 -> Word16 -> Word8 -> IO Int
+foreign import ccall "spi_transfer_tx_rx_2" spi_transfer_tx_rx_2
+  :: Int -> Ptr a -> Int -> Ptr a -> Int -> Word8 -> Word32 -> Word16 -> Word8 -> IO Int
+foreign import ccall "spi_transfer_tx_1" spi_transfer_tx_1
+  :: Int -> Ptr a -> Int -> Word8 -> Word32 -> Word16 -> Word8 -> IO Int
+foreign import ccall "spi_transfer_rx_1" spi_transfer_rx_1
+  :: Int -> Ptr a -> Int -> Word8 -> Word32 -> Word16 -> Word8 -> IO Int
+
+foreign import ccall "spi_get_mode" spi_get_mode :: Int -> Ptr Word8 -> IO Int
+foreign import ccall "spi_set_mode" spi_set_mode :: Int -> Word8 -> IO Int
+
+foreign import ccall "spi_get_lsb_first" spi_get_lsb_first :: Int -> Ptr Word8 -> IO Int
+foreign import ccall "spi_set_lsb_first" spi_set_lsb_first :: Int -> Word8 -> IO Int
+
+foreign import ccall "spi_get_bits_per_word" spi_get_bits_per_word :: Int -> Ptr Word8 -> IO Int
+foreign import ccall "spi_set_bits_per_word" spi_set_bits_per_word :: Int -> Word8 -> IO Int
+
+foreign import ccall "spi_get_max_speed_hz" spi_get_max_speed_hz :: Int -> Ptr Word32 -> IO Int
+foreign import ccall "spi_set_max_speed_hz" spi_set_max_speed_hz :: Int -> Word32 -> IO Int
+
+
+
+data SPIMode = Mode0
+             | Mode1
+             | Mode2
+             | Mode3
+              
+                                        
+instance Enum SPIMode where
+  
+  toEnum n | (fromIntegral n) == spi_mode0 = Mode0
+           | (fromIntegral n) == spi_mode1 = Mode1
+           | (fromIntegral n) == spi_mode2 = Mode2
+           | (fromIntegral n) == spi_mode3 = Mode3
+           | otherwise  = error "toEnum: convert error"
+
+  fromEnum Mode0 = (fromIntegral spi_mode0)
+  fromEnum Mode1 = (fromIntegral spi_mode1)
+  fromEnum Mode2 = (fromIntegral spi_mode2)
+  fromEnum Mode3 = (fromIntegral spi_mode3)
+
+
+
+-- | 'transferTxRx1' @fd@ @buf@ @count@ @bits@ @speed@ @delay@ @csChange@ transfer @count@ 8-bit bytes from the
+-- buffer @buf@ to the descriptor @fd@.
+transferTxRx1 :: FileDescriptor -> Ptr a -> Int -> Bits -> Speed -> Delay -> CSChange -> IO ()
+transferTxRx1 fd buf bufLen bits speed delay csChange =
+  spi_transfer_tx_rx_1 fd buf bufLen bits speed delay (fromIntegral $ fromEnum csChange)
+  >>= \rc -> case rc of
+    -1 -> throwErrno "transferTxRx1"
+    otherwize -> return ()
+    
+
+transferTxRx2 :: FileDescriptor -> Ptr a -> Int -> Ptr a -> Int -> Bits -> Speed -> Delay -> CSChange -> IO ()
+transferTxRx2 fd txBuf txBufLen rxBuf rxBufLen bits speed delay csChange =
+  spi_transfer_tx_rx_2 fd txBuf txBufLen rxBuf rxBufLen bits speed delay (fromIntegral $ fromEnum csChange)
+  >>= \rc -> case rc of
+    -1 -> throwErrno "transferTxRx2"
+    otherwize -> return ()
+  
+
+transferTx :: FileDescriptor -> Ptr a -> Int -> Bits -> Speed -> Delay -> CSChange -> IO ()
+transferTx fd buf bufLen bits speed delay csChange =
+  spi_transfer_tx_1 fd buf bufLen bits speed delay (fromIntegral $ fromEnum csChange)
+  >>= \rc -> case rc of
+    -1 -> throwErrno "transferTx"
+    otherwize -> return ()
+    
+
+transferRx :: FileDescriptor -> Ptr a -> Int -> Bits -> Speed -> Delay -> CSChange -> IO ()
+transferRx fd buf bufLen bits speed delay csChange =
+  spi_transfer_rx_1 fd buf bufLen bits speed delay (fromIntegral $ fromEnum csChange)
+  >>= \rc -> case rc of
+    -1 -> throwErrno "transferRx"
+    otherwize -> return ()
+
+
+
+-- | Computation 'getMode' @fd@ gets the spi mode for
+-- descriptor @fd@.
+getMode :: FileDescriptor -> IO SPIMode
+getMode fd = alloca $
+             \p -> spi_get_mode fd p >>= \rc -> case rc of
+               -1 -> throwErrno "getMode"
+               otherwize -> do
+                 mode <- peek p
+                 return $ toEnum $ fromIntegral mode
+
+
+-- | Computation 'setMode' @fd@ @mode@ sets the spi mode for
+-- descriptor @fd@.
+setMode :: FileDescriptor -> SPIMode -> IO ()
+setMode fd mode =
+  spi_set_mode fd (fromIntegral $ fromEnum mode)
+  >>= \rc -> case rc of
+    -1 -> throwErrno "setMode"
+    otherwize -> return ()
+
+
+-- | Computation 'getLsbFirst' @fd@ gets the LBS-first flag for
+-- descriptor @fd@.
+getLsbFirst :: FileDescriptor -> IO Bool
+getLsbFirst fd = alloca $
+                 \p -> spi_get_lsb_first fd p >>= \rc -> case rc of
+                   -1 -> throwErrno "getLsbFirst"
+                   otherwize -> do
+                     flag <- peek p
+                     return $ toEnum $ fromIntegral flag
+
+
+-- | Computation 'setLsbFirst' @fd@ @flag@ sets the LBS-first flag for
+-- descriptor @fd@.
+setLsbFirst :: FileDescriptor -> Bool -> IO ()
+setLsbFirst fd flag =
+  spi_set_lsb_first fd (fromIntegral $ fromEnum flag)
+  >>= \rc -> case rc of
+    -1 -> throwErrno "setLsbFirst"
+    otherwize -> return ()
+
+
+-- | Computation 'getBitsPerWord' @fd@ gets the number
+-- of bits in each SPI transfer word for
+-- descriptor @fd@.
+getBitsPerWord :: FileDescriptor -> IO Bits
+getBitsPerWord fd = alloca $
+  \p -> spi_get_bits_per_word fd p >>= \rc -> case rc of
+    -1 -> throwErrno "getBitsPerWord"
+    otherwize -> peek p
+
+
+-- | Computation 'setBitsPerWord' @fd@ @bits@ sets the number
+-- of bits in each SPI transfer word for
+-- descriptor @fd@.
+setBitsPerWord :: FileDescriptor -> Bits -> IO ()
+setBitsPerWord fd bits = spi_set_bits_per_word fd bits
+  >>= \rc -> case rc of
+    -1 -> throwErrno "setBitsPerWord"
+    otherwize -> return ()
+
+
+-- | Computation 'getMaxSpeedHz' @fd@ gets the maximum
+-- SPI transfer speed, in Hz for
+-- descriptor @fd@.
+getMaxSpeedHz :: FileDescriptor -> IO Speed
+getMaxSpeedHz fd = alloca $
+  \p -> spi_get_max_speed_hz fd p >>= \rc -> case rc of
+    -1 -> throwErrno "getMaxSpeedHz"
+    otherwize -> peek p
+
+
+-- | Computation 'setMaxSpeedHz' @fd@ @speed@ sets the maximum
+-- SPI transfer speed, in Hz for
+-- descriptor @fd@.
+setMaxSpeedHz :: FileDescriptor -> Speed -> IO ()
+setMaxSpeedHz fd speed = spi_set_max_speed_hz fd speed
+  >>= \rc -> case rc of
+    -1 -> throwErrno "setMaxSpeedHz"
+    otherwize -> return ()
+
+
