2 /// \file usbwrap_libusb_1_0.cc
3 /// USB API wrapper for libusb version 1.0
7 Copyright (C) 2005-2011, 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 ///////////////////////////////////////////////////////////////////////////////
253 DeviceList::DeviceList()
254 : m_impl(new DeviceListImpl())
256 m_impl
->m_list
= NULL
;
257 m_impl
->m_listcnt
= 0;
259 m_impl
->m_listcnt
= libusb_get_device_list(libusbctx
, &m_impl
->m_list
);
260 if( m_impl
->m_listcnt
< 0 ) {
261 throw Error("Failed to get device list");
264 for( int i
= 0; i
< m_impl
->m_listcnt
; ++i
) {
265 // Add the device to the list of devices
266 DeviceID
devID(new DeviceIDImpl(m_impl
->m_list
[i
]));
267 m_impl
->m_devices
.push_back(devID
);
271 DeviceList::~DeviceList()
273 if( m_impl
->m_list
) {
274 libusb_free_device_list(m_impl
->m_list
, 1);
278 std::vector
<DeviceID
> DeviceList::MatchDevices(int vendor
, int product
,
279 const char *busname
, const char *devname
)
281 std::vector
<DeviceID
> ret
;
284 std::vector
<DeviceID
>::iterator iter
= m_impl
->m_devices
.begin();
286 for( ; iter
!= m_impl
->m_devices
.end() ; ++iter
) {
287 struct libusb_device
* dev
= iter
->m_impl
->m_dev
;
289 // only search on given bus
290 if( busname
&& atoi(busname
) != libusb_get_bus_number(dev
) )
293 // search for specific device
294 if( devname
&& atoi(devname
) != libusb_get_device_address(dev
) )
297 struct libusb_device_descriptor desc
;
298 err
= libusb_get_device_descriptor(dev
, &desc
);
300 dout("Failed to get device descriptor: " << err
);
305 if( desc
.idVendor
== vendor
&&
306 ( desc
.idProduct
== product
||
307 product
== PRODUCT_ANY
)) {
308 ret
.push_back(*iter
);
315 ///////////////////////////////////////////////////////////////////////////////
318 Device::Device(const Usb::DeviceID
& id
, int timeout
)
322 dout("libusb_open(" << std::dec
<< id
.m_impl
.get() << ")");
324 throw Error("invalid USB device ID");
325 m_handle
.reset(new DeviceHandle());
326 int err
= libusb_open(id
.m_impl
->m_dev
, &(m_handle
->m_handle
));
329 throw Error("open failed");
334 dout("libusb_close(" << std::dec
<< m_handle
->m_handle
<< ")");
335 libusb_close(m_handle
->m_handle
);
338 bool Device::SetConfiguration(unsigned char cfg
)
340 dout("libusb_set_configuration(" << std::dec
<< m_handle
->m_handle
<< ", 0x" << std::hex
<< (unsigned int) cfg
<< ")");
341 int ret
= libusb_set_configuration(m_handle
->m_handle
, cfg
);
346 bool Device::ClearHalt(int ep
)
348 dout("libusb_clear_halt(" << std::dec
<< m_handle
->m_handle
<< ", 0x" << std::hex
<< ep
<< ")");
349 int ret
= libusb_clear_halt(m_handle
->m_handle
, ep
);
356 dout("libusb_reset_device(" << std::dec
<< m_handle
->m_handle
<< ")");
357 int ret
= libusb_reset_device(m_handle
->m_handle
);
362 bool Device::BulkRead(int ep
, Barry::Data
&data
, int timeout
)
364 ddout("BulkRead to endpoint 0x" << std::hex
<< ep
<< ":\n" << data
);
369 ret
= libusb_bulk_transfer(m_handle
->m_handle
,
370 ep
|= LIBUSB_ENDPOINT_IN
,
371 data
.GetBuffer(), data
.GetBufSize(),
373 timeout
== -1 ? m_timeout
: timeout
);
374 if( ret
< 0 && ret
!= LIBUSB_ERROR_INTERRUPTED
) {
376 // only notify of a timeout if no data was transferred,
377 // otherwise treat it as success.
378 if( ret
== LIBUSB_ERROR_TIMEOUT
) {
379 if( transferred
== 0 )
380 throw Timeout(ret
, "Timeout in BulkRead");
382 dout("Read timed out with some data transferred... possible partial read");
384 else if( ret
!= LIBUSB_ERROR_TIMEOUT
) {
385 std::ostringstream oss
;
386 oss
<< "Error in libusb_bulk_tranfer("
387 << m_handle
->m_handle
<< ", "
389 << data
.GetBufSize() << ", "
390 << transferred
<< ", "
391 << (timeout
== -1 ? m_timeout
: timeout
)
393 throw Error(ret
, oss
.str());
396 if( transferred
!= 0 )
397 data
.ReleaseBuffer(transferred
);
399 } while( ret
== -LIBUSB_ERROR_INTERRUPTED
);
404 bool Device::BulkWrite(int ep
, const Barry::Data
&data
, int timeout
)
406 ddout("BulkWrite to endpoint 0x" << std::hex
<< ep
<< ":\n" << data
);
410 ret
= libusb_bulk_transfer(m_handle
->m_handle
,
411 ep
| LIBUSB_ENDPOINT_OUT
,
412 const_cast<unsigned char*>(data
.GetData()),
415 timeout
== -1 ? m_timeout
: timeout
);
416 if( ret
< 0 && ret
!= LIBUSB_ERROR_INTERRUPTED
) {
418 // only notify of a timeout if no data was transferred,
419 // otherwise treat it as success.
420 if( ret
== LIBUSB_ERROR_TIMEOUT
&& transferred
== 0 )
421 throw Timeout(ret
, "Timeout in BulkWrite");
422 else if( ret
!= LIBUSB_ERROR_TIMEOUT
)
423 throw Error(ret
, "Error in BulkWrite");
426 (unsigned int)transferred
!= data
.GetSize() ) {
427 dout("Failed to write all data on ep: " << ep
<<
428 " attempted to write: " << data
.GetSize() <<
429 " but only wrote: " << transferred
);
430 throw Error("Failed to perform a complete write");
433 } while( ret
== -LIBUSB_ERROR_INTERRUPTED
);
438 bool Device::BulkWrite(int ep
, const void *data
, size_t size
, int timeout
)
440 #ifdef __DEBUG_MODE__
441 Barry::Data
dump(data
, size
);
442 ddout("BulkWrite to endpoint 0x" << std::hex
<< ep
<< ":\n" << dump
);
447 ret
= libusb_bulk_transfer(m_handle
->m_handle
,
448 ep
| LIBUSB_ENDPOINT_OUT
,
449 (unsigned char*)const_cast<void*>(data
),
452 timeout
== -1 ? m_timeout
: timeout
);
453 if( ret
< 0 && ret
!= LIBUSB_ERROR_INTERRUPTED
) {
455 // only notify of a timeout if no data was transferred,
456 // otherwise treat it as success.
457 if( ret
== LIBUSB_ERROR_TIMEOUT
&& transferred
== 0 )
458 throw Timeout(ret
, "Timeout in BulkWrite (2)");
459 else if( ret
!= LIBUSB_ERROR_TIMEOUT
)
460 throw Error(ret
, "Error in BulkWrite (2)");
462 if( ret
>= 0 && (unsigned int)transferred
!= size
) {
463 dout("Failed to write all data on ep: " << ep
<<
464 " attempted to write: " << size
<<
465 " but only wrote: " << transferred
);
466 throw Error("Failed to perform a complete write");
469 } while( ret
== -LIBUSB_ERROR_INTERRUPTED
);
474 bool Device::InterruptRead(int ep
, Barry::Data
&data
, int timeout
)
476 ddout("InterruptRead to endpoint 0x" << std::hex
<< ep
<< ":\n" << data
);
481 ret
= libusb_interrupt_transfer(m_handle
->m_handle
,
482 ep
| LIBUSB_ENDPOINT_IN
,
483 data
.GetBuffer(), data
.GetBufSize(),
485 timeout
== -1 ? m_timeout
: timeout
);
486 if( ret
< 0 && ret
!= LIBUSB_ERROR_INTERRUPTED
) {
488 // only notify of a timeout if no data was transferred,
489 // otherwise treat it as success.
490 if( ret
== LIBUSB_ERROR_TIMEOUT
) {
491 if( transferred
== 0 )
492 throw Timeout(ret
, "Timeout in InterruptRead");
494 dout("Read timed out with some data transferred... possible partial read");
496 else if( ret
!= LIBUSB_ERROR_TIMEOUT
)
497 throw Error(ret
, "Error in InterruptRead");
499 if( transferred
!= 0 )
500 data
.ReleaseBuffer(transferred
);
502 } while( ret
== -LIBUSB_ERROR_INTERRUPTED
);
508 bool Device::InterruptWrite(int ep
, const Barry::Data
&data
, int timeout
)
510 ddout("InterruptWrite to endpoint 0x" << std::hex
<< ep
<< ":\n" << data
);
514 ret
= libusb_interrupt_transfer(m_handle
->m_handle
,
515 ep
| LIBUSB_ENDPOINT_OUT
,
516 const_cast<unsigned char*>(data
.GetData()),
519 timeout
== -1 ? m_timeout
: timeout
);
520 if( ret
< 0 && ret
!= LIBUSB_ERROR_INTERRUPTED
) {
522 // only notify of a timeout if no data was transferred,
523 // otherwise treat it as success.
524 if( ret
== LIBUSB_ERROR_TIMEOUT
&& transferred
== 0 )
525 throw Timeout(ret
, "Timeout in InterruptWrite");
526 else if( ret
!= LIBUSB_ERROR_TIMEOUT
)
527 throw Error(ret
, "Error in InterruptWrite");
530 (unsigned int)transferred
!= data
.GetSize() ) {
531 dout("Failed to write all data on ep: " << ep
<<
532 " attempted to write: " << data
.GetSize() <<
533 " but only wrote: " << transferred
);
534 throw Error("Failed to perform a complete write");
537 } while( ret
== -LIBUSB_ERROR_INTERRUPTED
);
545 /// Reads anything available on the given endpoint, with a low timeout,
546 /// in order to clear any pending reads.
548 void Device::BulkDrain(int ep
, int timeout
)
552 while( BulkRead(ep
, data
, timeout
) )
555 catch( Usb::Error
& ) {}
561 /// Determines the currently selected USB configuration, returning it
562 /// in the cfg argument.
563 /// If unsuccessful, returns false.
565 bool Device::GetConfiguration(unsigned char &cfg
)
568 int result
= libusb_get_configuration(m_handle
->m_handle
, &config
);
571 m_lasterror
= result
;
575 // Returns the current power level of the device, or 0 if unknown
576 int Device::GetPowerLevel()
578 struct libusb_config_descriptor
* cfg
= NULL
;
580 int result
= libusb_get_active_config_descriptor(m_id
.m_impl
->m_dev
, &cfg
);
581 m_lasterror
= result
;
587 libusb_free_config_descriptor(cfg
);
592 bool Device::IsAttachKernelDriver(int iface
, std::string
& name
)
597 ret
= usb_get_driver_np(m_handle
->m_handle
, iface
, buffer
, sizeof(buffer
));
599 dout("interface (" << m_handle
->m_handle
<< ", 0x" << std::hex
<< iface
600 << ") already claimed by driver \"" << name
<< "\" "
601 << "attempting to detach it ");
609 // Requests that the kernel driver is detached, returning false on failure
610 bool Device::DetachKernelDriver(int iface
)
612 int result
= libusb_detach_kernel_driver(m_handle
->m_handle
, iface
);
613 m_lasterror
= result
;
617 // Sends a control message to the device, returning false on failure
618 bool Device::ControlMsg(int requesttype
, int request
, int value
,
619 int index
, char *bytes
, int size
, int timeout
)
621 int result
= libusb_control_transfer(m_handle
->m_handle
,
622 requesttype
, request
, value
, index
,
623 (unsigned char*)bytes
, size
, timeout
);
624 m_lasterror
= result
;
628 int Device::FindInterface(int ifaceClass
)
630 struct libusb_config_descriptor
* cfg
= NULL
;
631 int ret
= libusb_get_active_config_descriptor(m_id
.m_impl
->m_dev
, &cfg
);
633 for( int i
= 0; cfg
->interface
&& i
< cfg
->bNumInterfaces
; ++i
) {
634 const struct libusb_interface
& iface
= cfg
->interface
[i
];
636 iface
.altsetting
&& j
< iface
.num_altsetting
;
638 const struct libusb_interface_descriptor
& id
=
640 if( id
.bInterfaceClass
== ifaceClass
)
641 return id
.bInterfaceNumber
;
647 libusb_free_config_descriptor(cfg
);
652 ///////////////////////////////////////////////////////////////////////////////
655 Interface::Interface(Device
&dev
, int iface
)
656 : m_dev(dev
), m_iface(iface
)
658 dout("libusb_claim_interface(" << dev
.GetHandle()->m_handle
<< ", 0x" << std::hex
<< iface
<< ")");
659 int ret
= libusb_claim_interface(dev
.GetHandle()->m_handle
, iface
);
661 throw Error(ret
, "claim interface failed");
664 Interface::~Interface()
666 dout("libusb_release_interface(" << m_dev
.GetHandle()->m_handle
<< ", 0x" << std::hex
<< m_iface
<< ")");
667 libusb_release_interface(m_dev
.GetHandle()->m_handle
, m_iface
);
674 /// Sets the currently selected USB alternate setting of the current interface.
675 /// The iface parameter passed in should be a value specified
676 /// in the bAlternateSetting descriptor field.
677 /// If unsuccessful, returns false.
679 bool Interface::SetAltInterface(int altSetting
)
681 int result
= libusb_set_interface_alt_setting(
682 m_dev
.GetHandle()->m_handle
,
685 m_dev
.SetLastError(result
);
691 //////////////////////////////////////////////////////////////////
694 DeviceDescriptor::DeviceDescriptor(DeviceID
& devid
)
695 : m_impl(new DeviceDescriptorImpl())
697 if( !devid
.m_impl
.get() ) {
698 dout("DeviceDescriptor: empty devid");
701 m_impl
->m_devid
= devid
;
702 int ret
= libusb_get_device_descriptor(devid
.m_impl
->m_dev
, &m_impl
->m_desc
);
704 dout("Failed to read device descriptor with err: " << ret
);
707 dout("device_desc loaded"
708 << "\nbLength: " << std::dec
<< (unsigned int) m_impl
->m_desc
.bLength
709 << "\nbDescriptorType: " << std::dec
<< (unsigned int) m_impl
->m_desc
.bDescriptorType
710 << "\nbcdUSB: 0x" << std::hex
<< (unsigned int) m_impl
->m_desc
.bcdUSB
711 << "\nbDeviceClass: " << std::dec
<< (unsigned int) m_impl
->m_desc
.bDeviceClass
712 << "\nbDeviceSubClass: " << std::dec
<< (unsigned int) m_impl
->m_desc
.bDeviceSubClass
713 << "\nbDeviceProtocol: " << std::dec
<< (unsigned int) m_impl
->m_desc
.bDeviceProtocol
714 << "\nbMaxPacketSize0: " << std::dec
<< (unsigned int) m_impl
->m_desc
.bMaxPacketSize0
715 << "\nidVendor: 0x" << std::hex
<< (unsigned int) m_impl
->m_desc
.idVendor
716 << "\nidProduct: 0x" << std::hex
<< (unsigned int) m_impl
->m_desc
.idProduct
717 << "\nbcdDevice: 0x" << std::hex
<< (unsigned int) m_impl
->m_desc
.bcdDevice
718 << "\niManufacturer: " << std::dec
<< (unsigned int) m_impl
->m_desc
.iManufacturer
719 << "\niProduct: " << std::dec
<< (unsigned int) m_impl
->m_desc
.iProduct
720 << "\niSerialNumber: " << std::dec
<< (unsigned int) m_impl
->m_desc
.iSerialNumber
721 << "\nbNumConfigurations: " << std::dec
<< (unsigned int) m_impl
->m_desc
.bNumConfigurations
725 // Create all the configs
726 for( int i
= 0; i
< m_impl
->m_desc
.bNumConfigurations
; ++i
) {
727 std::auto_ptr
<ConfigDescriptor
> ptr(new ConfigDescriptor(*this, i
));
728 (*this)[ptr
->GetNumber()] = ptr
.get();
733 DeviceDescriptor::~DeviceDescriptor()
735 // Delete any pointers in the vector
736 std::for_each(begin(),
738 deleteMapPtr
<int, ConfigDescriptor
>);
741 ///////////////////////////////////////////////////////////////////
744 ConfigDescriptor::ConfigDescriptor(DeviceDescriptor
& dev
, int cfgnumber
)
745 : m_impl(new ConfigDescriptorImpl())
747 m_impl
->m_desc
= NULL
;
748 int ret
= libusb_get_config_descriptor(dev
.m_impl
->m_devid
.m_impl
->m_dev
,
749 cfgnumber
, &(m_impl
->m_desc
));
751 dout("Failed to read config descriptor with err: " << ret
);
755 dout(" config_desc #" << std::dec
<< cfgnumber
<< " loaded"
756 << "\nbLength: " << std::dec
<< (unsigned int) m_impl
->m_desc
->bLength
757 << "\nbDescriptorType: " << std::dec
<< (unsigned int) m_impl
->m_desc
->bDescriptorType
758 << "\nwTotalLength: " << std::dec
<< (unsigned int) m_impl
->m_desc
->wTotalLength
759 << "\nbNumInterfaces: " << std::dec
<< (unsigned int) m_impl
->m_desc
->bNumInterfaces
760 << "\nbConfigurationValue: " << std::dec
<< (unsigned int) m_impl
->m_desc
->bConfigurationValue
761 << "\niConfiguration: " << std::dec
<< (unsigned int) m_impl
->m_desc
->iConfiguration
762 << "\nbmAttributes: 0x" << std::hex
<< (unsigned int) m_impl
->m_desc
->bmAttributes
763 << "\nMaxPower: " << std::dec
<< (unsigned int) m_impl
->m_desc
->MaxPower
767 // just for debugging purposes, check for extra descriptors, and
768 // dump them to dout if they exist
769 if( m_impl
->m_desc
->extra
) {
770 dout("while parsing config descriptor, found a block of extra descriptors:");
771 Barry::Data
data(m_impl
->m_desc
->extra
, m_impl
->m_desc
->extra_length
);
775 // Create all the interfaces
776 for( int i
= 0; i
< m_impl
->m_desc
->bNumInterfaces
; ++i
) {
777 const struct libusb_interface
* interface
= &(m_impl
->m_desc
->interface
[i
]);
778 if( !interface
->altsetting
) {
779 dout("ConfigDescriptor: empty altsetting");
780 // some devices are buggy and return a higher bNumInterfaces
781 // than the number of interfaces available... in this case
782 // we just skip and continue
785 for( int j
= 0; j
< interface
->num_altsetting
; ++j
) {
786 std::auto_ptr
<InterfaceDescriptor
> ptr(
787 new InterfaceDescriptor(*this, i
, j
));
788 (*this)[ptr
->GetNumber()] = ptr
.get();
794 ConfigDescriptor::~ConfigDescriptor()
796 // Delete any pointers in the vector
797 std::for_each(begin(),
799 deleteMapPtr
<int, InterfaceDescriptor
>);
800 if( m_impl
->m_desc
) {
801 libusb_free_config_descriptor(m_impl
->m_desc
);
802 m_impl
->m_desc
= NULL
;
806 uint8_t ConfigDescriptor::GetNumber() const {
807 if( !m_impl
->m_desc
)
808 // Return an invalid config number
810 return m_impl
->m_desc
->bConfigurationValue
;
813 /////////////////////////////////////////////////////////////////////////
814 // InterfaceDescriptor
816 InterfaceDescriptor::InterfaceDescriptor(ConfigDescriptor
& cfgdesc
,
817 int interface
, int altsetting
)
818 : m_impl(new InterfaceDescriptorImpl())
820 m_impl
->m_desc
= NULL
;
822 // Find the descriptor
824 &(cfgdesc
.m_impl
->m_desc
825 ->interface
[interface
]
826 .altsetting
[altsetting
]);
827 dout(" interface_desc #" << std::dec
<< interface
<< " loaded"
828 << "\nbLength: " << std::dec
<< (unsigned) m_impl
->m_desc
->bLength
829 << "\nbDescriptorType: " << std::dec
<< (unsigned) m_impl
->m_desc
->bDescriptorType
830 << "\nbInterfaceNumber: " << std::dec
<< (unsigned) m_impl
->m_desc
->bInterfaceNumber
831 << "\nbAlternateSetting: " << std::dec
<< (unsigned) m_impl
->m_desc
->bAlternateSetting
832 << "\nbNumEndpoints: " << std::dec
<< (unsigned) m_impl
->m_desc
->bNumEndpoints
833 << "\nbInterfaceClass: " << std::dec
<< (unsigned) m_impl
->m_desc
->bInterfaceClass
834 << "\nbInterfaceSubClass: " << std::dec
<< (unsigned) m_impl
->m_desc
->bInterfaceSubClass
835 << "\nbInterfaceProtocol: " << std::dec
<< (unsigned) m_impl
->m_desc
->bInterfaceProtocol
836 << "\niInterface: " << std::dec
<< (unsigned) m_impl
->m_desc
->iInterface
840 if( !m_impl
->m_desc
->endpoint
) {
841 dout("InterfaceDescriptor: empty interface pointer");
845 // Create all the endpoints
846 for( int i
= 0; i
< m_impl
->m_desc
->bNumEndpoints
; ++i
) {
847 std::auto_ptr
<EndpointDescriptor
> ptr (
848 new EndpointDescriptor(*this, i
));
849 push_back(ptr
.get());
853 // just for debugging purposes, check for extra descriptors, and
854 // dump them to dout if they exist
855 if( m_impl
->m_desc
->extra
) {
856 dout("while parsing interface descriptor, found a block of extra descriptors:");
857 Barry::Data
data(m_impl
->m_desc
->extra
, m_impl
->m_desc
->extra_length
);
862 InterfaceDescriptor::~InterfaceDescriptor()
864 // Delete any pointers in the vector
865 std::for_each(begin(),
867 deletePtr
<EndpointDescriptor
>);
870 uint8_t InterfaceDescriptor::GetClass() const
872 return m_impl
->m_desc
->bInterfaceClass
;
875 uint8_t InterfaceDescriptor::GetNumber() const
877 if( !m_impl
->m_desc
)
878 // Return an invalid interface number
880 return m_impl
->m_desc
->bInterfaceNumber
;
883 uint8_t InterfaceDescriptor::GetAltSetting() const
885 if( !m_impl
->m_desc
)
886 // Return an invalid setting number
888 return m_impl
->m_desc
->bAlternateSetting
;
891 /////////////////////////////////////////////////////////////////////////////////
892 // EndpointDescriptor
894 EndpointDescriptor::EndpointDescriptor(InterfaceDescriptor
& intdesc
, int endpoint
)
895 : m_impl(new EndpointDescriptorImpl()),
900 // Copy the descriptor
901 m_impl
->m_desc
= &(intdesc
.m_impl
->m_desc
->endpoint
[endpoint
]);
903 dout(" endpoint_desc #" << std::dec
<< endpoint
<< " loaded"
904 << "\nbLength: " << std::dec
<< (unsigned ) m_impl
->m_desc
->bLength
905 << "\nbDescriptorType: " << std::dec
<< (unsigned ) m_impl
->m_desc
->bDescriptorType
906 << "\nbEndpointAddress: 0x" << std::hex
<< (unsigned ) m_impl
->m_desc
->bEndpointAddress
907 << "\nbmAttributes: 0x" << std::hex
<< (unsigned ) m_impl
->m_desc
->bmAttributes
908 << "\nwMaxPacketSize: " << std::dec
<< (unsigned ) m_impl
->m_desc
->wMaxPacketSize
909 << "\nbInterval: " << std::dec
<< (unsigned ) m_impl
->m_desc
->bInterval
910 << "\nbRefresh: " << std::dec
<< (unsigned ) m_impl
->m_desc
->bRefresh
911 << "\nbSynchAddress: " << std::dec
<< (unsigned ) m_impl
->m_desc
->bSynchAddress
915 m_read
= ((m_impl
->m_desc
->bEndpointAddress
& LIBUSB_ENDPOINT_DIR_MASK
) ==
917 m_addr
= (m_impl
->m_desc
->bEndpointAddress
& LIBUSB_ENDPOINT_ADDRESS_MASK
);
918 int type
= (m_impl
->m_desc
->bmAttributes
& LIBUSB_TRANSFER_TYPE_MASK
);
919 m_type
= static_cast<Usb::EndpointDescriptor::EpType
>(type
);
921 // just for debugging purposes, check for extra descriptors, and
922 // dump them to dout if they exist
923 if( m_impl
->m_desc
->extra
) {
924 dout("while parsing endpoint descriptor, found a block of extra descriptors:");
925 Barry::Data
data(m_impl
->m_desc
->extra
, m_impl
->m_desc
->extra_length
);
930 EndpointDescriptor::~EndpointDescriptor()