udev (empty) → 0.0.0.0
raw patch · 17 files changed
+1632/−0 lines, 17 filesdep +basedep +bytestringdep +selectsetup-changed
Dependencies added: base, bytestring, select, udev, unix
Files
- LICENSE +30/−0
- README.md +22/−0
- Setup.hs +2/−0
- changelog +1/−0
- examples/hidraw.hs +35/−0
- examples/monitor.hs +39/−0
- src/System/UDev.hs +39/−0
- src/System/UDev/Context.hs +158/−0
- src/System/UDev/Device.hs +409/−0
- src/System/UDev/Enumerate.hs +248/−0
- src/System/UDev/HWDB.hs +44/−0
- src/System/UDev/List.hs +59/−0
- src/System/UDev/Monitor.hs +187/−0
- src/System/UDev/Queue.hs +112/−0
- src/System/UDev/Types.hs +152/−0
- src/System/UDev/Util.hs +24/−0
- udev.cabal +71/−0
+ LICENSE view
@@ -0,0 +1,30 @@+Copyright (c) 2013, Sam Truzjan++All rights reserved.++Redistribution and use in source and binary forms, with or without+modification, are permitted provided that the following conditions are met:++ * Redistributions of source code must retain the above copyright+ notice, this list of conditions and the following disclaimer.++ * Redistributions in binary form must reproduce the above+ copyright notice, this list of conditions and the following+ disclaimer in the documentation and/or other materials provided+ with the distribution.++ * Neither the name of Sam Truzjan nor the names of other+ contributors may be used to endorse or promote products derived+ from this software without specific prior written permission.++THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ README.md view
@@ -0,0 +1,22 @@+This package provides Haskell bindings to [libudev][libudev], that+allows access to device information. `libudev` is part of [udev][udev]+device manager for linux kernel.++To build library you need to install `libudev-dev` (Debian, Ubuntu) first.++To build [examples](examples) you need to configure package with+`examples` flag. The examples are ported from this [tutorial][tutor].++### Build Status [![Build Status][status-img]][status-link]++### Maintainer <pxqr.sta@gmail.com>++Feel free to report bugs and suggestions via github+[issue tracker][issues] or the mail.++[udev]: http://cgit.freedesktop.org/systemd/systemd/tree/src/udev+[libudev]: http://www.freedesktop.org/software/systemd/libudev/+[tutor]: http://www.signal11.us/oss/udev+[status-img]: https://travis-ci.org/pxqr/udev.png+[status-link]: https://travis-ci.org/pxqr/udev+[issues]: https://github.com/pxqr/udev/issues
+ Setup.hs view
@@ -0,0 +1,2 @@+import Distribution.Simple+main = defaultMain
+ changelog view
@@ -0,0 +1,1 @@+* 0.0.0.0: Initial version.
+ examples/hidraw.hs view
@@ -0,0 +1,35 @@+{-# LANGUAGE OverloadedStrings #-}+module Main (main) where++import Data.ByteString as BS+import Data.ByteString.Char8 as BC++import System.UDev.Context+import System.UDev.Device+import System.UDev.Enumerate+import System.UDev.List+++main :: IO ()+main = do+ withUDev $ \ udev -> do+ e <- newEnumerate udev+ addMatchSubsystem e "hidraw"+ scanDevices e+ ls <- getListEntry e+ path <- getName ls+ print path+ dev <- newFromSysPath udev path+ print $ getDevnode dev+ mdev <- getParentWithSubsystemDevtype dev "usb" "usb_device"+ case mdev of+ Nothing -> BC.putStrLn "unable to find parent usb device"+ Just pdev -> do+ BC.putStrLn $ BS.concat+ [ "VID/PID: ", getSysattrValue pdev "idVendor" , " "+ , getSysattrValue pdev "idProduct", "\n"+ , getSysattrValue pdev "manufacturer", "\n"+ , getSysattrValue pdev "product" , "\n"+-- , "serial: ", getSysattrValue pdev "serial"+ ]+ return ()
+ examples/monitor.hs view
@@ -0,0 +1,39 @@+{-# LANGUAGE OverloadedStrings #-}+module Main (main) where++import Control.Monad+import Data.ByteString.Char8 as BC++import System.UDev.Context+import System.UDev.Device+import System.UDev.Monitor+import System.Posix.IO.Select+import System.Posix.IO.Select.Types+++dumpDeviceInfo :: Device -> IO ()+dumpDeviceInfo dev = do+ print $ getSubsystem dev+ print $ getDevtype dev+ print $ getSyspath dev+ print $ getSysname dev+ print $ getSysnum dev+ print $ getDevnode dev+ print $ getAction dev++main :: IO ()+main = do+ withUDev $ \ udev -> do+ setLogPriority udev LogDebug+ setLogger udev defaultLogger+ monitor <- newFromNetlink udev udevId+ enableReceiving monitor+ fd <- getFd monitor+ forever $ do+ res <- select' [fd] [] [] Never+ case res of+ Just ([_], [], []) -> do+ dev <- receiveDevice monitor+ dumpDeviceInfo dev+ Nothing -> return ()+ return ()
+ src/System/UDev.hs view
@@ -0,0 +1,39 @@+-- |+-- Copyright : (c) Sam Truzjan 2013+-- License : BSD3+-- Maintainer : pxqr.sta@gmail.com+-- Stability : experimental+-- Portability : portable+--+module System.UDev+ ( module System.UDev.Context+ , module System.UDev.Device+ , module System.UDev.Enumerate+ , module System.UDev.HWDB+ , module System.UDev.List+ , module System.UDev.Monitor+ , module System.UDev.Queue+ , module System.UDev.Util+ ) where++import Data.Monoid++import System.UDev.Context+import System.UDev.Device+import System.UDev.Enumerate+import System.UDev.HWDB+import System.UDev.List+import System.UDev.Monitor+import System.UDev.Queue+import System.UDev.Util+++type Devtype = ()+type Tag = ()++data Filter = Filter (Maybe (Subsystem, Devtype)) (Maybe Tag)++instance Monoid Filter where+ mempty = Filter Nothing Nothing+ Filter sda ta `mappend` Filter sdb tb+ = Filter (sda `mappend` sdb) (ta `mappend` tb)
+ src/System/UDev/Context.hs view
@@ -0,0 +1,158 @@+-- |+-- Copyright : (c) Sam Truzjan 2013+-- License : BSD3+-- Maintainer : pxqr.sta@gmail.com+-- Stability : stable+-- Portability : portable+--+-- The context contains the default values read from the udev config+-- file, and is passed to all library operations.+--+{-# LANGUAGE ForeignFunctionInterface #-}+{-# LANGUAGE OverloadedStrings #-}+module System.UDev.Context+ ( -- * Context+ UDev+ , UDevChild (..)+ , newUDev+ , withUDev++ -- * Logging+ , Priority (..)+ , Logger+ , getLogPriority+ , setLogPriority+ , setLogger+ , defaultLogger++ -- * User data+ , getUserdata+ , setUserdata+ ) where++import Control.Applicative+import Control.Exception+import Data.ByteString as BS+import Data.ByteString.Char8 as BC+import Foreign+import Foreign.C.String+import Foreign.C.Types+import Unsafe.Coerce++import System.UDev.Types+++foreign import ccall unsafe "udev_new"+ c_new :: IO UDev++-- | Create udev library context. This reads the udev configuration+-- file, and fills in the default values.+--+newUDev :: IO UDev+newUDev = c_new++-- | Like 'newUDev' but context will be released at exit.+withUDev :: (UDev -> IO a) -> IO a+withUDev = bracket c_new unref++{-----------------------------------------------------------------------+-- Logging+-----------------------------------------------------------------------}++-- | Log message priority.+data Priority = LogError -- ^ error conditions+ | LogInfo -- ^ informational+ | LogDebug -- ^ debug-level messages+ deriving (Show, Read, Eq, Ord, Enum, Bounded)++-- | Convert priority to priority code.+prioToNr :: Priority -> CInt+prioToNr LogError = 3+prioToNr LogInfo = 6+prioToNr LogDebug = 7++-- | Convert priority code to priority.+nrToPrio :: CInt -> IO Priority+nrToPrio 3 = pure LogError+nrToPrio 6 = pure LogInfo+nrToPrio 7 = pure LogDebug+nrToPrio n = throwIO $ PatternMatchFail msg+ where+ msg = "unknown priority number: " ++ show n++foreign import ccall unsafe "udev_get_log_priority"+ c_getLogPriority :: UDev -> IO CInt++-- | The initial logging priority is read from the udev config file at+-- startup.+getLogPriority :: UDev -> IO Priority+getLogPriority udev = nrToPrio =<< c_getLogPriority udev++foreign import ccall unsafe "udev_set_log_priority"+ c_setLogPriority :: UDev -> CInt -> IO ()++-- | Set the current logging priority. The value controls which+-- messages are logged.+setLogPriority :: UDev -> Priority -> IO ()+setLogPriority udev prio = c_setLogPriority udev (prioToNr prio)++type CLogger = UDev -> CInt -> CString -> CInt -> CString -> CString -> IO ()++-- | Logger function will called by udev on events.+type Logger = UDev+ -> Priority -- ^ message priority;+ -> ByteString -- ^ position: file+ -> Int -- ^ position: line+ -> ByteString -- ^ position: function+ -> ByteString -- ^ message body+ -> IO ()++marshLogger :: Logger -> CLogger+marshLogger logger udev c_priority c_file c_line c_fn c_format = do+ file <- packCString c_file+ fn <- packCString c_fn+ format <- packCString c_format+ prio <- nrToPrio c_priority+ logger udev prio file (fromIntegral c_line) fn format++foreign import ccall "wrapper"+ mkLogger :: CLogger -> IO (FunPtr CLogger)++foreign import ccall "udev_set_log_fn"+ c_setLogger :: UDev -> FunPtr CLogger -> IO ()++-- | The built-in logging writes to stderr. It can be overridden by a+-- custom function, to plug log messages into the users' logging+-- functionality.+setLogger :: UDev -> Logger -> IO ()+setLogger udev logger = c_setLogger udev =<< mkLogger (marshLogger logger)++-- | Default logger will just print @%PRIO %FILE:%LINE:\n%FN: %FORMAT@+-- to stdout.+defaultLogger :: Logger+defaultLogger _ priority file line fn format = do+ BC.putStrLn $ BS.concat+ [ BC.pack (show priority), " "+ , file, ":", BC.pack (show line), ":\n"+ , " ", fn, ": ", format+ ]++{-----------------------------------------------------------------------+-- Userdata+-----------------------------------------------------------------------}++foreign import ccall unsafe "udev_get_userdata"+ c_getUserdata :: UDev -> IO (Ptr ())++-- | Retrieve stored data pointer from library context. This might be+-- useful to access from callbacks like a custom logging function.+--+getUserdata :: UDev -> IO a+getUserdata udev = unsafeCoerce <$> c_getUserdata udev++foreign import ccall unsafe "udev_set_userdata"+ c_setUserdata :: UDev -> Ptr () -> IO ()++-- | Store custom userdata in the library context.+setUserdata :: UDev -> a -> IO ()+setUserdata udev ud = c_setUserdata udev (unsafeCoerce ud)
+ src/System/UDev/Device.hs view
@@ -0,0 +1,409 @@+-- |+-- Copyright : (c) Sam Truzjan 2013+-- License : BSD3+-- Maintainer : pxqr.sta@gmail.com+-- Stability : stable+-- Portability : portable+--+-- Representation of kernel sys devices. Devices are uniquely+-- identified by their syspath, every device has exactly one path in+-- the kernel sys filesystem. Devices usually belong to a kernel+-- subsystem, and have a unique name inside that subsystem.+--+module System.UDev.Device+ ( Device+ , Devnum++ -- * Create+ , newFromSysPath+ , newFromDevnum+ , newFromSubsystemSysname+ , newFromDeviceId+ , newFromEnvironment++ , getParent+ , getParentWithSubsystemDevtype++ -- * Query+ , getDevpath+ , getSubsystem+ , getDevtype+ , getSyspath+ , getSysname+ , getSysnum+ , getDevnode+ , isInitialized+ , getDevlinksListEntry+ , getPropertiesListEntry+ , getTagsListEntry+ , getPropertyValue+ , getDriver+ , getDevnum+ , getAction++ -- * Sysattrs+ , getSysattrValue+ , setSysattrValue+ , getSysattrListEntry++ -- * Misc+ , getSeqnum+ , getUsecSinceInitialized+ , hasTag+ ) where++import Control.Applicative+import Data.ByteString as BS+import Foreign hiding (unsafePerformIO)+import Foreign.C+import System.IO.Unsafe++import System.UDev.Context+import System.UDev.List+import System.UDev.Types+++foreign import ccall unsafe "udev_device_new_from_syspath"+ c_newFromSysPath :: UDev -> CString -> IO Device++-- TODO type SysPath = FilePath+type SysPath = ByteString++-- | Create new udev device, and fill in information from the sys+-- device and the udev database entry. The syspath is the absolute+-- path to the device, including the sys mount point.+--+newFromSysPath :: UDev -> SysPath -> IO Device+newFromSysPath udev sysPath = do+ Device <$> (throwErrnoIfNull "newFromSysPath" $ do+ useAsCString sysPath $ \ c_sysPath -> do+ getDevice <$> c_newFromSysPath udev c_sysPath)++type Dev_t = CULong++foreign import ccall unsafe "udev_device_new_from_devnum"+ c_newFromDevnum :: UDev -> CChar -> Dev_t -> IO Device++-- | Device number.+type Devnum = Int++-- | Create new udev device, and fill in information from the sys+-- device and the udev database entry. The device is looked-up by its+-- major/minor number and type. Character and block device numbers are+-- not unique across the two types.+--+newFromDevnum :: UDev -> Char -> Devnum -> IO Device+newFromDevnum udev char devnum+ = c_newFromDevnum udev (toEnum (fromEnum char)) (fromIntegral devnum)+{-# INLINE newFromDevnum #-}++foreign import ccall unsafe "udev_device_new_from_subsystem_sysname"+ c_newFromSubsystemSysname :: UDev -> CString -> CString -> IO Device++-- | The device is looked up by the subsystem and name string of the+-- device, like \"mem\" \/ \"zero\", or \"block\" \/ \"sda\".+--+newFromSubsystemSysname :: UDev -> ByteString -> ByteString -> IO Device+newFromSubsystemSysname udev subsystem sysname = do+ useAsCString subsystem $ \ c_subsystem ->+ useAsCString sysname $ \ c_sysname ->+ c_newFromSubsystemSysname udev c_subsystem c_sysname++foreign import ccall unsafe "udev_device_new_from_device_id"+ c_newFromDeviceId :: UDev -> CString -> IO Device++-- | The device is looked-up by a special string:+--+-- * b8:2 - block device major:minor+--+-- * c128:1 - char device major:minor+--+-- * n3 - network device ifindex+--+-- * +sound:card29 - kernel driver core subsystem:device name+--+newFromDeviceId :: UDev -> ByteString -> IO Device+newFromDeviceId udev devId = do+ useAsCString devId $ \ c_devId ->+ c_newFromDeviceId udev c_devId++foreign import ccall unsafe "udev_device_new_from_environment"+ c_newFromEnvironment :: UDev -> IO Device++-- | Create new udev device, and fill in information from the current+-- process environment. This only works reliable if the process is+-- called from a udev rule. It is usually used for tools executed from+-- @IMPORT=@ rules.+--+newFromEnvironment :: UDev -> IO Device+newFromEnvironment = c_newFromEnvironment++foreign import ccall unsafe "udev_device_get_parent"+ c_getParent :: Device -> IO Device++-- TODO: [MEM]: The returned the device is not referenced. It is+-- attached to the child device, and will be cleaned up when the child+-- device is cleaned up.++-- | Find the next parent device, and fill in information from the sys+-- device and the udev database entry.+getParent :: Device -> IO Device+getParent = c_getParent++foreign import ccall unsafe "udev_device_get_parent_with_subsystem_devtype"+ c_getParentWithSubsystemDevtype :: Device -> CString -> CString+ -> IO Device++-- | Find the next parent device, with a matching subsystem and devtype+-- value, and fill in information from the sys device and the udev+-- database entry.+--+getParentWithSubsystemDevtype :: Device -> ByteString -> ByteString+ -> IO (Maybe Device)+getParentWithSubsystemDevtype udev subsystem devtype = do+ mdev <- useAsCString subsystem $ \ c_subsystem ->+ useAsCString devtype $ \ c_devtype ->+ c_getParentWithSubsystemDevtype udev c_subsystem c_devtype+ return $ if getDevice mdev == nullPtr then Nothing else Just mdev++foreign import ccall unsafe "udev_device_get_devpath"+ c_getDevpath :: Device -> IO CString++-- TODO use RawFilePath++{-----------------------------------------------------------------------+-- Query+-----------------------------------------------------------------------}++-- | Retrieve the kernel devpath value of the udev device. The path+-- does not contain the sys mount point, and starts with a \'/\'.+--+getDevpath :: Device -> IO ByteString+getDevpath dev = packCString =<< c_getDevpath dev++foreign import ccall unsafe "udev_device_get_subsystem"+ c_getSubsystem :: Device -> IO CString++packCStringMaybe :: CString -> IO (Maybe ByteString)+packCStringMaybe cstring =+ if cstring == nullPtr+ then return Nothing+ else Just <$> packCString cstring++-- | Retrieve the subsystem string of the udev device. The string does+-- not contain any \"/\".+--+getSubsystem :: Device -> Maybe ByteString+getSubsystem dev = unsafePerformIO $ packCStringMaybe =<< c_getSubsystem dev++foreign import ccall unsafe "udev_device_get_devtype"+ c_getDevtype :: Device -> IO CString++-- | Retrieve the devtype string of the udev device.+getDevtype :: Device -> Maybe ByteString+getDevtype dev = unsafePerformIO $ packCStringMaybe =<< c_getDevtype dev++foreign import ccall unsafe "udev_device_get_syspath"+ c_getSyspath :: Device -> IO CString++-- | Retrieve the sys path of the udev device. The path is an absolute+-- path and starts with the sys mount point.+--+getSyspath :: Device -> ByteString+getSyspath dev = unsafePerformIO $ packCString =<< c_getSyspath dev++foreign import ccall unsafe "udev_device_get_sysname"+ c_getSysname :: Device -> IO CString++-- | Get the kernel device name in /sys.+getSysname :: Device -> ByteString+getSysname dev = unsafePerformIO $ packCString =<< c_getSysname dev++foreign import ccall unsafe "udev_device_get_sysnum"+ c_getSysnum :: Device -> IO CString++-- TODO :: Device -> Maybe Int ?++-- | Get the instance number of the device.+getSysnum :: Device -> Maybe ByteString+getSysnum dev = unsafePerformIO $ packCStringMaybe =<< c_getSysnum dev++foreign import ccall unsafe "udev_device_get_devnode"+ c_getDevnode :: Device -> IO CString++-- | Retrieve the device node file name belonging to the udev+-- device. The path is an absolute path, and starts with the device+-- directory.+--+getDevnode :: Device -> Maybe ByteString+getDevnode udev = unsafePerformIO $ packCStringMaybe =<< c_getDevnode udev++foreign import ccall unsafe "udev_device_get_is_initialized"+ c_isInitialized :: Device -> IO CInt++-- | Check if udev has already handled the device and has set up+-- device node permissions and context, or has renamed a network+-- device.+--+-- This is only implemented for devices with a device node or network+-- interfaces. All other devices return 1 here.+--+isInitialized :: Device -> IO Bool+isInitialized dev = (< 0) <$> c_isInitialized dev++foreign import ccall unsafe "udev_device_get_devlinks_list_entry"+ c_getDevlinksListEntry :: Device -> IO List++-- | Retrieve the list of device links pointing to the device file of+-- the udev device. The next list entry can be retrieved with+-- 'getNext', which returns 'Nothing' if no more entries exist. The+-- devlink path can be retrieved from the list entry by 'getName'. The+-- path is an absolute path, and starts with the device directory.+--+getDevlinksListEntry :: Device -> IO List+getDevlinksListEntry = c_getDevlinksListEntry+{-# INLINE getDevlinksListEntry #-}++foreign import ccall unsafe "udev_device_get_properties_list_entry"+ c_getPropertiesListEntry :: Device -> IO List++-- | Retrieve the list of key/value device properties of the udev+-- device. The next list entry can be retrieved with 'getNext', which+-- returns 'Nothing' if no more entries exist. The property name can+-- be retrieved from the list entry by 'getName', the property value+-- by 'getValue'.+--+getPropertiesListEntry :: Device -> IO List+getPropertiesListEntry = c_getPropertiesListEntry+{-# INLINE getPropertiesListEntry #-}++foreign import ccall unsafe "udev_device_get_tags_list_entry"+ c_getTagsListEntry :: Device -> IO List++-- | Retrieve the list of tags attached to the udev device. The next+-- list entry can be retrieved with 'getNext', which returns 'Nothing'+-- if no more entries exist. The tag string can be retrieved from the+-- list entry by 'getName'.+--+getTagsListEntry :: Device -> IO List+getTagsListEntry = c_getTagsListEntry+{-# INLINE getTagsListEntry #-}++foreign import ccall unsafe "udev_device_get_property_value"+ c_getPropertyValue :: Device -> CString -> IO CString++-- | Get the value of a given property.+getPropertyValue :: Device -> ByteString -> IO (Maybe ByteString)+getPropertyValue dev prop = do+ res <- useAsCString prop $ \ c_prop ->+ c_getPropertyValue dev c_prop+ if res == nullPtr then return Nothing else Just <$> packCString res++foreign import ccall unsafe "udev_device_get_driver"+ c_getDriver :: Device -> IO CString++-- TODO ByteString -> Text ?++-- | Get the kernel driver name.+getDriver :: Device -> IO ByteString+getDriver dev = packCString =<< c_getDriver dev++foreign import ccall unsafe "udev_device_get_devnum"+ c_getDevnum :: Device -> IO Devnum++-- | Get the device major/minor number.+getDevnum :: Device -> IO Devnum+getDevnum = c_getDevnum+{-# INLINE getDevnum #-}++foreign import ccall unsafe "udev_device_get_action"+ c_getAction :: Device -> CString++-- TODO data Action++-- | This is only valid if the device was received through a+-- monitor. Devices read from sys do not have an action string.+--+getAction :: Device -> Maybe ByteString+getAction dev+ | c_action == nullPtr = Nothing+ | otherwise = Just $ unsafePerformIO $ packCString c_action+ where+ c_action = c_getAction dev+++foreign import ccall unsafe "udev_device_get_sysattr_value"+ c_getSysattrValue :: Device -> CString -> CString++-- | The retrieved value is cached in the device. Repeated calls will+-- return the same value and not open the attribute again.+--+getSysattrValue :: Device -> ByteString -> ByteString+getSysattrValue dev sysattr = do+ unsafePerformIO $ do+ packCString =<< useAsCString sysattr (return . c_getSysattrValue dev)++foreign import ccall unsafe "udev_device_set_sysattr_value"+ c_setSysattrValue :: Device -> CString -> CString -> IO CInt++-- | Update the contents of the sys attribute and the cached value of+-- the device.+--+setSysattrValue :: Device+ -> ByteString -- ^ attribute name+ -> ByteString -- ^ new value to be set+ -> IO ()+setSysattrValue dev sysattr value = do+ throwErrnoIf_ (0 <) "setSysattrValue" $ do+ useAsCString sysattr $ \ c_sysattr ->+ useAsCString value $ \ c_value ->+ c_setSysattrValue dev c_sysattr c_value++foreign import ccall unsafe "udev_device_get_sysattr_list_entry"+ c_getSysAttrListEntry :: Device -> IO List++-- | Retrieve the list of available sysattrs, with value being empty;+-- This just return all available sysfs attributes for a particular+-- device without reading their values.+--+getSysattrListEntry :: Device -> IO List+getSysattrListEntry = c_getSysAttrListEntry+{-# INLINE getSysattrListEntry #-}++toMaybe :: CULLong -> Maybe Int+toMaybe 0 = Nothing+toMaybe n = Just (fromIntegral n)+{-# INLINE toMaybe #-}++foreign import ccall unsafe "udev_device_get_seqnum"+ c_getSeqnum :: Device -> IO CULLong++-- | This is only valid if the device was received through a+-- monitor. Devices read from sys do not have a sequence number.+--+getSeqnum :: Device -> IO (Maybe Int)+getSeqnum dev = toMaybe <$> c_getSeqnum dev+{-# INLINE getSeqnum #-}++foreign import ccall unsafe "udev_device_get_usec_since_initialized"+ c_getUsecSinceInitialized :: Device -> IO CULLong++-- | Return the number of microseconds passed since udev set up the+-- device for the first time.+--+-- This is only implemented for devices with need to store+-- properties in the udev database. All other devices return+-- 'Nothing' here.+--+getUsecSinceInitialized :: Device -> IO (Maybe Int)+getUsecSinceInitialized dev = toMaybe <$> c_getUsecSinceInitialized dev++foreign import ccall unsafe "udev_device_has_tag"+ c_hasTag :: Device -> CString -> IO CInt++-- | Check if a given device has a certain tag associated.+hasTag :: Device -> ByteString -> IO Bool+hasTag dev tag = do+ (1 ==) <$> do+ useAsCString tag $ \ c_tag ->+ c_hasTag dev c_tag
+ src/System/UDev/Enumerate.hs view
@@ -0,0 +1,248 @@+-- |+-- Copyright : (c) Sam Truzjan 2013+-- License : BSD3+-- Maintainer : pxqr.sta@gmail.com+-- Stability : stable+-- Portability : portable+--+-- Lookup devices in the sys filesystem, filter devices by+-- properties, and return a sorted list of devices.+--+{-# LANGUAGE ForeignFunctionInterface #-}+module System.UDev.Enumerate+ ( Enumerate++ , newEnumerate++ -- * Match+ , Subsystem+ , addMatchSubsystem+ , addNoMatchSubsystem++ , SysAttr+ , SysValue+ , addMatchSysattr+ , addNoMatchSysattr++ , addMatchProperty+ , addMatchTag+ , addMatchParent+ , addMatchIsInitialized+ , addMatchSysname+ , addSyspath++ -- * Scan+ , scanDevices+ , scanSubsystems++ -- * Query+ , getListEntry+ ) where++import Data.ByteString as BS+import Foreign+import Foreign.C.Error+import Foreign.C.String+import Foreign.C.Types++import System.UDev.Context+import System.UDev.Device+import System.UDev.List+import System.UDev.Types+++foreign import ccall unsafe "udev_enumerate_new"+ c_new :: UDev -> IO Enumerate++-- | Create an enumeration context to scan /sys.+newEnumerate :: UDev -> IO Enumerate+newEnumerate = c_new+{-# INLINE newEnumerate #-}++{-----------------------------------------------------------------------+-- Match+-----------------------------------------------------------------------}++foreign import ccall unsafe "udev_enumerate_add_match_subsystem"+ c_addMatchSubsystem :: Enumerate -> CString -> IO CInt++-- | Kernel subsystem string.+type Subsystem = ByteString++-- | Match only devices belonging to a certain kernel subsystem.+addMatchSubsystem :: Enumerate -- ^ context+ -> Subsystem -- ^ filter for a subsystem of the+ -- device to include in the list+ -> IO () -- ^ can throw exception+addMatchSubsystem enumerate subsystem = do+ throwErrnoIfMinus1_ "addMatchSubsystem" $ do+ useAsCString subsystem $+ c_addMatchSubsystem enumerate++foreign import ccall unsafe "udev_enumerate_add_nomatch_subsystem"+ c_addNoMatchSubsystem :: Enumerate -> CString -> IO CInt++-- | Match only devices not belonging to a certain kernel subsystem.+addNoMatchSubsystem :: Enumerate -- ^ context+ -> Subsystem -- ^ filter for a subsystem of the+ -- device to exclude from the list+ -> IO () -- ^ can throw exception+addNoMatchSubsystem enumerate subsystem = do+ throwErrnoIfMinus1_ "addNoMatchSubsystem" $ do+ useAsCString subsystem $+ c_addNoMatchSubsystem enumerate++-- | \/sys attribute string.+type SysAttr = ByteString++-- | Attribute specific \/sys value string. Can be an int or+-- identifier depending on attribute.+type SysValue = ByteString++foreign import ccall unsafe "udev_enumerate_add_match_sysattr"+ c_addMatchSysattr :: Enumerate -> CString -> CString -> IO CInt++-- | Match only devices with a certain \/sys device attribute.+addMatchSysattr :: Enumerate -- ^ context+ -> SysAttr -- ^ filter for a sys attribute at+ -- the device to include in the list+ -> Maybe SysValue -- ^ optional value of the sys attribute+ -> IO () -- ^ can throw exception+addMatchSysattr enumerate sysattr mvalue = do+ throwErrnoIf_ (< 0) "addMatchSysattr" $ do+ useAsCString sysattr $ \ c_sysattr -> do+ case mvalue of+ Nothing -> c_addMatchSysattr enumerate c_sysattr nullPtr+ Just value -> do+ useAsCString value $ \ c_value -> do+ c_addMatchSysattr enumerate c_sysattr c_value++foreign import ccall unsafe "udev_enumerate_add_nomatch_sysattr"+ c_addNoMatchSysattr :: Enumerate -> CString -> CString -> IO CInt++-- | Match only devices not having a certain /sys device attribute.+addNoMatchSysattr :: Enumerate -- ^ context+ -> ByteString -- ^ filter for a sys attribute at the+ -- device to exclude from the list+ -> Maybe ByteString -- ^ optional value of the sys+ -- attribute+ -> IO ()+addNoMatchSysattr enumerate sysattr mvalue = do+ throwErrnoIf_ (< 0) "addNoMatchSysattr" $ do+ useAsCString sysattr $ \ c_sysattr -> do+ case mvalue of+ Nothing -> c_addNoMatchSysattr enumerate c_sysattr nullPtr+ Just value -> do+ useAsCString value $ \ c_value -> do+ c_addNoMatchSysattr enumerate c_sysattr c_value++foreign import ccall unsafe "udev_enumerate_add_match_property"+ c_addMatchProperty :: Enumerate -> CString -> CString -> IO CInt++-- | Match only devices with a certain property.+addMatchProperty :: Enumerate -- ^ context+ -> ByteString -- ^ filter for a property of the+ -- device to include in the list+ -> ByteString -- ^ value of the property+ -> IO ()+addMatchProperty enumerate prop value = do+ throwErrnoIf_ (< 0) "addMatchProperty" $ do+ useAsCString prop $ \ c_prop -> do+ useAsCString value $ \ c_value -> do+ c_addMatchProperty enumerate c_prop c_value++foreign import ccall unsafe "udev_enumerate_add_match_tag"+ c_addMatchTag :: Enumerate -> CString -> IO CInt+++-- | Match only devices with a certain tag.+addMatchTag :: Enumerate -- ^ context+ -> ByteString -- ^ filter for a tag of the device to+ -- include in the list+ -> IO ()+addMatchTag enumerate tag = do+ throwErrnoIf_ (< 0) "addMatchTag" $ do+ useAsCString tag $ \ c_tag -> do+ c_addMatchTag enumerate c_tag++foreign import ccall unsafe "udev_enumerate_add_match_parent"+ c_addMatchParent :: Enumerate -> Device -> IO CInt++-- | Return the devices on the subtree of one given device. The parent+-- itself is included in the list.+--+-- A reference for the device is held until the udev_enumerate context+-- is cleaned up.+--+addMatchParent :: Enumerate -- ^ context+ -> Device -- ^ parent device where to start searching+ -> IO () -- ^ can throw exception+addMatchParent enumerate dev = do+ throwErrnoIf_ (< 0) "addMatchParent" $ do+ c_addMatchParent enumerate dev++foreign import ccall unsafe "udev_enumerate_add_match_is_initialized"+ c_addMatchIsInitialized :: Enumerate -> IO CInt++-- | Match only devices which udev has set up already.+addMatchIsInitialized :: Enumerate -> IO ()+addMatchIsInitialized enumerate = do+ throwErrnoIfMinus1_ "addMatchIsInitialized" $ do+ c_addMatchIsInitialized enumerate++foreign import ccall unsafe "udev_enumerate_add_match_sysname"+ c_addMatchSysname :: Enumerate -> CString -> IO CInt++-- | Match only devices with a given \/sys device name.+addMatchSysname :: Enumerate -- ^ context+ -> ByteString -- ^ filter for the name of the device+ -- to include in the list+ -> IO () -- ^ can throw exception+addMatchSysname enumerate sysName = do+ throwErrnoIfMinus1_ "addMatchSysname" $ do+ useAsCString sysName $+ c_addMatchSysname enumerate++foreign import ccall unsafe "udev_enumerate_add_syspath"+ c_addSyspath :: Enumerate -> CString -> IO CInt++-- | Add a device to the list of devices, to retrieve it back sorted+-- in dependency order.+--+addSyspath :: Enumerate -- ^ context+ -> ByteString -- ^ path of a device+ -> IO () -- ^ can throw exception+addSyspath enumerate syspath = do+ throwErrnoIf_ (< 0) "addSyspath" $ do+ useAsCString syspath $ \ c_syspath -> do+ c_addSyspath enumerate c_syspath++{-----------------------------------------------------------------------+-- Scan+-----------------------------------------------------------------------}++foreign import ccall unsafe "udev_enumerate_scan_devices"+ c_scanDevices :: Enumerate -> IO CInt++-- | Scan \/sys for all devices which match the given filters.+scanDevices :: Enumerate -> IO ()+scanDevices = throwErrnoIfMinus1_ "scanDevices" . c_scanDevices++foreign import ccall unsafe "udev_enumerate_scan_subsystems"+ c_scanSubsystems :: Enumerate -> IO CInt++-- | Scan \/sys for all devices which match the given filters.+scanSubsystems :: Enumerate -> IO ()+scanSubsystems = throwErrnoIfMinus1_ "scanSubsystems" . c_scanSubsystems++{-----------------------------------------------------------------------+-- Query+-----------------------------------------------------------------------}++foreign import ccall unsafe "udev_enumerate_get_list_entry"+ c_getListEntry :: Enumerate -> IO List++-- | Get the first entry of the sorted list of device paths.+getListEntry :: Enumerate -> IO List+getListEntry = c_getListEntry+{-# INLINE getListEntry #-}
+ src/System/UDev/HWDB.hs view
@@ -0,0 +1,44 @@+-- |+-- Copyright : (c) Sam Truzjan 2013+-- License : BSD3+-- Maintainer : pxqr.sta@gmail.com+-- Stability : stable+-- Portability : portable+--+-- Retrieve properties from the hardware database.+--+module System.UDev.HWDB+ ( HWDB+ , newHWDB+ , getPropertiesList+ ) where++import Data.ByteString as BS+import Foreign.C++import System.UDev.Context+import System.UDev.List+import System.UDev.Types+++foreign import ccall unsafe "udev_hwdb_new"+ c_new :: UDev -> IO HWDB++-- | Create a hardware database context to query properties for+-- devices.+newHWDB :: UDev -> IO HWDB+newHWDB = c_new++foreign import ccall unsafe "udev_hwdb_get_properties_list_entry"+ c_getPropertiesList :: HWDB -> CString -> CUInt -> IO List++-- | Lookup a matching device in the hardware database. The lookup key+-- is a modalias string, whose formats are defined for the Linux+-- kernel modules. Examples are: pci:v00008086d00001C2D*,+-- usb:v04F2pB221*. The first entry of a list of retrieved properties+-- is returned.+--+getPropertiesList :: HWDB -> ByteString -> IO List+getPropertiesList hwdb modalias =+ useAsCString modalias $ \ c_modalias ->+ c_getPropertiesList hwdb c_modalias 0
+ src/System/UDev/List.hs view
@@ -0,0 +1,59 @@+-- |+-- Copyright : (c) Sam Truzjan 2013+-- License : BSD3+-- Maintainer : pxqr.sta@gmail.com+-- Stability : experimental+-- Portability : portable+--+-- Libudev list operations.+--+module System.UDev.List+ ( List++ , getNext+ , getByName++ , getName+ , getValue+ ) where++import Control.Monad+import Data.ByteString+import Foreign.C.String+import Foreign.C.Types++import System.UDev.Types+++foreign import ccall unsafe "udev_list_entry_get_next"+ c_getNext :: List -> IO List++foreign import ccall unsafe "udev_list_entry_get_by_name"+ c_getByName :: List -> IO List++foreign import ccall unsafe "udev_list_entry_get_name"+ c_getName :: List -> IO CString++foreign import ccall unsafe "udev_list_entry_get_value"+ c_getValue :: List -> IO CString++-- | Get the next entry from the list.+getNext :: List -> IO (Maybe List)+getNext xxs = do+ xs <- c_getNext xxs+ return $ if xs == nil then Nothing else Just xs++-- | Lookup an entry in the list with a certain name.+getByName :: List -> IO (Maybe List)+getByName xs = do+ ys <- c_getByName xs+ return $ if ys == nil then Nothing else Just ys++-- TODO avoid copying?+-- | Get the name of a list entry.+getName :: List -> IO ByteString+getName = c_getName >=> packCString++-- | Get the value of list entry.+getValue :: List -> IO ByteString+getValue = c_getValue >=> packCString
+ src/System/UDev/Monitor.hs view
@@ -0,0 +1,187 @@+-- |+-- Copyright : (c) Sam Truzjan 2013+-- License : BSD3+-- Maintainer : pxqr.sta@gmail.com+-- Stability : experimental+-- Portability : portable+--+-- Connects to a device event source.+--+{-# LANGUAGE OverloadedStrings #-}+module System.UDev.Monitor+ ( Monitor++ -- * Creation+ , SourceId+ , udevId+ , kernelId+ , newFromNetlink++ -- * Receiving+ , enableReceiving+ , setReceiveBufferSize+ , getFd+ , getHandle+ , receiveDevice++ -- * Filter+ , filterAddMatchSubsystemDevtype+ , filterAddMatchTag+ , filterUpdate+ , filterRemove+ ) where++import Control.Applicative+import Control.Monad+import Data.ByteString as BS+import Foreign+import Foreign.C.Error+import Foreign.C.String+import Foreign.C.Types+import System.Posix.Types+import System.Posix.IO+import System.IO++import System.UDev.Context+import System.UDev.Device+import System.UDev.Types++-- | Opaque object handling an event source.+newtype Monitor = Monitor { getMonitor :: Ptr Monitor }+++foreign import ccall unsafe "udev_monitor_get_udev"+ c_getUDev :: Monitor -> UDev++instance UDevChild Monitor where+ getUDev = c_getUDev++foreign import ccall unsafe "udev_monitor_ref"+ c_ref :: Monitor -> IO Monitor++foreign import ccall unsafe "udev_monitor_unref"+ c_unref :: Monitor -> IO Monitor++instance Ref Monitor where+ ref = c_ref+ unref = c_unref++foreign import ccall unsafe "udev_monitor_new_from_netlink"+ c_newFromNetlink :: UDev -> CString -> IO Monitor++-- | Event source identifier.+newtype SourceId = SourceId ByteString++-- | Events are sent out just after kernel processes them.+--+-- Applications should usually not connect directly to the "kernel"+-- events, because the devices might not be useable at that time,+-- before udev has configured them, and created device nodes. Use+-- 'kernelId' instead.+--+kernelId :: SourceId+kernelId = SourceId "kernel"++-- | Events are sent out after udev has finished its event processing,+-- all rules have been processed, and needed device nodes are created.+udevId :: SourceId+udevId = SourceId "udev"+++-- | Create new udev monitor and connect to a specified event source.+newFromNetlink :: UDev -> SourceId -> IO Monitor+newFromNetlink udev (SourceId name) =+ Monitor <$> do+ throwErrnoIfNull "newFromNetlink" $ do+ useAsCString name $ \ c_name -> do+ getMonitor <$> c_newFromNetlink udev c_name+++foreign import ccall unsafe "udev_monitor_enable_receiving"+ c_enableReceiving :: Monitor -> IO CInt++-- | Binds the udev_monitor socket to the event source.+enableReceiving :: Monitor -> IO ()+enableReceiving monitor = do+ throwErrnoIfMinus1_ "enableReceiving" $ do+ c_enableReceiving monitor++foreign import ccall unsafe "udev_monitor_set_receive_buffer_size"+ c_setReceiveBufferSize :: Monitor -> CInt -> IO CInt++-- | Set the size of the kernel socket buffer.+setReceiveBufferSize :: Monitor -> Int -> IO ()+setReceiveBufferSize monitor size = do+ throwErrnoIfMinus1_ "setReceiveBufferSize" $ do+ c_setReceiveBufferSize monitor (fromIntegral size)++foreign import ccall unsafe "udev_monitor_get_fd"+ c_getFd :: Monitor -> IO CInt++-- | Retrieve the socket file descriptor associated with the monitor.+getFd :: Monitor -> IO Fd+getFd monitor = Fd <$> c_getFd monitor++-- | Retrieve the socket handle associated with the monitor.+getHandle :: Monitor -> IO Handle+getHandle = getFd >=> fdToHandle++foreign import ccall unsafe "udev_monitor_receive_device"+ c_receiveDevice :: Monitor -> IO Device++-- | Receive data from the udev monitor socket, allocate a new udev+-- device, fill in the received data, and return the device.+--+receiveDevice :: Monitor -> IO Device+receiveDevice monitor = do+ Device <$> do+ throwErrnoIfNull "receiveDevice" $ do+ getDevice <$> c_receiveDevice monitor++foreign import ccall unsafe "udev_monitor_filter_add_match_subsystem_devtype"+ c_filterAddMatchSubsystemDevtype :: Monitor -> CString -> CString -> IO CInt++-- | Filter events by subsystem and device type.+--+-- The filter /must be/ installed before the monitor is switched to+-- listening mode.+--+filterAddMatchSubsystemDevtype :: Monitor -> ByteString -> ByteString -> IO ()+filterAddMatchSubsystemDevtype monitor subsystem devtype = do+ throwErrnoIfMinus1_ "filterAddMatchSubsystemDevtype" $+ useAsCString subsystem $ \ c_subsystem ->+ useAsCString devtype $ \ c_devtype ->+ c_filterAddMatchSubsystemDevtype monitor c_subsystem c_devtype++foreign import ccall unsafe "udev_monitor_filter_add_match_tag"+ c_filterAddMatchTag :: Monitor -> CString -> IO CInt++-- | The filter must be installed before the monitor is switched to+-- listening mode.+--+filterAddMatchTag :: Monitor -> ByteString -> IO ()+filterAddMatchTag monitor tag = do+ throwErrnoIfMinus1_ "filterAddMatchTag" $ do+ useAsCString tag $ \ c_tag -> do+ c_filterAddMatchTag monitor c_tag++foreign import ccall unsafe "udev_monitor_filter_update"+ c_filterUpdate :: Monitor -> IO CInt++-- | Update the installed socket filter. This is only needed, if the+-- filter was removed or changed.+--+filterUpdate :: Monitor -> IO ()+filterUpdate monitor = do+ throwErrnoIfMinus1_ "filterUpdate" $ do+ c_filterUpdate monitor+++foreign import ccall unsafe "udev_monitor_filter_remove"+ c_filterRemove :: Monitor -> IO CInt++-- | Remove all filters from monitor.+filterRemove :: Monitor -> IO ()+filterRemove monitor = do+ throwErrnoIfMinus1_ "filterRemove" $ do+ c_filterRemove monitor
+ src/System/UDev/Queue.hs view
@@ -0,0 +1,112 @@+-- |+-- Copyright : (c) Sam Truzjan 2013+-- License : BSD3+-- Maintainer : pxqr.sta@gmail.com+-- Stability : experimental+-- Portability : portable+--+-- The udev daemon processes events asynchronously. All events which+-- do not have interdependencies run in parallel. This exports the+-- current state of the event processing queue, and the current+-- event sequence numbers from the kernel and the udev daemon.+--+module System.UDev.Queue+ ( Queue+ , Seqnum++ , newQueue+ , isActive+ , isEmpty+ , isFinished++ , getPending+ , sequenceIsFinished+ , getKernelSeqnum+ , getUDevSeqnum+ ) where++import Control.Applicative+import Foreign.C++import System.UDev.Context+import System.UDev.List+import System.UDev.Types+++foreign import ccall unsafe "udev_queue_new"+ c_newQueue :: UDev -> IO Queue++-- | Create a new queue.+newQueue :: UDev -> IO Queue+newQueue = c_newQueue+{-# INLINE newQueue #-}++foreign import ccall unsafe "udev_queue_get_udev_is_active"+ c_isActive :: Queue -> IO CInt++-- | Check if udev is active on the system.+isActive :: Queue -> IO Bool+isActive queue = (0 <) <$> c_isActive queue+{-# INLINE isActive #-}++foreign import ccall unsafe "udev_queue_get_queue_is_empty"+ c_isEmpty :: Queue -> IO CInt++-- | Check if udev is currently processing any events.+isEmpty :: Queue -> IO Bool+isEmpty queue = (0 <) <$> c_isEmpty queue+{-# INLINE isEmpty #-}++foreign import ccall unsafe "udev_queue_get_seqnum_is_finished"+ c_isFinished :: Queue -> CULLong -> IO CInt++-- | Sequence number of event.+type Seqnum = Int++-- | Check if udev is currently processing a given sequence number.+isFinished :: Queue -- ^ udev queue context+ -> Seqnum -- ^ sequence number+ -> IO Bool -- ^ if the given sequence number is currently+ -- active.+isFinished queue seqnr = (0 <) <$> c_isFinished queue (fromIntegral seqnr)+{-# INLINE isFinished #-}++foreign import ccall unsafe "udev_queue_get_seqnum_sequence_is_finished"+ c_sequenceIsFinished :: Queue -> CULLong -> CULLong -> IO CInt++-- | Check if udev is currently processing any events in a given+-- sequence number range.+--+sequenceIsFinished :: Queue -- ^ udev queue context+ -> Seqnum -- ^ first event sequence number+ -> Seqnum -- ^ last event sequence number+ -> IO Bool -- ^ if any of the sequence numbers in+ -- the given range is currently active+sequenceIsFinished queue start end = do+ (> 0) <$> c_sequenceIsFinished queue (fromIntegral start)+ (fromIntegral end)+{-# INLINE sequenceIsFinished #-}++foreign import ccall unsafe "udev_queue_get_queued_list_entry"+ c_getPending :: Queue -> IO List++-- | Get the first entry of the list of queued events.+getPending :: Queue -> IO List+getPending = c_getPending+{-# INLINE getPending #-}++foreign import ccall unsafe "udev_queue_get_kernel_seqnum"+ c_getKernelSeqnum :: Queue -> IO CULLong++-- | Get the current kernel event sequence number.+getKernelSeqnum :: Queue -> IO Seqnum+getKernelSeqnum queue = fromIntegral <$> c_getKernelSeqnum queue+{-# INLINE getKernelSeqnum #-}++foreign import ccall unsafe "udev_queue_get_udev_seqnum"+ c_getUDevSeqnum :: Queue -> IO CULLong++-- | Get the last known udev event sequence number.+getUDevSeqnum :: Queue -> IO Seqnum+getUDevSeqnum queue = fromIntegral <$> c_getUDevSeqnum queue+{-# INLINE getUDevSeqnum #-}
+ src/System/UDev/Types.hs view
@@ -0,0 +1,152 @@+-- |+-- Copyright : (c) Sam Truzjan 2013+-- License : BSD3+-- Maintainer : pxqr.sta@gmail.com+-- Stability : experimental+-- Portability : portable+--+-- Internal definitions; do not export this module.+--+module System.UDev.Types+ ( Ref (..)+ , UDevChild (..)++ , UDev (..)+ , Device (..)+ , Enumerate (..)+ , HWDB (..)+ , List (..), nil+ , Queue (..)+ ) where++import Foreign++{-----------------------------------------------------------------------+-- Classes+-----------------------------------------------------------------------}++class Ref a where+ ref :: a -> IO a+ unref :: a -> IO a++-- | Family of udev resources.+class UDevChild a where+ -- | Get the context a resource belong to.+ getUDev :: a -> UDev++{-----------------------------------------------------------------------+-- UDev+-----------------------------------------------------------------------}++-- | Opaque object representing the library context.+newtype UDev = UDev (Ptr UDev)+++instance UDevChild UDev where+ getUDev = id++foreign import ccall unsafe "udev_ref"+ c_ref :: UDev -> IO UDev++foreign import ccall unsafe "udev_unref"+ c_unref :: UDev -> IO UDev++instance Ref UDev where+ ref = c_ref+ unref = c_unref++{-----------------------------------------------------------------------+-- Device+-----------------------------------------------------------------------}++-- | Opaque object representing one kernel sys device.+newtype Device = Device { getDevice :: Ptr Device }++foreign import ccall unsafe "udev_device_ref"+ c_deviceRef :: Device -> IO Device++foreign import ccall unsafe "udev_device_unref"+ c_deviceUnref :: Device -> IO Device++instance Ref Device where+ ref = c_deviceRef+ unref = c_deviceUnref++foreign import ccall unsafe "udev_device_get_udev"+ c_getUDev :: Device -> UDev++instance UDevChild Device where+ getUDev = c_getUDev++{-----------------------------------------------------------------------+-- Enumerate+-----------------------------------------------------------------------}++-- | Opaque object representing one device lookup/sort context.+newtype Enumerate = Enumerate (Ptr Enumerate)++foreign import ccall unsafe "udev_enumerate_ref"+ c_EnumerateRef :: Enumerate -> IO Enumerate++foreign import ccall unsafe "udev_enumerate_unref"+ c_EnumerateUnref :: Enumerate -> IO Enumerate++instance Ref Enumerate where+ ref = c_EnumerateRef+ unref = c_EnumerateUnref++foreign import ccall unsafe "udev_enumerate_get_udev"+ c_EnumerateGetUDev :: Enumerate -> UDev++instance UDevChild Enumerate where+ getUDev = c_EnumerateGetUDev++{-----------------------------------------------------------------------+-- HWDB+-----------------------------------------------------------------------}++-- | Opaque object representing the hardware database.+newtype HWDB = HWDB (Ptr HWDB)++foreign import ccall unsafe "udev_hwdb_ref"+ c_HWDBRef :: HWDB -> IO HWDB++foreign import ccall unsafe "udev_hwdb_unref"+ c_HWDBUnref :: HWDB -> IO HWDB++instance Ref HWDB where+ ref = c_HWDBRef+ unref = c_HWDBUnref++{-----------------------------------------------------------------------+-- List+-----------------------------------------------------------------------}++-- TODO newtype List name value++-- | Opaque object representing one entry in a list. An entry contains+-- contains a name, and optionally a value.+--+newtype List = List (Ptr List)+ deriving Eq++nil :: List+nil = List nullPtr++{-----------------------------------------------------------------------+-- Queue+-----------------------------------------------------------------------}++-- | Opaque object representing the current event queue in the udev+-- daemon.+newtype Queue = Queue { getQueue :: Ptr Queue }++foreign import ccall unsafe "udev_queue_ref"+ c_queueRef :: Queue -> IO Queue++foreign import ccall unsafe "udev_queue_unref"+ c_queueUnref :: Queue -> IO Queue++instance Ref Queue where+ ref = c_queueRef+ unref = c_queueUnref
+ src/System/UDev/Util.hs view
@@ -0,0 +1,24 @@+-- |+-- Copyright : (c) Sam Truzjan 2013+-- License : BSD3+-- Maintainer : pxqr.sta@gmail.com+-- Stability : experimental+-- Portability : portable+--+-- Utilities useful when dealing with devices and device node names.+--+module System.UDev.Util+ ( encodeString+ ) where++import Foreign.C+++foreign import ccall unsafe "udev_util_encode_string"+ c_encodeString :: CString -> CString -> CSize -> IO ()++-- | Encode all potentially unsafe characters of a string to the+-- corresponding 2 char hex value prefixed by '\x'.+--+encodeString :: CString -> CString -> CSize -> IO ()+encodeString = c_encodeString
+ udev.cabal view
@@ -0,0 +1,71 @@+name: udev+version: 0.0.0.0+license: BSD3+license-file: LICENSE+author: Sam Truzjan+maintainer: pxqr.sta@gmail.com+copyright: (c) 2013, Sam Truzjan+category: System+stability: Experimental+build-type: Simple+cabal-version: >= 1.10+tested-with: GHC == 7.6.3+homepage: https://github.com/pxqr/udev+bug-reports: https://github.com/pxqr/udev/issues+synopsis: libudev bindings+description: libudev bindings++extra-source-files: README.md+ , changelog++source-repository head+ type: git+ location: git://github.com/pxqr/udev.git+ branch: master++source-repository this+ type: git+ location: git://github.com/pxqr/udev.git+ branch: master+ tag: v0.0.0.0++flag examples+ description: whether to build examples+ default: False++library+ default-language: Haskell2010+ default-extensions:+ hs-source-dirs: src+ exposed-modules: System.UDev+ , System.UDev.Context+ , System.UDev.Device+ , System.UDev.Enumerate+ , System.UDev.HWDB+ , System.UDev.List+ , System.UDev.Monitor+ , System.UDev.Queue+ , System.UDev.Util+ other-modules: System.UDev.Types+ pkgconfig-depends: libudev+ build-depends: base == 4.*+ , bytestring+ , unix+ build-tools: hsc2hs+ ghc-options: -Wall++executable hidraw+ default-language: Haskell2010+ hs-source-dirs: examples+ main-is: hidraw.hs+ build-depends: base, bytestring, udev+ if !flag(examples)+ buildable: False++executable monitor+ default-language: Haskell2010+ hs-source-dirs: examples+ main-is: monitor.hs+ build-depends: base, bytestring, udev, select+ if !flag(examples)+ buildable: False