Bumped copyright dates for 2013
[barry.git] / src / usbwrap_libusb_1_0.cc
blob16eddbcb323b40f480936067c260e21888537651
1 ///
2 /// \file usbwrap_libusb_1_0.cc
3 /// USB API wrapper for libusb version 1.0
4 ///
6 /*
7 Copyright (C) 2005-2013, Chris Frey
8 Portions Copyright (C) 2011, RealVNC Ltd.
10 This program is free software; you can redistribute it and/or modify
11 it under the terms of the GNU General Public License as published by
12 the Free Software Foundation; either version 2 of the License, or
13 (at your option) any later version.
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
19 See the GNU General Public License in the COPYING file at the
20 root directory of this project for more details.
23 #include "i18n.h"
25 #include "usbwrap_libusb_1_0.h"
27 #include "debug.h"
28 #include "data.h"
29 #include <errno.h>
30 #include <sstream>
31 #include <iostream>
32 #include <sstream>
33 #include <algorithm>
35 #ifndef __DEBUG_MODE__
36 #define __DEBUG_MODE__
37 #endif
38 #include "debug.h"
40 namespace Usb {
42 // helper functions to make deleting pointers in maps and vectors easier
43 template<typename T> static void deletePtr(T* ptr)
45 delete ptr;
48 template<typename K, typename T> static void deleteMapPtr(std::pair<K,T*> ptr)
50 delete ptr.second;
53 // lookup table translating LIBUSB errors to standard Linux errors
54 static const struct {
55 int libusb;
56 int system;
57 } errorCodes[] = {
58 { LIBUSB_SUCCESS, 0 },
59 { LIBUSB_ERROR_IO, -EIO },
60 { LIBUSB_ERROR_INVALID_PARAM, -EINVAL },
61 { LIBUSB_ERROR_ACCESS, -EACCES },
62 { LIBUSB_ERROR_NO_DEVICE, -ENODEV },
63 { LIBUSB_ERROR_NOT_FOUND, -ENOENT },
64 { LIBUSB_ERROR_BUSY, -EBUSY },
65 { LIBUSB_ERROR_TIMEOUT, -ETIMEDOUT },
66 { LIBUSB_ERROR_OVERFLOW, -EOVERFLOW },
67 { LIBUSB_ERROR_PIPE, -EPIPE },
68 { LIBUSB_ERROR_INTERRUPTED, -EINTR },
69 { LIBUSB_ERROR_NO_MEM, -ENOMEM },
70 { LIBUSB_ERROR_NOT_SUPPORTED, -ENOSYS },
71 // There isn't an errno.h value for generic errors, so
72 // return success, which, for TranslateErrcode(), means error.
73 { LIBUSB_ERROR_OTHER, 0 }
76 static const int errorCodeCnt = sizeof(errorCodes) / sizeof(errorCodes[0]);
79 ///////////////////////////////////////////////////////////////////////////////
80 // Global libusb library context
81 static libusb_context* libusbctx;
83 ///////////////////////////////////////////////////////////////////////////////
84 // Static functions
86 std::string LibraryInterface::GetLastErrorString(int libusb_errcode)
88 switch( libusb_errcode )
90 case LIBUSB_SUCCESS:
91 return _("Success");
92 case LIBUSB_ERROR_IO:
93 return _("IO Error");
94 case LIBUSB_ERROR_INVALID_PARAM:
95 return _("Invalid parameter");
96 case LIBUSB_ERROR_ACCESS:
97 return _("Access");
98 case LIBUSB_ERROR_NO_DEVICE:
99 return _("No device");
100 case LIBUSB_ERROR_NOT_FOUND:
101 return _("Not found");
102 case LIBUSB_ERROR_BUSY:
103 return _("Busy");
104 case LIBUSB_ERROR_TIMEOUT:
105 return _("Timeout");
106 case LIBUSB_ERROR_OVERFLOW:
107 return _("Overflow");
108 case LIBUSB_ERROR_PIPE:
109 return _("Pipe");
110 case LIBUSB_ERROR_INTERRUPTED:
111 return _("Interrupted");
112 case LIBUSB_ERROR_NO_MEM:
113 return _("No memory");
114 case LIBUSB_ERROR_NOT_SUPPORTED:
115 return _("Not supported");
116 case LIBUSB_ERROR_OTHER:
117 return _("Other");
118 default:
119 return _("Unknown LIBUSB error code");
123 // Helper function to translate libusb error codes into more useful values
125 // Note that this function assumes that libusb_errcode contains an error.
126 // It is helpful enough to return 0 if libusb_errcode contains 0, but
127 // if it is a positive success value (such as for a read or write)
128 // it will still return 0, since it won't find a corresponding errno code.
130 // Since this function assumes that libusb_errcode is already an error,
131 // it also assumes the caller already *knows* that it is an error, and
132 // therefore a return of success is an "error" for this function. :-)
134 int LibraryInterface::TranslateErrcode(int libusb_errcode)
136 for( int i = 0; i < errorCodeCnt; ++i ) {
137 if( errorCodes[i].libusb == libusb_errcode )
138 return errorCodes[i].system;
141 // default to 0 if unknown
142 eout("Failed to translate libusb errorcode: " << libusb_errcode);
143 return 0;
146 bool LibraryInterface::Init(int *libusb_errno)
148 // if the environment variable LIBUSB_DEBUG is set, that
149 // level value will be used instead of our 3 above...
150 // if you need to *force* this to 3, call SetDataDump(true)
151 // after Init()
152 if( !libusbctx ) {
153 int ret = libusb_init(&libusbctx);
155 // store errno for user if possible
156 if( libusb_errno )
157 *libusb_errno = ret;
159 // true on success
160 return ret >= 0;
162 return true;
165 void LibraryInterface::Uninit()
167 libusb_exit(libusbctx);
168 libusbctx = NULL;
171 void LibraryInterface::SetDataDump(bool data_dump_mode)
173 if( !libusbctx ) {
174 Init();
176 if( !libusbctx ) {
177 // Failed to init, can't do much but return
178 dout("SetDataDump: Failed to initialise libusb");
179 return;
181 if( data_dump_mode )
182 libusb_set_debug(libusbctx, 3);
183 else
184 libusb_set_debug(libusbctx, 0);
187 ///////////////////////////////////////////////////////////////////////////////
188 // DeviceIDImpl
190 DeviceIDImpl::DeviceIDImpl(libusb_device *dev)
191 : m_dev(dev)
193 libusb_ref_device(m_dev);
195 // Libusb 1.0 doesn't provide busnames or filenames
196 // so it's necessary to make some up.
197 std::ostringstream formatter;
198 formatter << "libusb1-"
199 << static_cast<int>(libusb_get_bus_number(m_dev));
200 m_busname = formatter.str();
202 formatter << "-"
203 << static_cast<int>(libusb_get_device_address(m_dev));
204 m_filename = formatter.str();
207 DeviceIDImpl::~DeviceIDImpl()
209 libusb_unref_device(m_dev);
212 ///////////////////////////////////////////////////////////////////////////////
213 // DeviceID
215 DeviceID::DeviceID(DeviceIDImpl* impl)
216 : m_impl(impl)
220 DeviceID::~DeviceID()
225 const char* DeviceID::GetBusName() const
227 return m_impl->m_busname.c_str();
230 uint16_t DeviceID::GetNumber() const
232 return libusb_get_device_address(m_impl->m_dev);
235 const char* DeviceID::GetFilename() const
237 return m_impl->m_filename.c_str();
240 uint16_t DeviceID::GetIdProduct() const
242 int ret = PRODUCT_UNKNOWN;
243 struct libusb_device_descriptor desc;
244 int err = libusb_get_device_descriptor(m_impl->m_dev, &desc);
245 if( err == 0 )
246 ret = desc.idProduct;
247 return ret;
250 std::string DeviceID::GetUsbName() const
252 // for libusb 1.0, we can use bus name and number...
253 // and we stay away from the product ID, since that requires
254 // communication with the device, which may not be possible
255 // in error conditions.
256 std::ostringstream oss;
257 oss << GetBusName() << ":" << GetNumber();
258 return oss.str();
261 ///////////////////////////////////////////////////////////////////////////////
262 // DeviceList
264 DeviceList::DeviceList()
265 : m_impl(new DeviceListImpl())
267 m_impl->m_list = NULL;
268 m_impl->m_listcnt = 0;
270 m_impl->m_listcnt = libusb_get_device_list(libusbctx, &m_impl->m_list);
271 if( m_impl->m_listcnt < 0 ) {
272 throw Error(m_impl->m_listcnt, _("Failed to get device list"));
275 for( int i = 0; i < m_impl->m_listcnt; ++i ) {
276 // Add the device to the list of devices
277 DeviceID devID(new DeviceIDImpl(m_impl->m_list[i]));
278 m_impl->m_devices.push_back(devID);
282 DeviceList::~DeviceList()
284 if( m_impl->m_list ) {
285 libusb_free_device_list(m_impl->m_list, 1);
289 std::vector<DeviceID> DeviceList::MatchDevices(int vendor, int product,
290 const char *busname, const char *devname)
292 std::vector<DeviceID> ret;
293 int err;
295 std::vector<DeviceID>::iterator iter = m_impl->m_devices.begin();
297 for( ; iter != m_impl->m_devices.end() ; ++iter ) {
298 struct libusb_device* dev = iter->m_impl->m_dev;
300 // only search on given bus
301 if( busname && atoi(busname) != libusb_get_bus_number(dev) )
302 continue;
304 // search for specific device
305 if( devname && atoi(devname) != libusb_get_device_address(dev) )
306 continue;
308 struct libusb_device_descriptor desc;
309 err = libusb_get_device_descriptor(dev, &desc);
310 if( err ) {
311 dout("Failed to get device descriptor: " << err);
312 continue;
315 // is there a match?
316 if( desc.idVendor == vendor &&
317 ( desc.idProduct == product ||
318 product == PRODUCT_ANY )) {
319 ret.push_back(*iter);
323 return ret;
326 ///////////////////////////////////////////////////////////////////////////////
327 // Device
329 Device::Device(const Usb::DeviceID& id, int timeout)
330 : m_id(id),
331 m_handle(new DeviceHandle()),
332 m_timeout(timeout)
334 dout("libusb_open(" << std::dec << id.m_impl.get() << ")");
335 if( !&(*id.m_impl) )
336 throw Error(_("invalid USB device ID"));
337 int err = libusb_open(id.m_impl->m_dev, &(m_handle->m_handle));
338 m_lasterror = err;
339 if( err )
340 throw Error(err, _("Failed to open USB device. Please check your system's USB device permissions."));
343 Device::~Device()
345 dout("libusb_close(" << std::dec << m_handle->m_handle << ")");
346 libusb_close(m_handle->m_handle);
349 bool Device::SetConfiguration(unsigned char cfg)
351 dout("libusb_set_configuration(" << std::dec << m_handle->m_handle << ", 0x" << std::hex << (unsigned int) cfg << ")");
352 int ret = libusb_set_configuration(m_handle->m_handle, cfg);
353 m_lasterror = ret;
354 return ret >= 0;
357 bool Device::ClearHalt(int ep)
359 dout("libusb_clear_halt(" << std::dec << m_handle->m_handle << ", 0x" << std::hex << ep << ")");
360 int ret = libusb_clear_halt(m_handle->m_handle, ep);
361 m_lasterror = ret;
362 return ret >= 0;
365 bool Device::Reset()
367 dout("libusb_reset_device(" << std::dec << m_handle->m_handle << ")");
368 int ret = libusb_reset_device(m_handle->m_handle);
369 m_lasterror = ret;
370 return ret == 0;
373 bool Device::BulkRead(int ep, Barry::Data &data, int timeout)
375 ddout("BulkRead to endpoint 0x" << std::hex << ep << ":\n" << data);
376 int ret;
377 do {
378 int transferred = 0;
379 data.QuickZap();
380 ret = libusb_bulk_transfer(m_handle->m_handle,
381 ep |= LIBUSB_ENDPOINT_IN,
382 data.GetBuffer(), data.GetBufSize(),
383 &transferred,
384 timeout == -1 ? m_timeout : timeout);
385 if( ret < 0 && ret != LIBUSB_ERROR_INTERRUPTED ) {
386 m_lasterror = ret;
387 // only notify of a timeout if no data was transferred,
388 // otherwise treat it as success.
389 if( ret == LIBUSB_ERROR_TIMEOUT ) {
390 if( transferred == 0 )
391 throw Timeout(ret, _("Timeout in BulkRead"));
392 else
393 dout("Read timed out with some data transferred... possible partial read");
395 else if( ret != LIBUSB_ERROR_TIMEOUT ) {
396 std::ostringstream oss;
397 oss << _("Error in libusb_bulk_tranfer(")
398 << m_handle->m_handle << ", "
399 << ep << ", buf, "
400 << data.GetBufSize() << ", "
401 << transferred << ", "
402 << (timeout == -1 ? m_timeout : timeout)
403 << ")";
404 throw Error(ret, oss.str());
407 if( transferred != 0 )
408 data.ReleaseBuffer(transferred);
410 } while( ret == LIBUSB_ERROR_INTERRUPTED );
412 return ret >= 0;
415 bool Device::BulkWrite(int ep, const Barry::Data &data, int timeout)
417 ddout("BulkWrite to endpoint 0x" << std::hex << ep << ":\n" << data);
418 int ret;
419 do {
420 int transferred;
421 ret = libusb_bulk_transfer(m_handle->m_handle,
422 ep | LIBUSB_ENDPOINT_OUT,
423 const_cast<unsigned char*>(data.GetData()),
424 data.GetSize(),
425 &transferred,
426 timeout == -1 ? m_timeout : timeout);
427 if( ret < 0 && ret != LIBUSB_ERROR_INTERRUPTED ) {
428 m_lasterror = ret;
429 // only notify of a timeout if no data was transferred,
430 // otherwise treat it as success.
431 if( ret == LIBUSB_ERROR_TIMEOUT && transferred == 0 )
432 throw Timeout(ret, _("Timeout in BulkWrite"));
433 else if( ret != LIBUSB_ERROR_TIMEOUT )
434 throw Error(ret, _("Error in BulkWrite"));
436 if( ret >= 0 &&
437 (unsigned int)transferred != data.GetSize() ) {
438 dout("Failed to write all data on ep: " << ep <<
439 " attempted to write: " << data.GetSize() <<
440 " but only wrote: " << transferred);
441 throw Error(_("Failed to perform a complete write"));
444 } while( ret == LIBUSB_ERROR_INTERRUPTED );
446 return ret >= 0;
449 bool Device::BulkWrite(int ep, const void *data, size_t size, int timeout)
451 #ifdef __DEBUG_MODE__
452 Barry::Data dump(data, size);
453 ddout("BulkWrite to endpoint 0x" << std::hex << ep << ":\n" << dump);
454 #endif
455 int ret;
456 do {
457 int transferred;
458 ret = libusb_bulk_transfer(m_handle->m_handle,
459 ep | LIBUSB_ENDPOINT_OUT,
460 (unsigned char*)const_cast<void*>(data),
461 size,
462 &transferred,
463 timeout == -1 ? m_timeout : timeout);
464 if( ret < 0 && ret != LIBUSB_ERROR_INTERRUPTED ) {
465 m_lasterror = ret;
466 // only notify of a timeout if no data was transferred,
467 // otherwise treat it as success.
468 if( ret == LIBUSB_ERROR_TIMEOUT && transferred == 0 )
469 throw Timeout(ret, _("Timeout in BulkWrite (2)"));
470 else if( ret != LIBUSB_ERROR_TIMEOUT )
471 throw Error(ret, _("Error in BulkWrite (2)"));
473 if( ret >= 0 && (unsigned int)transferred != size ) {
474 dout("Failed to write all data on ep: " << ep <<
475 " attempted to write: " << size <<
476 " but only wrote: " << transferred);
477 throw Error(_("Failed to perform a complete write"));
480 } while( ret == LIBUSB_ERROR_INTERRUPTED );
482 return ret >= 0;
485 bool Device::InterruptRead(int ep, Barry::Data &data, int timeout)
487 ddout("InterruptRead to endpoint 0x" << std::hex << ep << ":\n" << data);
488 int ret;
489 do {
490 int transferred = 0;
491 data.QuickZap();
492 ret = libusb_interrupt_transfer(m_handle->m_handle,
493 ep | LIBUSB_ENDPOINT_IN,
494 data.GetBuffer(), data.GetBufSize(),
495 &transferred,
496 timeout == -1 ? m_timeout : timeout);
497 if( ret < 0 && ret != LIBUSB_ERROR_INTERRUPTED ) {
498 m_lasterror = ret;
499 // only notify of a timeout if no data was transferred,
500 // otherwise treat it as success.
501 if( ret == LIBUSB_ERROR_TIMEOUT ) {
502 if( transferred == 0 )
503 throw Timeout(ret, _("Timeout in InterruptRead"));
504 else
505 dout("Read timed out with some data transferred... possible partial read");
507 else if( ret != LIBUSB_ERROR_TIMEOUT )
508 throw Error(ret, _("Error in InterruptRead"));
510 if( transferred != 0 )
511 data.ReleaseBuffer(transferred);
513 } while( ret == LIBUSB_ERROR_INTERRUPTED );
515 return ret >= 0;
519 bool Device::InterruptWrite(int ep, const Barry::Data &data, int timeout)
521 ddout("InterruptWrite to endpoint 0x" << std::hex << ep << ":\n" << data);
522 int ret;
523 do {
524 int transferred;
525 ret = libusb_interrupt_transfer(m_handle->m_handle,
526 ep | LIBUSB_ENDPOINT_OUT,
527 const_cast<unsigned char*>(data.GetData()),
528 data.GetSize(),
529 &transferred,
530 timeout == -1 ? m_timeout : timeout);
531 if( ret < 0 && ret != LIBUSB_ERROR_INTERRUPTED ) {
532 m_lasterror = ret;
533 // only notify of a timeout if no data was transferred,
534 // otherwise treat it as success.
535 if( ret == LIBUSB_ERROR_TIMEOUT && transferred == 0 )
536 throw Timeout(ret, _("Timeout in InterruptWrite"));
537 else if( ret != LIBUSB_ERROR_TIMEOUT )
538 throw Error(ret, _("Error in InterruptWrite"));
540 if( ret >= 0 &&
541 (unsigned int)transferred != data.GetSize() ) {
542 dout("Failed to write all data on ep: " << ep <<
543 " attempted to write: " << data.GetSize() <<
544 " but only wrote: " << transferred);
545 throw Error(_("Failed to perform a complete write"));
548 } while( ret == LIBUSB_ERROR_INTERRUPTED );
550 return ret >= 0;
554 // BulkDrain
556 /// Reads anything available on the given endpoint, with a low timeout,
557 /// in order to clear any pending reads.
559 void Device::BulkDrain(int ep, int timeout)
561 try {
562 Barry::Data data;
563 while( BulkRead(ep, data, timeout) )
566 catch( Usb::Error & ) {}
570 // GetConfiguration
572 /// Determines the currently selected USB configuration, returning it
573 /// in the cfg argument.
574 /// If unsuccessful, returns false.
576 bool Device::GetConfiguration(unsigned char &cfg)
578 int config = 0;
579 int result = libusb_get_configuration(m_handle->m_handle, &config);
580 if( result >= 0 )
581 cfg = config;
582 m_lasterror = result;
583 return result >= 0;
586 // Returns the current power level of the device, or 0 if unknown
587 int Device::GetPowerLevel()
589 struct libusb_config_descriptor* cfg = NULL;
590 int ret = 0;
591 int result = libusb_get_active_config_descriptor(m_id.m_impl->m_dev, &cfg);
592 m_lasterror = result;
593 if( result == 0 ) {
594 ret = cfg->MaxPower;
597 if( cfg )
598 libusb_free_config_descriptor(cfg);
600 return ret;
603 std::string Device::GetSimpleSerialNumber()
605 std::string sn;
607 struct libusb_device_descriptor desc;
608 int ret = libusb_get_device_descriptor(m_id.m_impl->m_dev, &desc);
609 m_lasterror = ret;
610 if( ret == 0 ) {
611 char buf[1024];
612 ret = libusb_get_string_descriptor_ascii(m_handle->m_handle,
613 desc.iSerialNumber, (unsigned char*)buf, sizeof(buf));
614 if( ret > 0 )
615 sn.assign(buf, ret);
616 else
617 m_lasterror = ret;
619 return sn;
622 bool Device::IsAttachKernelDriver(int iface)
624 int ret;
626 ret = libusb_kernel_driver_active(m_handle->m_handle, iface);
627 if (ret == 0) {
628 dout("interface (" << m_handle->m_handle << ", 0x" << std::hex << iface
629 << ") already claimed by a driver of unknown name.");
630 return true;
633 return false;
636 // Requests that the kernel driver is detached, returning false on failure
637 bool Device::DetachKernelDriver(int iface)
639 int result = libusb_detach_kernel_driver(m_handle->m_handle, iface);
640 m_lasterror = result;
641 return result >= 0;
644 // Sends a control message to the device, returning false on failure
645 bool Device::ControlMsg(int requesttype, int request, int value,
646 int index, char *bytes, int size, int timeout)
648 int result = libusb_control_transfer(m_handle->m_handle,
649 requesttype, request, value, index,
650 (unsigned char*)bytes, size, timeout);
651 m_lasterror = result;
652 return result >= 0;
655 int Device::FindInterface(int ifaceClass)
657 struct libusb_config_descriptor* cfg = NULL;
658 int ret = libusb_get_active_config_descriptor(m_id.m_impl->m_dev, &cfg);
659 if( ret == 0 ) {
660 for( int i = 0; cfg->interface && i < cfg->bNumInterfaces; ++i ) {
661 const struct libusb_interface& iface = cfg->interface[i];
662 for( int j = 0;
663 iface.altsetting && j < iface.num_altsetting;
664 ++j ) {
665 const struct libusb_interface_descriptor& id =
666 iface.altsetting[j];
667 if( id.bInterfaceClass == ifaceClass )
668 return id.bInterfaceNumber;
673 if( cfg )
674 libusb_free_config_descriptor(cfg);
676 return ret;
679 ///////////////////////////////////////////////////////////////////////////////
680 // Interface
682 Interface::Interface(Device &dev, int iface)
683 : m_dev(dev), m_iface(iface)
685 dout("libusb_claim_interface(" << dev.GetHandle()->m_handle << ", 0x" << std::hex << iface << ")");
686 int ret = libusb_claim_interface(dev.GetHandle()->m_handle, iface);
687 if( ret < 0 )
688 throw Error(ret, _("claim interface failed"));
691 Interface::~Interface()
693 dout("libusb_release_interface(" << m_dev.GetHandle()->m_handle << ", 0x" << std::hex << m_iface << ")");
694 libusb_release_interface(m_dev.GetHandle()->m_handle, m_iface);
699 // SetAltInterface
701 /// Sets the currently selected USB alternate setting of the current interface.
702 /// The iface parameter passed in should be a value specified
703 /// in the bAlternateSetting descriptor field.
704 /// If unsuccessful, returns false.
706 bool Interface::SetAltInterface(int altSetting)
708 int result = libusb_set_interface_alt_setting(
709 m_dev.GetHandle()->m_handle,
710 m_iface,
711 altSetting);
712 m_dev.SetLastError(result);
713 return result >= 0;
718 //////////////////////////////////////////////////////////////////
719 // DeviceDescriptor
721 DeviceDescriptor::DeviceDescriptor(DeviceID& devid)
722 : m_impl(new DeviceDescriptorImpl())
724 if( !devid.m_impl.get() ) {
725 dout("DeviceDescriptor: empty devid");
726 return;
728 m_impl->m_devid = devid;
729 int ret = libusb_get_device_descriptor(devid.m_impl->m_dev, &m_impl->m_desc);
730 if( ret != 0 ) {
731 dout("Failed to read device descriptor with err: " << ret);
732 return;
734 dout("device_desc loaded"
735 << "\nbLength: " << std::dec << (unsigned int) m_impl->m_desc.bLength
736 << "\nbDescriptorType: " << std::dec << (unsigned int) m_impl->m_desc.bDescriptorType
737 << "\nbcdUSB: 0x" << std::hex << (unsigned int) m_impl->m_desc.bcdUSB
738 << "\nbDeviceClass: " << std::dec << (unsigned int) m_impl->m_desc.bDeviceClass
739 << "\nbDeviceSubClass: " << std::dec << (unsigned int) m_impl->m_desc.bDeviceSubClass
740 << "\nbDeviceProtocol: " << std::dec << (unsigned int) m_impl->m_desc.bDeviceProtocol
741 << "\nbMaxPacketSize0: " << std::dec << (unsigned int) m_impl->m_desc.bMaxPacketSize0
742 << "\nidVendor: 0x" << std::hex << (unsigned int) m_impl->m_desc.idVendor
743 << "\nidProduct: 0x" << std::hex << (unsigned int) m_impl->m_desc.idProduct
744 << "\nbcdDevice: 0x" << std::hex << (unsigned int) m_impl->m_desc.bcdDevice
745 << "\niManufacturer: " << std::dec << (unsigned int) m_impl->m_desc.iManufacturer
746 << "\niProduct: " << std::dec << (unsigned int) m_impl->m_desc.iProduct
747 << "\niSerialNumber: " << std::dec << (unsigned int) m_impl->m_desc.iSerialNumber
748 << "\nbNumConfigurations: " << std::dec << (unsigned int) m_impl->m_desc.bNumConfigurations
749 << "\n"
752 // Create all the configs
753 for( int i = 0; i < m_impl->m_desc.bNumConfigurations; ++i ) {
754 std::auto_ptr<ConfigDescriptor> ptr(new ConfigDescriptor(*this, i));
755 (*this)[ptr->GetNumber()] = ptr.get();
756 ptr.release();
760 DeviceDescriptor::~DeviceDescriptor()
762 // Delete any pointers in the vector
763 std::for_each(begin(),
764 end(),
765 deleteMapPtr<int, ConfigDescriptor>);
768 ///////////////////////////////////////////////////////////////////
769 // ConfigDescriptor
771 ConfigDescriptor::ConfigDescriptor(DeviceDescriptor& dev, int cfgnumber)
772 : m_impl(new ConfigDescriptorImpl())
774 m_impl->m_desc = NULL;
775 int ret = libusb_get_config_descriptor(dev.m_impl->m_devid.m_impl->m_dev,
776 cfgnumber, &(m_impl->m_desc));
777 if( ret != 0 ) {
778 dout("Failed to read config descriptor with err: " << ret);
779 return;
782 dout(" config_desc #" << std::dec << cfgnumber << " loaded"
783 << "\nbLength: " << std::dec << (unsigned int) m_impl->m_desc->bLength
784 << "\nbDescriptorType: " << std::dec << (unsigned int) m_impl->m_desc->bDescriptorType
785 << "\nwTotalLength: " << std::dec << (unsigned int) m_impl->m_desc->wTotalLength
786 << "\nbNumInterfaces: " << std::dec << (unsigned int) m_impl->m_desc->bNumInterfaces
787 << "\nbConfigurationValue: " << std::dec << (unsigned int) m_impl->m_desc->bConfigurationValue
788 << "\niConfiguration: " << std::dec << (unsigned int) m_impl->m_desc->iConfiguration
789 << "\nbmAttributes: 0x" << std::hex << (unsigned int) m_impl->m_desc->bmAttributes
790 << "\nMaxPower: " << std::dec << (unsigned int) m_impl->m_desc->MaxPower
791 << "\n"
794 // just for debugging purposes, check for extra descriptors, and
795 // dump them to dout if they exist
796 if( m_impl->m_desc->extra ) {
797 dout("while parsing config descriptor, found a block of extra descriptors:");
798 Barry::Data data(m_impl->m_desc->extra, m_impl->m_desc->extra_length);
799 dout(data);
802 // Create all the interfaces
803 for( int i = 0; i < m_impl->m_desc->bNumInterfaces; ++i ) {
804 const struct libusb_interface* interface = &(m_impl->m_desc->interface[i]);
805 if( !interface->altsetting ) {
806 dout("ConfigDescriptor: empty altsetting");
807 // some devices are buggy and return a higher bNumInterfaces
808 // than the number of interfaces available... in this case
809 // we just skip and continue
810 continue;
812 for( int j = 0; j < interface->num_altsetting; ++j ) {
813 std::auto_ptr<InterfaceDescriptor> ptr(
814 new InterfaceDescriptor(*this, i, j));
815 (*this)[ptr->GetNumber()] = ptr.get();
816 ptr.release();
821 ConfigDescriptor::~ConfigDescriptor()
823 // Delete any pointers in the vector
824 std::for_each(begin(),
825 end(),
826 deleteMapPtr<int, InterfaceDescriptor>);
827 if( m_impl->m_desc ) {
828 libusb_free_config_descriptor(m_impl->m_desc);
829 m_impl->m_desc = NULL;
833 uint8_t ConfigDescriptor::GetNumber() const {
834 if( !m_impl->m_desc )
835 // Return an invalid config number
836 return 0;
837 return m_impl->m_desc->bConfigurationValue;
840 /////////////////////////////////////////////////////////////////////////
841 // InterfaceDescriptor
843 InterfaceDescriptor::InterfaceDescriptor(ConfigDescriptor& cfgdesc,
844 int iface, int altsetting)
845 : m_impl(new InterfaceDescriptorImpl())
847 m_impl->m_desc = NULL;
849 // Find the descriptor
850 m_impl->m_desc =
851 &(cfgdesc.m_impl->m_desc
852 ->interface[iface]
853 .altsetting[altsetting]);
854 dout(" interface_desc #" << std::dec << iface << " loaded"
855 << "\nbLength: " << std::dec << (unsigned) m_impl->m_desc->bLength
856 << "\nbDescriptorType: " << std::dec << (unsigned) m_impl->m_desc->bDescriptorType
857 << "\nbInterfaceNumber: " << std::dec << (unsigned) m_impl->m_desc->bInterfaceNumber
858 << "\nbAlternateSetting: " << std::dec << (unsigned) m_impl->m_desc->bAlternateSetting
859 << "\nbNumEndpoints: " << std::dec << (unsigned) m_impl->m_desc->bNumEndpoints
860 << "\nbInterfaceClass: " << std::dec << (unsigned) m_impl->m_desc->bInterfaceClass
861 << "\nbInterfaceSubClass: " << std::dec << (unsigned) m_impl->m_desc->bInterfaceSubClass
862 << "\nbInterfaceProtocol: " << std::dec << (unsigned) m_impl->m_desc->bInterfaceProtocol
863 << "\niInterface: " << std::dec << (unsigned) m_impl->m_desc->iInterface
864 << "\n"
867 if( !m_impl->m_desc->endpoint ) {
868 dout("InterfaceDescriptor: empty interface pointer");
869 return;
872 // Create all the endpoints
873 for( int i = 0; i < m_impl->m_desc->bNumEndpoints; ++i ) {
874 std::auto_ptr<EndpointDescriptor> ptr (
875 new EndpointDescriptor(*this, i));
876 push_back(ptr.get());
877 ptr.release();
880 // just for debugging purposes, check for extra descriptors, and
881 // dump them to dout if they exist
882 if( m_impl->m_desc->extra ) {
883 dout("while parsing interface descriptor, found a block of extra descriptors:");
884 Barry::Data data(m_impl->m_desc->extra, m_impl->m_desc->extra_length);
885 dout(data);
889 InterfaceDescriptor::~InterfaceDescriptor()
891 // Delete any pointers in the vector
892 std::for_each(begin(),
893 end(),
894 deletePtr<EndpointDescriptor>);
897 uint8_t InterfaceDescriptor::GetClass() const
899 return m_impl->m_desc->bInterfaceClass;
902 uint8_t InterfaceDescriptor::GetNumber() const
904 if( !m_impl->m_desc )
905 // Return an invalid interface number
906 return 0;
907 return m_impl->m_desc->bInterfaceNumber;
910 uint8_t InterfaceDescriptor::GetAltSetting() const
912 if( !m_impl->m_desc )
913 // Return an invalid setting number
914 return 0;
915 return m_impl->m_desc->bAlternateSetting;
918 /////////////////////////////////////////////////////////////////////////////////
919 // EndpointDescriptor
921 EndpointDescriptor::EndpointDescriptor(InterfaceDescriptor& intdesc, int endpoint)
922 : m_impl(new EndpointDescriptorImpl()),
923 m_read(false),
924 m_addr(0),
925 m_type(InvalidType)
927 // Copy the descriptor
928 m_impl->m_desc = &(intdesc.m_impl->m_desc->endpoint[endpoint]);
930 dout(" endpoint_desc #" << std::dec << endpoint << " loaded"
931 << "\nbLength: " << std::dec << (unsigned ) m_impl->m_desc->bLength
932 << "\nbDescriptorType: " << std::dec << (unsigned ) m_impl->m_desc->bDescriptorType
933 << "\nbEndpointAddress: 0x" << std::hex << (unsigned ) m_impl->m_desc->bEndpointAddress
934 << "\nbmAttributes: 0x" << std::hex << (unsigned ) m_impl->m_desc->bmAttributes
935 << "\nwMaxPacketSize: " << std::dec << (unsigned ) m_impl->m_desc->wMaxPacketSize
936 << "\nbInterval: " << std::dec << (unsigned ) m_impl->m_desc->bInterval
937 << "\nbRefresh: " << std::dec << (unsigned ) m_impl->m_desc->bRefresh
938 << "\nbSynchAddress: " << std::dec << (unsigned ) m_impl->m_desc->bSynchAddress
939 << "\n"
941 // Set up variables
942 m_read = ((m_impl->m_desc->bEndpointAddress & LIBUSB_ENDPOINT_DIR_MASK) ==
943 LIBUSB_ENDPOINT_IN);
944 m_addr = (m_impl->m_desc->bEndpointAddress & LIBUSB_ENDPOINT_ADDRESS_MASK);
945 int type = (m_impl->m_desc->bmAttributes & LIBUSB_TRANSFER_TYPE_MASK);
946 m_type = static_cast<Usb::EndpointDescriptor::EpType>(type);
948 // just for debugging purposes, check for extra descriptors, and
949 // dump them to dout if they exist
950 if( m_impl->m_desc->extra ) {
951 dout("while parsing endpoint descriptor, found a block of extra descriptors:");
952 Barry::Data data(m_impl->m_desc->extra, m_impl->m_desc->extra_length);
953 dout(data);
957 EndpointDescriptor::~EndpointDescriptor()
961 } // namespace Usb