-- Hoogle documentation, generated by Haddock -- See Hoogle, http://www.haskell.org/hoogle/ -- | Type-safe communication with USB devices. -- -- The usb library 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: -- -- -- -- 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: -- -- darcs get -- http://code.haskell.org/~basvandijk/code/usb-safe-examples @package usb-safe @version 0.4 -- | 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 -- -- 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: -- -- darcs get -- http://code.haskell.org/~basvandijk/code/usb-safe-examples module System.USB.Safe -- | Handy type synonym for a region in which USB devices can be opened -- which are automatically closed when the region terminates. -- -- You can run a device region with runRegionT. type DeviceRegionT s pr ± = RegionT Device s pr ± -- | Handy type synonym for a device region which has IO as its -- parent region which enables it to be: -- -- type TopDeviceRegion s ± = TopRegion Device s ± -- | Handy type synonym for a regional handle to an opened USB device. -- -- A regional handle to an opened USB device can be created by applying -- open or with to the USB device you wish to open. -- -- Note that you can also duplicate a regional device handle by -- applying dup to it. type RegionalDeviceHandle r = RegionalHandle Device r -- | 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 `ParentOf` 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 :: (ParentOf 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. 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 -- 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 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 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 :: (ParentOf pr cr, MonadCatchIO cr) => Config pr -> (forall sCfg. ConfigHandle sCfg -> cr ±) -> cr ± -- | This exception can be thrown in: -- -- -- -- to indicate that the device was already configured with a setting. data SettingAlreadySet -- | Apply the given 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 :: (ParentOf pr cr, MonadCatchIO cr) => RegionalDeviceHandle pr -> (forall sCfg. ConfigHandle sCfg -> cr ±) -> cr ± -- | This exception can be thrown in useActiveConfig to indicate -- that the device is currently not configured. data 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 :: (ParentOf pr cr, MonadCatchIO cr) => RegionalDeviceHandle pr -> (ConfigDesc -> Bool) -> (forall sCfg. ConfigHandle sCfg -> cr ±) -> cr ± -- | This exception will be thrown in setConfigWhich or -- setAlternateWhich to indicate that no setting was found which -- satisfies the given predicate. data NotFound -- | 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] -- | Handy type synonym for a region in which interfaces can be claimed -- which are automatically released when the region terminates. -- -- You can run an interface region with runRegionT. type IfRegionT sCfg s pr ± = RegionT (Interface sCfg) s pr ± -- | Handy type synonym for a regional handle to a claimed interface. -- -- A regional handle to a claimed interface can be created by applying -- claim or with to the interface you wish to claim. type RegionalIfHandle sCfg r = RegionalHandle (Interface sCfg) r -- | Claim the given interface in the interface region. -- -- Note that: claim = open which just reads better when -- applied to an interface. -- -- 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 :: (MonadCatchIO pr) => Interface sCfg -> IfRegionT sCfg s pr (RegionalIfHandle sCfg (RegionT (Interface sCfg) s pr)) -- | A supported Interface alternate setting. data Alternate sCfg r :: (* -> *) -- | Retrieve the supported alternate settings from the 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 :: RegionalIfHandle 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 sCfg sAlt r :: (* -> *) -- | 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 setAlternate, useActiveAlternate -- or setAlternateWhich 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 current active alternate use -- useActiveAlternate. -- -- This is a blocking function. -- -- Exceptions: -- -- setAlternate :: (ParentOf pr cr, MonadCatchIO cr) => Alternate sCfg pr -> (forall sAlt. AlternateHandle sCfg sAlt pr -> cr ±) -> cr ± -- | Apply the given function to the alternate handle of the current 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. -- -- Exceptions: -- -- useActiveAlternate :: (ParentOf pr cr, MonadCatchIO cr) => RegionalIfHandle sCfg pr -> (forall sAlt. AlternateHandle sCfg sAlt pr -> cr ±) -> 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 :: (ParentOf pr cr, MonadCatchIO cr) => RegionalIfHandle sCfg pr -> (InterfaceDesc -> Bool) -> (forall sAlt. AlternateHandle sCfg sAlt pr -> cr ±) -> 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 by 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 sCfg sAlt r -> TransferDirection transDir -> TransferType transType -> [Endpoint transDir transType sAlt r] -- | 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 pr cr, MonadIO cr) => Endpoint transDir transType sAlt pr -> cr () 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 data TransferType transType Control :: TransferType CONTROL Isochronous :: TransferType ISOCHRONOUS Bulk :: TransferType BULK Interrupt :: TransferType INTERRUPT data CONTROL data ISOCHRONOUS data BULK 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 r = Timeout -> Size -> r (ByteString, Bool) -- | 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 r = Timeout -> ByteString -> r (Size, Bool) -- | Read bytes from an IN endpoint with either a BULK or -- INTERRUPT transfer type. readEndpoint :: (ReadEndpoint transType, ParentOf pr cr, MonadIO cr) => Endpoint IN transType sAlt pr -> ReadAction cr -- | Write bytes to an OUT endpoint with either a BULK or -- INTERRUPT transfer type. writeEndpoint :: (WriteEndpoint transType, ParentOf pr cr, MonadIO cr) => Endpoint OUT transType sAlt pr -> WriteAction cr -- | 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 pr cr, MonadIO cr) => RegionalDeviceHandle pr -> RequestType -> Recipient -> Word8 -> Word16 -> Word16 -> Timeout -> cr () -- | Perform a USB control read. -- -- The value and index values should be given in -- host-endian byte order. -- -- Exceptions: -- -- readControl :: (ParentOf pr cr, MonadIO cr) => RegionalDeviceHandle pr -> RequestType -> Recipient -> Word8 -> Word16 -> Word16 -> ReadAction cr -- | Perform a USB control write. -- -- The value and index values should be given in -- host-endian byte order. -- -- Exceptions: -- -- writeControl :: (ParentOf pr cr, MonadIO cr) => RegionalDeviceHandle pr -> RequestType -> Recipient -> Word8 -> Word16 -> Word16 -> WriteAction cr -- | Retrieve a list of supported languages. -- -- This function may throw USBExceptions. getLanguages :: (ParentOf pr cr, MonadIO cr) => RegionalDeviceHandle pr -> cr [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 Handle. In other words I would like to -- get a type error when they are some arbitrary number or come from -- another device. getStrDesc :: (ParentOf pr cr, MonadIO cr) => RegionalDeviceHandle pr -> StrIx -> LangId -> Size -> cr 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 pr cr, MonadIO cr) => RegionalDeviceHandle pr -> StrIx -> Size -> cr 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 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 :: (ParentOf pr cr, MonadIO cr) => RegionalDeviceHandle pr -> InterfaceNumber -> cr () -- | Re-attach an interface's kernel driver, which was previously detached -- using detachKernelDriver. -- -- Exceptions: -- -- attachKernelDriver :: (ParentOf 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 :: (ParentOf pr cr, MonadCatchIO cr) => RegionalDeviceHandle pr -> InterfaceNumber -> cr ± -> cr ± instance [overlap ok] Typeable NotFound instance [overlap ok] Typeable NoActiveConfig instance [overlap ok] Typeable SettingAlreadySet instance [overlap ok] Show NotFound instance [overlap ok] Show NoActiveConfig instance [overlap ok] Show SettingAlreadySet instance [overlap ok] WriteEndpoint INTERRUPT instance [overlap ok] WriteEndpoint BULK instance [overlap ok] ReadEndpoint INTERRUPT instance [overlap ok] ReadEndpoint BULK instance [overlap ok] GetDescriptor (Endpoint transDir transType sAlt r) EndpointDesc instance [overlap ok] Dup (Alternate sCfg) (Interface sCfg) instance [overlap ok] GetDescriptor (Alternate sIntrf r) InterfaceDesc instance [overlap ok] Resource (Interface sCfg) instance [overlap ok] GetDescriptor (Interface sCfg) Interface instance [overlap ok] Exception NotFound instance [overlap ok] Exception NoActiveConfig instance [overlap ok] Exception SettingAlreadySet instance [overlap ok] Dup Config Device instance [overlap ok] GetDescriptor (Config r) ConfigDesc instance [overlap ok] GetDescriptor Device DeviceDesc instance [overlap ok] Resource Device