// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

// Use the <code>chrome.usb</code> API to interact with connected USB
// devices. This API provides access to USB operations from within the context
// of an app. Using this API, apps can function as drivers for hardware devices.
//
// Errors generated by this API are reported by setting
// $(ref:runtime.lastError) and executing the function's regular callback. The
// callback's regular parameters will be undefined in this case.
namespace usb {

  // Direction, Recipient, RequestType, and TransferType all map to their
  // namesakes within the USB specification.
  enum Direction {in, out};
  enum Recipient {device, _interface, endpoint, other};
  enum RequestType {standard, class, vendor, reserved};
  enum TransferType {control, interrupt, isochronous, bulk};

  // For isochronous mode, SynchronizationType and UsageType map to their
  // namesakes within the USB specification.
  enum SynchronizationType {asynchronous, adaptive, synchronous};
  enum UsageType {data, feedback, explicitFeedback};

  dictionary Device {
    // An opaque ID for the USB device. It remains unchanged until the device is
    // unplugged.
    long device;
    // The device vendor ID.
    long vendorId;
    // The product ID.
    long productId;
  };

  dictionary ConnectionHandle {
    // An opaque handle representing this connection to the USB device and all
    // associated claimed interfaces and pending transfers. A new handle is
    // created each time the device is opened. The connection handle is
    // different from $(ref:Device.device).
    long handle;
    // The device vendor ID.
    long vendorId;
    // The product ID.
    long productId;
  };

  [noinline_doc] dictionary EndpointDescriptor {
    // Endpoint address.
    long address;
    // Transfer type.
    TransferType type;
    // Transfer direction.
    Direction direction;
    // Maximum packet size.
    long maximumPacketSize;
    // Transfer synchronization mode (isochronous only).
    SynchronizationType? synchronization;
    // Endpoint usage hint.
    UsageType? usage;
    // Polling interval (interrupt and isochronous only).
    long? pollingInterval;
    // Extra descriptor data associated with this endpoint.
    ArrayBuffer extra_data;
  };

  [noinline_doc] dictionary InterfaceDescriptor {
    // The interface number.
    long interfaceNumber;
    // The interface alternate setting number (defaults to <code>0</code).
    long alternateSetting;
    // The USB interface class.
    long interfaceClass;
    // The USB interface sub-class.
    long interfaceSubclass;
    // The USB interface protocol.
    long interfaceProtocol;
    // Description of the interface.
    DOMString? description;
    // Available endpoints.
    EndpointDescriptor[] endpoints;
    // Extra descriptor data associated with this interface.
    ArrayBuffer extra_data;
  };

  [noinline_doc] dictionary ConfigDescriptor {
    // The configuration number.
    long configurationValue;
    // Description of the configuration.
    DOMString? description;
    // The device is self-powered.
    boolean selfPowered;
    // The device supports remote wakeup.
    boolean remoteWakeup;
    // The maximum power needed by this device in milliamps (mA).
    long maxPower;
    // Available interfaces.
    InterfaceDescriptor[] interfaces;
    // Extra descriptor data associated with this configuration.
    ArrayBuffer extra_data;
  };

  dictionary ControlTransferInfo {
    // The transfer direction (<code>"in"</code> or <code>"out"</code>).
    Direction direction;

    // The transfer target. The target given by <code>index</code> must be
    // claimed if <code>"interface"</code> or <code>"endpoint"</code>.
    Recipient recipient;

    // The request type.
    RequestType requestType;

    // The <code>bRequest</code> field, see <i>Universal Serial Bus Specification
    // Revision 1.1</i> &sect; 9.3.
    long request;
    // The <code>wValue</code> field, see <i>Ibid</i>.
    long value;
    // The <code>wIndex</code> field, see <i>Ibid</i>.
    long index;

    // The amount of data to receive (required only by input transfers).
    long? length;

    // The data to transmit (required only by output transfers).
    ArrayBuffer? data;
  };

  dictionary GenericTransferInfo {
    // The transfer direction (<code>"in"</code> or <code>"out"</code>).
    Direction direction;

    // The target endpoint address. The interface containing this endpoint must
    // be claimed.
    long endpoint;

    // The amount of data to receive (required only by input transfers).
    long? length;

    // The data to transmit (required only by output transfers).
    ArrayBuffer? data;
  };

  dictionary IsochronousTransferInfo {
    // Transfer parameters. The transfer length or data buffer specified in this
    // parameter block is split along <code>packetLength</code> boundaries to
    // form the individual packets of the transfer.
    GenericTransferInfo transferInfo;

    // The total number of packets in this transfer.
    long packets;

    // The length of each of the packets in this transfer.
    long packetLength;
  };

  dictionary TransferResultInfo {
    // A value of <code>0</code> indicates that the transfer was a success.
    // Other values indicate failure.
    long? resultCode;

    // The data returned by an input transfer. <code>undefined</code> for output
    // transfers.
    ArrayBuffer? data;
  };

  [noinline_doc] dictionary DeviceFilter {
    // Device vendor ID.
    long? vendorId;
    // Device product ID, checked only if the vendor ID matches.
    long? productId;
    // USB interface class, matches any interface on the device.
    long? interfaceClass;
    // USB interface sub-class, checked only if the interface class matches.
    long? interfaceSubclass;
    // USB interface protocol, checked only if the interface sub-class matches.
    long? interfaceProtocol;
  };

  dictionary EnumerateDevicesOptions {
    [deprecated="Equivalent to setting $(ref:DeviceFilter.vendorId)."]
    long? vendorId;
    [deprecated="Equivalent to setting $(ref:DeviceFilter.productId)."]
    long? productId;
    // A device matching any given filter will be returned. An empty filter list
    // will return all devices the app has permission for.
    DeviceFilter[]? filters;
  };
  
