-- Hoogle documentation, generated by Haddock
-- See Hoogle, http://www.haskell.org/hoogle/
-- | Type-safe communication with USB devices.
--
-- The usb package provides a standard Haskell abstraction 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 will be closed
-- automatically.
-- - You can't reference handles to configurations that have not been
-- set.
-- - You can't reference handles to interfaces that have not been
-- claimed.
-- - Just like with devices, the programmer can specify the region in
-- which interfaces should remain claimed. On exit from the region the
-- claimed interfaces will be released automatically.
-- - 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.
--
--
-- 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
--
-- This technique is implemented in the regions package which is
-- re-exported from usb-safe.
--
-- See the usb-safe-examples package for examples how to use
-- this library:
--
--
-- git clone https://github.com/basvandijk/usb-safe-examples
--
@package usb-safe
@version 0.13
-- | 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 can specify the region in which devices
-- should remain open. On exit from the region the opened devices will be
-- closed automatically.
-- - You can't reference handles to configurations that have not been
-- set.
-- - You can't reference handles to interfaces that have not been
-- claimed.
-- - Just like with devices, the programmer can specify the region in
-- which interfaces should remain claimed. On exit from the region the
-- claimed interfaces will be released automatically.
-- - 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.
--
--
-- 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
--
-- This technique is implemented in the regions package of which
-- the Control.Monad.Trans.Region module is re-exported by this
-- module.
--
-- See the usb-safe-examples package for examples how to use
-- this library:
--
--
-- git clone https://github.com/basvandijk/usb-safe-examples
--
module System.USB.Safe
-- | A regional handle to an opened USB device.
--
-- A regional handle to an opened USB device can be created by applying
-- openDevice or withDevice to the USB device you wish to
-- open.
--
-- Note that you can also duplicate a regional device handle by
-- applying dup to it.
data RegionalDeviceHandle r :: (* -> *)
-- | Open a device and obtain a regional device handle. The device is
-- automatically closed when the region terminates.
--
-- This is a non-blocking function; no requests are sent over the bus.
--
-- Exceptions:
--
--
openDevice :: MonadControlIO pr => Device -> RegionT s pr (RegionalDeviceHandle (RegionT s pr))
-- | Convenience function which opens the device, applies the given
-- continuation function to the resulting regional device handle and runs
-- the resulting region.
withDevice :: MonadControlIO pr => Device -> (forall s. RegionalDeviceHandle (RegionT s pr) -> RegionT s pr α) -> pr α
-- | Convenience function which finds the first device attached to the
-- system which satisfies the given predicate on its descriptor, then
-- opens that device and applies the given continuation function to the
-- resulting device handle.
--
-- Exceptions:
--
--
withDeviceWhich :: MonadControlIO pr => Ctx -> (DeviceDesc -> Bool) -> (forall s. RegionalDeviceHandle (RegionT s pr) -> RegionT s pr α) -> pr α
-- | Convenience function for retrieving the device from the given regional
-- handle.
getDevice :: RegionalDeviceHandle r -> Device
class GetDescriptor α desc | α -> desc, desc -> α
getDesc :: GetDescriptor α desc => α -> desc
-- | 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.
--
-- Note the constraint: pr `AncestorRegion` cr. This allows this
-- function to be executed in any child region cr of the parent
-- region pr in which the given regional handle was created.
--
-- You can only reset a device when all computations passed to
-- setConfig, useActiveConfig and setConfigWhich
-- 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 :: (AncestorRegion pr cr, MonadIO cr) => RegionalDeviceHandle pr -> cr ()
-- | A supported configuration of a USB device parameterized by the region
-- r in which it was created.
--
-- Note that, just like a regional device handle, a configuration can be
-- duplicated to a parent region using dup.
--
-- Also note that you can get the descriptor of the configuration by
-- applying getDesc to it.
data Config r :: (* -> *)
-- | Retrieve the supported configurations from the given regional handle.
--
-- Note that the configuration is parameterized by the same region
-- r in which the regional handle was created. This ensures you
-- can never use a configuration outside that region.
getConfigs :: RegionalDeviceHandle r -> [Config r]
-- | A handle to an active Config which you can get using:
-- setConfig, useActiveConfig or setConfigWhich.
--
-- The type variable sCfg is used to ensure that you can't
-- return this handle from these functions.
data ConfigHandle sCfg
-- | Set the active configuration for a device and then apply the given
-- continuation 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
-- setConfig, useActiveConfig or setConfigWhich no
-- threads may 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: useActiveConfig.
--
-- 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:
--
--
setConfig :: (AncestorRegion pr (RegionT s cr), MonadControlIO cr) => Config pr -> (forall sCfg. ConfigHandle sCfg -> RegionT s cr α) -> RegionT s cr α
-- | This exception can be thrown in:
--
--
--
-- to indicate that the device was already configured with a setting.
data SettingAlreadySet
SettingAlreadySet :: SettingAlreadySet
-- | Apply the given continuation function to the configuration handle of
-- the current 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.
--
-- Exceptions:
--
--
useActiveConfig :: (AncestorRegion pr (RegionT s cr), MonadControlIO cr) => RegionalDeviceHandle pr -> (forall sCfg. ConfigHandle sCfg -> RegionT s cr α) -> RegionT s cr α
-- | This exception can be thrown in useActiveConfig to indicate
-- that the device is currently not configured.
data NoActiveConfig
NoActiveConfig :: NoActiveConfig
-- | Convenience function which finds the first configuration of the given
-- device handle which satisfies the given predicate on its descriptor,
-- then sets that configuration and applies the given function to the
-- resulting configuration handle.
--
-- This function calls setConfig so do see its documentation.
--
-- Exceptions:
--
--
setConfigWhich :: (AncestorRegion pr (RegionT s cr), MonadControlIO cr) => RegionalDeviceHandle pr -> (ConfigDesc -> Bool) -> (forall sCfg. ConfigHandle sCfg -> RegionT s cr α) -> RegionT s cr α
-- | A supported interface of a configuration which you can retrieve using
-- getInterfaces.
--
-- To retrieve the Interface descriptors of an interface use
-- getDesc.
data Interface sCfg
-- | Retrieve the supported interfaces from the configuration handle.
--
-- Note that the interface is parameterized by the sCfg of the
-- configuration handle it is derived from. This ensures that it can
-- never be returned from the functions that created this configuration
-- handle: setConfig, useActiveConfig and
-- setConfigWhich.
--
-- The latter is useful because outside those functions the active
-- configuration may change. If at that moment you still have an
-- interface of the old configuration claiming it would be an error.
getInterfaces :: ConfigHandle sCfg -> [Interface sCfg]
-- | A regional handle to a claimed interface.
--
-- A regional handle to a claimed interface can be created by applying
-- claim or withInterface to the interface you wish to
-- claim.
data RegionalInterfaceHandle sCfg r :: (* -> *)
-- | Claim the given interface in the region. When the region terminates
-- the interface is released automatically.
--
-- 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:
--
--
claim :: MonadControlIO pr => Interface sCfg -> RegionT s pr (RegionalInterfaceHandle sCfg (RegionT s pr))
withInterface :: MonadControlIO pr => Interface sCfg -> (forall s. RegionalInterfaceHandle sCfg (RegionT s pr) -> RegionT s pr α) -> pr α
-- | Convenience function which finds the first interface of the given
-- configuration handle which satisfies the given predicate on its
-- descriptors, then claims that interfaces and applies the given
-- continuation function to the resulting regional handle.
--
-- Exceptions:
--
--
withInterfaceWhich :: MonadControlIO pr => ConfigHandle sCfg -> (Interface -> Bool) -> (forall s. RegionalInterfaceHandle sCfg (RegionT s pr) -> RegionT s pr α) -> pr α
-- | A supported Interface alternate setting which you can retrieve
-- using getAlternates.
data Alternate sCfg r :: (* -> *)
-- | Retrieve the supported alternate settings from the given interface
-- handle.
--
-- Note that the alternate setting is parameterized by the same type
-- variables as the interface handle. This ensures you can never use an
-- alternate setting outside the region in which the interface handle was
-- created.
getAlternates :: RegionalInterfaceHandle sCfg r -> [Alternate sCfg r]
-- | A handle to a setted alternate setting.
--
-- You get a handle to an alternate using setAlternate,
-- useActiveAlternate or setAlternateWhich.
--
-- The type variable sAlt is used to ensure that you can't
-- return this handle from these functions.
data AlternateHandle sAlt r :: (* -> *)
-- | Activate an alternate setting for an interface and then apply the
-- given continuation 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 setAlternate, useActiveAlternate
-- or setAlternateWhich no threads may 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 has always set an interface in one of the
-- available alternates. If you want to use the current active alternate:
-- useActiveAlternate.
--
-- This is a blocking function.
--
-- Exceptions:
--
--
setAlternate :: (AncestorRegion pr (RegionT s cr), MonadControlIO cr) => Alternate sCfg pr -> (forall sAlt. AlternateHandle sAlt pr -> RegionT s cr α) -> RegionT s cr α
-- | Apply the given function to the alternate handle of the current active
-- alternate of the given interface handle.
--
-- To determine the current active alternate this function will block
-- while a control transfer is submitted to retrieve the information.
--
-- Note that unlike configurations an interface is always set in one of
-- the available alternates, so unlike useActiveConfig this
-- function will never throw an exception like NoActiveConfig.
--
-- Exceptions:
--
--
useActiveAlternate :: (AncestorRegion pr (RegionT s cr), MonadControlIO cr) => RegionalInterfaceHandle sCfg pr -> (forall sAlt. AlternateHandle sAlt pr -> RegionT s cr α) -> RegionT s cr α
-- | Convenience function which finds the first alternate of the given
-- interface handle which satisfies the given predicate on its
-- descriptor, then sets that alternate and applies the given function to
-- the resulting alternate handle.
--
-- This function calls setAlternate so do see its documentation.
--
-- Exceptions:
--
--
setAlternateWhich :: (AncestorRegion pr (RegionT s cr), MonadControlIO cr) => RegionalInterfaceHandle sCfg pr -> (InterfaceDesc -> Bool) -> (forall sAlt. AlternateHandle sAlt pr -> RegionT s cr α) -> RegionT s cr α
-- | 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 like readEndpoint and
-- writeEndpoint can specify which endpoints they support.
--
-- You can retrieve the endpoints of an alternate using
-- getEndpoints.
data Endpoint transDir transType sAlt r :: (* -> *)
-- | Retrieve all the endpoints from the given alternate handle which are
-- of the given transfer direction and transfer type.
getEndpoints :: AlternateHandle sAlt r -> TransferDirection transDir -> TransferType transType -> [Endpoint transDir transType sAlt r]
-- | Similar to getEndpoints but will retrieve the endpoints based
-- on the inferred type of transfer direction and transfer type.
--
-- Note that: getEndpoints' altHndl = getEndpoints altHndl
-- mkTransferDirection mkTransferType.
getEndpoints' :: MkTransferDirection transDir => MkTransferType transType => AlternateHandle sAlt r -> [Endpoint transDir transType sAlt r]
data TransferDirection transDir
Out :: TransferDirection Out
In :: TransferDirection In
-- | Out transfer direction (host -> device) used for writing.
data Out
-- | In transfer direction (device -> host) used for reading.
data In
class MkTransferDirection transDir
mkTransferDirection :: MkTransferDirection transDir => TransferDirection transDir
data TransferType transType
Control :: TransferType Control
Isochronous :: TransferType Isochronous
Bulk :: TransferType Bulk
Interrupt :: TransferType Interrupt
data Control
data Isochronous
data Bulk
data Interrupt
class MkTransferType transType
mkTransferType :: MkTransferType transType => TransferType transType
-- | 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 :: (AncestorRegion pr cr, MonadIO cr) => Endpoint transDir transType sAlt pr -> cr ()
-- | Handy type synonym for read transfers.
--
-- A ReadAction is a function which takes a size which defines
-- how many bytes to read and a timeout. 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 r = Size -> Timeout -> r (ByteString, Status)
-- | Handy type synonym for write transfers.
--
-- A WriteAction is a function which takes the bytestring to
-- write and a timeout. 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 r = ByteString -> Timeout -> r (Size, Status)
-- | Class of transfer types that support reading.
class ReadEndpoint transType
readEndpoint :: (ReadEndpoint transType, AncestorRegion pr cr, MonadIO cr) => Endpoint In transType sAlt pr -> ReadAction cr
-- | Class of transfer types that support writing
class WriteEndpoint transType
writeEndpoint :: (WriteEndpoint transType, AncestorRegion pr cr, MonadIO cr) => Endpoint Out transType sAlt pr -> WriteAction cr
-- | Class of transfer types that support enumeration.
class EnumReadEndpoint transType
enumReadEndpoint :: (EnumReadEndpoint transType, AncestorRegion pr cr, MonadControlIO cr, ReadableChunk s Word8, NullPoint s) => Endpoint In transType sAlt pr -> Size -> Timeout -> Enumerator s cr α
-- | Perform a USB isochronous read.
--
-- WARNING: You need to enable the threaded runtime
-- (-threaded) for this function to work correctly. It throws a
-- runtime error otherwise!
--
-- Exceptions:
--
--
readIsochronousEndpoint :: (AncestorRegion pr cr, MonadIO cr) => Endpoint In Isochronous sAlt pr -> [Size] -> Timeout -> cr [ByteString]
-- | Perform a USB isochronous write.
--
-- WARNING: You need to enable the threaded runtime
-- (-threaded) for this function to work correctly. It throws a
-- runtime error otherwise!
--
-- Exceptions:
--
--
writeIsochronousEndpoint :: (AncestorRegion pr cr, MonadIO cr) => Endpoint Out Isochronous sAlt pr -> [ByteString] -> Timeout -> cr [Size]
-- | Iteratee enumerator for reading isochronous endpoints.
--
-- WARNING: You need to enable the threaded runtime
-- (-threaded) for this function to work correctly. It throws a
-- runtime error otherwise!
enumReadIsochronousEndpoint :: (ReadableChunk s Word8, AncestorRegion pr cr, MonadControlIO cr) => Endpoint In Isochronous sAlt pr -> [Size] -> Timeout -> Enumerator [s] cr α
-- | Handy type synonym that names the parameters of a control transfer.
type ControlAction α = RequestType -> Recipient -> Request -> Value -> Index -> α
-- | 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.
--
-- Exceptions:
--
--
control :: (AncestorRegion pr cr, MonadIO cr) => RegionalDeviceHandle pr -> ControlAction (Timeout -> cr ())
-- | Perform a USB control read.
--
-- Exceptions:
--
--
readControl :: (AncestorRegion pr cr, MonadIO cr) => RegionalDeviceHandle pr -> ControlAction (ReadAction cr)
-- | A convenience function similar to readControl which checks if
-- the specified number of bytes to read were actually read. Throws an
-- IOException if this is not the case.
readControlExact :: (AncestorRegion pr cr, MonadIO cr) => RegionalDeviceHandle pr -> ControlAction (ReadExactAction cr)
-- | Perform a USB control write.
--
-- Exceptions:
--
--
writeControl :: (AncestorRegion pr cr, MonadIO cr) => RegionalDeviceHandle pr -> ControlAction (WriteAction cr)
-- | A convenience function similar to writeControl which checks if
-- the given bytes were actually fully written. Throws an
-- incompleteWriteException if this is not the case.
writeControlExact :: (AncestorRegion pr cr, MonadIO cr) => RegionalDeviceHandle pr -> ControlAction (WriteExactAction cr)
-- | Retrieve a list of supported languages.
--
-- This function may throw USBExceptions.
getLanguages :: (AncestorRegion pr cr, MonadIO cr) => RegionalDeviceHandle pr -> cr [LangId]
-- | Retrieve a string descriptor from a device.
--
-- 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 Handle. In other words I would like to
-- get a type error when they are some arbitrary number or come from
-- another device.
getStrDesc :: (AncestorRegion pr cr, MonadIO cr) => RegionalDeviceHandle pr -> StrIx -> LangId -> Int -> cr Text
-- | Retrieve a string descriptor from a device using the first supported
-- language.
--
-- This function may throw USBExceptions.
getStrDescFirstLang :: (AncestorRegion pr cr, MonadIO cr) => RegionalDeviceHandle pr -> StrIx -> Int -> cr Text
-- | 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 :: (AncestorRegion pr cr, MonadIO cr) => RegionalDeviceHandle pr -> InterfaceNumber -> cr 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 :: (AncestorRegion pr cr, MonadIO cr) => RegionalDeviceHandle pr -> InterfaceNumber -> cr ()
-- | Re-attach an interface's kernel driver, which was previously detached
-- using detachKernelDriver.
--
-- Exceptions:
--
--
attachKernelDriver :: (AncestorRegion pr cr, MonadIO cr) => RegionalDeviceHandle pr -> InterfaceNumber -> cr ()
-- | 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 :: (AncestorRegion pr (RegionT s cr), MonadControlIO cr) => RegionalDeviceHandle pr -> InterfaceNumber -> RegionT s cr α -> RegionT s cr α
instance Typeable SettingAlreadySet
instance Typeable NoActiveConfig
instance Show SettingAlreadySet
instance Show NoActiveConfig
instance EnumReadEndpoint Interrupt
instance EnumReadEndpoint Bulk
instance WriteEndpoint Interrupt
instance WriteEndpoint Bulk
instance ReadEndpoint Interrupt
instance ReadEndpoint Bulk
instance MkTransferType Interrupt
instance MkTransferType Bulk
instance MkTransferType Isochronous
instance MkTransferType Control
instance MkTransferDirection In
instance MkTransferDirection Out
instance GetDescriptor (Endpoint transDir transType sAlt r) EndpointDesc
instance Dup (Alternate sCfg)
instance GetDescriptor (Alternate sIntrf r) InterfaceDesc
instance Dup (RegionalInterfaceHandle sCfg)
instance GetDescriptor (Interface sCfg) Interface
instance Exception NoActiveConfig
instance Exception SettingAlreadySet
instance Dup Config
instance GetDescriptor (Config r) ConfigDesc
instance GetDescriptor Device DeviceDesc
instance Dup RegionalDeviceHandle