{-# LINE 1 "System/Linux/HIDRaw.hsc" #-}
{-# LANGUAGE MultiParamTypeClasses, ForeignFunctionInterface #-}
{-# LINE 2 "System/Linux/HIDRaw.hsc" #-}
-- | Minimal interface to hidraw ioctls, sufficient for blink(1)
module System.Linux.HIDRaw
  ( DevInfo(..)
  , devInfo
  , setFeature
  , getFeature
  ) where

import Data.Bits ((.|.), shiftL)
import Data.Word (Word8, Word16, Word32)
import Foreign.C.Error
import Foreign.C.Types
import Foreign.Ptr (Ptr)
import Foreign.Marshal.Alloc (alloca)
import Foreign.Marshal.Array
import Foreign.Storable
import System.Posix.Types (Fd)


{-# LINE 21 "System/Linux/HIDRaw.hsc" #-}

{-# LINE 22 "System/Linux/HIDRaw.hsc" #-}

-- the ioctl package doesn't support variable-length data, so we call them directly

foreign import ccall unsafe "ioctl" c_ioctl :: CInt -> CInt -> Ptr a -> IO CInt

ioctl :: Storable p => Fd -> CInt -> Ptr p -> IO ()
ioctl f r p = throwErrnoIfMinus1_ "ioctl" $ c_ioctl (fromIntegral f) r p

data DevInfo = DevInfo 
  { devBustype :: Word32
  , devVendor :: Word16
  , devProduct :: Word16
  }

instance Storable DevInfo where
  sizeOf _ = (8)
{-# LINE 38 "System/Linux/HIDRaw.hsc" #-}
  alignment _ = 4 -- #alignment struct hidraw_devinfo
  peek p = do
    b <- (\hsc_ptr -> peekByteOff hsc_ptr 0) p
{-# LINE 41 "System/Linux/HIDRaw.hsc" #-}
    v <- (\hsc_ptr -> peekByteOff hsc_ptr 4) p
{-# LINE 42 "System/Linux/HIDRaw.hsc" #-}
    i <- (\hsc_ptr -> peekByteOff hsc_ptr 6) p
{-# LINE 43 "System/Linux/HIDRaw.hsc" #-}
    return $ DevInfo b v i
  poke p (DevInfo b v i) = do
    (\hsc_ptr -> pokeByteOff hsc_ptr 0) p b
{-# LINE 46 "System/Linux/HIDRaw.hsc" #-}
    (\hsc_ptr -> pokeByteOff hsc_ptr 4) p v
{-# LINE 47 "System/Linux/HIDRaw.hsc" #-}
    (\hsc_ptr -> pokeByteOff hsc_ptr 6) p i
{-# LINE 48 "System/Linux/HIDRaw.hsc" #-}

devInfo :: Fd -> IO DevInfo
devInfo d = alloca $ \p -> ioctl d 2148026371 p >> peek p
{-# LINE 51 "System/Linux/HIDRaw.hsc" #-}

ioctlLen :: Storable p => Fd -> CInt -> Int -> Ptr p -> IO ()
ioctlLen f r l p 
  | len > mask = ioError $ errnoToIOError "ioctlLen" eMSGSIZE Nothing Nothing
  | otherwise = ioctl f (r .|. (len `shiftL` shift)) p
  where 
    len = fromIntegral $ l * sizeOf (ptrType p)
    ptrType :: Ptr p -> p
    ptrType _ = undefined
    shift = 16
{-# LINE 61 "System/Linux/HIDRaw.hsc" #-}
    mask = 16383
{-# LINE 62 "System/Linux/HIDRaw.hsc" #-}

setFeature :: Fd -> [Word8] -> IO ()
setFeature d x = withArrayLen x $ ioctlLen d 3221243910
{-# LINE 65 "System/Linux/HIDRaw.hsc" #-}

getFeature :: Fd -> Int -> IO [Word8]
getFeature d l = allocaArray l $ \p -> do
  ioctlLen d 3221243911 l p
{-# LINE 69 "System/Linux/HIDRaw.hsc" #-}
  peekArray l p