1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "device/serial/serial_device_enumerator_linux.h"
7 #include "base/logging.h"
8 #include "base/memory/linked_ptr.h"
9 #include "base/strings/string_number_conversions.h"
15 const char kSerialSubsystem
[] = "tty";
17 const char kHostPathKey
[] = "DEVNAME";
18 const char kHostBusKey
[] = "ID_BUS";
19 const char kVendorIDKey
[] = "ID_VENDOR_ID";
20 const char kProductIDKey
[] = "ID_MODEL_ID";
21 const char kProductNameKey
[] = "ID_MODEL";
23 struct UdevEnumerateDeleter
{
24 void operator()(udev_enumerate
* enumerate
) {
25 udev_enumerate_unref(enumerate
);
29 struct UdevDeviceDeleter
{
30 void operator()(udev_device
* device
) { udev_device_unref(device
); }
33 typedef scoped_ptr
<udev_enumerate
, UdevEnumerateDeleter
> ScopedUdevEnumeratePtr
;
34 typedef scoped_ptr
<udev_device
, UdevDeviceDeleter
> ScopedUdevDevicePtr
;
38 scoped_ptr
<SerialDeviceEnumerator
> SerialDeviceEnumerator::Create() {
39 return scoped_ptr
<SerialDeviceEnumerator
>(new SerialDeviceEnumeratorLinux());
42 SerialDeviceEnumeratorLinux::SerialDeviceEnumeratorLinux() {
43 udev_
.reset(udev_new());
46 SerialDeviceEnumeratorLinux::~SerialDeviceEnumeratorLinux() {}
48 void SerialDeviceEnumeratorLinux::GetDevices(SerialDeviceInfoList
* devices
) {
51 ScopedUdevEnumeratePtr
enumerate(udev_enumerate_new(udev_
.get()));
53 LOG(ERROR
) << "Serial device enumeration failed.";
56 if (udev_enumerate_add_match_subsystem(enumerate
.get(), kSerialSubsystem
)) {
57 LOG(ERROR
) << "Serial device enumeration failed.";
60 if (udev_enumerate_scan_devices(enumerate
.get())) {
61 LOG(ERROR
) << "Serial device enumeration failed.";
65 udev_list_entry
* entry
= udev_enumerate_get_list_entry(enumerate
.get());
66 for (; entry
!= NULL
; entry
= udev_list_entry_get_next(entry
)) {
67 ScopedUdevDevicePtr
device(udev_device_new_from_syspath(
68 udev_
.get(), udev_list_entry_get_name(entry
)));
69 // TODO(rockot): There may be a better way to filter serial devices here,
70 // but it's not clear what that would be. Udev will list lots of virtual
71 // devices with no real endpoint to back them anywhere. The presence of
72 // a bus identifier (e.g., "pci" or "usb") seems to be a good heuristic
73 // for detecting actual devices.
75 udev_device_get_property_value(device
.get(), kHostPathKey
);
76 const char* bus
= udev_device_get_property_value(device
.get(), kHostBusKey
);
77 if (path
!= NULL
&& bus
!= NULL
) {
78 linked_ptr
<SerialDeviceInfo
> info(new SerialDeviceInfo());
79 info
->path
= std::string(path
);
81 const char* vendor_id
=
82 udev_device_get_property_value(device
.get(), kVendorIDKey
);
83 const char* product_id
=
84 udev_device_get_property_value(device
.get(), kProductIDKey
);
85 const char* product_name
=
86 udev_device_get_property_value(device
.get(), kProductNameKey
);
89 if (vendor_id
&& base::HexStringToUInt(vendor_id
, &int_value
))
90 info
->vendor_id
.reset(new uint16(int_value
));
91 if (product_id
&& base::HexStringToUInt(product_id
, &int_value
))
92 info
->product_id
.reset(new uint16(int_value
));
94 info
->display_name
.reset(new std::string(product_name
));
96 devices
->push_back(info
);
101 void SerialDeviceEnumeratorLinux::UdevDeleter::operator()(udev
* handle
) {
105 } // namespace device