| Index: Source/modules/webusb/USBDevice.cpp | 
| diff --git a/Source/modules/webusb/USBDevice.cpp b/Source/modules/webusb/USBDevice.cpp | 
| index 27ac189ded768a74efce69e7e988682a37687538..afaa2f85ec6f41a6c805385d5ff916d8e4b0c94d 100644 | 
| --- a/Source/modules/webusb/USBDevice.cpp | 
| +++ b/Source/modules/webusb/USBDevice.cpp | 
| @@ -5,10 +5,129 @@ | 
| #include "config.h" | 
| #include "modules/webusb/USBDevice.h" | 
|  | 
| +#include "bindings/core/v8/CallbackPromiseAdapter.h" | 
| +#include "bindings/core/v8/ScriptPromise.h" | 
| +#include "bindings/core/v8/ScriptPromiseResolver.h" | 
| +#include "bindings/core/v8/ToV8.h" | 
| +#include "core/dom/DOMArrayBuffer.h" | 
| +#include "core/dom/DOMArrayBufferView.h" | 
| +#include "core/dom/DOMException.h" | 
| +#include "core/dom/ExceptionCode.h" | 
| #include "modules/webusb/USBConfiguration.h" | 
| +#include "modules/webusb/USBControlTransferParameters.h" | 
| +#include "modules/webusb/USBError.h" | 
| +#include "modules/webusb/USBInTransferResult.h" | 
| +#include "modules/webusb/USBOutTransferResult.h" | 
| +#include "public/platform/modules/webusb/WebUSBTransferInfo.h" | 
|  | 
| namespace blink { | 
|  | 
| +namespace { | 
| + | 
| +DOMException* convertControlTransferParameters( | 
| +    WebUSBDevice::TransferDirection direction, | 
| +    const USBControlTransferParameters& parameters, | 
| +    WebUSBDevice::ControlTransferParameters* webParameters) | 
| +{ | 
| +    webParameters->direction = direction; | 
| + | 
| +    if (parameters.requestType() == "standard") | 
| +        webParameters->type = WebUSBDevice::RequestType::Standard; | 
| +    else if (parameters.requestType() == "class") | 
| +        webParameters->type = WebUSBDevice::RequestType::Class; | 
| +    else if (parameters.requestType() == "vendor") | 
| +        webParameters->type = WebUSBDevice::RequestType::Vendor; | 
| +    else | 
| +        return DOMException::create(TypeMismatchError, "The control transfer requestType parameter is invalid."); | 
| + | 
| +    if (parameters.recipient() == "device") | 
| +        webParameters->recipient = WebUSBDevice::RequestRecipient::Device; | 
| +    else if (parameters.recipient() == "interface") | 
| +        webParameters->recipient = WebUSBDevice::RequestRecipient::Interface; | 
| +    else if (parameters.recipient() == "endpoint") | 
| +        webParameters->recipient = WebUSBDevice::RequestRecipient::Endpoint; | 
| +    else if (parameters.recipient() == "other") | 
| +        webParameters->recipient = WebUSBDevice::RequestRecipient::Other; | 
| +    else | 
| +        return DOMException::create(TypeMismatchError, "The control transfer recipient parameter is invalid."); | 
| + | 
| +    webParameters->request = parameters.request(); | 
| +    webParameters->value = parameters.value(); | 
| +    webParameters->index = parameters.index(); | 
| +    return nullptr; | 
| +} | 
| + | 
| +String convertTransferStatus(const WebUSBTransferInfo::Status& status) | 
| +{ | 
| +    switch (status) { | 
| +    case WebUSBTransferInfo::Status::Ok: | 
| +        return "ok"; | 
| +    case WebUSBTransferInfo::Status::Stall: | 
| +        return "stall"; | 
| +    case WebUSBTransferInfo::Status::Babble: | 
| +        return "babble"; | 
| +    default: | 
| +        ASSERT_NOT_REACHED(); | 
| +        return ""; | 
| +    } | 
| +} | 
| + | 
| +class InputTransferResult { | 
| +    WTF_MAKE_NONCOPYABLE(InputTransferResult); | 
| +public: | 
| +    using WebType = OwnPtr<WebUSBTransferInfo>; | 
| + | 
| +    static USBInTransferResult* take(ScriptPromiseResolver*, PassOwnPtr<WebUSBTransferInfo> webTransferInfo) | 
| +    { | 
| +        return USBInTransferResult::create(convertTransferStatus(webTransferInfo->status), webTransferInfo->data); | 
| +    } | 
| + | 
| +private: | 
| +    InputTransferResult() = delete; | 
| +}; | 
| + | 
| +class OutputTransferResult { | 
| +    WTF_MAKE_NONCOPYABLE(OutputTransferResult); | 
| +public: | 
| +    using WebType = OwnPtr<WebUSBTransferInfo>; | 
| + | 
| +    static USBOutTransferResult* take(ScriptPromiseResolver*, PassOwnPtr<WebUSBTransferInfo> webTransferInfo) | 
| +    { | 
| +        return USBOutTransferResult::create(convertTransferStatus(webTransferInfo->status), webTransferInfo->bytesWritten); | 
| +    } | 
| + | 
| +private: | 
| +    OutputTransferResult() = delete; | 
| +}; | 
| + | 
| +class BufferSource { | 
| +    WTF_MAKE_NONCOPYABLE(BufferSource); | 
| +public: | 
| +    BufferSource(const ArrayBufferOrArrayBufferView& buffer) : m_buffer(buffer) | 
| +    { | 
| +        ASSERT(!m_buffer.isNull()); | 
| +    } | 
| + | 
| +    uint8_t* data() const | 
| +    { | 
| +        if (m_buffer.isArrayBuffer()) | 
| +            return static_cast<uint8_t*>(m_buffer.getAsArrayBuffer()->data()); | 
| +        return static_cast<uint8_t*>(m_buffer.getAsArrayBufferView()->baseAddress()); | 
| +    } | 
| + | 
| +    unsigned size() const | 
| +    { | 
| +        if (m_buffer.isArrayBuffer()) | 
| +            return m_buffer.getAsArrayBuffer()->byteLength(); | 
| +        return m_buffer.getAsArrayBufferView()->byteLength(); | 
| +    } | 
| + | 
| +private: | 
| +    const ArrayBufferOrArrayBufferView& m_buffer; | 
| +}; | 
| + | 
| +} // namespace | 
| + | 
| HeapVector<Member<USBConfiguration>> USBDevice::configurations() const | 
| { | 
| HeapVector<Member<USBConfiguration>> configurations; | 
| @@ -17,4 +136,126 @@ HeapVector<Member<USBConfiguration>> USBDevice::configurations() const | 
| return configurations; | 
| } | 
|  | 
| +ScriptPromise USBDevice::open(ScriptState* scriptState) | 
| +{ | 
| +    ScriptPromiseResolver* resolver = ScriptPromiseResolver::create(scriptState); | 
| +    ScriptPromise promise = resolver->promise(); | 
| +    m_device->open(new CallbackPromiseAdapter<void, USBError>(resolver)); | 
| +    return promise; | 
| +} | 
| + | 
| +ScriptPromise USBDevice::close(ScriptState* scriptState) | 
| +{ | 
| +    ScriptPromiseResolver* resolver = ScriptPromiseResolver::create(scriptState); | 
| +    ScriptPromise promise = resolver->promise(); | 
| +    m_device->close(new CallbackPromiseAdapter<void, USBError>(resolver)); | 
| +    return promise; | 
| +} | 
| + | 
| +ScriptPromise USBDevice::setConfiguration(ScriptState* scriptState, uint8_t configurationValue) | 
| +{ | 
| +    ScriptPromiseResolver* resolver = ScriptPromiseResolver::create(scriptState); | 
| +    ScriptPromise promise = resolver->promise(); | 
| +    m_device->setConfiguration(configurationValue, new CallbackPromiseAdapter<void, USBError>(resolver)); | 
| +    return promise; | 
| +} | 
| + | 
| +ScriptPromise USBDevice::claimInterface(ScriptState* scriptState, uint8_t interfaceNumber) | 
| +{ | 
| +    ScriptPromiseResolver* resolver = ScriptPromiseResolver::create(scriptState); | 
| +    ScriptPromise promise = resolver->promise(); | 
| +    m_device->claimInterface(interfaceNumber, new CallbackPromiseAdapter<void, USBError>(resolver)); | 
| +    return promise; | 
| +} | 
| + | 
| +ScriptPromise USBDevice::releaseInterface(ScriptState* scriptState, uint8_t interfaceNumber) | 
| +{ | 
| +    ScriptPromiseResolver* resolver = ScriptPromiseResolver::create(scriptState); | 
| +    ScriptPromise promise = resolver->promise(); | 
| +    m_device->releaseInterface(interfaceNumber, new CallbackPromiseAdapter<void, USBError>(resolver)); | 
| +    return promise; | 
| +} | 
| + | 
| +ScriptPromise USBDevice::setInterface(ScriptState* scriptState, uint8_t interfaceNumber, uint8_t alternateSetting) | 
| +{ | 
| +    ScriptPromiseResolver* resolver = ScriptPromiseResolver::create(scriptState); | 
| +    ScriptPromise promise = resolver->promise(); | 
| +    m_device->setInterface(interfaceNumber, alternateSetting, new CallbackPromiseAdapter<void, USBError>(resolver)); | 
| +    return promise; | 
| +} | 
| + | 
| +ScriptPromise USBDevice::controlTransferIn(ScriptState* scriptState, const USBControlTransferParameters& setup, unsigned length) | 
| +{ | 
| +    ScriptPromiseResolver* resolver = ScriptPromiseResolver::create(scriptState); | 
| +    ScriptPromise promise = resolver->promise(); | 
| +    WebUSBDevice::ControlTransferParameters parameters; | 
| +    DOMException* error = convertControlTransferParameters(WebUSBDevice::TransferDirection::In, setup, ¶meters); | 
| +    if (error) | 
| +        resolver->reject(error); | 
| +    else | 
| +        m_device->controlTransfer(parameters, nullptr, length, 0, new CallbackPromiseAdapter<InputTransferResult, USBError>(resolver)); | 
| +    return promise; | 
| +} | 
| + | 
| +ScriptPromise USBDevice::controlTransferOut(ScriptState* scriptState, const USBControlTransferParameters& setup) | 
| +{ | 
| +    ScriptPromiseResolver* resolver = ScriptPromiseResolver::create(scriptState); | 
| +    ScriptPromise promise = resolver->promise(); | 
| +    WebUSBDevice::ControlTransferParameters parameters; | 
| +    DOMException* error = convertControlTransferParameters(WebUSBDevice::TransferDirection::Out, setup, ¶meters); | 
| +    if (error) | 
| +        resolver->reject(error); | 
| +    else | 
| +        m_device->controlTransfer(parameters, nullptr, 0, 0, new CallbackPromiseAdapter<OutputTransferResult, USBError>(resolver)); | 
| +    return promise; | 
| +} | 
| + | 
| +ScriptPromise USBDevice::controlTransferOut(ScriptState* scriptState, const USBControlTransferParameters& setup, const ArrayBufferOrArrayBufferView& data) | 
| +{ | 
| +    ScriptPromiseResolver* resolver = ScriptPromiseResolver::create(scriptState); | 
| +    ScriptPromise promise = resolver->promise(); | 
| +    WebUSBDevice::ControlTransferParameters parameters; | 
| +    DOMException* error = convertControlTransferParameters(WebUSBDevice::TransferDirection::Out, setup, ¶meters); | 
| +    if (error) { | 
| +        resolver->reject(error); | 
| +    } else { | 
| +        BufferSource buffer(data); | 
| +        m_device->controlTransfer(parameters, buffer.data(), buffer.size(), 0, new CallbackPromiseAdapter<OutputTransferResult, USBError>(resolver)); | 
| +    } | 
| +    return promise; | 
| +} | 
| + | 
| +ScriptPromise USBDevice::clearHalt(ScriptState* scriptState, uint8_t endpointNumber) | 
| +{ | 
| +    ScriptPromiseResolver* resolver = ScriptPromiseResolver::create(scriptState); | 
| +    ScriptPromise promise = resolver->promise(); | 
| +    m_device->clearHalt(endpointNumber, new CallbackPromiseAdapter<void, USBError>(resolver)); | 
| +    return promise; | 
| +} | 
| + | 
| +ScriptPromise USBDevice::transferIn(ScriptState* scriptState, uint8_t endpointNumber, unsigned length) | 
| +{ | 
| +    ScriptPromiseResolver* resolver = ScriptPromiseResolver::create(scriptState); | 
| +    ScriptPromise promise = resolver->promise(); | 
| +    m_device->transfer(WebUSBDevice::TransferDirection::In, endpointNumber, nullptr, length, 0, new CallbackPromiseAdapter<InputTransferResult, USBError>(resolver)); | 
| +    return promise; | 
| +} | 
| + | 
| +ScriptPromise USBDevice::transferOut(ScriptState* scriptState, uint8_t endpointNumber, const ArrayBufferOrArrayBufferView& data) | 
| +{ | 
| +    ScriptPromiseResolver* resolver = ScriptPromiseResolver::create(scriptState); | 
| +    ScriptPromise promise = resolver->promise(); | 
| +    BufferSource buffer(data); | 
| +    m_device->transfer(WebUSBDevice::TransferDirection::Out, endpointNumber, buffer.data(), buffer.size(), 0, new CallbackPromiseAdapter<OutputTransferResult, USBError>(resolver)); | 
| +    return promise; | 
| +} | 
| + | 
| +ScriptPromise USBDevice::reset(ScriptState* scriptState) | 
| +{ | 
| +    ScriptPromiseResolver* resolver = ScriptPromiseResolver::create(scriptState); | 
| +    ScriptPromise promise = resolver->promise(); | 
| +    m_device->reset(new CallbackPromiseAdapter<void, USBError>(resolver)); | 
| +    return promise; | 
| +} | 
| + | 
| } // namespace blink | 
|  |