2 /// \file usbwrap_libusb_1_0.cc
3 /// USB API wrapper for libusb version 1.0
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.
25 #include "usbwrap_libusb_1_0.h"
35 #ifndef __DEBUG_MODE__
36 #define __DEBUG_MODE__
42 // helper functions to make deleting pointers in maps and vectors easier
43 template<typename T
> static void deletePtr(T
* ptr
)
48 template<typename K
, typename T
> static void deleteMapPtr(std::pair
<K
,T
*> ptr
)
53 // lookup table translating LIBUSB errors to standard Linux errors
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 ///////////////////////////////////////////////////////////////////////////////
86 std::string
LibraryInterface::GetLastErrorString(int libusb_errcode
)
88 switch( libusb_errcode
)
94 case LIBUSB_ERROR_INVALID_PARAM
:
95 return _("Invalid parameter");
96 case LIBUSB_ERROR_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
:
104 case LIBUSB_ERROR_TIMEOUT
:
106 case LIBUSB_ERROR_OVERFLOW
:
107 return _("Overflow");
108 case LIBUSB_ERROR_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
:
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
);
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)
153 int ret
= libusb_init(&libusbctx
);
155 // store errno for user if possible
165 void LibraryInterface::Uninit()
167 libusb_exit(libusbctx
);
171 void LibraryInterface::SetDataDump(bool data_dump_mode
)
177 // Failed to init, can't do much but return
178 dout("SetDataDump: Failed to initialise libusb");
182 libusb_set_debug(libusbctx
, 3);
184 libusb_set_debug(libusbctx
, 0);
187 ///////////////////////////////////////////////////////////////////////////////
190 DeviceIDImpl::DeviceIDImpl(libusb_device
*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();
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 ///////////////////////////////////////////////////////////////////////////////
215 DeviceID::DeviceID(DeviceIDImpl
* 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
);
246 ret
= desc
.idProduct
;
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();
261 ///////////////////////////////////////////////////////////////////////////////
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
;
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
) )
304 // search for specific device
305 if( devname
&& atoi(devname
) != libusb_get_device_address(dev
) )
308 struct libusb_device_descriptor desc
;
309 err
= libusb_get_device_descriptor(dev
, &desc
);
311 dout("Failed to get device descriptor: " << err
);
316 if( desc
.idVendor
== vendor
&&
317 ( desc
.idProduct
== product
||
318 product
== PRODUCT_ANY
)) {
319 ret
.push_back(*iter
);
326 ///////////////////////////////////////////////////////////////////////////////
329 Device::Device(const Usb::DeviceID
& id
, int timeout
)
331 m_handle(new DeviceHandle()),
334 dout("libusb_open(" << std::dec
<< id
.m_impl
.get() << ")");
336 throw Error(_("invalid USB device ID"));
337 int err
= libusb_open(id
.m_impl
->m_dev
, &(m_handle
->m_handle
));
340 throw Error(err
, _("Failed to open USB device. Please check your system's USB device permissions."));
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
);
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
);
367 dout("libusb_reset_device(" << std::dec
<< m_handle
->m_handle
<< ")");
368 int ret
= libusb_reset_device(m_handle
->m_handle
);
373 bool Device::BulkRead(int ep
, Barry::Data
&data
, int timeout
)
375 ddout("BulkRead to endpoint 0x" << std::hex
<< ep
<< ":\n" << data
);
380 ret
= libusb_bulk_transfer(m_handle
->m_handle
,
381 ep
|= LIBUSB_ENDPOINT_IN
,
382 data
.GetBuffer(), data
.GetBufSize(),
384 timeout
== -1 ? m_timeout
: timeout
);
385 if( ret
< 0 && ret
!= LIBUSB_ERROR_INTERRUPTED
) {
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"));
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
<< ", "
400 << data
.GetBufSize() << ", "
401 << transferred
<< ", "
402 << (timeout
== -1 ? m_timeout
: timeout
)
404 throw Error(ret
, oss
.str());
407 if( transferred
!= 0 )
408 data
.ReleaseBuffer(transferred
);
410 } while( ret
== LIBUSB_ERROR_INTERRUPTED
);
415 bool Device::BulkWrite(int ep
, const Barry::Data
&data
, int timeout
)
417 ddout("BulkWrite to endpoint 0x" << std::hex
<< ep
<< ":\n" << data
);
421 ret
= libusb_bulk_transfer(m_handle
->m_handle
,
422 ep
| LIBUSB_ENDPOINT_OUT
,
423 const_cast<unsigned char*>(data
.GetData()),
426 timeout
== -1 ? m_timeout
: timeout
);
427 if( ret
< 0 && ret
!= LIBUSB_ERROR_INTERRUPTED
) {
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"));
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
);
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
);
458 ret
= libusb_bulk_transfer(m_handle
->m_handle
,
459 ep
| LIBUSB_ENDPOINT_OUT
,
460 (unsigned char*)const_cast<void*>(data
),
463 timeout
== -1 ? m_timeout
: timeout
);
464 if( ret
< 0 && ret
!= LIBUSB_ERROR_INTERRUPTED
) {
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
);
485 bool Device::InterruptRead(int ep
, Barry::Data
&data
, int timeout
)
487 ddout("InterruptRead to endpoint 0x" << std::hex
<< ep
<< ":\n" << data
);
492 ret
= libusb_interrupt_transfer(m_handle
->m_handle
,
493 ep
| LIBUSB_ENDPOINT_IN
,
494 data
.GetBuffer(), data
.GetBufSize(),
496 timeout
== -1 ? m_timeout
: timeout
);
497 if( ret
< 0 && ret
!= LIBUSB_ERROR_INTERRUPTED
) {
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"));
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
);
519 bool Device::InterruptWrite(int ep
, const Barry::Data
&data
, int timeout
)
521 ddout("InterruptWrite to endpoint 0x" << std::hex
<< ep
<< ":\n" << data
);
525 ret
= libusb_interrupt_transfer(m_handle
->m_handle
,
526 ep
| LIBUSB_ENDPOINT_OUT
,
527 const_cast<unsigned char*>(data
.GetData()),
530 timeout
== -1 ? m_timeout
: timeout
);
531 if( ret
< 0 && ret
!= LIBUSB_ERROR_INTERRUPTED
) {
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"));
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
);
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
)
563 while( BulkRead(ep
, data
, timeout
) )
566 catch( Usb::Error
& ) {}
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
)
579 int result
= libusb_get_configuration(m_handle
->m_handle
, &config
);
582 m_lasterror
= result
;
586 // Returns the current power level of the device, or 0 if unknown
587 int Device::GetPowerLevel()
589 struct libusb_config_descriptor
* cfg
= NULL
;
591 int result
= libusb_get_active_config_descriptor(m_id
.m_impl
->m_dev
, &cfg
);
592 m_lasterror
= result
;
598 libusb_free_config_descriptor(cfg
);
603 std::string
Device::GetSimpleSerialNumber()
607 struct libusb_device_descriptor desc
;
608 int ret
= libusb_get_device_descriptor(m_id
.m_impl
->m_dev
, &desc
);
612 ret
= libusb_get_string_descriptor_ascii(m_handle
->m_handle
,
613 desc
.iSerialNumber
, (unsigned char*)buf
, sizeof(buf
));
622 bool Device::IsAttachKernelDriver(int iface
)
626 ret
= libusb_kernel_driver_active(m_handle
->m_handle
, iface
);
628 dout("interface (" << m_handle
->m_handle
<< ", 0x" << std::hex
<< iface
629 << ") already claimed by a driver of unknown name.");
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
;
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
;
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
);
660 for( int i
= 0; cfg
->interface
&& i
< cfg
->bNumInterfaces
; ++i
) {
661 const struct libusb_interface
& iface
= cfg
->interface
[i
];
663 iface
.altsetting
&& j
< iface
.num_altsetting
;
665 const struct libusb_interface_descriptor
& id
=
667 if( id
.bInterfaceClass
== ifaceClass
)
668 return id
.bInterfaceNumber
;
674 libusb_free_config_descriptor(cfg
);
679 ///////////////////////////////////////////////////////////////////////////////
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
);
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
);
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
,
712 m_dev
.SetLastError(result
);
718 //////////////////////////////////////////////////////////////////
721 DeviceDescriptor::DeviceDescriptor(DeviceID
& devid
)
722 : m_impl(new DeviceDescriptorImpl())
724 if( !devid
.m_impl
.get() ) {
725 dout("DeviceDescriptor: empty devid");
728 m_impl
->m_devid
= devid
;
729 int ret
= libusb_get_device_descriptor(devid
.m_impl
->m_dev
, &m_impl
->m_desc
);
731 dout("Failed to read device descriptor with err: " << ret
);
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
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();
760 DeviceDescriptor::~DeviceDescriptor()
762 // Delete any pointers in the vector
763 std::for_each(begin(),
765 deleteMapPtr
<int, ConfigDescriptor
>);
768 ///////////////////////////////////////////////////////////////////
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
));
778 dout("Failed to read config descriptor with err: " << ret
);
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
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
);
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
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();
821 ConfigDescriptor::~ConfigDescriptor()
823 // Delete any pointers in the vector
824 std::for_each(begin(),
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
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
851 &(cfgdesc
.m_impl
->m_desc
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
867 if( !m_impl
->m_desc
->endpoint
) {
868 dout("InterfaceDescriptor: empty interface pointer");
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());
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
);
889 InterfaceDescriptor::~InterfaceDescriptor()
891 // Delete any pointers in the vector
892 std::for_each(begin(),
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
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
915 return m_impl
->m_desc
->bAlternateSetting
;
918 /////////////////////////////////////////////////////////////////////////////////
919 // EndpointDescriptor
921 EndpointDescriptor::EndpointDescriptor(InterfaceDescriptor
& intdesc
, int endpoint
)
922 : m_impl(new EndpointDescriptorImpl()),
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
942 m_read
= ((m_impl
->m_desc
->bEndpointAddress
& LIBUSB_ENDPOINT_DIR_MASK
) ==
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
);
957 EndpointDescriptor::~EndpointDescriptor()