  dictionary EnumerateDevicesAndRequestAccessOptions {
    // The device vendor ID.
    long vendorId;
    // The product ID.
    long productId;
    // The interface ID to request access to.
    // Only available on ChromeOS. It has no effect on other platforms.
    long? interfaceId;
  };

  callback VoidCallback = void ();
  callback GetDevicesCallback = void (Device[] devices);
  callback RequestAccessCallback = void (boolean success);
  callback OpenDeviceCallback = void (ConnectionHandle handle);
  callback FindDevicesCallback = void (ConnectionHandle[] handles);
  callback GetConfigurationCallback = void (ConfigDescriptor config);
  callback ListInterfacesCallback = void (InterfaceDescriptor[] descriptors);
  callback CloseDeviceCallback = void ();
  callback TransferCallback = void (TransferResultInfo info);
  callback ResetDeviceCallback = void(boolean success);

  interface Functions {
    // Enumerates connected USB devices.
    // |options|: The properties to search for on target devices.
    static void getDevices(EnumerateDevicesOptions options,
                           GetDevicesCallback callback);

    // Requests access from the permission broker to a device claimed by
    // ChromeOS if the given interface on the device is not claimed.
    //
    // <b>Note:</b> This method is ChromeOS specific. Calling this method on
    // other platforms will fail.
    //
    // |device|: The $(ref:Device) to request access to.
    // |interfaceId|: The particular interface requested.
    static void requestAccess(Device device,
                              long interfaceId,
                              RequestAccessCallback callback);

    // Opens a USB device returned by $(ref:getDevices).
    // |device|: The $(ref:Device) to open.
    static void openDevice(Device device, OpenDeviceCallback callback);

    // Finds USB devices specified by the vendor, product and (optionally)
    // interface IDs and if permissions allow opens them for use.
    //
    // On Chrome OS, you can specify the interface ID. In that case the method
    // will request access from permission broker in the same way as
    // $(ref:requestAccess).
    //
    // If the access request is rejected or the device fails to be opened a
    // connection handle will not be created or returned.
    //
    // Calling this method is equivalent to calling $(ref:getDevices followed by
    // $(ref:requestAccess) (if it is on ChromeOS) and $(ref:openDevice) for
    // each device.
    //
    // |options|: The properties to search for on target devices.
    static void findDevices(EnumerateDevicesAndRequestAccessOptions options,
                            FindDevicesCallback callback);

    // Closes a connection handle. Invoking operations on a handle after it
    // has been closed is a safe operation but causes no action to be taken.
    // |handle|: The $(ref:ConnectionHandle) to close.
    static void closeDevice(ConnectionHandle handle,
                            optional CloseDeviceCallback callback);

    // Gets the configuration descriptor for the currently selected
    // configuration.
    // |handle|: An open connection to the device.
    static void getConfiguration(ConnectionHandle handle,
                                 GetConfigurationCallback callback);

    // Lists all interfaces on a USB device.
    // |handle|: An open connection to the device.
    static void listInterfaces(ConnectionHandle handle,
                               ListInterfacesCallback callback);

    // Claims an interface on a USB device.
    // Before data can be transfered to an interface or associated endpoints the
    // interface must be claimed. Only one connection handle can claim an
    // interface at any given time. If the interface is already claimed, this
    // call will fail.
    //
    // $(ref:releaseInterface) should be called when the interface is no longer
    // needed.
    //
    // |handle|: An open connection to the device.
    // |interfaceNumber|: The interface to be claimed.
    static void claimInterface(ConnectionHandle handle, long interfaceNumber,
                               VoidCallback callback);

    // Releases a claimed interface.
    // |handle|: An open connection to the device.
    // |interfaceNumber|: The interface to be released.
    static void releaseInterface(ConnectionHandle handle, long interfaceNumber,
                                 VoidCallback callback);

    // Selects an alternate setting on a previously claimed interface.
    // |handle|: An open connection to the device where this interface has been
    //     claimed.
    // |interfaceNumber|: The interface to configure.
    // |alternateSetting|: The alternate setting to configure.
    static void setInterfaceAlternateSetting(ConnectionHandle handle,
                                             long interfaceNumber,
                                             long alternateSetting,
                                             VoidCallback callback);

    // Performs a control transfer on the specified device.
    //
    // Control transfers refer to either the device, an interface or an
    // endpoint. Transfers to an interface or endpoint require the interface to
    // be claimed.
    //
    // |handle|: An open connection to the device.
    static void controlTransfer(ConnectionHandle handle,
                                ControlTransferInfo transferInfo,
                                TransferCallback callback);

    // Performs a bulk transfer on the specified device.
    // |handle|: An open connection to the device.
    // |transferInfo|: The transfer parameters.
    static void bulkTransfer(ConnectionHandle handle,
                             GenericTransferInfo transferInfo,
                             TransferCallback callback);

    // Performs an interrupt transfer on the specified device.
    // |handle|: An open connection to the device.
    // |transferInfo|: The transfer parameters.
    static void interruptTransfer(ConnectionHandle handle,
                                  GenericTransferInfo transferInfo,
                                  TransferCallback callback);

    // Performs an isochronous transfer on the specific device.
    // |handle|: An open connection to the device.
    static void isochronousTransfer(ConnectionHandle handle,
                                    IsochronousTransferInfo transferInfo,
                                    TransferCallback callback);

    // Tries to reset the USB device.
    // If the reset fails, the given connection handle will be closed and the 
    // USB device will appear to be disconnected then reconnected. 
    // In this case $(ref:getDevices) or $(ref:findDevices) must be called again
    // to acquire the device.
    //
    // |handle|: A connection handle to reset.
    static void resetDevice(ConnectionHandle handle,
                            ResetDeviceCallback callback);
  };
};