-- Hoogle documentation, generated by Haddock -- See Hoogle, http://www.haskell.org/hoogle/ -- | Wrapper around the usb package adding extra type-safety -- -- The usb library provides a standard Haskell abstracting layer over -- bindings-libusb providing: abstract types instead of Ptrs, automatic -- marshalling and unmarshalling, automatic garbage collection, -- exceptions instead of integer return codes, etc.. -- -- While all that is very nice there are still some things that you can -- do wrong. For example doing I/O with a closed device or reading from -- or writing to an endpoint which doesn't belong to the claimed -- interface. Or reading from an Out endpoint or writing to an In -- endpoint. -- -- usb-safe provides the following guarantees: -- -- -- -- The primary technique used in usb-safe is called "Lightweight monadic -- regions" which was invented by Oleg Kiselyov and Chung-chieh Shan. -- See: -- -- http://okmij.org/ftp/Haskell/regions.html#light-weight @package usb-safe @version 0.2 -- | This modules provides the following guarantees for working with USB -- devices: -- -- -- -- This modules makes use of a technique called Lightweight monadic -- regions invented by Oleg Kiselyov and Chung-chieh Shan -- -- See: http://okmij.org/ftp/Haskell/regions.html#light-weight module System.USB.Safe -- | A monad transformer in which Devices can be opened wich are -- automatically closed on exit from the region. data DeviceRegionT s m ± -- | Execute a region. -- -- All Devices which have been opened in the given region using -- openDevice, and which haven't been duplicated using -- dupDeviceHandle, will be closed on exit from this function -- wether by normal termination or by raising an exception. -- -- Also all devices which have been duplicated to this region from a -- child region are closed on exit if they haven't been duplicated -- themselves. -- -- Note the type variable s of the region wich is only -- quantified over the region itself. This ensures that no values, that -- have a type which has s in it, can be returned from this -- function. (Note the similarity with the ST monad.) -- -- DeviceHandles are parameterised with the region in which they -- were created. So device handles which were created by -- openDevice in the given region have this s in their -- type. This ensures that these device handles, which may have been -- closed on exit from this function, can't be returned by this function. -- This ensures you can never do any IO with closed device handles. -- -- Note that it is possible to run a region inside another region. -- -- TODO: Say something more about this nesting of regions... runDeviceRegionT :: (MonadCatchIO m) => (forall s. DeviceRegionT s m ±) -> m ± -- | A region which does not have parent regions and can be directly -- executed in IO by runTopDeviceRegion or concurrently -- executed in another region by forkTopDeviceRegion. type TopDeviceRegion s = DeviceRegionT s IO -- | Convenience funtion for running a top-level region in -- IO. -- -- Note that: runTopDeviceRegion = runDeviceRegionT runTopDeviceRegion :: (forall s. TopDeviceRegion s ±) -> IO ± -- | Return a region which executes the given top-level region in a -- new thread. -- -- Note that the forked region has the same type variable s as -- the resulting region. This means that all DeviceHandles which -- can be referenced in the resulting region can also be referenced in -- the forked region. forkTopDeviceRegion :: (MonadIO m) => TopDeviceRegion s () -> DeviceRegionT s m ThreadId -- | Transform the computation inside a region. mapDeviceRegionT :: (m ± -> n ²) -> DeviceRegionT s m ± -> DeviceRegionT s n ² -- | Lift a catchError operation to the new monad. liftCatch :: (m ± -> (e -> m ±) -> m ±) -> DeviceRegionT s m ± -> (e -> DeviceRegionT s m ±) -> DeviceRegionT s m ± -- | A handle to an opened Device. data DeviceHandle m :: (* -> *) -- | Open a device in a region. -- -- Note that the returned device handle is parameterised with the region -- in which it was created. This is to ensure that device handles can -- never escape their region and to support operations on device handles -- that are used in a child region of the region in which the device was -- created. -- -- This is a non-blocking function; no requests are sent over the bus. -- -- Exceptions: -- -- openDevice :: (MonadCatchIO m) => Device -> DeviceRegionT s m (DeviceHandle (DeviceRegionT s m)) -- | Duplicate a device handle in the parent region. -- -- For example, suppose you run the following region: -- --
--   runDeviceRegionT $ do
--   
-- -- Inside this region you run a nested child region like: -- --
--   d1hDup <- runDeviceRegionT $ do
--   
-- -- Now in this child region you open the device d1: -- --
--   d1h <- openDevice d1
--   
-- -- Note that d1h :: DeviceHandle (DeviceRegion sC (DeviceRegion sP -- m)) where sC is bound by the inner -- runDeviceRegionT and sP is bound by the outer -- runDeviceRegionT. -- -- Suppose you want to use the resulting device handle d1h in -- the parent device region. You can't simply return d1h -- because then the type variable sC, escapes the inner region. -- -- However, if you duplicate the device handle you can safely return it. -- --
--   d1hDup <- dupDeviceHandle d1h
--   return d1hDup
--   
-- -- Note that d1hDup :: DeviceHandle (DeviceRegionT sP m) -- -- Back in the parent region you can safely operate on d1hDup. dupDeviceHandle :: (MonadCatchIO m) => DeviceHandle (DeviceRegionT sC (DeviceRegionT sP m)) -> DeviceRegionT sC (DeviceRegionT sP m) (DeviceHandle (DeviceRegionT sP m)) -- | A convenience function which opens the given device, applies the given -- function to the resulting device handle and runs the resulting region. -- -- Note that: withDevice dev f = runDeviceRegionT $ -- openDevice dev >>= f withDevice :: (MonadCatchIO m) => Device -> (forall s. DeviceHandle (DeviceRegionT s m) -> DeviceRegionT s m ±) -> m ± -- | Retrieve the device from the device handle. getDevice :: DeviceHandle m -> Device -- | Perform a USB port reset to reinitialize a device. -- -- The system will attempt to restore the previous configuration and -- alternate settings after the reset has completed. -- -- You can only reset a device when all computations passed to -- withConfig or withActiveConfig have been terminated. If -- you call resetDevice and such a computation is still running -- a SettingAlreadySet exception is thrown. -- -- If the reset fails, the descriptors change, or the previous state -- cannot be restored, the device will appear to be disconnected and -- reconnected. This means that the device handle is no longer valid (you -- should close it) and rediscover the device. A NotFoundException is -- raised to indicate that this is the case. -- -- TODO: Think about how to handle the implications of the the -- previous paragraph! -- -- This is a blocking function which usually incurs a noticeable delay. -- -- Exceptions: -- -- resetDevice :: (ParentOf mP mC, MonadIO mC) => DeviceHandle mP -> mC () -- | A supported configuration of a Device. data Config m :: (* -> *) -- | Retrieve the supported configurations from the device handle. -- -- Note that the configuration is parameterised by the same region in -- which the device handle was created. This ensures you can never use a -- configuration outside that region. getConfigs :: DeviceHandle m -> [Config m] -- | Retrieve the configuration descriptor from the given configuration. getConfigDesc :: Config m -> ConfigDesc -- | Duplicate a configuration in the parent region. -- -- Also see: dupDeviceHandle. dupConfig :: (MonadCatchIO m) => Config (DeviceRegionT sC (DeviceRegionT sP m)) -> DeviceRegionT sC (DeviceRegionT sP m) (Config (DeviceRegionT sP m)) -- | A handle to an active Config. data ConfigHandle s m :: (* -> *) -- | This exception can be thrown in: -- -- -- -- to indicate that the device was already configured with a setting. data SettingAlreadySet -- | Set the active configuration for a device and then apply the given -- function to the resulting configuration handle. -- -- USB devices support multiple configurations of which only one can be -- active at any given time. When a configuration is set using -- withConfig or withActiveConfig no threads can set a new -- configuration until the computation passed to these functions -- terminates. If you do try to set one a SettingAlreadySet -- exception will be thrown. -- -- The operating system may or may not have already set an active -- configuration on the device. It is up to your application to ensure -- the correct configuration is selected before you attempt to claim -- interfaces and perform other operations. If you want to use the -- current active configuration use withActiveConfig. -- -- If you call this function on a device already configured with the -- selected configuration, then this function will act as a lightweight -- device reset: it will issue a SET_CONFIGURATION request using the -- current configuration, causing most USB-related device state to be -- reset (altsetting reset to zero, endpoint halts cleared, toggles -- reset). -- -- You cannot change/reset configuration if other applications or drivers -- have claimed interfaces. -- -- This is a blocking function. -- -- Exceptions: -- -- withConfig :: (ParentOf mP mC, MonadCatchIO mC) => Config mP -> (forall s. ConfigHandle s mP -> mC ±) -> mC ± -- | This exception can be thrown in withActiveConfig to indicate -- that the device is currently not configured. data NoActiveConfig -- | Apply the given function to the configuration handle of the currently -- active configuration of the given device handle. -- -- This function needs to determine the current active configuration. -- This information may be cached by the operating system. If it isn't -- cached this function will block while a control transfer is submitted -- to retrieve the information. -- -- TODO: I'm not yet sure if this is the best way of handling already -- configured devices. So this may change in the future! -- -- Exceptions: -- -- withActiveConfig :: (ParentOf mP mC, MonadCatchIO mC) => DeviceHandle mP -> (forall s. ConfigHandle s mP -> mC ±) -> mC ± -- | A supported interface of a Config. data Interface s m :: (* -> *) -- | Retrieve the supported interfaces from the configuration handle. -- -- Note that the interface is parameterised by the same type variables as -- the configuration handle. This ensures you can never use an interface -- outside the scope of the function passed to withConfig or -- withActiveConfig. getInterfaces :: ConfigHandle s m -> [Interface s m] -- | Retrieve the alternate interface descriptors of the interface. getInterfaceDescs :: Interface s m -> Interface -- | A handle to a claimed Interface. data InterfaceHandle s m :: (* -> *) -- | Claim the given interface, then apply the given function to the -- resulting interface handle and finally release the interface on exit -- from the function wether by normal termination or by raising an -- exception. -- -- Note that it is allowed to claim an already-claimed interface. -- -- Claiming of interfaces is a purely logical operation; it does not -- cause any requests to be sent over the bus. Interface claiming is used -- to instruct the underlying operating system that your application -- wishes to take ownership of the interface. -- -- This is a non-blocking function. -- -- Exceptions: -- -- withInterface :: (ParentOf mP mC, MonadCatchIO mC) => Interface s mP -> (forall s2. InterfaceHandle s2 mP -> mC ±) -> mC ± -- | A supported Interface alternate setting. data Alternate s m :: (* -> *) -- | Retrieve the supported alternate settings from the interface handle. -- -- Note that the alternate setting is parameterised by the same type -- variables as the interface handle. This ensures you can never use an -- alternate setting outside the scope of the function passed to -- withInterface. getAlternates :: InterfaceHandle s m -> [Alternate s m] -- | Retrieve the interface descriptor of this alternate setting. getInterfaceDesc :: Alternate s m -> InterfaceDesc -- | A handle to a setted alternate setting. data AlternateHandle s m :: (* -> *) -- | Activate an alternate setting for an interface and then apply the -- given function to the resulting alternate handle. -- -- Simillary to configurations, interfaces support multiple alternate -- settings of which only one can be active at any given time. When an -- alternate is set using withAlternate or -- withActiveAlternate no threads can set a new alternate until -- the computation passed to these functions terminates. If you do try to -- set one a SettingAlreadySet exception will be thrown. -- -- The operating system may already have set an alternate for the -- interface. If you want to use this currently active alternate use -- withActiveAlternate. -- -- This is a blocking function. -- -- Exceptions: -- -- withAlternate :: (ParentOf mP mC, MonadCatchIO mC) => Alternate s mP -> (forall s2. AlternateHandle s2 mP -> mC ±) -> mC ± -- | Apply the given function to the alternate handle of the currently -- active alternate of the give interface handle. -- -- To determine the current active alternate this function will block -- while a control transfer is submitted to retrieve the information. -- -- TODO: I'm not yet sure if this is the best way of handling already -- configured devices. So this may change in the future! -- -- Exceptions: -- -- withActiveAlternate :: (ParentOf mP mC, MonadCatchIO mC) => InterfaceHandle s mP -> (forall s2. AlternateHandle s2 mP -> mC ±) -> mC ± -- | A supported endpoint from an Alternate. data Endpoint s m :: (* -> *) -- | Retrieve the supported endpoints from the alternate handle. -- -- Note that the endpoint is parameterised by the same type variables as -- the alternate handle. This ensures you can never use an endpoint -- outside the scope of the function passed to withAlternate or -- withActiveAlternate. getEndpoints :: AlternateHandle s m -> [Endpoint s m] -- | I/O operations on endpoints are type-safe. You can only read from an -- endpoint with an In transfer direction and you can only write -- to an endpoint with an Out transfer direction. -- -- Reading and writing also have different implementations for the -- different endpoint transfer types like: Bulk and -- Interrupt. I/O with endpoints of other transfer types like -- Control and Isochronous is not possible. -- -- This type lifts the transfer direction and transfer type information -- to the type-level so that I/O operations can specify which endpoints -- they support. data EndpointHandle transDir transType s m :: (* -> *) -- | The Endpoint type is not rich enough to encode the transfer -- direction and transfer type. In order to introduce this type -- information we have to filter the list of endpoints and get back a -- list of endpoint handles which have the specified transfer direction -- and transfer type and also expres this in their type. filterEndpoints :: (TransferDirection transDir, TransferType transType) => [Endpoint s m] -> [EndpointHandle transDir transType s m] -- | Retrieve the endpoint descriptor from the given endpoint handle. getEndpointDesc :: EndpointHandle transDir transType s m -> EndpointDesc -- | Clear the halt/stall condition for an endpoint. -- -- Endpoints with halt status are unable to receive or transmit data -- until the halt condition is stalled. -- -- You should cancel all pending transfers before attempting to clear the -- halt condition. -- -- This is a blocking function. -- -- Exceptions: -- -- clearHalt :: (ParentOf mP mC, MonadIO mC) => EndpointHandle transDir transType s mP -> mC () -- | In transfer direction (device -> host) used for reading. data In -- | Out transfer direction (host -> device) used for writing. data Out -- | Control endpoints don't support read and write operations. data Control -- | Isochronous endpoints don't support read and write -- operations. data Isochronous -- | Bulk endpoints support read and write operations. data Bulk -- | Interrupt endpoints support read and write operations. data Interrupt -- | Handy type synonym for read transfers. -- -- A ReadAction is a function which takes a timeout and a size -- which defines how many bytes to read. The function returns an action -- which, when executed, performs the actual read and returns the -- bytestring that was read paired with an indication if the transfer -- timed out. type ReadAction m = Timeout -> Size -> m (ByteString, Bool) -- | Class of transfer types that support reading. -- -- (Only Bulk and Interrupt transfer types are supported.) class (TransferType transType) => ReadEndpoint transType readEndpoint :: (ReadEndpoint transType, ParentOf mP mC, MonadIO mC) => EndpointHandle In transType s mP -> ReadAction mC -- | Handy type synonym for write transfers. -- -- A WriteAction is a function which takes a timeout and the -- bytestring to write. The function returns an action which, when -- exectued, returns the number of bytes that were actually written -- paired with an indication if the transfer timed out. type WriteAction m = Timeout -> ByteString -> m (Size, Bool) -- | Class of transfer types that support writing -- -- (Only Bulk and Interrupt transfer types are supported.) class (TransferType transType) => WriteEndpoint transType writeEndpoint :: (WriteEndpoint transType, ParentOf mP mC, MonadIO mC) => EndpointHandle Out transType s mP -> WriteAction mC -- | Control transfers can have three request types: Standard, -- Class and Vendor. We disallow Standard -- requests however because with them you can destroy the safety -- guarantees that this module provides. data RequestType Class :: RequestType Vendor :: RequestType -- | Perform a USB control request that does not transfer data. -- -- The value and index values should be given in -- host-endian byte order. -- -- Exceptions: -- -- control :: (ParentOf mP mC, MonadIO mC) => DeviceHandle mP -> RequestType -> Recipient -> Word8 -> Word16 -> Word16 -> Timeout -> mC () -- | Perform a USB control read. -- -- The value and index values should be given in -- host-endian byte order. -- -- Exceptions: -- -- readControl :: (ParentOf mP mC, MonadIO mC) => DeviceHandle mP -> RequestType -> Recipient -> Word8 -> Word16 -> Word16 -> ReadAction mC -- | Perform a USB control write. -- -- The value and index values should be given in -- host-endian byte order. -- -- Exceptions: -- -- writeControl :: (ParentOf mP mC, MonadIO mC) => DeviceHandle mP -> RequestType -> Recipient -> Word8 -> Word16 -> Word16 -> WriteAction mC -- | Retrieve a list of supported languages. -- -- This function may throw USBExceptions. getLanguages :: (ParentOf mP mC, MonadIO mC) => DeviceHandle mP -> mC [LangId] -- | Retrieve a string descriptor from a device. -- -- This is a convenience function which formulates the appropriate -- control message to retrieve the descriptor. The string returned is -- Unicode, as detailed in the USB specifications. -- -- This function may throw USBExceptions. -- -- TODO: The following can be made more type-safe! -- -- When I call getStrDesc I would like the type system to -- guarantee that the given StrIx and LangId actually -- belong to the given DeviceHandle. In other words I would like -- to get a type error when they are some arbitrary number or come from -- another device. getStrDesc :: (ParentOf mP mC, MonadIO mC) => DeviceHandle mP -> StrIx -> LangId -> Size -> mC String -- | Retrieve a string descriptor from a device using the first supported -- language. -- -- This is a convenience function which formulates the appropriate -- control message to retrieve the descriptor. The string returned is -- Unicode, as detailed in the USB specifications. -- -- This function may throw USBExceptions. getStrDescFirstLang :: (ParentOf mP mC, MonadIO mC) => DeviceHandle mP -> StrIx -> Size -> mC String -- | Determine if a kernel driver is active on an interface. -- -- If a kernel driver is active, you cannot claim the interface, and -- libusb will be unable to perform I/O. -- -- Exceptions: -- -- kernelDriverActive :: (ParentOf mP mC, MonadIO mC) => DeviceHandle mP -> InterfaceNumber -> mC Bool -- | Detach a kernel driver from an interface. -- -- If successful, you will then be able to claim the interface and -- perform I/O. -- -- Exceptions: -- -- detachKernelDriver :: (ParentOf mP mC, MonadIO mC) => DeviceHandle mP -> InterfaceNumber -> mC () -- | Re-attach an interface's kernel driver, which was previously detached -- using detachKernelDriver. -- -- Exceptions: -- -- attachKernelDriver :: (ParentOf mP mC, MonadIO mC) => DeviceHandle mP -> InterfaceNumber -> mC () -- | If a kernel driver is active on the specified interface the driver is -- detached and the given action is executed. If the action terminates, -- whether by normal termination or by raising an exception, the kernel -- driver is attached again. If a kernel driver is not active on the -- specified interface the action is just executed. -- -- Exceptions: -- -- withDetachedKernelDriver :: (ParentOf mP mC, MonadCatchIO mC) => DeviceHandle mP -> InterfaceNumber -> mC ± -> mC ± instance [overlap ok] Typeable NoActiveConfig instance [overlap ok] Typeable SettingAlreadySet instance [overlap ok] Show NoActiveConfig instance [overlap ok] Show SettingAlreadySet instance [overlap ok] (Monad m) => Monad (DeviceRegionT s m) instance [overlap ok] MonadTrans (DeviceRegionT s) instance [overlap ok] (MonadIO m) => MonadIO (DeviceRegionT s m) instance [overlap ok] (MonadCatchIO m) => MonadCatchIO (DeviceRegionT s m) instance [overlap ok] (MonadCont m) => MonadCont (DeviceRegionT s m) instance [overlap ok] WriteEndpoint Interrupt instance [overlap ok] WriteEndpoint Bulk instance [overlap ok] ReadEndpoint Interrupt instance [overlap ok] ReadEndpoint Bulk instance [overlap ok] TransferType Interrupt instance [overlap ok] TransferType Bulk instance [overlap ok] TransferType Isochronous instance [overlap ok] TransferType Control instance [overlap ok] TransferDirection In instance [overlap ok] TransferDirection Out instance [overlap ok] Exception NoActiveConfig instance [overlap ok] Exception SettingAlreadySet instance [overlap ok] TypeCast2'' () a a instance [overlap ok] (TypeCast2'' t a b) => TypeCast2' t a b instance [overlap ok] (TypeCast2' () a b) => TypeCast2 a b instance [overlap ok] (Monad mC, TypeCast2 mC (DeviceRegionT s mC'), ParentOf mP mC') => ParentOf mP mC instance [overlap ok] (Monad m) => ParentOf m m instance [overlap ok] (MonadWriter w m) => MonadWriter w (DeviceRegionT s m) instance [overlap ok] (MonadState st m) => MonadState st (DeviceRegionT s m) instance [overlap ok] (MonadReader r m) => MonadReader r (DeviceRegionT s m) instance [overlap ok] (MonadRWS r w st m) => MonadRWS r w st (DeviceRegionT s m) instance [overlap ok] (MonadError e m) => MonadError e (DeviceRegionT s m)