2 * Copyright (C) 2005-2013 Team XBMC
5 * This Program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2, or (at your option)
10 * This Program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with XBMC; see the file COPYING. If not, see
17 * <http://www.gnu.org/licenses/>.
21 #include "PeripheralBusUSBLibUdev.h"
22 #include "peripherals/Peripherals.h"
27 #include "utils/log.h"
29 #ifndef USB_CLASS_PER_INTERFACE
30 #define USB_CLASS_PER_INTERFACE 0
33 #ifndef USB_CLASS_AUDIO
34 #define USB_CLASS_AUDIO 1
37 #ifndef USB_CLASS_COMM
38 #define USB_CLASS_COMM 2
42 #define USB_CLASS_HID 3
45 #ifndef USB_CLASS_PHYSICAL
46 #define USB_CLASS_PHYSICAL 5
50 #define USB_CLASS_PTP 6
53 #ifndef USB_CLASS_PRINTER
54 #define USB_CLASS_PRINTER 7
57 #ifndef USB_CLASS_MASS_STORAGE
58 #define USB_CLASS_MASS_STORAGE 8
62 #define USB_CLASS_HUB 9
65 #ifndef USB_CLASS_DATA
66 #define USB_CLASS_DATA 10
69 #ifndef USB_CLASS_APP_SPEC
70 #define USB_CLASS_APP_SPEC 0xfe
73 #ifndef USB_CLASS_VENDOR_SPEC
74 #define USB_CLASS_VENDOR_SPEC 0xff
77 using namespace PERIPHERALS;
79 CPeripheralBusUSB::CPeripheralBusUSB(CPeripherals *manager) :
80 CPeripheralBus("PeripBusUSBUdev", manager, PERIPHERAL_BUS_USB)
82 /* the Process() method in this class overrides the one in CPeripheralBus, so leave this set to true */
83 m_bNeedsPolling = true;
88 if (!(m_udev = udev_new()))
90 CLog::Log(LOGERROR, "%s - failed to allocate udev context", __FUNCTION__);
94 /* set up a devices monitor that listen for any device change */
95 m_udevMon = udev_monitor_new_from_netlink(m_udev, "udev");
96 udev_monitor_enable_receiving(m_udevMon);
98 CLog::Log(LOGDEBUG, "%s - initialised udev monitor", __FUNCTION__);
101 CPeripheralBusUSB::~CPeripheralBusUSB(void)
104 udev_monitor_unref(m_udevMon);
108 bool CPeripheralBusUSB::PerformDeviceScan(PeripheralScanResults &results)
110 struct udev_enumerate *enumerate;
111 struct udev_list_entry *devices, *dev_list_entry;
112 struct udev_device *dev(NULL), *parent(NULL);
113 enumerate = udev_enumerate_new(m_udev);
114 udev_enumerate_scan_devices(enumerate);
115 devices = udev_enumerate_get_list_entry(enumerate);
117 bool bContinue(true);
118 CStdString strPath, strClass;
119 udev_list_entry_foreach(dev_list_entry, devices)
121 strPath = udev_list_entry_get_name(dev_list_entry);
122 if (strPath.IsEmpty())
127 if (!(parent = udev_device_new_from_syspath(m_udev, strPath)))
133 dev = udev_device_get_parent(udev_device_get_parent(parent));
134 if (!dev || !udev_device_get_sysattr_value(dev,"idVendor") || !udev_device_get_sysattr_value(dev, "idProduct"))
140 strClass = udev_device_get_sysattr_value(dev, "bDeviceClass");
141 if (strClass.IsEmpty())
147 int iClass = PeripheralTypeTranslator::HexStringToInt(strClass.c_str());
148 if (iClass == USB_CLASS_PER_INTERFACE)
150 //TODO just assume this is a HID device for now, since the only devices that we're currently
151 // interested in are HID devices
152 iClass = USB_CLASS_HID;
155 PeripheralScanResult result(m_type);
156 result.m_iVendorId = PeripheralTypeTranslator::HexStringToInt(udev_device_get_sysattr_value(dev, "idVendor"));
157 result.m_iProductId = PeripheralTypeTranslator::HexStringToInt(udev_device_get_sysattr_value(dev, "idProduct"));
158 result.m_type = GetType(iClass);
159 result.m_strLocation = udev_device_get_syspath(dev);
160 result.m_iSequence = GetNumberOfPeripheralsWithId(result.m_iVendorId, result.m_iProductId);
161 if (!results.ContainsResult(result))
162 results.m_results.push_back(result);
168 /* unref the _parent_ device */
169 udev_device_unref(parent);
173 /* Free the enumerator object */
174 udev_enumerate_unref(enumerate);
179 const PeripheralType CPeripheralBusUSB::GetType(int iDeviceClass)
181 switch (iDeviceClass)
184 return PERIPHERAL_HID;
186 return PERIPHERAL_NIC;
187 case USB_CLASS_MASS_STORAGE:
188 return PERIPHERAL_DISK;
189 case USB_CLASS_PER_INTERFACE:
190 case USB_CLASS_AUDIO:
191 case USB_CLASS_PRINTER:
195 case USB_CLASS_VENDOR_SPEC:
197 return PERIPHERAL_UNKNOWN;
201 void CPeripheralBusUSB::Process(void)
203 bool bUpdated(false);
207 bUpdated = WaitForUpdate();
208 if (bUpdated && !m_bStop)
212 m_bIsStarted = false;
215 void CPeripheralBusUSB::Clear(void)
219 CPeripheralBus::Clear();
222 bool CPeripheralBusUSB::WaitForUpdate()
224 int udevFd = udev_monitor_get_fd(m_udevMon);
228 CLog::Log(LOGERROR, "%s - get udev monitor", __FUNCTION__);
232 /* poll for udev changes */
233 struct pollfd pollFd;
235 pollFd.events = POLLIN;
237 while (!m_bStop && ((iPollResult = poll(&pollFd, 1, 100)) <= 0))
238 if (errno != EINTR && iPollResult != 0)
241 /* the thread is being stopped, so just return false */
245 /* we have to read the message from the queue, even though we're not actually using it */
246 struct udev_device *dev = udev_monitor_receive_device(m_udevMon);
248 udev_device_unref(dev);
251 CLog::Log(LOGERROR, "%s - failed to get device from udev_monitor_receive_device()", __FUNCTION__);