-- 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:
--
--
-- - You can't reference handles to devices that are closed. In other
-- words: no I/O with closed handles is possible.
-- - The programmer specifies the region in which devices should remain
-- open. On exit from the region the opened devices are automatically
-- closed.
-- - You can't reference handles to configurations that have not been
-- set.
-- - You can't reference handles to interfaces that have not been
-- claimed.
-- - You can't reference handles to alternates that have not been
-- set.
-- - You can't reference endpoints that don't belong to a setted
-- alternate.
-- - You can't read from an endpoint with an Out transfer
-- direction.
-- - You can't write to an endpoint with an In transfer direction.
-- - You can't read from or write to endpoints with the unsupported
-- transfer types Control and Isochronous. Only I/O with endpoints with
-- the Bulk and Interrupt transfer types is allowed.
--
--
-- 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:
--
--
-- - You can't reference handles to devices that are closed. In other
-- words: no I/O with closed handles is possible.
-- - The programmer specifies the region in which devices should
-- remain open. On exit from the region the opened devices are
-- automatically closed.
-- - You can't reference handles to configurations that have not been
-- set.
-- - You can't reference handles to interfaces that have not been
-- claimed.
-- - You can't reference handles to alternates that have not been
-- set.
-- - You can't reference endpoints that don't belong to a setted
-- alternate.
-- - You can't read from an endpoint with an Out transfer
-- direction.
-- - You can't write to an endpoint with an In transfer
-- direction.
-- - You can't read from or write to endpoints with the unsupported
-- transfer types Control and Isochronous. Only I/O with
-- endpoints with the Bulk and Interrupt transfer types is
-- allowed.
--
--
-- 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:
--
--
-- - NoMemException if there is a memory allocation failure.
-- - AccessException if the user has insufficient permissions.
-- - NoDeviceException if the device has been disconnected.
-- - Another USBException.
--
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:
--
--
-- - NotFoundException if re-enumeration is required, or if the device
-- has been disconnected.
-- - SettingAlreadySet if a configuration has been set using
-- withConfig or withActiveConfig.
-- - Another USBException.
--
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:
--
--
-- - BusyException if interfaces are currently claimed.
-- - NoDeviceException if the device has been disconnected
-- - SettingAlreadySet if a configuration has already been set
-- using withConfig or withActiveConfig.
-- - Another USBException.
--
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:
--
--
-- - BusyException if the interface is already claimed.
-- - NoDeviceException if the device has been disconnected.
-- - Another USBException.
--
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:
--
--
-- - NoDeviceException if the device has been disconnected.
-- - Another USBException.
--
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:
--
--
-- - TimeoutException if the transfer timed out.
-- - PipeException if the control request was not supported by the
-- device
-- - NoDeviceException if the device has been disconnected.
-- - Another USBException.
--
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:
--
--
-- - PipeException if the control request was not supported by the
-- device
-- - NoDeviceException if the device has been disconnected.
-- - Another USBException.
--
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:
--
--
-- - PipeException if the control request was not supported by the
-- device
-- - NoDeviceException if the device has been disconnected.
-- - Another USBException.
--
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:
--
--
-- - NoDeviceException if the device has been disconnected.
-- - Another USBException.
--
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:
--
--
-- - NotFoundException if no kernel driver was active.
-- - InvalidParamException if the interface does not exist.
-- - NoDeviceException if the device has been disconnected.
-- - Another USBException.
--
detachKernelDriver :: (ParentOf mP mC, MonadIO mC) => DeviceHandle mP -> InterfaceNumber -> mC ()
-- | Re-attach an interface's kernel driver, which was previously detached
-- using detachKernelDriver.
--
-- Exceptions:
--
--
-- - NotFoundException if no kernel driver was active.
-- - InvalidParamException if the interface does not exist.
-- - NoDeviceException if the device has been disconnected.
-- - BusyException if the driver cannot be attached because the
-- interface is claimed by a program or driver.
-- - Another USBException.
--
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:
--
--
-- - NoDeviceException if the device has been disconnected.
-- - Another USBException.
--
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)