desktop/debian: moved bsyncjail to pkglibexecdir
[barry/progweb.git] / src / usbwrap_libusb.cc
blob842b8abcc16ab6d353b7b303d9ff4dc5b2baa608
1 ///
2 /// \file usbwrap_libusb.cc
3 /// USB API wrapper for libusb version 0.1
4 ///
6 /*
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.
23 #include "usbwrap_libusb.h"
25 #include "debug.h"
26 #include "data.h"
27 #include <errno.h>
28 #include <string.h>
29 #include <iostream>
30 #include <sstream>
31 #include <algorithm>
33 #ifndef __DEBUG_MODE__
34 #define __DEBUG_MODE__
35 #endif
36 #include "debug.h"
38 namespace Usb {
40 // helper function to make deleting pointers in maps and vectors easier
41 template<typename T> static void deletePtr(T* ptr) {
42 delete ptr;
45 template<typename K, typename T> static void deleteMapPtr(std::pair<K,T*> ptr) {
46 delete ptr.second;
49 ///////////////////////////////////////////////////////////////////////////////
50 // Static functions
52 std::string LibraryInterface::GetLastErrorString(int /*libusb_errcode*/)
54 // Errcode is unused by libusb, so just call the last error
55 return std::string(usb_strerror());
58 int LibraryInterface::TranslateErrcode(int libusb_errcode)
60 // libusb errcode == system errcode
61 return libusb_errcode;
64 bool LibraryInterface::Init(int *libusb_errno)
66 // if the environment variable USB_DEBUG is set, that
67 // level value will be used instead of our 9 below...
68 // if you need to *force* this to 9, call SetDataDump(true)
69 // after Init()
70 usb_init();
71 // Can never fail, so return success
72 return true;
75 void LibraryInterface::Uninit()
77 // Nothing to do
80 void LibraryInterface::SetDataDump(bool data_dump_mode)
82 if( data_dump_mode )
83 usb_set_debug(9);
84 else
85 usb_set_debug(0);
88 ///////////////////////////////////////////////////////////////////////////////
89 // DeviceID
91 DeviceID::DeviceID(DeviceIDImpl* impl)
92 : m_impl(impl)
96 DeviceID::~DeviceID()
100 const char* DeviceID::GetBusName() const
102 return m_impl->m_dev->bus->dirname;
105 uint16_t DeviceID::GetNumber() const
107 return m_impl->m_dev->devnum;
110 const char* DeviceID::GetFilename() const
112 return m_impl->m_dev->filename;
115 uint16_t DeviceID::GetIdProduct() const
117 return m_impl->m_dev->descriptor.idProduct;
120 std::string DeviceID::GetUsbName() const
122 // for libusb 0.1, we need both the bus name and the filename
123 // and we stay away from the product ID, since that requires
124 // communication with the device, which may not be possible
125 // in error conditions.
126 std::ostringstream oss;
127 oss << GetBusName() << ":" << GetFilename();
128 return oss.str();
131 ///////////////////////////////////////////////////////////////////////////////
132 // DeviceList
134 DeviceList::DeviceList()
135 : m_impl(new DeviceListImpl())
137 // Work out what devices are on the bus at the moment
138 usb_find_busses();
139 usb_find_devices();
140 struct usb_bus* busses = usb_get_busses();
141 for( ; busses; busses = busses->next ) {
142 struct usb_device* dev = busses->devices;
143 for( ; dev; dev = dev->next ) {
144 // Add the device to the list of devices
145 std::auto_ptr<DeviceIDImpl> impl( new DeviceIDImpl() );
146 impl->m_dev = dev;
147 DeviceID devID(impl.release());
148 m_impl->m_devices.push_back(devID);
153 DeviceList::~DeviceList()
158 static bool ToNum(const char *str, long &num)
160 char *end = 0;
161 num = strtol(str, &end, 10);
162 return num >= 0 && // no negative numbers
163 num != LONG_MIN && num != LONG_MAX && // no overflow
164 str != end && *end == '\0'; // whole string valid
168 // Linux treats bus and device path names as numbers, sometimes left
169 // padded with zeros. Other platforms, such as Windows, use strings,
170 // such as "bus-1" or similar.
172 // Here we try to convert each string to a number, and if successful,
173 // compare them. If unable to convert, then compare as strings.
174 // This way, "3" == "003" and "bus-foobar" == "bus-foobar".
176 static bool NameCompare(const char *n1, const char *n2)
178 long l1, l2;
179 if( ToNum(n1, l1) && ToNum(n2, l2) ) {
180 return l1 == l2;
182 else {
183 return strcmp(n1, n2) == 0;
187 std::vector<DeviceID> DeviceList::MatchDevices(int vendor, int product,
188 const char *busname, const char *devname)
190 std::vector<DeviceID> ret;
192 std::vector<DeviceID>::iterator iter = m_impl->m_devices.begin();
194 for( ; iter != m_impl->m_devices.end() ; ++iter ) {
195 struct usb_device* dev = iter->m_impl->m_dev;
197 // only search on given bus
198 if( busname && !NameCompare(busname, dev->bus->dirname) )
199 continue;
201 // search for specific device
202 if( devname && !NameCompare(devname, dev->filename) )
203 continue;
205 // is there a match?
206 if( dev->descriptor.idVendor == vendor &&
207 ( dev->descriptor.idProduct == product ||
208 product == PRODUCT_ANY )) {
209 ret.push_back(*iter);
213 return ret;
216 ///////////////////////////////////////////////////////////////////////////////
217 // Device
219 Device::Device(const Usb::DeviceID& id, int timeout)
220 : m_id(id),
221 m_timeout(timeout)
223 dout("usb_open(" << std::dec << id.m_impl.get() << ")");
224 if( !id.m_impl.get() )
225 throw Error("invalid USB device ID");
226 m_handle.reset(new DeviceHandle());
227 m_handle->m_handle = usb_open(id.m_impl->m_dev);
228 if( !m_handle->m_handle )
229 throw Error("Failed to open USB device. Please check your system's USB device permissions.");
232 Device::~Device()
234 dout("usb_close(" << std::dec << m_handle->m_handle << ")");
235 usb_close(m_handle->m_handle);
238 bool Device::SetConfiguration(unsigned char cfg)
240 dout("usb_set_configuration(" << std::dec << m_handle->m_handle << ", 0x" << std::hex << (unsigned int) cfg << ")");
241 int ret = usb_set_configuration(m_handle->m_handle, cfg);
242 m_lasterror = ret;
243 return ret >= 0;
246 bool Device::ClearHalt(int ep)
248 dout("usb_clear_halt(" << std::dec << m_handle->m_handle << ", 0x" << std::hex << ep << ")");
249 int ret = usb_clear_halt(m_handle->m_handle, ep);
250 m_lasterror = ret;
251 return ret >= 0;
254 bool Device::Reset()
256 dout("usb_reset(" << std::dec << m_handle->m_handle << ")");
257 int ret = usb_reset(m_handle->m_handle);
258 m_lasterror = ret;
259 return ret == 0;
262 bool Device::BulkRead(int ep, Barry::Data &data, int timeout)
264 int ret;
265 do {
266 data.QuickZap();
267 ret = usb_bulk_read(m_handle->m_handle, ep,
268 (char*) data.GetBuffer(), data.GetBufSize(),
269 timeout == -1 ? m_timeout : timeout);
270 if( ret < 0 && ret != -EINTR && ret != -EAGAIN ) {
271 m_lasterror = ret;
272 if( ret == -ETIMEDOUT )
273 throw Timeout(ret, "Timeout in usb_bulk_read");
274 else {
275 std::ostringstream oss;
276 oss << "Error in usb_bulk_read("
277 << m_handle->m_handle << ", "
278 << ep << ", buf, "
279 << data.GetBufSize() << ")";
280 throw Error(ret, oss.str());
283 else if( ret > 0 )
284 data.ReleaseBuffer(ret);
285 } while( ret == -EINTR || ret == -EAGAIN );
287 return ret >= 0;
290 bool Device::BulkWrite(int ep, const Barry::Data &data, int timeout)
292 ddout("BulkWrite to endpoint 0x" << std::hex << ep << ":\n" << data);
293 int ret;
294 do {
295 ret = usb_bulk_write(m_handle->m_handle, ep,
296 (char*) data.GetData(), data.GetSize(),
297 timeout == -1 ? m_timeout : timeout);
298 if( ret < 0 && ret != -EINTR && ret != -EAGAIN ) {
299 m_lasterror = ret;
300 if( ret == -ETIMEDOUT )
301 throw Timeout(ret, "Timeout in usb_bulk_write (1)");
302 else
303 throw Error(ret, "Error in usb_bulk_write (1)");
305 } while( ret == -EINTR || ret == -EAGAIN );
307 return ret >= 0;
310 bool Device::BulkWrite(int ep, const void *data, size_t size, int timeout)
312 #ifdef __DEBUG_MODE__
313 Barry::Data dump(data, size);
314 ddout("BulkWrite to endpoint 0x" << std::hex << ep << ":\n" << dump);
315 #endif
317 int ret;
318 do {
319 ret = usb_bulk_write(m_handle->m_handle, ep,
320 (char*) data, size,
321 timeout == -1 ? m_timeout : timeout);
322 if( ret < 0 && ret != -EINTR && ret != -EAGAIN ) {
323 m_lasterror = ret;
324 if( ret == -ETIMEDOUT )
325 throw Timeout(ret, "Timeout in usb_bulk_write (2)");
326 else
327 throw Error(ret, "Error in usb_bulk_write (2)");
329 } while( ret == -EINTR || ret == -EAGAIN );
331 return ret >= 0;
334 bool Device::InterruptRead(int ep, Barry::Data &data, int timeout)
336 int ret;
337 do {
338 data.QuickZap();
339 ret = usb_interrupt_read(m_handle->m_handle, ep,
340 (char*) data.GetBuffer(), data.GetBufSize(),
341 timeout == -1 ? m_timeout : timeout);
342 if( ret < 0 && ret != -EINTR && ret != -EAGAIN ) {
343 m_lasterror = ret;
344 if( ret == -ETIMEDOUT )
345 throw Timeout(ret, "Timeout in usb_interrupt_read");
346 else
347 throw Error(ret, "Error in usb_interrupt_read");
349 else if( ret > 0 )
350 data.ReleaseBuffer(ret);
351 } while( ret == -EINTR || ret == -EAGAIN );
353 return ret >= 0;
356 bool Device::InterruptWrite(int ep, const Barry::Data &data, int timeout)
358 ddout("InterruptWrite to endpoint 0x" << std::hex << ep << ":\n" << data);
360 int ret;
361 do {
362 ret = usb_interrupt_write(m_handle->m_handle, ep,
363 (char*) data.GetData(), data.GetSize(),
364 timeout == -1 ? m_timeout : timeout);
365 if( ret < 0 && ret != -EINTR && ret != -EAGAIN ) {
366 m_lasterror = ret;
367 if( ret == -ETIMEDOUT )
368 throw Timeout(ret, "Timeout in usb_interrupt_write");
369 else
370 throw Error(ret, "Error in usb_interrupt_write");
372 } while( ret == -EINTR || ret == -EAGAIN );
374 return ret >= 0;
378 // BulkDrain
380 /// Reads anything available on the given endpoint, with a low timeout,
381 /// in order to clear any pending reads.
383 void Device::BulkDrain(int ep, int timeout)
385 try {
386 Barry::Data data;
387 while( BulkRead(ep, data, timeout) )
390 catch( Usb::Error & ) {}
394 // GetConfiguration
396 /// Uses the GET_CONFIGURATION control message to determine the currently
397 /// selected USB configuration, returning it in the cfg argument.
398 /// If unsuccessful, returns false.
400 bool Device::GetConfiguration(unsigned char &cfg)
402 int result = usb_control_msg(m_handle->m_handle, 0x80, USB_REQ_GET_CONFIGURATION, 0, 0,
403 (char*) &cfg, 1, m_timeout);
404 m_lasterror = result;
405 return result >= 0;
408 // Returns the current power level of the device, or 0 if unknown
409 int Device::GetPowerLevel()
411 if( !m_id.m_impl->m_dev->config ||
412 !m_id.m_impl->m_dev->descriptor.bNumConfigurations < 1 )
413 return 0;
415 return m_id.m_impl->m_dev->config[0].MaxPower;
418 bool Device::IsAttachKernelDriver(int iface)
420 int ret;
421 char buffer[64];
423 #if LIBUSB_HAS_GET_DRIVER_NP
424 ret = usb_get_driver_np(m_handle->m_handle, iface, buffer, sizeof(buffer));
425 if (ret == 0) {
426 dout("interface (" << m_handle->m_handle << ", 0x" << std::hex << iface
427 << ") already claimed by driver \"" << buffer << "\"");
428 return true;
430 m_lasterror = ret;
431 #else
432 m_lasterror = -ENOSYS;
433 #endif
435 return false;
438 // Requests that the kernel driver is detached, returning false on failure
439 bool Device::DetachKernelDriver(int iface)
441 #if LIBUSB_HAS_DETACH_KERNEL_DRIVER_NP
442 int result = usb_detach_kernel_driver_np(m_handle->m_handle, iface);
443 m_lasterror = result;
444 return result >= 0;
445 #else
446 m_lasterror = -ENOSYS;
447 return false;
448 #endif
451 // Sends a control message to the device, returning false on failure
452 bool Device::ControlMsg(int requesttype, int request, int value,
453 int index, char *bytes, int size, int timeout)
455 int result = usb_control_msg(m_handle->m_handle,
456 requesttype, request, value, index,
457 bytes, size, timeout);
458 m_lasterror = result;
459 return result >= 0;
463 int Device::FindInterface(int ifaceClass)
465 struct usb_config_descriptor *cfg = m_id.m_impl->m_dev->config;
467 if( cfg ) {
469 for( unsigned i = 0; cfg->interface && i < cfg->bNumInterfaces; i++ ) {
470 struct usb_interface *iface = &cfg->interface[i];
471 for( int a = 0; iface->altsetting && a < iface->num_altsetting; a++ ) {
472 struct usb_interface_descriptor *id = &iface->altsetting[a];
473 if( id->bInterfaceClass == ifaceClass )
474 return id->bInterfaceNumber;
479 return -1;
483 ///////////////////////////////////////////////////////////////////////////////
484 // Interface
486 Interface::Interface(Device &dev, int iface)
487 : m_dev(dev), m_iface(iface)
489 dout("usb_claim_interface(" << dev.GetHandle()->m_handle << ", 0x" << std::hex << iface << ")");
490 int ret = usb_claim_interface(dev.GetHandle()->m_handle, iface);
491 if( ret < 0 )
492 throw Error(ret, "claim interface failed");
495 Interface::~Interface()
497 dout("usb_release_interface(" << m_dev.GetHandle()->m_handle << ", 0x" << std::hex << m_iface << ")");
498 usb_release_interface(m_dev.GetHandle()->m_handle, m_iface);
502 // SetAltInterface
504 /// Uses the usb_set_altinterface() function to set the currently
505 /// selected USB alternate setting of the current interface.
506 /// The iface parameter passed in should be a value specified
507 /// in the bAlternateSetting descriptor field.
508 /// If unsuccessful, returns false.
510 bool Interface::SetAltInterface(int altSetting)
512 int result = usb_set_altinterface(m_dev.GetHandle()->m_handle, altSetting);
513 m_dev.SetLastError(result);
514 return result >= 0;
517 //////////////////////////////////////////////////////////////////
518 // DeviceDescriptor
520 DeviceDescriptor::DeviceDescriptor(DeviceID& devid)
521 : m_impl(new DeviceDescriptorImpl())
523 if( !devid.m_impl.get() ) {
524 dout("DeviceDescriptor: empty devid");
525 return;
527 // Copy the descriptor over to our memory
528 m_impl->m_dev = devid.m_impl->m_dev;
529 m_impl->m_desc = devid.m_impl->m_dev->descriptor;
530 dout("device_desc loaded"
531 << "\nbLength: " << std::dec << (unsigned int) m_impl->m_desc.bLength
532 << "\nbDescriptorType: " << std::dec << (unsigned int) m_impl->m_desc.bDescriptorType
533 << "\nbcdUSB: 0x" << std::hex << (unsigned int) m_impl->m_desc.bcdUSB
534 << "\nbDeviceClass: " << std::dec << (unsigned int) m_impl->m_desc.bDeviceClass
535 << "\nbDeviceSubClass: " << std::dec << (unsigned int) m_impl->m_desc.bDeviceSubClass
536 << "\nbDeviceProtocol: " << std::dec << (unsigned int) m_impl->m_desc.bDeviceProtocol
537 << "\nbMaxPacketSize0: " << std::dec << (unsigned int) m_impl->m_desc.bMaxPacketSize0
538 << "\nidVendor: 0x" << std::hex << (unsigned int) m_impl->m_desc.idVendor
539 << "\nidProduct: 0x" << std::hex << (unsigned int) m_impl->m_desc.idProduct
540 << "\nbcdDevice: 0x" << std::hex << (unsigned int) m_impl->m_desc.bcdDevice
541 << "\niManufacturer: " << std::dec << (unsigned int) m_impl->m_desc.iManufacturer
542 << "\niProduct: " << std::dec << (unsigned int) m_impl->m_desc.iProduct
543 << "\niSerialNumber: " << std::dec << (unsigned int) m_impl->m_desc.iSerialNumber
544 << "\nbNumConfigurations: " << std::dec << (unsigned int) m_impl->m_desc.bNumConfigurations
545 << "\n"
548 // Create all the configs
549 for( int i = 0; i < m_impl->m_desc.bNumConfigurations; ++i ) {
550 std::auto_ptr<ConfigDescriptor> ptr(new ConfigDescriptor(*this, i));
551 (*this)[ptr->GetNumber()] = ptr.get();
552 ptr.release();
556 DeviceDescriptor::~DeviceDescriptor()
558 // Delete any pointers in the map
559 std::for_each(begin(),
560 end(),
561 deleteMapPtr<int, ConfigDescriptor>);
564 ///////////////////////////////////////////////////////////////////
565 // ConfigDescriptor
567 ConfigDescriptor::ConfigDescriptor(DeviceDescriptor& dev, int cfgnumber)
568 : m_impl(new ConfigDescriptorImpl())
570 // Copy the config descriptor locally
571 m_impl->m_desc = dev.m_impl->m_dev->config[cfgnumber];
572 dout(" config_desc #" << std::dec << cfgnumber << " loaded"
573 << "\nbLength: " << std::dec << (unsigned int) m_impl->m_desc.bLength
574 << "\nbDescriptorType: " << std::dec << (unsigned int) m_impl->m_desc.bDescriptorType
575 << "\nwTotalLength: " << std::dec << (unsigned int) m_impl->m_desc.wTotalLength
576 << "\nbNumInterfaces: " << std::dec << (unsigned int) m_impl->m_desc.bNumInterfaces
577 << "\nbConfigurationValue: " << std::dec << (unsigned int) m_impl->m_desc.bConfigurationValue
578 << "\niConfiguration: " << std::dec << (unsigned int) m_impl->m_desc.iConfiguration
579 << "\nbmAttributes: 0x" << std::hex << (unsigned int) m_impl->m_desc.bmAttributes
580 << "\nMaxPower: " << std::dec << (unsigned int) m_impl->m_desc.MaxPower
581 << "\n"
584 // just for debugging purposes, check for extra descriptors, and
585 // dump them to dout if they exist
586 if( m_impl->m_desc.extra ) {
587 dout("while parsing config descriptor, found a block of extra descriptors:");
588 Barry::Data data(m_impl->m_desc.extra, m_impl->m_desc.extralen);
589 dout(data);
592 // Create all the interfaces
593 for( int i = 0; i < m_impl->m_desc.bNumInterfaces; ++i ) {
594 struct usb_interface* interface = &(m_impl->m_desc.interface[i]);
595 if( !interface->altsetting ) {
596 dout("ConfigDescriptor: empty altsetting");
597 // some devices are buggy and return a higher bNumInterfaces
598 // than the number of interfaces available... in this case
599 // we just skip and continue
600 continue;
602 for( int j = 0; j < interface->num_altsetting; ++j ) {
603 std::auto_ptr<InterfaceDescriptor> ptr(
604 new InterfaceDescriptor(*this, i, j));
605 (*this)[ptr->GetNumber()] = ptr.get();
606 ptr.release();
611 ConfigDescriptor::~ConfigDescriptor()
613 // Delete any pointers in the map
614 std::for_each(begin(),
615 end(),
616 deleteMapPtr<int, InterfaceDescriptor>);
619 uint8_t ConfigDescriptor::GetNumber() const {
620 return m_impl->m_desc.bConfigurationValue;
623 /////////////////////////////////////////////////////////////////////////
624 // InterfaceDescriptor
626 InterfaceDescriptor::InterfaceDescriptor(ConfigDescriptor& cfg,
627 int interface, int altsetting)
628 : m_impl(new InterfaceDescriptorImpl())
630 // Copy the descriptor
631 m_impl->m_desc = cfg.m_impl->m_desc
632 .interface[interface]
633 .altsetting[altsetting];
634 dout(" interface_desc #" << std::dec << interface << " loaded"
635 << "\nbLength: " << std::dec << (unsigned) m_impl->m_desc.bLength
636 << "\nbDescriptorType: " << std::dec << (unsigned) m_impl->m_desc.bDescriptorType
637 << "\nbInterfaceNumber: " << std::dec << (unsigned) m_impl->m_desc.bInterfaceNumber
638 << "\nbAlternateSetting: " << std::dec << (unsigned) m_impl->m_desc.bAlternateSetting
639 << "\nbNumEndpoints: " << std::dec << (unsigned) m_impl->m_desc.bNumEndpoints
640 << "\nbInterfaceClass: " << std::dec << (unsigned) m_impl->m_desc.bInterfaceClass
641 << "\nbInterfaceSubClass: " << std::dec << (unsigned) m_impl->m_desc.bInterfaceSubClass
642 << "\nbInterfaceProtocol: " << std::dec << (unsigned) m_impl->m_desc.bInterfaceProtocol
643 << "\niInterface: " << std::dec << (unsigned) m_impl->m_desc.iInterface
644 << "\n"
647 if( !m_impl->m_desc.endpoint ) {
648 dout("InterfaceDescriptor: empty interface pointer");
649 return;
652 // Create all the endpoints
653 for( int i = 0; i < m_impl->m_desc.bNumEndpoints; ++i ) {
654 std::auto_ptr<EndpointDescriptor> ptr (
655 new EndpointDescriptor(*this, i));
656 this->push_back(ptr.get());
657 ptr.release();
660 // just for debugging purposes, check for extra descriptors, and
661 // dump them to dout if they exist
662 if( m_impl->m_desc.extra ) {
663 dout("while parsing interface descriptor, found a block of extra descriptors:");
664 Barry::Data data(m_impl->m_desc.extra, m_impl->m_desc.extralen);
665 dout(data);
669 InterfaceDescriptor::~InterfaceDescriptor()
671 // Delete any pointers in the vector
672 std::for_each(begin(),
673 end(),
674 deletePtr<EndpointDescriptor>);
677 uint8_t InterfaceDescriptor::GetClass() const
679 return m_impl->m_desc.bInterfaceClass;
682 uint8_t InterfaceDescriptor::GetNumber() const
684 return m_impl->m_desc.bInterfaceNumber;
687 uint8_t InterfaceDescriptor::GetAltSetting() const
689 return m_impl->m_desc.bAlternateSetting;
692 /////////////////////////////////////////////////////////////////////////////////
693 // EndpointDescriptor
695 EndpointDescriptor::EndpointDescriptor(InterfaceDescriptor& interface, int endpoint)
696 : m_impl(new EndpointDescriptorImpl()),
697 m_read(false),
698 m_addr(0),
699 m_type(InvalidType)
701 // Copy the descriptor
702 m_impl->m_desc = interface.m_impl->m_desc.endpoint[endpoint];
703 dout(" endpoint_desc #" << std::dec << endpoint << " loaded"
704 << "\nbLength: " << std::dec << (unsigned ) m_impl->m_desc.bLength
705 << "\nbDescriptorType: " << std::dec << (unsigned ) m_impl->m_desc.bDescriptorType
706 << "\nbEndpointAddress: 0x" << std::hex << (unsigned ) m_impl->m_desc.bEndpointAddress
707 << "\nbmAttributes: 0x" << std::hex << (unsigned ) m_impl->m_desc.bmAttributes
708 << "\nwMaxPacketSize: " << std::dec << (unsigned ) m_impl->m_desc.wMaxPacketSize
709 << "\nbInterval: " << std::dec << (unsigned ) m_impl->m_desc.bInterval
710 << "\nbRefresh: " << std::dec << (unsigned ) m_impl->m_desc.bRefresh
711 << "\nbSynchAddress: " << std::dec << (unsigned ) m_impl->m_desc.bSynchAddress
712 << "\n"
714 // Set up variables
715 m_read = ((m_impl->m_desc.bEndpointAddress & USB_ENDPOINT_DIR_MASK) != 0);
716 m_addr = (m_impl->m_desc.bEndpointAddress & USB_ENDPOINT_ADDRESS_MASK);
717 int type = (m_impl->m_desc.bmAttributes & USB_ENDPOINT_TYPE_MASK);
718 m_type = static_cast<Usb::EndpointDescriptor::EpType>(type);
720 // just for debugging purposes, check for extra descriptors, and
721 // dump them to dout if they exist
722 if( m_impl->m_desc.extra ) {
723 dout("while parsing endpoint descriptor, found a block of extra descriptors:");
724 Barry::Data data(m_impl->m_desc.extra, m_impl->m_desc.extralen);
725 dout(data);
729 EndpointDescriptor::~EndpointDescriptor()
733 } // namespace Usb