16e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)// Copyright 2014 The Chromium Authors. All rights reserved.
26e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
36e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)// found in the LICENSE file.
46e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
51320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "device/usb/usb_device_filter.h"
66e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
76e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)#include "base/values.h"
81320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "device/usb/usb_descriptors.h"
91320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "device/usb/usb_device.h"
106e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
111320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccinamespace device {
126e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
136e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)namespace {
146e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
156e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)const char kProductIdKey[] = "productId";
166e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)const char kVendorIdKey[] = "vendorId";
176e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)const char kInterfaceClassKey[] = "interfaceClass";
186e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)const char kInterfaceSubclassKey[] = "interfaceSubclass";
196e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)const char kInterfaceProtocolKey[] = "interfaceProtocol";
206e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
216e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)}  // namespace
226e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
236e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)UsbDeviceFilter::UsbDeviceFilter()
246e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    : vendor_id_set_(false),
256e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      product_id_set_(false),
266e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      interface_class_set_(false),
276e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      interface_subclass_set_(false),
286e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      interface_protocol_set_(false) {
296e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)}
306e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
316e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)UsbDeviceFilter::~UsbDeviceFilter() {
326e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)}
336e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
346e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)void UsbDeviceFilter::SetVendorId(uint16 vendor_id) {
356e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  vendor_id_set_ = true;
366e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  vendor_id_ = vendor_id;
376e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)}
386e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
396e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)void UsbDeviceFilter::SetProductId(uint16 product_id) {
406e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  product_id_set_ = true;
416e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  product_id_ = product_id;
426e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)}
436e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
446e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)void UsbDeviceFilter::SetInterfaceClass(uint8 interface_class) {
456e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  interface_class_set_ = true;
466e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  interface_class_ = interface_class;
476e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)}
486e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
496e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)void UsbDeviceFilter::SetInterfaceSubclass(uint8 interface_subclass) {
506e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  interface_subclass_set_ = true;
516e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  interface_subclass_ = interface_subclass;
526e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)}
536e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
546e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)void UsbDeviceFilter::SetInterfaceProtocol(uint8 interface_protocol) {
556e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  interface_protocol_set_ = true;
566e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  interface_protocol_ = interface_protocol;
576e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)}
586e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
591320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccibool UsbDeviceFilter::Matches(scoped_refptr<UsbDevice> device) const {
606e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  if (vendor_id_set_) {
616e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    if (device->vendor_id() != vendor_id_) {
626e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      return false;
636e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    }
646e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
656e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    if (product_id_set_ && device->product_id() != product_id_) {
666e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      return false;
676e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    }
686e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  }
696e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
706e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  if (interface_class_set_) {
716e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    bool foundMatch = false;
721320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    const UsbConfigDescriptor& config = device->GetConfiguration();
736e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
746e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    // TODO(reillyg): Check device configuration if the class is not defined at
756e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    // a per-interface level. This is not really important because most devices
766e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    // have per-interface classes. The only counter-examples I know of are hubs.
776e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
781320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    for (UsbInterfaceDescriptor::Iterator ifaceIt = config.interfaces.begin();
791320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci         ifaceIt != config.interfaces.end() && !foundMatch;
801320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci         ++ifaceIt) {
811320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      if (ifaceIt->interface_class == interface_class_ &&
821320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci          (!interface_subclass_set_ ||
831320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci           (ifaceIt->interface_subclass == interface_subclass_ &&
841320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci            (!interface_protocol_set_ ||
851320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci             ifaceIt->interface_protocol == interface_protocol_)))) {
861320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        foundMatch = true;
876e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      }
886e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    }
896e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
906e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    if (!foundMatch) {
916e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      return false;
926e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    }
936e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  }
946e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
956e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  return true;
966e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)}
976e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
986e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)base::Value* UsbDeviceFilter::ToValue() const {
996e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  scoped_ptr<base::DictionaryValue> obj(new base::DictionaryValue());
1006e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
1016e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  if (vendor_id_set_) {
1026e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    obj->SetInteger(kVendorIdKey, vendor_id_);
1036e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    if (product_id_set_) {
1046e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      obj->SetInteger(kProductIdKey, product_id_);
1056e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    }
1066e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  }
1076e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
1086e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  if (interface_class_set_) {
1096e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    obj->SetInteger(kInterfaceClassKey, interface_class_);
1106e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    if (interface_subclass_set_) {
1116e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      obj->SetInteger(kInterfaceSubclassKey, interface_subclass_);
1126e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      if (interface_protocol_set_) {
1136e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)        obj->SetInteger(kInterfaceProtocolKey, interface_protocol_);
1146e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      }
1156e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    }
1166e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  }
1176e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
1186e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  return obj.release();
1196e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)}
1206e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
1211320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci// static
1221320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccibool UsbDeviceFilter::MatchesAny(scoped_refptr<UsbDevice> device,
1231320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                                 const std::vector<UsbDeviceFilter>& filters) {
1241320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  for (std::vector<UsbDeviceFilter>::const_iterator i = filters.begin();
1251320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci       i != filters.end();
1261320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci       ++i) {
1271320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    if (i->Matches(device)) {
1281320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      return true;
1291320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    }
1301320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  }
1311320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  return false;
1321320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci}
1331320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
1341320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci}  // namespace device
135