debian: fixed broken debian/*.install target files
[barry/progweb.git] / src / usbwrap_libusb_1_0.cc
blob5cf4b30b73a2de2e3f80528834357caa2ba22746
1 ///
2 /// \file usbwrap_libusb_1_0.cc
3 /// USB API wrapper for libusb version 1.0
4 ///
6 /*
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"
27 #include "debug.h"
28 #include "data.h"
29 #include <errno.h>
30 #include <sstream>
31 #include <iostream>
32 #include <algorithm>
34 #ifndef __DEBUG_MODE__
35 #define __DEBUG_MODE__
36 #endif
37 #include "debug.h"
39 namespace Usb {
41 // helper functions to make deleting pointers in maps and vectors easier
42 template<typename T> static void deletePtr(T* ptr)
44 delete ptr;
47 template<typename K, typename T> static void deleteMapPtr(std::pair<K,T*> ptr)
49 delete ptr.second;
52 // lookup table translating LIBUSB errors to standard Linux errors
53 static const struct {
54 int libusb;
55 int system;
56 } errorCodes[] = {
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 ///////////////////////////////////////////////////////////////////////////////
84 // Static functions
86 std::string LibraryInterface::GetLastErrorString(int libusb_errcode)
88 switch( libusb_errcode )
90 case LIBUSB_SUCCESS:
91 return "Success";
92 case LIBUSB_ERROR_IO:
93 return "IO Error";
94 case LIBUSB_ERROR_INVALID_PARAM:
95 return "Invalid parameter";
96 case LIBUSB_ERROR_ACCESS:
97 return "Access";
98 case LIBUSB_ERROR_NO_DEVICE:
99 return "No device";
100 case LIBUSB_ERROR_NOT_FOUND:
101 return "Not found";
102 case LIBUSB_ERROR_BUSY:
103 return "Busy";
104 case LIBUSB_ERROR_TIMEOUT:
105 return "Timeout";
106 case LIBUSB_ERROR_OVERFLOW:
107 return "Overflow";
108 case LIBUSB_ERROR_PIPE:
109 return "Pipe";
110 case LIBUSB_ERROR_INTERRUPTED:
111 return "Interrupted";
112 case LIBUSB_ERROR_NO_MEM:
113 return "No memory";
114 case LIBUSB_ERROR_NOT_SUPPORTED:
115 return "Not supported";
116 case LIBUSB_ERROR_OTHER:
117 return "Other";
118 default:
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
132 return 0;
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)
140 // after Init()
141 return libusb_init(&libusbctx);
144 void LibraryInterface::Uninit()
146 libusb_exit(libusbctx);
149 void LibraryInterface::SetDataDump(bool data_dump_mode)
151 if( !libusbctx ) {
152 Init();
154 if( !libusbctx ) {
155 // Failed to init, can't do much but return
156 dout("SetDataDump: Failed to initialise libusb");
157 return;
159 if( data_dump_mode )
160 libusb_set_debug(libusbctx, 3);
161 else
162 libusb_set_debug(libusbctx, 0);
165 ///////////////////////////////////////////////////////////////////////////////
166 // DeviceIDImpl
168 DeviceIDImpl::DeviceIDImpl(libusb_device *dev)
169 : m_dev(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();
180 formatter << "-"
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 ///////////////////////////////////////////////////////////////////////////////
191 // DeviceID
193 DeviceID::DeviceID(DeviceIDImpl* impl)
194 : m_impl(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);
223 if( err == 0 )
224 ret = desc.idProduct;
225 return ret;
228 ///////////////////////////////////////////////////////////////////////////////
229 // DeviceList
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;
260 int err;
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) )
269 continue;
271 // search for specific device
272 if( devname && atoi(devname) != libusb_get_device_address(dev) )
273 continue;
275 struct libusb_device_descriptor desc;
276 err = libusb_get_device_descriptor(dev, &desc);
277 if( err ) {
278 dout("Failed to get device descriptor: " << err);
279 continue;
282 // is there a match?
283 if( desc.idVendor == vendor &&
284 ( desc.idProduct == product ||
285 product == PRODUCT_ANY )) {
286 ret.push_back(*iter);
290 return ret;
293 ///////////////////////////////////////////////////////////////////////////////
294 // Device
296 Device::Device(const Usb::DeviceID& id, int timeout)
297 : m_id(id),
298 m_timeout(timeout)
300 dout("libusb_open(" << std::dec << id.m_impl.get() << ")");
301 if( !&(*id.m_impl) )
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));
305 m_lasterror = err;
306 if( err )
307 throw Error("open failed");
310 Device::~Device()
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);
320 m_lasterror = ret;
321 return ret >= 0;
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);
328 m_lasterror = ret;
329 return ret >= 0;
332 bool Device::Reset()
334 dout("libusb_reset_device(" << std::dec << m_handle->m_handle << ")");
335 int ret = libusb_reset_device(m_handle->m_handle);
336 m_lasterror = ret;
337 return ret == 0;
340 bool Device::BulkRead(int ep, Barry::Data &data, int timeout)
342 ddout("BulkRead to endpoint 0x" << std::hex << ep << ":\n" << data);
343 int ret;
344 do {
345 int transferred = 0;
346 data.QuickZap();
347 ret = libusb_bulk_transfer(m_handle->m_handle,
348 ep |= LIBUSB_ENDPOINT_IN,
349 data.GetBuffer(), data.GetBufSize(),
350 &transferred,
351 timeout == -1 ? m_timeout : timeout);
352 if( ret < 0 && ret != LIBUSB_ERROR_INTERRUPTED ) {
353 m_lasterror = ret;
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");
359 else
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 );
370 return ret >= 0;
373 bool Device::BulkWrite(int ep, const Barry::Data &data, int timeout)
375 ddout("BulkWrite to endpoint 0x" << std::hex << ep << ":\n" << data);
376 int ret;
377 do {
378 int transferred;
379 ret = libusb_bulk_transfer(m_handle->m_handle,
380 ep | LIBUSB_ENDPOINT_OUT,
381 const_cast<unsigned char*>(data.GetData()),
382 data.GetSize(),
383 &transferred,
384 timeout == -1 ? m_timeout : timeout);
385 if( ret < 0 && ret != LIBUSB_ERROR_INTERRUPTED ) {
386 m_lasterror = ret;
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");
394 if( ret >= 0 &&
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 );
404 return ret >= 0;
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);
412 #endif
413 int ret;
414 do {
415 int transferred;
416 ret = libusb_bulk_transfer(m_handle->m_handle,
417 ep | LIBUSB_ENDPOINT_OUT,
418 (unsigned char*)const_cast<void*>(data),
419 size,
420 &transferred,
421 timeout == -1 ? m_timeout : timeout);
422 if( ret < 0 && ret != LIBUSB_ERROR_INTERRUPTED ) {
423 m_lasterror = ret;
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 );
440 return ret >= 0;
443 bool Device::InterruptRead(int ep, Barry::Data &data, int timeout)
445 ddout("InterruptRead to endpoint 0x" << std::hex << ep << ":\n" << data);
446 int ret;
447 do {
448 int transferred = 0;
449 data.QuickZap();
450 ret = libusb_interrupt_transfer(m_handle->m_handle,
451 ep | LIBUSB_ENDPOINT_IN,
452 data.GetBuffer(), data.GetBufSize(),
453 &transferred,
454 timeout == -1 ? m_timeout : timeout);
455 if( ret < 0 && ret != LIBUSB_ERROR_INTERRUPTED ) {
456 m_lasterror = ret;
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");
462 else
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 );
473 return ret >= 0;
477 bool Device::InterruptWrite(int ep, const Barry::Data &data, int timeout)
479 ddout("InterruptWrite to endpoint 0x" << std::hex << ep << ":\n" << data);
480 int ret;
481 do {
482 int transferred;
483 ret = libusb_interrupt_transfer(m_handle->m_handle,
484 ep | LIBUSB_ENDPOINT_OUT,
485 const_cast<unsigned char*>(data.GetData()),
486 data.GetSize(),
487 &transferred,
488 timeout == -1 ? m_timeout : timeout);
489 if( ret < 0 && ret != LIBUSB_ERROR_INTERRUPTED ) {
490 m_lasterror = ret;
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");
498 if( ret >= 0 &&
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 );
508 return ret >= 0;
512 // BulkDrain
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)
519 try {
520 Barry::Data data;
521 while( BulkRead(ep, data, timeout) )
524 catch( Usb::Error & ) {}
528 // GetConfiguration
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)
536 int config = 0;
537 int result = libusb_get_configuration(m_handle->m_handle, &config);
538 if( result >= 0 )
539 cfg = config;
540 m_lasterror = result;
541 return result >= 0;
544 // Returns the current power level of the device, or 0 if unknown
545 int Device::GetPowerLevel()
547 struct libusb_config_descriptor* cfg = NULL;
548 int ret = 0;
549 int result = libusb_get_active_config_descriptor(m_id.m_impl->m_dev, &cfg);
550 m_lasterror = result;
551 if( result == 0 ) {
552 ret = cfg->MaxPower;
555 if( cfg )
556 libusb_free_config_descriptor(cfg);
558 return ret;
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;
566 return result >= 0;
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;
577 return result >= 0;
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);
584 if( ret == 0 ) {
585 for( int i = 0; cfg->interface && i < cfg->bNumInterfaces; ++i ) {
586 const struct libusb_interface& iface = cfg->interface[i];
587 for( int j = 0;
588 iface.altsetting && j < iface.num_altsetting;
589 ++j ) {
590 const struct libusb_interface_descriptor& id =
591 iface.altsetting[j];
592 if( id.bInterfaceClass == ifaceClass )
593 return id.bInterfaceNumber;
598 if( cfg )
599 libusb_free_config_descriptor(cfg);
601 return ret;
604 ///////////////////////////////////////////////////////////////////////////////
605 // Interface
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);
612 if( ret < 0 )
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);
624 // SetAltInterface
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,
635 m_iface,
636 altSetting);
637 m_dev.SetLastError(result);
638 return result >= 0;
643 //////////////////////////////////////////////////////////////////
644 // DeviceDescriptor
646 DeviceDescriptor::DeviceDescriptor(DeviceID& devid)
647 : m_impl(new DeviceDescriptorImpl())
649 if( !devid.m_impl.get() ) {
650 dout("DeviceDescriptor: empty devid");
651 return;
653 m_impl->m_devid = devid;
654 int ret = libusb_get_device_descriptor(devid.m_impl->m_dev, &m_impl->m_desc);
655 if( ret != 0 ) {
656 dout("Failed to read device descriptor with err: " << ret);
657 return;
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
674 << "\n"
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();
681 ptr.release();
685 DeviceDescriptor::~DeviceDescriptor()
687 // Delete any pointers in the vector
688 std::for_each(begin(),
689 end(),
690 deleteMapPtr<int, ConfigDescriptor>);
693 ///////////////////////////////////////////////////////////////////
694 // ConfigDescriptor
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));
702 if( ret != 0 ) {
703 dout("Failed to read config descriptor with err: " << ret);
704 return;
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
716 << "\n"
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);
724 dout(data);
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
735 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();
741 ptr.release();
746 ConfigDescriptor::~ConfigDescriptor()
748 // Delete any pointers in the vector
749 std::for_each(begin(),
750 end(),
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
772 m_impl->m_desc =
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
786 << "\n"
789 if( !m_impl->m_desc->endpoint ) {
790 dout("InterfaceDescriptor: empty interface pointer");
791 return;
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());
799 ptr.release();
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);
807 dout(data);
811 InterfaceDescriptor::~InterfaceDescriptor()
813 // Delete any pointers in the vector
814 std::for_each(begin(),
815 end(),
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()),
839 m_read(false),
840 m_addr(0),
841 m_type(InvalidType)
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
855 << "\n"
857 // Set up variables
858 m_read = ((m_impl->m_desc->bEndpointAddress & LIBUSB_ENDPOINT_DIR_MASK) ==
859 LIBUSB_ENDPOINT_IN);
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);
869 dout(data);
873 EndpointDescriptor::~EndpointDescriptor()
877 } // namespace Usb