2 /// \file usbwrap_libusb.cc
3 /// USB API wrapper for libusb version 0.1
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.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()),
226 dout("usb_open(" << std::dec
<< id
.m_impl
.get() << ")");
227 if( !id
.m_impl
.get() )
228 throw Error(_("invalid USB device ID"));
229 m_handle
->m_handle
= usb_open(id
.m_impl
->m_dev
);
230 if( !m_handle
->m_handle
)
231 throw Error(_("Failed to open USB device. Please check your system's USB device permissions."));
236 dout("usb_close(" << std::dec
<< m_handle
->m_handle
<< ")");
237 usb_close(m_handle
->m_handle
);
240 bool Device::SetConfiguration(unsigned char cfg
)
242 dout("usb_set_configuration(" << std::dec
<< m_handle
->m_handle
<< ", 0x" << std::hex
<< (unsigned int) cfg
<< ")");
243 int ret
= usb_set_configuration(m_handle
->m_handle
, cfg
);
248 bool Device::ClearHalt(int ep
)
250 dout("usb_clear_halt(" << std::dec
<< m_handle
->m_handle
<< ", 0x" << std::hex
<< ep
<< ")");
251 int ret
= usb_clear_halt(m_handle
->m_handle
, ep
);
258 dout("usb_reset(" << std::dec
<< m_handle
->m_handle
<< ")");
259 int ret
= usb_reset(m_handle
->m_handle
);
264 bool Device::BulkRead(int ep
, Barry::Data
&data
, int timeout
)
269 ret
= usb_bulk_read(m_handle
->m_handle
, ep
,
270 (char*) data
.GetBuffer(), data
.GetBufSize(),
271 timeout
== -1 ? m_timeout
: timeout
);
272 if( ret
< 0 && ret
!= -EINTR
&& ret
!= -EAGAIN
) {
274 if( ret
== -ETIMEDOUT
)
275 throw Timeout(ret
, _("Timeout in usb_bulk_read"));
277 std::ostringstream oss
;
278 oss
<< _("Error in usb_bulk_read(")
279 << m_handle
->m_handle
<< ", "
281 << data
.GetBufSize() << ")";
282 throw Error(ret
, oss
.str());
286 data
.ReleaseBuffer(ret
);
287 } while( ret
== -EINTR
|| ret
== -EAGAIN
);
292 bool Device::BulkWrite(int ep
, const Barry::Data
&data
, int timeout
)
294 ddout("BulkWrite to endpoint 0x" << std::hex
<< ep
<< ":\n" << data
);
297 ret
= usb_bulk_write(m_handle
->m_handle
, ep
,
298 (char*) data
.GetData(), data
.GetSize(),
299 timeout
== -1 ? m_timeout
: timeout
);
300 if( ret
< 0 && ret
!= -EINTR
&& ret
!= -EAGAIN
) {
302 if( ret
== -ETIMEDOUT
)
303 throw Timeout(ret
, _("Timeout in usb_bulk_write (1)"));
305 throw Error(ret
, _("Error in usb_bulk_write (1)"));
307 } while( ret
== -EINTR
|| ret
== -EAGAIN
);
312 bool Device::BulkWrite(int ep
, const void *data
, size_t size
, int timeout
)
314 #ifdef __DEBUG_MODE__
315 Barry::Data
dump(data
, size
);
316 ddout("BulkWrite to endpoint 0x" << std::hex
<< ep
<< ":\n" << dump
);
321 ret
= usb_bulk_write(m_handle
->m_handle
, ep
,
323 timeout
== -1 ? m_timeout
: timeout
);
324 if( ret
< 0 && ret
!= -EINTR
&& ret
!= -EAGAIN
) {
326 if( ret
== -ETIMEDOUT
)
327 throw Timeout(ret
, _("Timeout in usb_bulk_write (2)"));
329 throw Error(ret
, _("Error in usb_bulk_write (2)"));
331 } while( ret
== -EINTR
|| ret
== -EAGAIN
);
336 bool Device::InterruptRead(int ep
, Barry::Data
&data
, int timeout
)
341 ret
= usb_interrupt_read(m_handle
->m_handle
, ep
,
342 (char*) data
.GetBuffer(), data
.GetBufSize(),
343 timeout
== -1 ? m_timeout
: timeout
);
344 if( ret
< 0 && ret
!= -EINTR
&& ret
!= -EAGAIN
) {
346 if( ret
== -ETIMEDOUT
)
347 throw Timeout(ret
, _("Timeout in usb_interrupt_read"));
349 throw Error(ret
, _("Error in usb_interrupt_read"));
352 data
.ReleaseBuffer(ret
);
353 } while( ret
== -EINTR
|| ret
== -EAGAIN
);
358 bool Device::InterruptWrite(int ep
, const Barry::Data
&data
, int timeout
)
360 ddout("InterruptWrite to endpoint 0x" << std::hex
<< ep
<< ":\n" << data
);
364 ret
= usb_interrupt_write(m_handle
->m_handle
, ep
,
365 (char*) data
.GetData(), data
.GetSize(),
366 timeout
== -1 ? m_timeout
: timeout
);
367 if( ret
< 0 && ret
!= -EINTR
&& ret
!= -EAGAIN
) {
369 if( ret
== -ETIMEDOUT
)
370 throw Timeout(ret
, _("Timeout in usb_interrupt_write"));
372 throw Error(ret
, _("Error in usb_interrupt_write"));
374 } while( ret
== -EINTR
|| ret
== -EAGAIN
);
382 /// Reads anything available on the given endpoint, with a low timeout,
383 /// in order to clear any pending reads.
385 void Device::BulkDrain(int ep
, int timeout
)
389 while( BulkRead(ep
, data
, timeout
) )
392 catch( Usb::Error
& ) {}
398 /// Uses the GET_CONFIGURATION control message to determine the currently
399 /// selected USB configuration, returning it in the cfg argument.
400 /// If unsuccessful, returns false.
402 bool Device::GetConfiguration(unsigned char &cfg
)
404 int result
= usb_control_msg(m_handle
->m_handle
, 0x80, USB_REQ_GET_CONFIGURATION
, 0, 0,
405 (char*) &cfg
, 1, m_timeout
);
406 m_lasterror
= result
;
410 // Returns the current power level of the device, or 0 if unknown
411 int Device::GetPowerLevel()
413 if( !m_id
.m_impl
->m_dev
->config
||
414 !m_id
.m_impl
->m_dev
->descriptor
.bNumConfigurations
< 1 )
417 return m_id
.m_impl
->m_dev
->config
[0].MaxPower
;
420 std::string
Device::GetSimpleSerialNumber()
424 int ret
= usb_get_string_simple(m_handle
->m_handle
,
425 m_id
.m_impl
->m_dev
->descriptor
.iSerialNumber
, buf
, sizeof(buf
));
431 bool Device::IsAttachKernelDriver(int iface
)
436 #if LIBUSB_HAS_GET_DRIVER_NP
437 ret
= usb_get_driver_np(m_handle
->m_handle
, iface
, buffer
, sizeof(buffer
));
439 dout("interface (" << m_handle
->m_handle
<< ", 0x" << std::hex
<< iface
440 << ") already claimed by driver \"" << buffer
<< "\"");
445 m_lasterror
= -ENOSYS
;
451 // Requests that the kernel driver is detached, returning false on failure
452 bool Device::DetachKernelDriver(int iface
)
454 #if LIBUSB_HAS_DETACH_KERNEL_DRIVER_NP
455 int result
= usb_detach_kernel_driver_np(m_handle
->m_handle
, iface
);
456 m_lasterror
= result
;
459 m_lasterror
= -ENOSYS
;
464 // Sends a control message to the device, returning false on failure
465 bool Device::ControlMsg(int requesttype
, int request
, int value
,
466 int index
, char *bytes
, int size
, int timeout
)
468 int result
= usb_control_msg(m_handle
->m_handle
,
469 requesttype
, request
, value
, index
,
470 bytes
, size
, timeout
);
471 m_lasterror
= result
;
476 int Device::FindInterface(int ifaceClass
)
478 struct usb_config_descriptor
*cfg
= m_id
.m_impl
->m_dev
->config
;
482 for( unsigned i
= 0; cfg
->interface
&& i
< cfg
->bNumInterfaces
; i
++ ) {
483 struct usb_interface
*iface
= &cfg
->interface
[i
];
484 for( int a
= 0; iface
->altsetting
&& a
< iface
->num_altsetting
; a
++ ) {
485 struct usb_interface_descriptor
*id
= &iface
->altsetting
[a
];
486 if( id
->bInterfaceClass
== ifaceClass
)
487 return id
->bInterfaceNumber
;
496 ///////////////////////////////////////////////////////////////////////////////
499 Interface::Interface(Device
&dev
, int iface
)
500 : m_dev(dev
), m_iface(iface
)
502 dout("usb_claim_interface(" << dev
.GetHandle()->m_handle
<< ", 0x" << std::hex
<< iface
<< ")");
503 int ret
= usb_claim_interface(dev
.GetHandle()->m_handle
, iface
);
505 throw Error(ret
, _("claim interface failed"));
508 Interface::~Interface()
510 dout("usb_release_interface(" << m_dev
.GetHandle()->m_handle
<< ", 0x" << std::hex
<< m_iface
<< ")");
511 usb_release_interface(m_dev
.GetHandle()->m_handle
, m_iface
);
517 /// Uses the usb_set_altinterface() function to set the currently
518 /// selected USB alternate setting of the current interface.
519 /// The iface parameter passed in should be a value specified
520 /// in the bAlternateSetting descriptor field.
521 /// If unsuccessful, returns false.
523 bool Interface::SetAltInterface(int altSetting
)
525 int result
= usb_set_altinterface(m_dev
.GetHandle()->m_handle
, altSetting
);
526 m_dev
.SetLastError(result
);
530 //////////////////////////////////////////////////////////////////
533 DeviceDescriptor::DeviceDescriptor(DeviceID
& devid
)
534 : m_impl(new DeviceDescriptorImpl())
536 if( !devid
.m_impl
.get() ) {
537 dout("DeviceDescriptor: empty devid");
540 // Copy the descriptor over to our memory
541 m_impl
->m_dev
= devid
.m_impl
->m_dev
;
542 m_impl
->m_desc
= devid
.m_impl
->m_dev
->descriptor
;
543 dout("device_desc loaded"
544 << "\nbLength: " << std::dec
<< (unsigned int) m_impl
->m_desc
.bLength
545 << "\nbDescriptorType: " << std::dec
<< (unsigned int) m_impl
->m_desc
.bDescriptorType
546 << "\nbcdUSB: 0x" << std::hex
<< (unsigned int) m_impl
->m_desc
.bcdUSB
547 << "\nbDeviceClass: " << std::dec
<< (unsigned int) m_impl
->m_desc
.bDeviceClass
548 << "\nbDeviceSubClass: " << std::dec
<< (unsigned int) m_impl
->m_desc
.bDeviceSubClass
549 << "\nbDeviceProtocol: " << std::dec
<< (unsigned int) m_impl
->m_desc
.bDeviceProtocol
550 << "\nbMaxPacketSize0: " << std::dec
<< (unsigned int) m_impl
->m_desc
.bMaxPacketSize0
551 << "\nidVendor: 0x" << std::hex
<< (unsigned int) m_impl
->m_desc
.idVendor
552 << "\nidProduct: 0x" << std::hex
<< (unsigned int) m_impl
->m_desc
.idProduct
553 << "\nbcdDevice: 0x" << std::hex
<< (unsigned int) m_impl
->m_desc
.bcdDevice
554 << "\niManufacturer: " << std::dec
<< (unsigned int) m_impl
->m_desc
.iManufacturer
555 << "\niProduct: " << std::dec
<< (unsigned int) m_impl
->m_desc
.iProduct
556 << "\niSerialNumber: " << std::dec
<< (unsigned int) m_impl
->m_desc
.iSerialNumber
557 << "\nbNumConfigurations: " << std::dec
<< (unsigned int) m_impl
->m_desc
.bNumConfigurations
561 // Create all the configs
562 for( int i
= 0; i
< m_impl
->m_desc
.bNumConfigurations
; ++i
) {
563 std::auto_ptr
<ConfigDescriptor
> ptr(new ConfigDescriptor(*this, i
));
564 (*this)[ptr
->GetNumber()] = ptr
.get();
569 DeviceDescriptor::~DeviceDescriptor()
571 // Delete any pointers in the map
572 std::for_each(begin(),
574 deleteMapPtr
<int, ConfigDescriptor
>);
577 ///////////////////////////////////////////////////////////////////
580 ConfigDescriptor::ConfigDescriptor(DeviceDescriptor
& dev
, int cfgnumber
)
581 : m_impl(new ConfigDescriptorImpl())
583 // Copy the config descriptor locally
584 m_impl
->m_desc
= dev
.m_impl
->m_dev
->config
[cfgnumber
];
585 dout(" config_desc #" << std::dec
<< cfgnumber
<< " loaded"
586 << "\nbLength: " << std::dec
<< (unsigned int) m_impl
->m_desc
.bLength
587 << "\nbDescriptorType: " << std::dec
<< (unsigned int) m_impl
->m_desc
.bDescriptorType
588 << "\nwTotalLength: " << std::dec
<< (unsigned int) m_impl
->m_desc
.wTotalLength
589 << "\nbNumInterfaces: " << std::dec
<< (unsigned int) m_impl
->m_desc
.bNumInterfaces
590 << "\nbConfigurationValue: " << std::dec
<< (unsigned int) m_impl
->m_desc
.bConfigurationValue
591 << "\niConfiguration: " << std::dec
<< (unsigned int) m_impl
->m_desc
.iConfiguration
592 << "\nbmAttributes: 0x" << std::hex
<< (unsigned int) m_impl
->m_desc
.bmAttributes
593 << "\nMaxPower: " << std::dec
<< (unsigned int) m_impl
->m_desc
.MaxPower
597 // just for debugging purposes, check for extra descriptors, and
598 // dump them to dout if they exist
599 if( m_impl
->m_desc
.extra
) {
600 dout("while parsing config descriptor, found a block of extra descriptors:");
601 Barry::Data
data(m_impl
->m_desc
.extra
, m_impl
->m_desc
.extralen
);
605 // Create all the interfaces
606 for( int i
= 0; i
< m_impl
->m_desc
.bNumInterfaces
; ++i
) {
607 struct usb_interface
* interface
= &(m_impl
->m_desc
.interface
[i
]);
608 if( !interface
->altsetting
) {
609 dout("ConfigDescriptor: empty altsetting");
610 // some devices are buggy and return a higher bNumInterfaces
611 // than the number of interfaces available... in this case
612 // we just skip and continue
615 for( int j
= 0; j
< interface
->num_altsetting
; ++j
) {
616 std::auto_ptr
<InterfaceDescriptor
> ptr(
617 new InterfaceDescriptor(*this, i
, j
));
618 (*this)[ptr
->GetNumber()] = ptr
.get();
624 ConfigDescriptor::~ConfigDescriptor()
626 // Delete any pointers in the map
627 std::for_each(begin(),
629 deleteMapPtr
<int, InterfaceDescriptor
>);
632 uint8_t ConfigDescriptor::GetNumber() const {
633 return m_impl
->m_desc
.bConfigurationValue
;
636 /////////////////////////////////////////////////////////////////////////
637 // InterfaceDescriptor
639 InterfaceDescriptor::InterfaceDescriptor(ConfigDescriptor
& cfg
,
640 int interface
, int altsetting
)
641 : m_impl(new InterfaceDescriptorImpl())
643 // Copy the descriptor
644 m_impl
->m_desc
= cfg
.m_impl
->m_desc
645 .interface
[interface
]
646 .altsetting
[altsetting
];
647 dout(" interface_desc #" << std::dec
<< interface
<< " loaded"
648 << "\nbLength: " << std::dec
<< (unsigned) m_impl
->m_desc
.bLength
649 << "\nbDescriptorType: " << std::dec
<< (unsigned) m_impl
->m_desc
.bDescriptorType
650 << "\nbInterfaceNumber: " << std::dec
<< (unsigned) m_impl
->m_desc
.bInterfaceNumber
651 << "\nbAlternateSetting: " << std::dec
<< (unsigned) m_impl
->m_desc
.bAlternateSetting
652 << "\nbNumEndpoints: " << std::dec
<< (unsigned) m_impl
->m_desc
.bNumEndpoints
653 << "\nbInterfaceClass: " << std::dec
<< (unsigned) m_impl
->m_desc
.bInterfaceClass
654 << "\nbInterfaceSubClass: " << std::dec
<< (unsigned) m_impl
->m_desc
.bInterfaceSubClass
655 << "\nbInterfaceProtocol: " << std::dec
<< (unsigned) m_impl
->m_desc
.bInterfaceProtocol
656 << "\niInterface: " << std::dec
<< (unsigned) m_impl
->m_desc
.iInterface
660 if( !m_impl
->m_desc
.endpoint
) {
661 dout("InterfaceDescriptor: empty interface pointer");
665 // Create all the endpoints
666 for( int i
= 0; i
< m_impl
->m_desc
.bNumEndpoints
; ++i
) {
667 std::auto_ptr
<EndpointDescriptor
> ptr (
668 new EndpointDescriptor(*this, i
));
669 this->push_back(ptr
.get());
673 // just for debugging purposes, check for extra descriptors, and
674 // dump them to dout if they exist
675 if( m_impl
->m_desc
.extra
) {
676 dout("while parsing interface descriptor, found a block of extra descriptors:");
677 Barry::Data
data(m_impl
->m_desc
.extra
, m_impl
->m_desc
.extralen
);
682 InterfaceDescriptor::~InterfaceDescriptor()
684 // Delete any pointers in the vector
685 std::for_each(begin(),
687 deletePtr
<EndpointDescriptor
>);
690 uint8_t InterfaceDescriptor::GetClass() const
692 return m_impl
->m_desc
.bInterfaceClass
;
695 uint8_t InterfaceDescriptor::GetNumber() const
697 return m_impl
->m_desc
.bInterfaceNumber
;
700 uint8_t InterfaceDescriptor::GetAltSetting() const
702 return m_impl
->m_desc
.bAlternateSetting
;
705 /////////////////////////////////////////////////////////////////////////////////
706 // EndpointDescriptor
708 EndpointDescriptor::EndpointDescriptor(InterfaceDescriptor
& interface
, int endpoint
)
709 : m_impl(new EndpointDescriptorImpl()),
714 // Copy the descriptor
715 m_impl
->m_desc
= interface
.m_impl
->m_desc
.endpoint
[endpoint
];
716 dout(" endpoint_desc #" << std::dec
<< endpoint
<< " loaded"
717 << "\nbLength: " << std::dec
<< (unsigned ) m_impl
->m_desc
.bLength
718 << "\nbDescriptorType: " << std::dec
<< (unsigned ) m_impl
->m_desc
.bDescriptorType
719 << "\nbEndpointAddress: 0x" << std::hex
<< (unsigned ) m_impl
->m_desc
.bEndpointAddress
720 << "\nbmAttributes: 0x" << std::hex
<< (unsigned ) m_impl
->m_desc
.bmAttributes
721 << "\nwMaxPacketSize: " << std::dec
<< (unsigned ) m_impl
->m_desc
.wMaxPacketSize
722 << "\nbInterval: " << std::dec
<< (unsigned ) m_impl
->m_desc
.bInterval
723 << "\nbRefresh: " << std::dec
<< (unsigned ) m_impl
->m_desc
.bRefresh
724 << "\nbSynchAddress: " << std::dec
<< (unsigned ) m_impl
->m_desc
.bSynchAddress
728 m_read
= ((m_impl
->m_desc
.bEndpointAddress
& USB_ENDPOINT_DIR_MASK
) != 0);
729 m_addr
= (m_impl
->m_desc
.bEndpointAddress
& USB_ENDPOINT_ADDRESS_MASK
);
730 int type
= (m_impl
->m_desc
.bmAttributes
& USB_ENDPOINT_TYPE_MASK
);
731 m_type
= static_cast<Usb::EndpointDescriptor::EpType
>(type
);
733 // just for debugging purposes, check for extra descriptors, and
734 // dump them to dout if they exist
735 if( m_impl
->m_desc
.extra
) {
736 dout("while parsing endpoint descriptor, found a block of extra descriptors:");
737 Barry::Data
data(m_impl
->m_desc
.extra
, m_impl
->m_desc
.extralen
);
742 EndpointDescriptor::~EndpointDescriptor()