2 /// \file usbwrap_libusb_1_0.cc
3 /// USB API wrapper for libusb version 1.0
7 Copyright (C) 2005-2012, 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
:
100 case LIBUSB_ERROR_NOT_FOUND
:
102 case LIBUSB_ERROR_BUSY
:
104 case LIBUSB_ERROR_TIMEOUT
:
106 case LIBUSB_ERROR_OVERFLOW
:
108 case LIBUSB_ERROR_PIPE
:
110 case LIBUSB_ERROR_INTERRUPTED
:
111 return "Interrupted";
112 case LIBUSB_ERROR_NO_MEM
:
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
)
333 dout("libusb_open(" << std::dec
<< id
.m_impl
.get() << ")");
335 throw Error("invalid USB device ID");
336 m_handle
.reset(new DeviceHandle());
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 bool Device::IsAttachKernelDriver(int iface
)
607 ret
= libusb_kernel_driver_active(m_handle
->m_handle
, iface
);
609 dout("interface (" << m_handle
->m_handle
<< ", 0x" << std::hex
<< iface
610 << ") already claimed by a driver of unknown name.");
617 // Requests that the kernel driver is detached, returning false on failure
618 bool Device::DetachKernelDriver(int iface
)
620 int result
= libusb_detach_kernel_driver(m_handle
->m_handle
, iface
);
621 m_lasterror
= result
;
625 // Sends a control message to the device, returning false on failure
626 bool Device::ControlMsg(int requesttype
, int request
, int value
,
627 int index
, char *bytes
, int size
, int timeout
)
629 int result
= libusb_control_transfer(m_handle
->m_handle
,
630 requesttype
, request
, value
, index
,
631 (unsigned char*)bytes
, size
, timeout
);
632 m_lasterror
= result
;
636 int Device::FindInterface(int ifaceClass
)
638 struct libusb_config_descriptor
* cfg
= NULL
;
639 int ret
= libusb_get_active_config_descriptor(m_id
.m_impl
->m_dev
, &cfg
);
641 for( int i
= 0; cfg
->interface
&& i
< cfg
->bNumInterfaces
; ++i
) {
642 const struct libusb_interface
& iface
= cfg
->interface
[i
];
644 iface
.altsetting
&& j
< iface
.num_altsetting
;
646 const struct libusb_interface_descriptor
& id
=
648 if( id
.bInterfaceClass
== ifaceClass
)
649 return id
.bInterfaceNumber
;
655 libusb_free_config_descriptor(cfg
);
660 ///////////////////////////////////////////////////////////////////////////////
663 Interface::Interface(Device
&dev
, int iface
)
664 : m_dev(dev
), m_iface(iface
)
666 dout("libusb_claim_interface(" << dev
.GetHandle()->m_handle
<< ", 0x" << std::hex
<< iface
<< ")");
667 int ret
= libusb_claim_interface(dev
.GetHandle()->m_handle
, iface
);
669 throw Error(ret
, "claim interface failed");
672 Interface::~Interface()
674 dout("libusb_release_interface(" << m_dev
.GetHandle()->m_handle
<< ", 0x" << std::hex
<< m_iface
<< ")");
675 libusb_release_interface(m_dev
.GetHandle()->m_handle
, m_iface
);
682 /// Sets the currently selected USB alternate setting of the current interface.
683 /// The iface parameter passed in should be a value specified
684 /// in the bAlternateSetting descriptor field.
685 /// If unsuccessful, returns false.
687 bool Interface::SetAltInterface(int altSetting
)
689 int result
= libusb_set_interface_alt_setting(
690 m_dev
.GetHandle()->m_handle
,
693 m_dev
.SetLastError(result
);
699 //////////////////////////////////////////////////////////////////
702 DeviceDescriptor::DeviceDescriptor(DeviceID
& devid
)
703 : m_impl(new DeviceDescriptorImpl())
705 if( !devid
.m_impl
.get() ) {
706 dout("DeviceDescriptor: empty devid");
709 m_impl
->m_devid
= devid
;
710 int ret
= libusb_get_device_descriptor(devid
.m_impl
->m_dev
, &m_impl
->m_desc
);
712 dout("Failed to read device descriptor with err: " << ret
);
715 dout("device_desc loaded"
716 << "\nbLength: " << std::dec
<< (unsigned int) m_impl
->m_desc
.bLength
717 << "\nbDescriptorType: " << std::dec
<< (unsigned int) m_impl
->m_desc
.bDescriptorType
718 << "\nbcdUSB: 0x" << std::hex
<< (unsigned int) m_impl
->m_desc
.bcdUSB
719 << "\nbDeviceClass: " << std::dec
<< (unsigned int) m_impl
->m_desc
.bDeviceClass
720 << "\nbDeviceSubClass: " << std::dec
<< (unsigned int) m_impl
->m_desc
.bDeviceSubClass
721 << "\nbDeviceProtocol: " << std::dec
<< (unsigned int) m_impl
->m_desc
.bDeviceProtocol
722 << "\nbMaxPacketSize0: " << std::dec
<< (unsigned int) m_impl
->m_desc
.bMaxPacketSize0
723 << "\nidVendor: 0x" << std::hex
<< (unsigned int) m_impl
->m_desc
.idVendor
724 << "\nidProduct: 0x" << std::hex
<< (unsigned int) m_impl
->m_desc
.idProduct
725 << "\nbcdDevice: 0x" << std::hex
<< (unsigned int) m_impl
->m_desc
.bcdDevice
726 << "\niManufacturer: " << std::dec
<< (unsigned int) m_impl
->m_desc
.iManufacturer
727 << "\niProduct: " << std::dec
<< (unsigned int) m_impl
->m_desc
.iProduct
728 << "\niSerialNumber: " << std::dec
<< (unsigned int) m_impl
->m_desc
.iSerialNumber
729 << "\nbNumConfigurations: " << std::dec
<< (unsigned int) m_impl
->m_desc
.bNumConfigurations
733 // Create all the configs
734 for( int i
= 0; i
< m_impl
->m_desc
.bNumConfigurations
; ++i
) {
735 std::auto_ptr
<ConfigDescriptor
> ptr(new ConfigDescriptor(*this, i
));
736 (*this)[ptr
->GetNumber()] = ptr
.get();
741 DeviceDescriptor::~DeviceDescriptor()
743 // Delete any pointers in the vector
744 std::for_each(begin(),
746 deleteMapPtr
<int, ConfigDescriptor
>);
749 ///////////////////////////////////////////////////////////////////
752 ConfigDescriptor::ConfigDescriptor(DeviceDescriptor
& dev
, int cfgnumber
)
753 : m_impl(new ConfigDescriptorImpl())
755 m_impl
->m_desc
= NULL
;
756 int ret
= libusb_get_config_descriptor(dev
.m_impl
->m_devid
.m_impl
->m_dev
,
757 cfgnumber
, &(m_impl
->m_desc
));
759 dout("Failed to read config descriptor with err: " << ret
);
763 dout(" config_desc #" << std::dec
<< cfgnumber
<< " loaded"
764 << "\nbLength: " << std::dec
<< (unsigned int) m_impl
->m_desc
->bLength
765 << "\nbDescriptorType: " << std::dec
<< (unsigned int) m_impl
->m_desc
->bDescriptorType
766 << "\nwTotalLength: " << std::dec
<< (unsigned int) m_impl
->m_desc
->wTotalLength
767 << "\nbNumInterfaces: " << std::dec
<< (unsigned int) m_impl
->m_desc
->bNumInterfaces
768 << "\nbConfigurationValue: " << std::dec
<< (unsigned int) m_impl
->m_desc
->bConfigurationValue
769 << "\niConfiguration: " << std::dec
<< (unsigned int) m_impl
->m_desc
->iConfiguration
770 << "\nbmAttributes: 0x" << std::hex
<< (unsigned int) m_impl
->m_desc
->bmAttributes
771 << "\nMaxPower: " << std::dec
<< (unsigned int) m_impl
->m_desc
->MaxPower
775 // just for debugging purposes, check for extra descriptors, and
776 // dump them to dout if they exist
777 if( m_impl
->m_desc
->extra
) {
778 dout("while parsing config descriptor, found a block of extra descriptors:");
779 Barry::Data
data(m_impl
->m_desc
->extra
, m_impl
->m_desc
->extra_length
);
783 // Create all the interfaces
784 for( int i
= 0; i
< m_impl
->m_desc
->bNumInterfaces
; ++i
) {
785 const struct libusb_interface
* interface
= &(m_impl
->m_desc
->interface
[i
]);
786 if( !interface
->altsetting
) {
787 dout("ConfigDescriptor: empty altsetting");
788 // some devices are buggy and return a higher bNumInterfaces
789 // than the number of interfaces available... in this case
790 // we just skip and continue
793 for( int j
= 0; j
< interface
->num_altsetting
; ++j
) {
794 std::auto_ptr
<InterfaceDescriptor
> ptr(
795 new InterfaceDescriptor(*this, i
, j
));
796 (*this)[ptr
->GetNumber()] = ptr
.get();
802 ConfigDescriptor::~ConfigDescriptor()
804 // Delete any pointers in the vector
805 std::for_each(begin(),
807 deleteMapPtr
<int, InterfaceDescriptor
>);
808 if( m_impl
->m_desc
) {
809 libusb_free_config_descriptor(m_impl
->m_desc
);
810 m_impl
->m_desc
= NULL
;
814 uint8_t ConfigDescriptor::GetNumber() const {
815 if( !m_impl
->m_desc
)
816 // Return an invalid config number
818 return m_impl
->m_desc
->bConfigurationValue
;
821 /////////////////////////////////////////////////////////////////////////
822 // InterfaceDescriptor
824 InterfaceDescriptor::InterfaceDescriptor(ConfigDescriptor
& cfgdesc
,
825 int interface
, int altsetting
)
826 : m_impl(new InterfaceDescriptorImpl())
828 m_impl
->m_desc
= NULL
;
830 // Find the descriptor
832 &(cfgdesc
.m_impl
->m_desc
833 ->interface
[interface
]
834 .altsetting
[altsetting
]);
835 dout(" interface_desc #" << std::dec
<< interface
<< " loaded"
836 << "\nbLength: " << std::dec
<< (unsigned) m_impl
->m_desc
->bLength
837 << "\nbDescriptorType: " << std::dec
<< (unsigned) m_impl
->m_desc
->bDescriptorType
838 << "\nbInterfaceNumber: " << std::dec
<< (unsigned) m_impl
->m_desc
->bInterfaceNumber
839 << "\nbAlternateSetting: " << std::dec
<< (unsigned) m_impl
->m_desc
->bAlternateSetting
840 << "\nbNumEndpoints: " << std::dec
<< (unsigned) m_impl
->m_desc
->bNumEndpoints
841 << "\nbInterfaceClass: " << std::dec
<< (unsigned) m_impl
->m_desc
->bInterfaceClass
842 << "\nbInterfaceSubClass: " << std::dec
<< (unsigned) m_impl
->m_desc
->bInterfaceSubClass
843 << "\nbInterfaceProtocol: " << std::dec
<< (unsigned) m_impl
->m_desc
->bInterfaceProtocol
844 << "\niInterface: " << std::dec
<< (unsigned) m_impl
->m_desc
->iInterface
848 if( !m_impl
->m_desc
->endpoint
) {
849 dout("InterfaceDescriptor: empty interface pointer");
853 // Create all the endpoints
854 for( int i
= 0; i
< m_impl
->m_desc
->bNumEndpoints
; ++i
) {
855 std::auto_ptr
<EndpointDescriptor
> ptr (
856 new EndpointDescriptor(*this, i
));
857 push_back(ptr
.get());
861 // just for debugging purposes, check for extra descriptors, and
862 // dump them to dout if they exist
863 if( m_impl
->m_desc
->extra
) {
864 dout("while parsing interface descriptor, found a block of extra descriptors:");
865 Barry::Data
data(m_impl
->m_desc
->extra
, m_impl
->m_desc
->extra_length
);
870 InterfaceDescriptor::~InterfaceDescriptor()
872 // Delete any pointers in the vector
873 std::for_each(begin(),
875 deletePtr
<EndpointDescriptor
>);
878 uint8_t InterfaceDescriptor::GetClass() const
880 return m_impl
->m_desc
->bInterfaceClass
;
883 uint8_t InterfaceDescriptor::GetNumber() const
885 if( !m_impl
->m_desc
)
886 // Return an invalid interface number
888 return m_impl
->m_desc
->bInterfaceNumber
;
891 uint8_t InterfaceDescriptor::GetAltSetting() const
893 if( !m_impl
->m_desc
)
894 // Return an invalid setting number
896 return m_impl
->m_desc
->bAlternateSetting
;
899 /////////////////////////////////////////////////////////////////////////////////
900 // EndpointDescriptor
902 EndpointDescriptor::EndpointDescriptor(InterfaceDescriptor
& intdesc
, int endpoint
)
903 : m_impl(new EndpointDescriptorImpl()),
908 // Copy the descriptor
909 m_impl
->m_desc
= &(intdesc
.m_impl
->m_desc
->endpoint
[endpoint
]);
911 dout(" endpoint_desc #" << std::dec
<< endpoint
<< " loaded"
912 << "\nbLength: " << std::dec
<< (unsigned ) m_impl
->m_desc
->bLength
913 << "\nbDescriptorType: " << std::dec
<< (unsigned ) m_impl
->m_desc
->bDescriptorType
914 << "\nbEndpointAddress: 0x" << std::hex
<< (unsigned ) m_impl
->m_desc
->bEndpointAddress
915 << "\nbmAttributes: 0x" << std::hex
<< (unsigned ) m_impl
->m_desc
->bmAttributes
916 << "\nwMaxPacketSize: " << std::dec
<< (unsigned ) m_impl
->m_desc
->wMaxPacketSize
917 << "\nbInterval: " << std::dec
<< (unsigned ) m_impl
->m_desc
->bInterval
918 << "\nbRefresh: " << std::dec
<< (unsigned ) m_impl
->m_desc
->bRefresh
919 << "\nbSynchAddress: " << std::dec
<< (unsigned ) m_impl
->m_desc
->bSynchAddress
923 m_read
= ((m_impl
->m_desc
->bEndpointAddress
& LIBUSB_ENDPOINT_DIR_MASK
) ==
925 m_addr
= (m_impl
->m_desc
->bEndpointAddress
& LIBUSB_ENDPOINT_ADDRESS_MASK
);
926 int type
= (m_impl
->m_desc
->bmAttributes
& LIBUSB_TRANSFER_TYPE_MASK
);
927 m_type
= static_cast<Usb::EndpointDescriptor::EpType
>(type
);
929 // just for debugging purposes, check for extra descriptors, and
930 // dump them to dout if they exist
931 if( m_impl
->m_desc
->extra
) {
932 dout("while parsing endpoint descriptor, found a block of extra descriptors:");
933 Barry::Data
data(m_impl
->m_desc
->extra
, m_impl
->m_desc
->extra_length
);
938 EndpointDescriptor::~EndpointDescriptor()