2 /// \file usbwrap_libusb.cc
3 /// USB API wrapper for libusb version 0.1
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.h"
35 #ifndef __DEBUG_MODE__
36 #define __DEBUG_MODE__
42 // helper function to make deleting pointers in maps and vectors easier
43 template<typename T
> static void deletePtr(T
* ptr
) {
47 template<typename K
, typename T
> static void deleteMapPtr(std::pair
<K
,T
*> ptr
) {
51 ///////////////////////////////////////////////////////////////////////////////
54 std::string
LibraryInterface::GetLastErrorString(int /*libusb_errcode*/)
56 // Errcode is unused by libusb, so just call the last error
57 return std::string(usb_strerror());
60 int LibraryInterface::TranslateErrcode(int libusb_errcode
)
62 // libusb errcode == system errcode
63 return libusb_errcode
;
66 bool LibraryInterface::Init(int *libusb_errno
)
68 // if the environment variable USB_DEBUG is set, that
69 // level value will be used instead of our 9 below...
70 // if you need to *force* this to 9, call SetDataDump(true)
73 // Can never fail, so return success
77 void LibraryInterface::Uninit()
82 void LibraryInterface::SetDataDump(bool data_dump_mode
)
90 ///////////////////////////////////////////////////////////////////////////////
93 DeviceID::DeviceID(DeviceIDImpl
* impl
)
102 const char* DeviceID::GetBusName() const
104 return m_impl
->m_dev
->bus
->dirname
;
107 uint16_t DeviceID::GetNumber() const
109 return m_impl
->m_dev
->devnum
;
112 const char* DeviceID::GetFilename() const
114 return m_impl
->m_dev
->filename
;
117 uint16_t DeviceID::GetIdProduct() const
119 return m_impl
->m_dev
->descriptor
.idProduct
;
122 std::string
DeviceID::GetUsbName() const
124 // for libusb 0.1, we need both the bus name and the filename
125 // and we stay away from the product ID, since that requires
126 // communication with the device, which may not be possible
127 // in error conditions.
128 std::ostringstream oss
;
129 oss
<< GetBusName() << ":" << GetFilename();
133 ///////////////////////////////////////////////////////////////////////////////
136 DeviceList::DeviceList()
137 : m_impl(new DeviceListImpl())
139 // Work out what devices are on the bus at the moment
142 struct usb_bus
* busses
= usb_get_busses();
143 for( ; busses
; busses
= busses
->next
) {
144 struct usb_device
* dev
= busses
->devices
;
145 for( ; dev
; dev
= dev
->next
) {
146 // Add the device to the list of devices
147 std::auto_ptr
<DeviceIDImpl
> impl( new DeviceIDImpl() );
149 DeviceID
devID(impl
.release());
150 m_impl
->m_devices
.push_back(devID
);
155 DeviceList::~DeviceList()
160 static bool ToNum(const char *str
, long &num
)
163 num
= strtol(str
, &end
, 10);
164 return num
>= 0 && // no negative numbers
165 num
!= LONG_MIN
&& num
!= LONG_MAX
&& // no overflow
166 str
!= end
&& *end
== '\0'; // whole string valid
170 // Linux treats bus and device path names as numbers, sometimes left
171 // padded with zeros. Other platforms, such as Windows, use strings,
172 // such as "bus-1" or similar.
174 // Here we try to convert each string to a number, and if successful,
175 // compare them. If unable to convert, then compare as strings.
176 // This way, "3" == "003" and "bus-foobar" == "bus-foobar".
178 static bool NameCompare(const char *n1
, const char *n2
)
181 if( ToNum(n1
, l1
) && ToNum(n2
, l2
) ) {
185 return strcmp(n1
, n2
) == 0;
189 std::vector
<DeviceID
> DeviceList::MatchDevices(int vendor
, int product
,
190 const char *busname
, const char *devname
)
192 std::vector
<DeviceID
> ret
;
194 std::vector
<DeviceID
>::iterator iter
= m_impl
->m_devices
.begin();
196 for( ; iter
!= m_impl
->m_devices
.end() ; ++iter
) {
197 struct usb_device
* dev
= iter
->m_impl
->m_dev
;
199 // only search on given bus
200 if( busname
&& !NameCompare(busname
, dev
->bus
->dirname
) )
203 // search for specific device
204 if( devname
&& !NameCompare(devname
, dev
->filename
) )
208 if( dev
->descriptor
.idVendor
== vendor
&&
209 ( dev
->descriptor
.idProduct
== product
||
210 product
== PRODUCT_ANY
)) {
211 ret
.push_back(*iter
);
218 ///////////////////////////////////////////////////////////////////////////////
221 Device::Device(const Usb::DeviceID
& id
, int timeout
)
223 m_handle(new DeviceHandle()),
227 dout("usb_open(" << std::dec
<< id
.m_impl
.get() << ")");
228 if( !id
.m_impl
.get() )
229 throw Error(_("invalid USB device ID"));
230 m_handle
->m_handle
= usb_open(id
.m_impl
->m_dev
);
231 if( !m_handle
->m_handle
)
232 throw Error(_("Failed to open USB device. Please check your system's USB device permissions."));
237 dout("usb_close(" << std::dec
<< m_handle
->m_handle
<< ")");
238 usb_close(m_handle
->m_handle
);
241 bool Device::SetConfiguration(unsigned char cfg
)
243 dout("usb_set_configuration(" << std::dec
<< m_handle
->m_handle
<< ", 0x" << std::hex
<< (unsigned int) cfg
<< ")");
244 int ret
= usb_set_configuration(m_handle
->m_handle
, cfg
);
249 bool Device::ClearHalt(int ep
)
251 dout("usb_clear_halt(" << std::dec
<< m_handle
->m_handle
<< ", 0x" << std::hex
<< ep
<< ")");
252 int ret
= usb_clear_halt(m_handle
->m_handle
, ep
);
259 dout("usb_reset(" << std::dec
<< m_handle
->m_handle
<< ")");
260 int ret
= usb_reset(m_handle
->m_handle
);
265 bool Device::BulkRead(int ep
, Barry::Data
&data
, int timeout
)
270 ret
= usb_bulk_read(m_handle
->m_handle
, ep
,
271 (char*) data
.GetBuffer(), data
.GetBufSize(),
272 timeout
== -1 ? m_timeout
: timeout
);
273 if( ret
< 0 && ret
!= -EINTR
&& ret
!= -EAGAIN
) {
275 if( ret
== -ETIMEDOUT
)
276 throw Timeout(ret
, _("Timeout in usb_bulk_read"));
278 std::ostringstream oss
;
279 oss
<< _("Error in usb_bulk_read(")
280 << m_handle
->m_handle
<< ", "
282 << data
.GetBufSize() << ")";
283 throw Error(ret
, oss
.str());
287 data
.ReleaseBuffer(ret
);
288 } while( ret
== -EINTR
|| ret
== -EAGAIN
);
293 bool Device::BulkWrite(int ep
, const Barry::Data
&data
, int timeout
)
295 ddout("BulkWrite to endpoint 0x" << std::hex
<< ep
<< ":\n" << data
);
298 ret
= usb_bulk_write(m_handle
->m_handle
, ep
,
299 (char*) data
.GetData(), data
.GetSize(),
300 timeout
== -1 ? m_timeout
: timeout
);
301 if( ret
< 0 && ret
!= -EINTR
&& ret
!= -EAGAIN
) {
303 if( ret
== -ETIMEDOUT
)
304 throw Timeout(ret
, _("Timeout in usb_bulk_write (1)"));
306 throw Error(ret
, _("Error in usb_bulk_write (1)"));
308 } while( ret
== -EINTR
|| ret
== -EAGAIN
);
313 bool Device::BulkWrite(int ep
, const void *data
, size_t size
, int timeout
)
315 #ifdef __DEBUG_MODE__
316 Barry::Data
dump(data
, size
);
317 ddout("BulkWrite to endpoint 0x" << std::hex
<< ep
<< ":\n" << dump
);
322 ret
= usb_bulk_write(m_handle
->m_handle
, ep
,
324 timeout
== -1 ? m_timeout
: timeout
);
325 if( ret
< 0 && ret
!= -EINTR
&& ret
!= -EAGAIN
) {
327 if( ret
== -ETIMEDOUT
)
328 throw Timeout(ret
, _("Timeout in usb_bulk_write (2)"));
330 throw Error(ret
, _("Error in usb_bulk_write (2)"));
332 } while( ret
== -EINTR
|| ret
== -EAGAIN
);
337 bool Device::InterruptRead(int ep
, Barry::Data
&data
, int timeout
)
342 ret
= usb_interrupt_read(m_handle
->m_handle
, ep
,
343 (char*) data
.GetBuffer(), data
.GetBufSize(),
344 timeout
== -1 ? m_timeout
: timeout
);
345 if( ret
< 0 && ret
!= -EINTR
&& ret
!= -EAGAIN
) {
347 if( ret
== -ETIMEDOUT
)
348 throw Timeout(ret
, _("Timeout in usb_interrupt_read"));
350 throw Error(ret
, _("Error in usb_interrupt_read"));
353 data
.ReleaseBuffer(ret
);
354 } while( ret
== -EINTR
|| ret
== -EAGAIN
);
359 bool Device::InterruptWrite(int ep
, const Barry::Data
&data
, int timeout
)
361 ddout("InterruptWrite to endpoint 0x" << std::hex
<< ep
<< ":\n" << data
);
365 ret
= usb_interrupt_write(m_handle
->m_handle
, ep
,
366 (char*) data
.GetData(), data
.GetSize(),
367 timeout
== -1 ? m_timeout
: timeout
);
368 if( ret
< 0 && ret
!= -EINTR
&& ret
!= -EAGAIN
) {
370 if( ret
== -ETIMEDOUT
)
371 throw Timeout(ret
, _("Timeout in usb_interrupt_write"));
373 throw Error(ret
, _("Error in usb_interrupt_write"));
375 } while( ret
== -EINTR
|| ret
== -EAGAIN
);
383 /// Reads anything available on the given endpoint, with a low timeout,
384 /// in order to clear any pending reads.
386 void Device::BulkDrain(int ep
, int timeout
)
390 while( BulkRead(ep
, data
, timeout
) )
393 catch( Usb::Error
& ) {}
399 /// Uses the GET_CONFIGURATION control message to determine the currently
400 /// selected USB configuration, returning it in the cfg argument.
401 /// If unsuccessful, returns false.
403 bool Device::GetConfiguration(unsigned char &cfg
)
405 int result
= usb_control_msg(m_handle
->m_handle
, 0x80, USB_REQ_GET_CONFIGURATION
, 0, 0,
406 (char*) &cfg
, 1, m_timeout
);
407 m_lasterror
= result
;
411 // Returns the current power level of the device, or 0 if unknown
412 int Device::GetPowerLevel()
414 if( !m_id
.m_impl
->m_dev
->config
||
415 !m_id
.m_impl
->m_dev
->descriptor
.bNumConfigurations
< 1 )
418 return m_id
.m_impl
->m_dev
->config
[0].MaxPower
;
421 std::string
Device::GetSimpleSerialNumber()
425 int ret
= usb_get_string_simple(m_handle
->m_handle
,
426 m_id
.m_impl
->m_dev
->descriptor
.iSerialNumber
, buf
, sizeof(buf
));
432 bool Device::IsAttachKernelDriver(int iface
)
437 #if LIBUSB_HAS_GET_DRIVER_NP
438 ret
= usb_get_driver_np(m_handle
->m_handle
, iface
, buffer
, sizeof(buffer
));
440 dout("interface (" << m_handle
->m_handle
<< ", 0x" << std::hex
<< iface
441 << ") already claimed by driver \"" << buffer
<< "\"");
446 m_lasterror
= -ENOSYS
;
452 // Requests that the kernel driver is detached, returning false on failure
453 bool Device::DetachKernelDriver(int iface
)
455 #if LIBUSB_HAS_DETACH_KERNEL_DRIVER_NP
456 int result
= usb_detach_kernel_driver_np(m_handle
->m_handle
, iface
);
457 m_lasterror
= result
;
460 m_lasterror
= -ENOSYS
;
465 // Sends a control message to the device, returning false on failure
466 bool Device::ControlMsg(int requesttype
, int request
, int value
,
467 int index
, char *bytes
, int size
, int timeout
)
469 int result
= usb_control_msg(m_handle
->m_handle
,
470 requesttype
, request
, value
, index
,
471 bytes
, size
, timeout
);
472 m_lasterror
= result
;
477 int Device::FindInterface(int ifaceClass
)
479 struct usb_config_descriptor
*cfg
= m_id
.m_impl
->m_dev
->config
;
483 for( unsigned i
= 0; cfg
->interface
&& i
< cfg
->bNumInterfaces
; i
++ ) {
484 struct usb_interface
*iface
= &cfg
->interface
[i
];
485 for( int a
= 0; iface
->altsetting
&& a
< iface
->num_altsetting
; a
++ ) {
486 struct usb_interface_descriptor
*id
= &iface
->altsetting
[a
];
487 if( id
->bInterfaceClass
== ifaceClass
)
488 return id
->bInterfaceNumber
;
497 ///////////////////////////////////////////////////////////////////////////////
500 Interface::Interface(Device
&dev
, int iface
)
501 : m_dev(dev
), m_iface(iface
)
503 dout("usb_claim_interface(" << dev
.GetHandle()->m_handle
<< ", 0x" << std::hex
<< iface
<< ")");
504 int ret
= usb_claim_interface(dev
.GetHandle()->m_handle
, iface
);
506 throw Error(ret
, _("claim interface failed"));
509 Interface::~Interface()
511 dout("usb_release_interface(" << m_dev
.GetHandle()->m_handle
<< ", 0x" << std::hex
<< m_iface
<< ")");
512 usb_release_interface(m_dev
.GetHandle()->m_handle
, m_iface
);
518 /// Uses the usb_set_altinterface() function to set the currently
519 /// selected USB alternate setting of the current interface.
520 /// The iface parameter passed in should be a value specified
521 /// in the bAlternateSetting descriptor field.
522 /// If unsuccessful, returns false.
524 bool Interface::SetAltInterface(int altSetting
)
526 int result
= usb_set_altinterface(m_dev
.GetHandle()->m_handle
, altSetting
);
527 m_dev
.SetLastError(result
);
531 //////////////////////////////////////////////////////////////////
534 DeviceDescriptor::DeviceDescriptor(DeviceID
& devid
)
535 : m_impl(new DeviceDescriptorImpl())
537 if( !devid
.m_impl
.get() ) {
538 dout("DeviceDescriptor: empty devid");
541 // Copy the descriptor over to our memory
542 m_impl
->m_dev
= devid
.m_impl
->m_dev
;
543 m_impl
->m_desc
= devid
.m_impl
->m_dev
->descriptor
;
544 dout("device_desc loaded"
545 << "\nbLength: " << std::dec
<< (unsigned int) m_impl
->m_desc
.bLength
546 << "\nbDescriptorType: " << std::dec
<< (unsigned int) m_impl
->m_desc
.bDescriptorType
547 << "\nbcdUSB: 0x" << std::hex
<< (unsigned int) m_impl
->m_desc
.bcdUSB
548 << "\nbDeviceClass: " << std::dec
<< (unsigned int) m_impl
->m_desc
.bDeviceClass
549 << "\nbDeviceSubClass: " << std::dec
<< (unsigned int) m_impl
->m_desc
.bDeviceSubClass
550 << "\nbDeviceProtocol: " << std::dec
<< (unsigned int) m_impl
->m_desc
.bDeviceProtocol
551 << "\nbMaxPacketSize0: " << std::dec
<< (unsigned int) m_impl
->m_desc
.bMaxPacketSize0
552 << "\nidVendor: 0x" << std::hex
<< (unsigned int) m_impl
->m_desc
.idVendor
553 << "\nidProduct: 0x" << std::hex
<< (unsigned int) m_impl
->m_desc
.idProduct
554 << "\nbcdDevice: 0x" << std::hex
<< (unsigned int) m_impl
->m_desc
.bcdDevice
555 << "\niManufacturer: " << std::dec
<< (unsigned int) m_impl
->m_desc
.iManufacturer
556 << "\niProduct: " << std::dec
<< (unsigned int) m_impl
->m_desc
.iProduct
557 << "\niSerialNumber: " << std::dec
<< (unsigned int) m_impl
->m_desc
.iSerialNumber
558 << "\nbNumConfigurations: " << std::dec
<< (unsigned int) m_impl
->m_desc
.bNumConfigurations
562 // Create all the configs
563 for( int i
= 0; i
< m_impl
->m_desc
.bNumConfigurations
; ++i
) {
564 std::auto_ptr
<ConfigDescriptor
> ptr(new ConfigDescriptor(*this, i
));
565 (*this)[ptr
->GetNumber()] = ptr
.get();
570 DeviceDescriptor::~DeviceDescriptor()
572 // Delete any pointers in the map
573 std::for_each(begin(),
575 deleteMapPtr
<int, ConfigDescriptor
>);
578 ///////////////////////////////////////////////////////////////////
581 ConfigDescriptor::ConfigDescriptor(DeviceDescriptor
& dev
, int cfgnumber
)
582 : m_impl(new ConfigDescriptorImpl())
584 // Copy the config descriptor locally
585 m_impl
->m_desc
= dev
.m_impl
->m_dev
->config
[cfgnumber
];
586 dout(" config_desc #" << std::dec
<< cfgnumber
<< " loaded"
587 << "\nbLength: " << std::dec
<< (unsigned int) m_impl
->m_desc
.bLength
588 << "\nbDescriptorType: " << std::dec
<< (unsigned int) m_impl
->m_desc
.bDescriptorType
589 << "\nwTotalLength: " << std::dec
<< (unsigned int) m_impl
->m_desc
.wTotalLength
590 << "\nbNumInterfaces: " << std::dec
<< (unsigned int) m_impl
->m_desc
.bNumInterfaces
591 << "\nbConfigurationValue: " << std::dec
<< (unsigned int) m_impl
->m_desc
.bConfigurationValue
592 << "\niConfiguration: " << std::dec
<< (unsigned int) m_impl
->m_desc
.iConfiguration
593 << "\nbmAttributes: 0x" << std::hex
<< (unsigned int) m_impl
->m_desc
.bmAttributes
594 << "\nMaxPower: " << std::dec
<< (unsigned int) m_impl
->m_desc
.MaxPower
598 // just for debugging purposes, check for extra descriptors, and
599 // dump them to dout if they exist
600 if( m_impl
->m_desc
.extra
) {
601 dout("while parsing config descriptor, found a block of extra descriptors:");
602 Barry::Data
data(m_impl
->m_desc
.extra
, m_impl
->m_desc
.extralen
);
606 // Create all the interfaces
607 for( int i
= 0; i
< m_impl
->m_desc
.bNumInterfaces
; ++i
) {
608 struct usb_interface
* interface
= &(m_impl
->m_desc
.interface
[i
]);
609 if( !interface
->altsetting
) {
610 dout("ConfigDescriptor: empty altsetting");
611 // some devices are buggy and return a higher bNumInterfaces
612 // than the number of interfaces available... in this case
613 // we just skip and continue
616 for( int j
= 0; j
< interface
->num_altsetting
; ++j
) {
617 std::auto_ptr
<InterfaceDescriptor
> ptr(
618 new InterfaceDescriptor(*this, i
, j
));
619 (*this)[ptr
->GetNumber()] = ptr
.get();
625 ConfigDescriptor::~ConfigDescriptor()
627 // Delete any pointers in the map
628 std::for_each(begin(),
630 deleteMapPtr
<int, InterfaceDescriptor
>);
633 uint8_t ConfigDescriptor::GetNumber() const {
634 return m_impl
->m_desc
.bConfigurationValue
;
637 /////////////////////////////////////////////////////////////////////////
638 // InterfaceDescriptor
640 InterfaceDescriptor::InterfaceDescriptor(ConfigDescriptor
& cfg
,
641 int interface
, int altsetting
)
642 : m_impl(new InterfaceDescriptorImpl())
644 // Copy the descriptor
645 m_impl
->m_desc
= cfg
.m_impl
->m_desc
646 .interface
[interface
]
647 .altsetting
[altsetting
];
648 dout(" interface_desc #" << std::dec
<< interface
<< " loaded"
649 << "\nbLength: " << std::dec
<< (unsigned) m_impl
->m_desc
.bLength
650 << "\nbDescriptorType: " << std::dec
<< (unsigned) m_impl
->m_desc
.bDescriptorType
651 << "\nbInterfaceNumber: " << std::dec
<< (unsigned) m_impl
->m_desc
.bInterfaceNumber
652 << "\nbAlternateSetting: " << std::dec
<< (unsigned) m_impl
->m_desc
.bAlternateSetting
653 << "\nbNumEndpoints: " << std::dec
<< (unsigned) m_impl
->m_desc
.bNumEndpoints
654 << "\nbInterfaceClass: " << std::dec
<< (unsigned) m_impl
->m_desc
.bInterfaceClass
655 << "\nbInterfaceSubClass: " << std::dec
<< (unsigned) m_impl
->m_desc
.bInterfaceSubClass
656 << "\nbInterfaceProtocol: " << std::dec
<< (unsigned) m_impl
->m_desc
.bInterfaceProtocol
657 << "\niInterface: " << std::dec
<< (unsigned) m_impl
->m_desc
.iInterface
661 if( !m_impl
->m_desc
.endpoint
) {
662 dout("InterfaceDescriptor: empty interface pointer");
666 // Create all the endpoints
667 for( int i
= 0; i
< m_impl
->m_desc
.bNumEndpoints
; ++i
) {
668 std::auto_ptr
<EndpointDescriptor
> ptr (
669 new EndpointDescriptor(*this, i
));
670 this->push_back(ptr
.get());
674 // just for debugging purposes, check for extra descriptors, and
675 // dump them to dout if they exist
676 if( m_impl
->m_desc
.extra
) {
677 dout("while parsing interface descriptor, found a block of extra descriptors:");
678 Barry::Data
data(m_impl
->m_desc
.extra
, m_impl
->m_desc
.extralen
);
683 InterfaceDescriptor::~InterfaceDescriptor()
685 // Delete any pointers in the vector
686 std::for_each(begin(),
688 deletePtr
<EndpointDescriptor
>);
691 uint8_t InterfaceDescriptor::GetClass() const
693 return m_impl
->m_desc
.bInterfaceClass
;
696 uint8_t InterfaceDescriptor::GetNumber() const
698 return m_impl
->m_desc
.bInterfaceNumber
;
701 uint8_t InterfaceDescriptor::GetAltSetting() const
703 return m_impl
->m_desc
.bAlternateSetting
;
706 /////////////////////////////////////////////////////////////////////////////////
707 // EndpointDescriptor
709 EndpointDescriptor::EndpointDescriptor(InterfaceDescriptor
& interface
, int endpoint
)
710 : m_impl(new EndpointDescriptorImpl()),
715 // Copy the descriptor
716 m_impl
->m_desc
= interface
.m_impl
->m_desc
.endpoint
[endpoint
];
717 dout(" endpoint_desc #" << std::dec
<< endpoint
<< " loaded"
718 << "\nbLength: " << std::dec
<< (unsigned ) m_impl
->m_desc
.bLength
719 << "\nbDescriptorType: " << std::dec
<< (unsigned ) m_impl
->m_desc
.bDescriptorType
720 << "\nbEndpointAddress: 0x" << std::hex
<< (unsigned ) m_impl
->m_desc
.bEndpointAddress
721 << "\nbmAttributes: 0x" << std::hex
<< (unsigned ) m_impl
->m_desc
.bmAttributes
722 << "\nwMaxPacketSize: " << std::dec
<< (unsigned ) m_impl
->m_desc
.wMaxPacketSize
723 << "\nbInterval: " << std::dec
<< (unsigned ) m_impl
->m_desc
.bInterval
724 << "\nbRefresh: " << std::dec
<< (unsigned ) m_impl
->m_desc
.bRefresh
725 << "\nbSynchAddress: " << std::dec
<< (unsigned ) m_impl
->m_desc
.bSynchAddress
729 m_read
= ((m_impl
->m_desc
.bEndpointAddress
& USB_ENDPOINT_DIR_MASK
) != 0);
730 m_addr
= (m_impl
->m_desc
.bEndpointAddress
& USB_ENDPOINT_ADDRESS_MASK
);
731 int type
= (m_impl
->m_desc
.bmAttributes
& USB_ENDPOINT_TYPE_MASK
);
732 m_type
= static_cast<Usb::EndpointDescriptor::EpType
>(type
);
734 // just for debugging purposes, check for extra descriptors, and
735 // dump them to dout if they exist
736 if( m_impl
->m_desc
.extra
) {
737 dout("while parsing endpoint descriptor, found a block of extra descriptors:");
738 Barry::Data
data(m_impl
->m_desc
.extra
, m_impl
->m_desc
.extralen
);
743 EndpointDescriptor::~EndpointDescriptor()