// 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 interrupt and isochronous modes, SynchronizationType and UsageType map
  // to their namesakes within the USB specification.
  enum SynchronizationType {asynchronous, adaptive, synchronous};
  enum UsageType {data, feedback, explicitFeedback, periodic, notification};

  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;
    // The device version (bcdDevice field).
    long version;
    // The iProduct string read from the device, if available.
    DOMString productName;
    // The iManufacturer string read from the device, if available.
    DOMString manufacturerName;
    // The iSerialNumber string read from the device, if available.
    DOMString serialNumber;
  };

  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 {
    // Is this the active configuration?
    boolean active;
    // 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 maximum number of bytes to receive (required only by input
    // transfers).
    long? length;

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

    // Request timeout (in milliseconds). The default value <code>0</code>
    // indicates no timeout.
    long? timeout;
  };

  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 maximum number of bytes to receive (required only by input
    // transfers).
    long? length;

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

    // Request timeout (in milliseconds). The default value <code>0</code>
    // indicates no timeout.
    long? timeout;
  };

  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 Chrome OS. It has no effect on other platforms.
    long? interfaceId;
  };

  dictionary DevicePromptOptions {
    // Allow the user to select multiple devices.
    boolean? multiple;
    // Filter the list of devices presented to the user. If multiple filters are
    // provided devices matching any filter will be displayed.
    DeviceFilter[]? filters;
  };

  callback VoidCallback = void ();
  callback GetDevicesCallback = void (Device[] devices);
  callback GetConfigurationsCallback = void (ConfigDescriptor[] configs);
  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);

    // Presents a device picker to the user and returns the $(ref:Device)s
    // selected.
    // If the user cancels the picker devices will be empty. A user gesture
    // is required for the dialog to display. Without a user gesture, the
    // callback will run as though the user cancelled.
    // |options|: Configuration of the device picker dialog box.
    // |callback|: Invoked with a list of chosen $(ref:Device)s.
    static void getUserSelectedDevices(DevicePromptOptions options,
                                       GetDevicesCallback callback);

    // Returns the full set of device configuration descriptors.
    // |device|: The $(ref:Device) to fetch descriptors from.
    static void getConfigurations(Device device,
                                  GetConfigurationsCallback callback);

    // Requests access from the permission broker to a device claimed by
    // Chrome OS if the given interface on the device is not claimed.
    //
    // |device|: The $(ref:Device) to request access to.
    // |interfaceId|: The particular interface requested.
    [deprecated="This function was Chrome OS specific and calling it on other
    platforms would fail. This operation is now implicitly performed as part of
    $(ref:openDevice) and this function will return <code>true</code> on all
    platforms."]
    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.
    //
    // 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: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);

    // Select a device configuration.
    //
    // This function effectively resets the device by selecting one of the
    // device's available configurations. Only configuration values greater
    // than <code>0</code> are valid however some buggy devices have a working
    // configuration <code>0</code> and so this value is allowed.
    // |handle|: An open connection to the device.
    static void setConfiguration(ConnectionHandle handle,
                                 long configurationValue,
                                 VoidCallback 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);
  };

  interface Events {
    // Event generated when a device is added to the system. Events are only
    // broadcast to apps and extensions that have permission to access the
    // device. Permission may have been granted at install time, when the user
    // accepted an optional permission (see $(ref:permissions.request)), or
    // through $(ref:getUserSelectedDevices).
    static void onDeviceAdded(Device device);

    // Event generated when a device is removed from the system. See
    // $(ref:onDeviceAdded) for which events are delivered.
    static void onDeviceRemoved(Device device);
  };
};
