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"
34 #ifndef __DEBUG_MODE__
35 #define __DEBUG_MODE__
41 // helper functions to make deleting pointers in maps and vectors easier
42 template<typename T
> static void deletePtr(T
* ptr
)
47 template<typename K
, typename T
> static void deleteMapPtr(std::pair
<K
,T
*> ptr
)
52 // lookup table translating LIBUSB errors to standard Linux errors
57 { LIBUSB_SUCCESS
, 0 },
58 { LIBUSB_ERROR_IO
, -EIO
},
59 { LIBUSB_ERROR_INVALID_PARAM
, -EINVAL
},
60 { LIBUSB_ERROR_ACCESS
, -EACCES
},
61 { LIBUSB_ERROR_NO_DEVICE
, -ENODEV
},
62 { LIBUSB_ERROR_NOT_FOUND
, -ENOENT
},
63 { LIBUSB_ERROR_BUSY
, -EBUSY
},
64 { LIBUSB_ERROR_TIMEOUT
, -ETIMEDOUT
},
65 { LIBUSB_ERROR_OVERFLOW
, -EOVERFLOW
},
66 { LIBUSB_ERROR_PIPE
, -EPIPE
},
67 { LIBUSB_ERROR_INTERRUPTED
, -EINTR
},
68 { LIBUSB_ERROR_NO_MEM
, -ENOMEM
},
69 { LIBUSB_ERROR_NOT_SUPPORTED
, -ENOSYS
},
70 // FIXME - Permissions errors should be explicit... otherwise we might
71 // be chasing the wrong error. Change the system error to 0
72 // to indicate unknown, but keep support for the "Other" message.
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
124 int LibraryInterface::TranslateErrcode(int libusb_errcode
)
126 for( int i
= 0; i
< errorCodeCnt
; ++i
) {
127 if( errorCodes
[i
].libusb
== libusb_errcode
)
128 return errorCodes
[i
].system
;
131 // default to 0 if unknown
135 int LibraryInterface::Init()
137 // if the environment variable LIBUSB_DEBUG is set, that
138 // level value will be used instead of our 3 above...
139 // if you need to *force* this to 3, call SetDataDump(true)
141 return libusb_init(&libusbctx
);
144 void LibraryInterface::Uninit()
146 libusb_exit(libusbctx
);
149 void LibraryInterface::SetDataDump(bool data_dump_mode
)
155 // Failed to init, can't do much but return
156 dout("SetDataDump: Failed to initialise libusb");
160 libusb_set_debug(libusbctx
, 3);
162 libusb_set_debug(libusbctx
, 0);
165 ///////////////////////////////////////////////////////////////////////////////
168 DeviceIDImpl::DeviceIDImpl(libusb_device
*dev
)
171 libusb_ref_device(m_dev
);
173 // Libusb 1.0 doesn't provide busnames or filenames
174 // so it's necessary to make some up.
175 std::ostringstream formatter
;
176 formatter
<< "libusb1-"
177 << static_cast<int>(libusb_get_bus_number(m_dev
));
178 m_busname
= formatter
.str();
181 << static_cast<int>(libusb_get_device_address(m_dev
));
182 m_filename
= formatter
.str();
185 DeviceIDImpl::~DeviceIDImpl()
187 libusb_unref_device(m_dev
);
190 ///////////////////////////////////////////////////////////////////////////////
193 DeviceID::DeviceID(DeviceIDImpl
* impl
)
198 DeviceID::~DeviceID()
203 const char* DeviceID::GetBusName() const
205 return m_impl
->m_busname
.c_str();
208 uint16_t DeviceID::GetNumber() const
210 return libusb_get_device_address(m_impl
->m_dev
);
213 const char* DeviceID::GetFilename() const
215 return m_impl
->m_filename
.c_str();
218 uint16_t DeviceID::GetIdProduct() const
220 int ret
= PRODUCT_UNKNOWN
;
221 struct libusb_device_descriptor desc
;
222 int err
= libusb_get_device_descriptor(m_impl
->m_dev
, &desc
);
224 ret
= desc
.idProduct
;
228 ///////////////////////////////////////////////////////////////////////////////
231 DeviceList::DeviceList()
232 : m_impl(new DeviceListImpl())
234 m_impl
->m_list
= NULL
;
235 m_impl
->m_listcnt
= 0;
237 m_impl
->m_listcnt
= libusb_get_device_list(libusbctx
, &m_impl
->m_list
);
238 if( m_impl
->m_listcnt
< 0 ) {
239 throw Error("Failed to get device list");
242 for( int i
= 0; i
< m_impl
->m_listcnt
; ++i
) {
243 // Add the device to the list of devices
244 DeviceID
devID(new DeviceIDImpl(m_impl
->m_list
[i
]));
245 m_impl
->m_devices
.push_back(devID
);
249 DeviceList::~DeviceList()
251 if( m_impl
->m_list
) {
252 libusb_free_device_list(m_impl
->m_list
, 1);
256 std::vector
<DeviceID
> DeviceList::MatchDevices(int vendor
, int product
,
257 const char *busname
, const char *devname
)
259 std::vector
<DeviceID
> ret
;
262 std::vector
<DeviceID
>::iterator iter
= m_impl
->m_devices
.begin();
264 for( ; iter
!= m_impl
->m_devices
.end() ; ++iter
) {
265 struct libusb_device
* dev
= iter
->m_impl
->m_dev
;
267 // only search on given bus
268 if( busname
&& atoi(busname
) != libusb_get_bus_number(dev
) )
271 // search for specific device
272 if( devname
&& atoi(devname
) != libusb_get_device_address(dev
) )
275 struct libusb_device_descriptor desc
;
276 err
= libusb_get_device_descriptor(dev
, &desc
);
278 dout("Failed to get device descriptor: " << err
);
283 if( desc
.idVendor
== vendor
&&
284 ( desc
.idProduct
== product
||
285 product
== PRODUCT_ANY
)) {
286 ret
.push_back(*iter
);
293 ///////////////////////////////////////////////////////////////////////////////
296 Device::Device(const Usb::DeviceID
& id
, int timeout
)
300 dout("libusb_open(" << std::dec
<< id
.m_impl
.get() << ")");
302 throw Error("invalid USB device ID");
303 m_handle
.reset(new DeviceHandle());
304 int err
= libusb_open(id
.m_impl
->m_dev
, &(m_handle
->m_handle
));
307 throw Error("open failed");
312 dout("libusb_close(" << std::dec
<< m_handle
->m_handle
<< ")");
313 libusb_close(m_handle
->m_handle
);
316 bool Device::SetConfiguration(unsigned char cfg
)
318 dout("libusb_set_configuration(" << std::dec
<< m_handle
->m_handle
<< ", 0x" << std::hex
<< (unsigned int) cfg
<< ")");
319 int ret
= libusb_set_configuration(m_handle
->m_handle
, cfg
);
324 bool Device::ClearHalt(int ep
)
326 dout("libusb_clear_halt(" << std::dec
<< m_handle
->m_handle
<< ", 0x" << std::hex
<< ep
<< ")");
327 int ret
= libusb_clear_halt(m_handle
->m_handle
, ep
);
334 dout("libusb_reset_device(" << std::dec
<< m_handle
->m_handle
<< ")");
335 int ret
= libusb_reset_device(m_handle
->m_handle
);
340 bool Device::BulkRead(int ep
, Barry::Data
&data
, int timeout
)
342 ddout("BulkRead to endpoint 0x" << std::hex
<< ep
<< ":\n" << data
);
347 ret
= libusb_bulk_transfer(m_handle
->m_handle
,
348 ep
|= LIBUSB_ENDPOINT_IN
,
349 data
.GetBuffer(), data
.GetBufSize(),
351 timeout
== -1 ? m_timeout
: timeout
);
352 if( ret
< 0 && ret
!= LIBUSB_ERROR_INTERRUPTED
) {
354 // only notify of a timeout if no data was transferred,
355 // otherwise treat it as success.
356 if( ret
== LIBUSB_ERROR_TIMEOUT
) {
357 if( transferred
== 0 )
358 throw Timeout(ret
, "Timeout in BulkRead");
360 dout("Read timed out with some data transferred... possible partial read");
362 else if( ret
!= LIBUSB_ERROR_TIMEOUT
)
363 throw Error(ret
, "Error in BulkRead");
365 if( transferred
!= 0 )
366 data
.ReleaseBuffer(transferred
);
368 } while( ret
== -LIBUSB_ERROR_INTERRUPTED
);
373 bool Device::BulkWrite(int ep
, const Barry::Data
&data
, int timeout
)
375 ddout("BulkWrite to endpoint 0x" << std::hex
<< ep
<< ":\n" << data
);
379 ret
= libusb_bulk_transfer(m_handle
->m_handle
,
380 ep
| LIBUSB_ENDPOINT_OUT
,
381 const_cast<unsigned char*>(data
.GetData()),
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
&& transferred
== 0 )
390 throw Timeout(ret
, "Timeout in BulkWrite");
391 else if( ret
!= LIBUSB_ERROR_TIMEOUT
)
392 throw Error(ret
, "Error in BulkWrite");
395 (unsigned int)transferred
!= data
.GetSize() ) {
396 dout("Failed to write all data on ep: " << ep
<<
397 " attempted to write: " << data
.GetSize() <<
398 " but only wrote: " << transferred
);
399 throw Error("Failed to perform a complete write");
402 } while( ret
== -LIBUSB_ERROR_INTERRUPTED
);
407 bool Device::BulkWrite(int ep
, const void *data
, size_t size
, int timeout
)
409 #ifdef __DEBUG_MODE__
410 Barry::Data
dump(data
, size
);
411 ddout("BulkWrite to endpoint 0x" << std::hex
<< ep
<< ":\n" << dump
);
416 ret
= libusb_bulk_transfer(m_handle
->m_handle
,
417 ep
| LIBUSB_ENDPOINT_OUT
,
418 (unsigned char*)const_cast<void*>(data
),
421 timeout
== -1 ? m_timeout
: timeout
);
422 if( ret
< 0 && ret
!= LIBUSB_ERROR_INTERRUPTED
) {
424 // only notify of a timeout if no data was transferred,
425 // otherwise treat it as success.
426 if( ret
== LIBUSB_ERROR_TIMEOUT
&& transferred
== 0 )
427 throw Timeout(ret
, "Timeout in BulkWrite (2)");
428 else if( ret
!= LIBUSB_ERROR_TIMEOUT
)
429 throw Error(ret
, "Error in BulkWrite (2)");
431 if( ret
>= 0 && (unsigned int)transferred
!= size
) {
432 dout("Failed to write all data on ep: " << ep
<<
433 " attempted to write: " << size
<<
434 " but only wrote: " << transferred
);
435 throw Error("Failed to perform a complete write");
438 } while( ret
== -LIBUSB_ERROR_INTERRUPTED
);
443 bool Device::InterruptRead(int ep
, Barry::Data
&data
, int timeout
)
445 ddout("InterruptRead to endpoint 0x" << std::hex
<< ep
<< ":\n" << data
);
450 ret
= libusb_interrupt_transfer(m_handle
->m_handle
,
451 ep
| LIBUSB_ENDPOINT_IN
,
452 data
.GetBuffer(), data
.GetBufSize(),
454 timeout
== -1 ? m_timeout
: timeout
);
455 if( ret
< 0 && ret
!= LIBUSB_ERROR_INTERRUPTED
) {
457 // only notify of a timeout if no data was transferred,
458 // otherwise treat it as success.
459 if( ret
== LIBUSB_ERROR_TIMEOUT
) {
460 if( transferred
== 0 )
461 throw Timeout(ret
, "Timeout in InterruptRead");
463 dout("Read timed out with some data transferred... possible partial read");
465 else if( ret
!= LIBUSB_ERROR_TIMEOUT
)
466 throw Error(ret
, "Error in InterruptRead");
468 if( transferred
!= 0 )
469 data
.ReleaseBuffer(transferred
);
471 } while( ret
== -LIBUSB_ERROR_INTERRUPTED
);
477 bool Device::InterruptWrite(int ep
, const Barry::Data
&data
, int timeout
)
479 ddout("InterruptWrite to endpoint 0x" << std::hex
<< ep
<< ":\n" << data
);
483 ret
= libusb_interrupt_transfer(m_handle
->m_handle
,
484 ep
| LIBUSB_ENDPOINT_OUT
,
485 const_cast<unsigned char*>(data
.GetData()),
488 timeout
== -1 ? m_timeout
: timeout
);
489 if( ret
< 0 && ret
!= LIBUSB_ERROR_INTERRUPTED
) {
491 // only notify of a timeout if no data was transferred,
492 // otherwise treat it as success.
493 if( ret
== LIBUSB_ERROR_TIMEOUT
&& transferred
== 0 )
494 throw Timeout(ret
, "Timeout in InterruptWrite");
495 else if( ret
!= LIBUSB_ERROR_TIMEOUT
)
496 throw Error(ret
, "Error in InterruptWrite");
499 (unsigned int)transferred
!= data
.GetSize() ) {
500 dout("Failed to write all data on ep: " << ep
<<
501 " attempted to write: " << data
.GetSize() <<
502 " but only wrote: " << transferred
);
503 throw Error("Failed to perform a complete write");
506 } while( ret
== -LIBUSB_ERROR_INTERRUPTED
);
514 /// Reads anything available on the given endpoint, with a low timeout,
515 /// in order to clear any pending reads.
517 void Device::BulkDrain(int ep
, int timeout
)
521 while( BulkRead(ep
, data
, timeout
) )
524 catch( Usb::Error
& ) {}
530 /// Determines the currently selected USB configuration, returning it
531 /// in the cfg argument.
532 /// If unsuccessful, returns false.
534 bool Device::GetConfiguration(unsigned char &cfg
)
537 int result
= libusb_get_configuration(m_handle
->m_handle
, &config
);
540 m_lasterror
= result
;
544 // Returns the current power level of the device, or 0 if unknown
545 int Device::GetPowerLevel()
547 struct libusb_config_descriptor
* cfg
= NULL
;
549 int result
= libusb_get_active_config_descriptor(m_id
.m_impl
->m_dev
, &cfg
);
550 m_lasterror
= result
;
556 libusb_free_config_descriptor(cfg
);
561 // Requests that the kernel driver is detached, returning false on failure
562 bool Device::DetachKernelDriver(int iface
)
564 int result
= libusb_detach_kernel_driver(m_handle
->m_handle
, iface
);
565 m_lasterror
= result
;
569 // Sends a control message to the device, returning false on failure
570 bool Device::ControlMsg(int requesttype
, int request
, int value
,
571 int index
, char *bytes
, int size
, int timeout
)
573 int result
= libusb_control_transfer(m_handle
->m_handle
,
574 requesttype
, request
, value
, index
,
575 (unsigned char*)bytes
, size
, timeout
);
576 m_lasterror
= result
;
580 int Device::FindInterface(int ifaceClass
)
582 struct libusb_config_descriptor
* cfg
= NULL
;
583 int ret
= libusb_get_active_config_descriptor(m_id
.m_impl
->m_dev
, &cfg
);
585 for( int i
= 0; cfg
->interface
&& i
< cfg
->bNumInterfaces
; ++i
) {
586 const struct libusb_interface
& iface
= cfg
->interface
[i
];
588 iface
.altsetting
&& j
< iface
.num_altsetting
;
590 const struct libusb_interface_descriptor
& id
=
592 if( id
.bInterfaceClass
== ifaceClass
)
593 return id
.bInterfaceNumber
;
599 libusb_free_config_descriptor(cfg
);
604 ///////////////////////////////////////////////////////////////////////////////
607 Interface::Interface(Device
&dev
, int iface
)
608 : m_dev(dev
), m_iface(iface
)
610 dout("libusb_claim_interface(" << dev
.GetHandle()->m_handle
<< ", 0x" << std::hex
<< iface
<< ")");
611 int ret
= libusb_claim_interface(dev
.GetHandle()->m_handle
, iface
);
613 throw Error(ret
, "claim interface failed");
616 Interface::~Interface()
618 dout("libusb_release_interface(" << m_dev
.GetHandle()->m_handle
<< ", 0x" << std::hex
<< m_iface
<< ")");
619 libusb_release_interface(m_dev
.GetHandle()->m_handle
, m_iface
);
626 /// Sets the currently selected USB alternate setting of the current interface.
627 /// The iface parameter passed in should be a value specified
628 /// in the bAlternateSetting descriptor field.
629 /// If unsuccessful, returns false.
631 bool Interface::SetAltInterface(int altSetting
)
633 int result
= libusb_set_interface_alt_setting(
634 m_dev
.GetHandle()->m_handle
,
637 m_dev
.SetLastError(result
);
643 //////////////////////////////////////////////////////////////////
646 DeviceDescriptor::DeviceDescriptor(DeviceID
& devid
)
647 : m_impl(new DeviceDescriptorImpl())
649 if( !devid
.m_impl
.get() ) {
650 dout("DeviceDescriptor: empty devid");
653 m_impl
->m_devid
= devid
;
654 int ret
= libusb_get_device_descriptor(devid
.m_impl
->m_dev
, &m_impl
->m_desc
);
656 dout("Failed to read device descriptor with err: " << ret
);
659 dout("device_desc loaded"
660 << "\nbLength: " << std::dec
<< (unsigned int) m_impl
->m_desc
.bLength
661 << "\nbDescriptorType: " << std::dec
<< (unsigned int) m_impl
->m_desc
.bDescriptorType
662 << "\nbcdUSB: 0x" << std::hex
<< (unsigned int) m_impl
->m_desc
.bcdUSB
663 << "\nbDeviceClass: " << std::dec
<< (unsigned int) m_impl
->m_desc
.bDeviceClass
664 << "\nbDeviceSubClass: " << std::dec
<< (unsigned int) m_impl
->m_desc
.bDeviceSubClass
665 << "\nbDeviceProtocol: " << std::dec
<< (unsigned int) m_impl
->m_desc
.bDeviceProtocol
666 << "\nbMaxPacketSize0: " << std::dec
<< (unsigned int) m_impl
->m_desc
.bMaxPacketSize0
667 << "\nidVendor: 0x" << std::hex
<< (unsigned int) m_impl
->m_desc
.idVendor
668 << "\nidProduct: 0x" << std::hex
<< (unsigned int) m_impl
->m_desc
.idProduct
669 << "\nbcdDevice: 0x" << std::hex
<< (unsigned int) m_impl
->m_desc
.bcdDevice
670 << "\niManufacturer: " << std::dec
<< (unsigned int) m_impl
->m_desc
.iManufacturer
671 << "\niProduct: " << std::dec
<< (unsigned int) m_impl
->m_desc
.iProduct
672 << "\niSerialNumber: " << std::dec
<< (unsigned int) m_impl
->m_desc
.iSerialNumber
673 << "\nbNumConfigurations: " << std::dec
<< (unsigned int) m_impl
->m_desc
.bNumConfigurations
677 // Create all the configs
678 for( int i
= 0; i
< m_impl
->m_desc
.bNumConfigurations
; ++i
) {
679 std::auto_ptr
<ConfigDescriptor
> ptr(new ConfigDescriptor(*this, i
));
680 (*this)[ptr
->GetNumber()] = ptr
.get();
685 DeviceDescriptor::~DeviceDescriptor()
687 // Delete any pointers in the vector
688 std::for_each(begin(),
690 deleteMapPtr
<int, ConfigDescriptor
>);
693 ///////////////////////////////////////////////////////////////////
696 ConfigDescriptor::ConfigDescriptor(DeviceDescriptor
& dev
, int cfgnumber
)
697 : m_impl(new ConfigDescriptorImpl())
699 m_impl
->m_desc
= NULL
;
700 int ret
= libusb_get_config_descriptor(dev
.m_impl
->m_devid
.m_impl
->m_dev
,
701 cfgnumber
, &(m_impl
->m_desc
));
703 dout("Failed to read config descriptor with err: " << ret
);
707 dout(" config_desc #" << std::dec
<< cfgnumber
<< " loaded"
708 << "\nbLength: " << std::dec
<< (unsigned int) m_impl
->m_desc
->bLength
709 << "\nbDescriptorType: " << std::dec
<< (unsigned int) m_impl
->m_desc
->bDescriptorType
710 << "\nwTotalLength: " << std::dec
<< (unsigned int) m_impl
->m_desc
->wTotalLength
711 << "\nbNumInterfaces: " << std::dec
<< (unsigned int) m_impl
->m_desc
->bNumInterfaces
712 << "\nbConfigurationValue: " << std::dec
<< (unsigned int) m_impl
->m_desc
->bConfigurationValue
713 << "\niConfiguration: " << std::dec
<< (unsigned int) m_impl
->m_desc
->iConfiguration
714 << "\nbmAttributes: 0x" << std::hex
<< (unsigned int) m_impl
->m_desc
->bmAttributes
715 << "\nMaxPower: " << std::dec
<< (unsigned int) m_impl
->m_desc
->MaxPower
719 // just for debugging purposes, check for extra descriptors, and
720 // dump them to dout if they exist
721 if( m_impl
->m_desc
->extra
) {
722 dout("while parsing config descriptor, found a block of extra descriptors:");
723 Barry::Data
data(m_impl
->m_desc
->extra
, m_impl
->m_desc
->extra_length
);
727 // Create all the interfaces
728 for( int i
= 0; i
< m_impl
->m_desc
->bNumInterfaces
; ++i
) {
729 const struct libusb_interface
* interface
= &(m_impl
->m_desc
->interface
[i
]);
730 if( !interface
->altsetting
) {
731 dout("ConfigDescriptor: empty altsetting");
732 // some devices are buggy and return a higher bNumInterfaces
733 // than the number of interfaces available... in this case
734 // we just skip and continue
737 for( int j
= 0; j
< interface
->num_altsetting
; ++j
) {
738 std::auto_ptr
<InterfaceDescriptor
> ptr(
739 new InterfaceDescriptor(*this, i
, j
));
740 (*this)[ptr
->GetNumber()] = ptr
.get();
746 ConfigDescriptor::~ConfigDescriptor()
748 // Delete any pointers in the vector
749 std::for_each(begin(),
751 deleteMapPtr
<int, InterfaceDescriptor
>);
752 if( m_impl
->m_desc
) {
753 libusb_free_config_descriptor(m_impl
->m_desc
);
754 m_impl
->m_desc
= NULL
;
758 uint8_t ConfigDescriptor::GetNumber() const {
759 return m_impl
->m_desc
->bConfigurationValue
;
762 /////////////////////////////////////////////////////////////////////////
763 // InterfaceDescriptor
765 InterfaceDescriptor::InterfaceDescriptor(ConfigDescriptor
& cfgdesc
,
766 int interface
, int altsetting
)
767 : m_impl(new InterfaceDescriptorImpl())
769 m_impl
->m_desc
= NULL
;
771 // Find the descriptor
773 &(cfgdesc
.m_impl
->m_desc
774 ->interface
[interface
]
775 .altsetting
[altsetting
]);
776 dout(" interface_desc #" << std::dec
<< interface
<< " loaded"
777 << "\nbLength: " << std::dec
<< (unsigned) m_impl
->m_desc
->bLength
778 << "\nbDescriptorType: " << std::dec
<< (unsigned) m_impl
->m_desc
->bDescriptorType
779 << "\nbInterfaceNumber: " << std::dec
<< (unsigned) m_impl
->m_desc
->bInterfaceNumber
780 << "\nbAlternateSetting: " << std::dec
<< (unsigned) m_impl
->m_desc
->bAlternateSetting
781 << "\nbNumEndpoints: " << std::dec
<< (unsigned) m_impl
->m_desc
->bNumEndpoints
782 << "\nbInterfaceClass: " << std::dec
<< (unsigned) m_impl
->m_desc
->bInterfaceClass
783 << "\nbInterfaceSubClass: " << std::dec
<< (unsigned) m_impl
->m_desc
->bInterfaceSubClass
784 << "\nbInterfaceProtocol: " << std::dec
<< (unsigned) m_impl
->m_desc
->bInterfaceProtocol
785 << "\niInterface: " << std::dec
<< (unsigned) m_impl
->m_desc
->iInterface
789 if( !m_impl
->m_desc
->endpoint
) {
790 dout("InterfaceDescriptor: empty interface pointer");
794 // Create all the endpoints
795 for( int i
= 0; i
< m_impl
->m_desc
->bNumEndpoints
; ++i
) {
796 std::auto_ptr
<EndpointDescriptor
> ptr (
797 new EndpointDescriptor(*this, i
));
798 push_back(ptr
.get());
802 // just for debugging purposes, check for extra descriptors, and
803 // dump them to dout if they exist
804 if( m_impl
->m_desc
->extra
) {
805 dout("while parsing interface descriptor, found a block of extra descriptors:");
806 Barry::Data
data(m_impl
->m_desc
->extra
, m_impl
->m_desc
->extra_length
);
811 InterfaceDescriptor::~InterfaceDescriptor()
813 // Delete any pointers in the vector
814 std::for_each(begin(),
816 deletePtr
<EndpointDescriptor
>);
819 uint8_t InterfaceDescriptor::GetClass() const
821 return m_impl
->m_desc
->bInterfaceClass
;
824 uint8_t InterfaceDescriptor::GetNumber() const
826 return m_impl
->m_desc
->bInterfaceNumber
;
829 uint8_t InterfaceDescriptor::GetAltSetting() const
831 return m_impl
->m_desc
->bAlternateSetting
;
834 /////////////////////////////////////////////////////////////////////////////////
835 // EndpointDescriptor
837 EndpointDescriptor::EndpointDescriptor(InterfaceDescriptor
& intdesc
, int endpoint
)
838 : m_impl(new EndpointDescriptorImpl()),
843 // Copy the descriptor
844 m_impl
->m_desc
= &(intdesc
.m_impl
->m_desc
->endpoint
[endpoint
]);
846 dout(" endpoint_desc #" << std::dec
<< endpoint
<< " loaded"
847 << "\nbLength: " << std::dec
<< (unsigned ) m_impl
->m_desc
->bLength
848 << "\nbDescriptorType: " << std::dec
<< (unsigned ) m_impl
->m_desc
->bDescriptorType
849 << "\nbEndpointAddress: 0x" << std::hex
<< (unsigned ) m_impl
->m_desc
->bEndpointAddress
850 << "\nbmAttributes: 0x" << std::hex
<< (unsigned ) m_impl
->m_desc
->bmAttributes
851 << "\nwMaxPacketSize: " << std::dec
<< (unsigned ) m_impl
->m_desc
->wMaxPacketSize
852 << "\nbInterval: " << std::dec
<< (unsigned ) m_impl
->m_desc
->bInterval
853 << "\nbRefresh: " << std::dec
<< (unsigned ) m_impl
->m_desc
->bRefresh
854 << "\nbSynchAddress: " << std::dec
<< (unsigned ) m_impl
->m_desc
->bSynchAddress
858 m_read
= ((m_impl
->m_desc
->bEndpointAddress
& LIBUSB_ENDPOINT_DIR_MASK
) ==
860 m_addr
= (m_impl
->m_desc
->bEndpointAddress
& LIBUSB_ENDPOINT_ADDRESS_MASK
);
861 int type
= (m_impl
->m_desc
->bmAttributes
& LIBUSB_TRANSFER_TYPE_MASK
);
862 m_type
= static_cast<Usb::EndpointDescriptor::EpType
>(type
);
864 // just for debugging purposes, check for extra descriptors, and
865 // dump them to dout if they exist
866 if( m_impl
->m_desc
->extra
) {
867 dout("while parsing endpoint descriptor, found a block of extra descriptors:");
868 Barry::Data
data(m_impl
->m_desc
->extra
, m_impl
->m_desc
->extra_length
);
873 EndpointDescriptor::~EndpointDescriptor()