def bulk_transfer(args={}, &block)
      timeout = args.delete(:timeout) || 1000
      endpoint = args.delete(:endpoint) || raise(ArgumentError, "no endpoint given")
      endpoint = endpoint.bEndpointAddress if endpoint.respond_to? :bEndpointAddress
      if endpoint&ENDPOINT_IN != 0
        dataIn = args.delete(:dataIn) || raise(ArgumentError, "no :dataIn given for bulk read")
      else
        dataOut = args.delete(:dataOut) || raise(ArgumentError, "no :dataOut given for bulk write")
      end
      raise ArgumentError, "invalid params #{args.inspect}" unless args.empty?

      # reuse transfer struct to speed up transfer
      @bulk_transfer ||= BulkTransfer.new dev_handle: self, allow_device_memory: true
      tr = @bulk_transfer
      tr.endpoint = endpoint
      tr.timeout = timeout
      if dataOut
        tr.buffer = dataOut
      else
        tr.alloc_buffer(dataIn)
      end

      submit_transfer(tr, dataIn, 0, &block)
    end
def bulk_transfer(args={}, &block)
      timeout = args.delete(:timeout) || 1000
      endpoint = args.delete(:endpoint) || raise(ArgumentError, "no endpoint given")
      endpoint = endpoint.bEndpointAddress if endpoint.respond_to? :bEndpointAddress
      if endpoint&ENDPOINT_IN != 0
        dataIn = args.delete(:dataIn) || raise(ArgumentError, "no :dataIn given for bulk read")
      else
        dataOut = args.delete(:dataOut) || raise(ArgumentError, "no :dataOut given for bulk write")
      end
      raise ArgumentError, "invalid params #{args.inspect}" unless args.empty?

      # reuse transfer struct to speed up transfer
      @bulk_transfer ||= BulkTransfer.new dev_handle: self, allow_device_memory: true
      tr = @bulk_transfer
      tr.endpoint = endpoint
      tr.timeout = timeout
      if dataOut
        tr.buffer = dataOut
      else
        tr.alloc_buffer(dataIn)
      end

      submit_transfer(tr, dataIn, 0, &block)
    end
Perform a USB bulk transfer.

 When called without a block, the transfer is done synchronously - so all events are handled
 internally and the sent/received data will be returned after completion or an exception will be raised.

 When called with a block, the method returns immediately after submitting the transfer.
 You then have to ensure, that {Context#handle_events} is called properly. As soon as the
 transfer is completed, the block is called with the sent/received data in case of success
 or the exception instance in case of failure.

 The direction of the transfer is inferred from the direction bits of the
 endpoint address.

 For bulk reads, the +:dataIn+ param indicates the maximum length of data you are
 expecting to receive. If less data arrives than expected, this function will
 return that data.

 You should check the returned number of bytes for bulk writes. Not all of the
 data may have been written.

 Also check {Error#transferred} when dealing with a timeout exception. libusb may have
 to split your transfer into a number of chunks to satisfy underlying O/S
 requirements, meaning that the timeout may expire after the first few chunks
 have completed. libusb is careful not to lose any data that may have been
 transferred; do not assume that timeout conditions indicate a complete lack of
 I/O.

 @param [Hash] args
 @option args [Endpoint, Fixnum] :endpoint  the (address of a) valid endpoint to communicate with
 @option args [String] :dataOut  the data to send with an outgoing transfer
 @option args [Fixnum] :dataIn   the number of bytes expected to receive with an ingoing transfer
 @option args [Fixnum] :timeout   timeout (in millseconds) that this function should wait before giving
   up due to no response being received. For an unlimited timeout, use value 0. Defaults to 1000 ms.

 @return [Fixnum] Number of bytes sent for an outgoing transfer
 @return [String] Received data for an ingoing transfer
 @return [self]  When called with a block

 @yieldparam [String, Integer, LIBUSB::Error] result  result of the transfer is yielded to the block,
   when the asynchronous transfer has finished
 @raise [ArgumentError, LIBUSB::Error] in case of failure