lib: remove the message about attempt to detach from libusb code
[barry/progweb.git] / src / usbwrap_libusb_1_0.cc
blob5baa861fa14da6505e22dc932f4fe1655983ed43
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 <sstream>
33 #include <algorithm>
35 #ifndef __DEBUG_MODE__
36 #define __DEBUG_MODE__
37 #endif
38 #include "debug.h"
40 namespace Usb {
42 // helper functions to make deleting pointers in maps and vectors easier
43 template<typename T> static void deletePtr(T* ptr)
45 delete ptr;
48 template<typename K, typename T> static void deleteMapPtr(std::pair<K,T*> ptr)
50 delete ptr.second;
53 // lookup table translating LIBUSB errors to standard Linux errors
54 static const struct {
55 int libusb;
56 int system;
57 } errorCodes[] = {
58 { LIBUSB_SUCCESS, 0 },
59 { LIBUSB_ERROR_IO, -EIO },
60 { LIBUSB_ERROR_INVALID_PARAM, -EINVAL },
61 { LIBUSB_ERROR_ACCESS, -EACCES },
62 { LIBUSB_ERROR_NO_DEVICE, -ENODEV },
63 { LIBUSB_ERROR_NOT_FOUND, -ENOENT },
64 { LIBUSB_ERROR_BUSY, -EBUSY },
65 { LIBUSB_ERROR_TIMEOUT, -ETIMEDOUT },
66 { LIBUSB_ERROR_OVERFLOW, -EOVERFLOW },
67 { LIBUSB_ERROR_PIPE, -EPIPE },
68 { LIBUSB_ERROR_INTERRUPTED, -EINTR },
69 { LIBUSB_ERROR_NO_MEM, -ENOMEM },
70 { LIBUSB_ERROR_NOT_SUPPORTED, -ENOSYS },
71 // There isn't an errno.h value for generic errors, so
72 // return success, which, for TranslateErrcode(), means error.
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
125 // Note that this function assumes that libusb_errcode contains an error.
126 // It is helpful enough to return 0 if libusb_errcode contains 0, but
127 // if it is a positive success value (such as for a read or write)
128 // it will still return 0, since it won't find a corresponding errno code.
130 // Since this function assumes that libusb_errcode is already an error,
131 // it also assumes the caller already *knows* that it is an error, and
132 // therefore a return of success is an "error" for this function. :-)
134 int LibraryInterface::TranslateErrcode(int libusb_errcode)
136 for( int i = 0; i < errorCodeCnt; ++i ) {
137 if( errorCodes[i].libusb == libusb_errcode )
138 return errorCodes[i].system;
141 // default to 0 if unknown
142 eout("Failed to translate libusb errorcode: " << libusb_errcode);
143 return 0;
146 bool LibraryInterface::Init(int *libusb_errno)
148 // if the environment variable LIBUSB_DEBUG is set, that
149 // level value will be used instead of our 3 above...
150 // if you need to *force* this to 3, call SetDataDump(true)
151 // after Init()
152 if( !libusbctx ) {
153 int ret = libusb_init(&libusbctx);
155 // store errno for user if possible
156 if( libusb_errno )
157 *libusb_errno = ret;
159 // true on success
160 return ret >= 0;
162 return true;
165 void LibraryInterface::Uninit()
167 libusb_exit(libusbctx);
168 libusbctx = NULL;
171 void LibraryInterface::SetDataDump(bool data_dump_mode)
173 if( !libusbctx ) {
174 Init();
176 if( !libusbctx ) {
177 // Failed to init, can't do much but return
178 dout("SetDataDump: Failed to initialise libusb");
179 return;
181 if( data_dump_mode )
182 libusb_set_debug(libusbctx, 3);
183 else
184 libusb_set_debug(libusbctx, 0);
187 ///////////////////////////////////////////////////////////////////////////////
188 // DeviceIDImpl
190 DeviceIDImpl::DeviceIDImpl(libusb_device *dev)
191 : m_dev(dev)
193 libusb_ref_device(m_dev);
195 // Libusb 1.0 doesn't provide busnames or filenames
196 // so it's necessary to make some up.
197 std::ostringstream formatter;
198 formatter << "libusb1-"
199 << static_cast<int>(libusb_get_bus_number(m_dev));
200 m_busname = formatter.str();
202 formatter << "-"
203 << static_cast<int>(libusb_get_device_address(m_dev));
204 m_filename = formatter.str();
207 DeviceIDImpl::~DeviceIDImpl()
209 libusb_unref_device(m_dev);
212 ///////////////////////////////////////////////////////////////////////////////
213 // DeviceID
215 DeviceID::DeviceID(DeviceIDImpl* impl)
216 : m_impl(impl)
220 DeviceID::~DeviceID()
225 const char* DeviceID::GetBusName() const
227 return m_impl->m_busname.c_str();
230 uint16_t DeviceID::GetNumber() const
232 return libusb_get_device_address(m_impl->m_dev);
235 const char* DeviceID::GetFilename() const
237 return m_impl->m_filename.c_str();
240 uint16_t DeviceID::GetIdProduct() const
242 int ret = PRODUCT_UNKNOWN;
243 struct libusb_device_descriptor desc;
244 int err = libusb_get_device_descriptor(m_impl->m_dev, &desc);
245 if( err == 0 )
246 ret = desc.idProduct;
247 return ret;
250 ///////////////////////////////////////////////////////////////////////////////
251 // DeviceList
253 DeviceList::DeviceList()
254 : m_impl(new DeviceListImpl())
256 m_impl->m_list = NULL;
257 m_impl->m_listcnt = 0;
259 m_impl->m_listcnt = libusb_get_device_list(libusbctx, &m_impl->m_list);
260 if( m_impl->m_listcnt < 0 ) {
261 throw Error("Failed to get device list");
264 for( int i = 0; i < m_impl->m_listcnt; ++i ) {
265 // Add the device to the list of devices
266 DeviceID devID(new DeviceIDImpl(m_impl->m_list[i]));
267 m_impl->m_devices.push_back(devID);
271 DeviceList::~DeviceList()
273 if( m_impl->m_list ) {
274 libusb_free_device_list(m_impl->m_list, 1);
278 std::vector<DeviceID> DeviceList::MatchDevices(int vendor, int product,
279 const char *busname, const char *devname)
281 std::vector<DeviceID> ret;
282 int err;
284 std::vector<DeviceID>::iterator iter = m_impl->m_devices.begin();
286 for( ; iter != m_impl->m_devices.end() ; ++iter ) {
287 struct libusb_device* dev = iter->m_impl->m_dev;
289 // only search on given bus
290 if( busname && atoi(busname) != libusb_get_bus_number(dev) )
291 continue;
293 // search for specific device
294 if( devname && atoi(devname) != libusb_get_device_address(dev) )
295 continue;
297 struct libusb_device_descriptor desc;
298 err = libusb_get_device_descriptor(dev, &desc);
299 if( err ) {
300 dout("Failed to get device descriptor: " << err);
301 continue;
304 // is there a match?
305 if( desc.idVendor == vendor &&
306 ( desc.idProduct == product ||
307 product == PRODUCT_ANY )) {
308 ret.push_back(*iter);
312 return ret;
315 ///////////////////////////////////////////////////////////////////////////////
316 // Device
318 Device::Device(const Usb::DeviceID& id, int timeout)
319 : m_id(id),
320 m_timeout(timeout)
322 dout("libusb_open(" << std::dec << id.m_impl.get() << ")");
323 if( !&(*id.m_impl) )
324 throw Error("invalid USB device ID");
325 m_handle.reset(new DeviceHandle());
326 int err = libusb_open(id.m_impl->m_dev, &(m_handle->m_handle));
327 m_lasterror = err;
328 if( err )
329 throw Error("open failed");
332 Device::~Device()
334 dout("libusb_close(" << std::dec << m_handle->m_handle << ")");
335 libusb_close(m_handle->m_handle);
338 bool Device::SetConfiguration(unsigned char cfg)
340 dout("libusb_set_configuration(" << std::dec << m_handle->m_handle << ", 0x" << std::hex << (unsigned int) cfg << ")");
341 int ret = libusb_set_configuration(m_handle->m_handle, cfg);
342 m_lasterror = ret;
343 return ret >= 0;
346 bool Device::ClearHalt(int ep)
348 dout("libusb_clear_halt(" << std::dec << m_handle->m_handle << ", 0x" << std::hex << ep << ")");
349 int ret = libusb_clear_halt(m_handle->m_handle, ep);
350 m_lasterror = ret;
351 return ret >= 0;
354 bool Device::Reset()
356 dout("libusb_reset_device(" << std::dec << m_handle->m_handle << ")");
357 int ret = libusb_reset_device(m_handle->m_handle);
358 m_lasterror = ret;
359 return ret == 0;
362 bool Device::BulkRead(int ep, Barry::Data &data, int timeout)
364 ddout("BulkRead to endpoint 0x" << std::hex << ep << ":\n" << data);
365 int ret;
366 do {
367 int transferred = 0;
368 data.QuickZap();
369 ret = libusb_bulk_transfer(m_handle->m_handle,
370 ep |= LIBUSB_ENDPOINT_IN,
371 data.GetBuffer(), data.GetBufSize(),
372 &transferred,
373 timeout == -1 ? m_timeout : timeout);
374 if( ret < 0 && ret != LIBUSB_ERROR_INTERRUPTED ) {
375 m_lasterror = ret;
376 // only notify of a timeout if no data was transferred,
377 // otherwise treat it as success.
378 if( ret == LIBUSB_ERROR_TIMEOUT ) {
379 if( transferred == 0 )
380 throw Timeout(ret, "Timeout in BulkRead");
381 else
382 dout("Read timed out with some data transferred... possible partial read");
384 else if( ret != LIBUSB_ERROR_TIMEOUT ) {
385 std::ostringstream oss;
386 oss << "Error in libusb_bulk_tranfer("
387 << m_handle->m_handle << ", "
388 << ep << ", buf, "
389 << data.GetBufSize() << ", "
390 << transferred << ", "
391 << (timeout == -1 ? m_timeout : timeout)
392 << ")";
393 throw Error(ret, oss.str());
396 if( transferred != 0 )
397 data.ReleaseBuffer(transferred);
399 } while( ret == -LIBUSB_ERROR_INTERRUPTED );
401 return ret >= 0;
404 bool Device::BulkWrite(int ep, const Barry::Data &data, int timeout)
406 ddout("BulkWrite to endpoint 0x" << std::hex << ep << ":\n" << data);
407 int ret;
408 do {
409 int transferred;
410 ret = libusb_bulk_transfer(m_handle->m_handle,
411 ep | LIBUSB_ENDPOINT_OUT,
412 const_cast<unsigned char*>(data.GetData()),
413 data.GetSize(),
414 &transferred,
415 timeout == -1 ? m_timeout : timeout);
416 if( ret < 0 && ret != LIBUSB_ERROR_INTERRUPTED ) {
417 m_lasterror = ret;
418 // only notify of a timeout if no data was transferred,
419 // otherwise treat it as success.
420 if( ret == LIBUSB_ERROR_TIMEOUT && transferred == 0 )
421 throw Timeout(ret, "Timeout in BulkWrite");
422 else if( ret != LIBUSB_ERROR_TIMEOUT )
423 throw Error(ret, "Error in BulkWrite");
425 if( ret >= 0 &&
426 (unsigned int)transferred != data.GetSize() ) {
427 dout("Failed to write all data on ep: " << ep <<
428 " attempted to write: " << data.GetSize() <<
429 " but only wrote: " << transferred);
430 throw Error("Failed to perform a complete write");
433 } while( ret == -LIBUSB_ERROR_INTERRUPTED );
435 return ret >= 0;
438 bool Device::BulkWrite(int ep, const void *data, size_t size, int timeout)
440 #ifdef __DEBUG_MODE__
441 Barry::Data dump(data, size);
442 ddout("BulkWrite to endpoint 0x" << std::hex << ep << ":\n" << dump);
443 #endif
444 int ret;
445 do {
446 int transferred;
447 ret = libusb_bulk_transfer(m_handle->m_handle,
448 ep | LIBUSB_ENDPOINT_OUT,
449 (unsigned char*)const_cast<void*>(data),
450 size,
451 &transferred,
452 timeout == -1 ? m_timeout : timeout);
453 if( ret < 0 && ret != LIBUSB_ERROR_INTERRUPTED ) {
454 m_lasterror = ret;
455 // only notify of a timeout if no data was transferred,
456 // otherwise treat it as success.
457 if( ret == LIBUSB_ERROR_TIMEOUT && transferred == 0 )
458 throw Timeout(ret, "Timeout in BulkWrite (2)");
459 else if( ret != LIBUSB_ERROR_TIMEOUT )
460 throw Error(ret, "Error in BulkWrite (2)");
462 if( ret >= 0 && (unsigned int)transferred != size ) {
463 dout("Failed to write all data on ep: " << ep <<
464 " attempted to write: " << size <<
465 " but only wrote: " << transferred);
466 throw Error("Failed to perform a complete write");
469 } while( ret == -LIBUSB_ERROR_INTERRUPTED );
471 return ret >= 0;
474 bool Device::InterruptRead(int ep, Barry::Data &data, int timeout)
476 ddout("InterruptRead to endpoint 0x" << std::hex << ep << ":\n" << data);
477 int ret;
478 do {
479 int transferred = 0;
480 data.QuickZap();
481 ret = libusb_interrupt_transfer(m_handle->m_handle,
482 ep | LIBUSB_ENDPOINT_IN,
483 data.GetBuffer(), data.GetBufSize(),
484 &transferred,
485 timeout == -1 ? m_timeout : timeout);
486 if( ret < 0 && ret != LIBUSB_ERROR_INTERRUPTED ) {
487 m_lasterror = ret;
488 // only notify of a timeout if no data was transferred,
489 // otherwise treat it as success.
490 if( ret == LIBUSB_ERROR_TIMEOUT ) {
491 if( transferred == 0 )
492 throw Timeout(ret, "Timeout in InterruptRead");
493 else
494 dout("Read timed out with some data transferred... possible partial read");
496 else if( ret != LIBUSB_ERROR_TIMEOUT )
497 throw Error(ret, "Error in InterruptRead");
499 if( transferred != 0 )
500 data.ReleaseBuffer(transferred);
502 } while( ret == -LIBUSB_ERROR_INTERRUPTED );
504 return ret >= 0;
508 bool Device::InterruptWrite(int ep, const Barry::Data &data, int timeout)
510 ddout("InterruptWrite to endpoint 0x" << std::hex << ep << ":\n" << data);
511 int ret;
512 do {
513 int transferred;
514 ret = libusb_interrupt_transfer(m_handle->m_handle,
515 ep | LIBUSB_ENDPOINT_OUT,
516 const_cast<unsigned char*>(data.GetData()),
517 data.GetSize(),
518 &transferred,
519 timeout == -1 ? m_timeout : timeout);
520 if( ret < 0 && ret != LIBUSB_ERROR_INTERRUPTED ) {
521 m_lasterror = ret;
522 // only notify of a timeout if no data was transferred,
523 // otherwise treat it as success.
524 if( ret == LIBUSB_ERROR_TIMEOUT && transferred == 0 )
525 throw Timeout(ret, "Timeout in InterruptWrite");
526 else if( ret != LIBUSB_ERROR_TIMEOUT )
527 throw Error(ret, "Error in InterruptWrite");
529 if( ret >= 0 &&
530 (unsigned int)transferred != data.GetSize() ) {
531 dout("Failed to write all data on ep: " << ep <<
532 " attempted to write: " << data.GetSize() <<
533 " but only wrote: " << transferred);
534 throw Error("Failed to perform a complete write");
537 } while( ret == -LIBUSB_ERROR_INTERRUPTED );
539 return ret >= 0;
543 // BulkDrain
545 /// Reads anything available on the given endpoint, with a low timeout,
546 /// in order to clear any pending reads.
548 void Device::BulkDrain(int ep, int timeout)
550 try {
551 Barry::Data data;
552 while( BulkRead(ep, data, timeout) )
555 catch( Usb::Error & ) {}
559 // GetConfiguration
561 /// Determines the currently selected USB configuration, returning it
562 /// in the cfg argument.
563 /// If unsuccessful, returns false.
565 bool Device::GetConfiguration(unsigned char &cfg)
567 int config = 0;
568 int result = libusb_get_configuration(m_handle->m_handle, &config);
569 if( result >= 0 )
570 cfg = config;
571 m_lasterror = result;
572 return result >= 0;
575 // Returns the current power level of the device, or 0 if unknown
576 int Device::GetPowerLevel()
578 struct libusb_config_descriptor* cfg = NULL;
579 int ret = 0;
580 int result = libusb_get_active_config_descriptor(m_id.m_impl->m_dev, &cfg);
581 m_lasterror = result;
582 if( result == 0 ) {
583 ret = cfg->MaxPower;
586 if( cfg )
587 libusb_free_config_descriptor(cfg);
589 return ret;
592 bool Device::IsAttachKernelDriver(int iface, std::string& name)
594 int ret;
595 char buffer[64];
597 ret = usb_get_driver_np(m_handle->m_handle, iface, buffer, sizeof(buffer));
598 if (ret == 0) {
599 dout("interface (" << m_handle->m_handle << ", 0x" << std::hex << iface
600 << ") already claimed by driver \"" << name << "\"");
601 name = buffer;
602 return true;
605 return false;
608 // Requests that the kernel driver is detached, returning false on failure
609 bool Device::DetachKernelDriver(int iface)
611 int result = libusb_detach_kernel_driver(m_handle->m_handle, iface);
612 m_lasterror = result;
613 return result >= 0;
616 // Sends a control message to the device, returning false on failure
617 bool Device::ControlMsg(int requesttype, int request, int value,
618 int index, char *bytes, int size, int timeout)
620 int result = libusb_control_transfer(m_handle->m_handle,
621 requesttype, request, value, index,
622 (unsigned char*)bytes, size, timeout);
623 m_lasterror = result;
624 return result >= 0;
627 int Device::FindInterface(int ifaceClass)
629 struct libusb_config_descriptor* cfg = NULL;
630 int ret = libusb_get_active_config_descriptor(m_id.m_impl->m_dev, &cfg);
631 if( ret == 0 ) {
632 for( int i = 0; cfg->interface && i < cfg->bNumInterfaces; ++i ) {
633 const struct libusb_interface& iface = cfg->interface[i];
634 for( int j = 0;
635 iface.altsetting && j < iface.num_altsetting;
636 ++j ) {
637 const struct libusb_interface_descriptor& id =
638 iface.altsetting[j];
639 if( id.bInterfaceClass == ifaceClass )
640 return id.bInterfaceNumber;
645 if( cfg )
646 libusb_free_config_descriptor(cfg);
648 return ret;
651 ///////////////////////////////////////////////////////////////////////////////
652 // Interface
654 Interface::Interface(Device &dev, int iface)
655 : m_dev(dev), m_iface(iface)
657 dout("libusb_claim_interface(" << dev.GetHandle()->m_handle << ", 0x" << std::hex << iface << ")");
658 int ret = libusb_claim_interface(dev.GetHandle()->m_handle, iface);
659 if( ret < 0 )
660 throw Error(ret, "claim interface failed");
663 Interface::~Interface()
665 dout("libusb_release_interface(" << m_dev.GetHandle()->m_handle << ", 0x" << std::hex << m_iface << ")");
666 libusb_release_interface(m_dev.GetHandle()->m_handle, m_iface);
671 // SetAltInterface
673 /// Sets the currently selected USB alternate setting of the current interface.
674 /// The iface parameter passed in should be a value specified
675 /// in the bAlternateSetting descriptor field.
676 /// If unsuccessful, returns false.
678 bool Interface::SetAltInterface(int altSetting)
680 int result = libusb_set_interface_alt_setting(
681 m_dev.GetHandle()->m_handle,
682 m_iface,
683 altSetting);
684 m_dev.SetLastError(result);
685 return result >= 0;
690 //////////////////////////////////////////////////////////////////
691 // DeviceDescriptor
693 DeviceDescriptor::DeviceDescriptor(DeviceID& devid)
694 : m_impl(new DeviceDescriptorImpl())
696 if( !devid.m_impl.get() ) {
697 dout("DeviceDescriptor: empty devid");
698 return;
700 m_impl->m_devid = devid;
701 int ret = libusb_get_device_descriptor(devid.m_impl->m_dev, &m_impl->m_desc);
702 if( ret != 0 ) {
703 dout("Failed to read device descriptor with err: " << ret);
704 return;
706 dout("device_desc loaded"
707 << "\nbLength: " << std::dec << (unsigned int) m_impl->m_desc.bLength
708 << "\nbDescriptorType: " << std::dec << (unsigned int) m_impl->m_desc.bDescriptorType
709 << "\nbcdUSB: 0x" << std::hex << (unsigned int) m_impl->m_desc.bcdUSB
710 << "\nbDeviceClass: " << std::dec << (unsigned int) m_impl->m_desc.bDeviceClass
711 << "\nbDeviceSubClass: " << std::dec << (unsigned int) m_impl->m_desc.bDeviceSubClass
712 << "\nbDeviceProtocol: " << std::dec << (unsigned int) m_impl->m_desc.bDeviceProtocol
713 << "\nbMaxPacketSize0: " << std::dec << (unsigned int) m_impl->m_desc.bMaxPacketSize0
714 << "\nidVendor: 0x" << std::hex << (unsigned int) m_impl->m_desc.idVendor
715 << "\nidProduct: 0x" << std::hex << (unsigned int) m_impl->m_desc.idProduct
716 << "\nbcdDevice: 0x" << std::hex << (unsigned int) m_impl->m_desc.bcdDevice
717 << "\niManufacturer: " << std::dec << (unsigned int) m_impl->m_desc.iManufacturer
718 << "\niProduct: " << std::dec << (unsigned int) m_impl->m_desc.iProduct
719 << "\niSerialNumber: " << std::dec << (unsigned int) m_impl->m_desc.iSerialNumber
720 << "\nbNumConfigurations: " << std::dec << (unsigned int) m_impl->m_desc.bNumConfigurations
721 << "\n"
724 // Create all the configs
725 for( int i = 0; i < m_impl->m_desc.bNumConfigurations; ++i ) {
726 std::auto_ptr<ConfigDescriptor> ptr(new ConfigDescriptor(*this, i));
727 (*this)[ptr->GetNumber()] = ptr.get();
728 ptr.release();
732 DeviceDescriptor::~DeviceDescriptor()
734 // Delete any pointers in the vector
735 std::for_each(begin(),
736 end(),
737 deleteMapPtr<int, ConfigDescriptor>);
740 ///////////////////////////////////////////////////////////////////
741 // ConfigDescriptor
743 ConfigDescriptor::ConfigDescriptor(DeviceDescriptor& dev, int cfgnumber)
744 : m_impl(new ConfigDescriptorImpl())
746 m_impl->m_desc = NULL;
747 int ret = libusb_get_config_descriptor(dev.m_impl->m_devid.m_impl->m_dev,
748 cfgnumber, &(m_impl->m_desc));
749 if( ret != 0 ) {
750 dout("Failed to read config descriptor with err: " << ret);
751 return;
754 dout(" config_desc #" << std::dec << cfgnumber << " loaded"
755 << "\nbLength: " << std::dec << (unsigned int) m_impl->m_desc->bLength
756 << "\nbDescriptorType: " << std::dec << (unsigned int) m_impl->m_desc->bDescriptorType
757 << "\nwTotalLength: " << std::dec << (unsigned int) m_impl->m_desc->wTotalLength
758 << "\nbNumInterfaces: " << std::dec << (unsigned int) m_impl->m_desc->bNumInterfaces
759 << "\nbConfigurationValue: " << std::dec << (unsigned int) m_impl->m_desc->bConfigurationValue
760 << "\niConfiguration: " << std::dec << (unsigned int) m_impl->m_desc->iConfiguration
761 << "\nbmAttributes: 0x" << std::hex << (unsigned int) m_impl->m_desc->bmAttributes
762 << "\nMaxPower: " << std::dec << (unsigned int) m_impl->m_desc->MaxPower
763 << "\n"
766 // just for debugging purposes, check for extra descriptors, and
767 // dump them to dout if they exist
768 if( m_impl->m_desc->extra ) {
769 dout("while parsing config descriptor, found a block of extra descriptors:");
770 Barry::Data data(m_impl->m_desc->extra, m_impl->m_desc->extra_length);
771 dout(data);
774 // Create all the interfaces
775 for( int i = 0; i < m_impl->m_desc->bNumInterfaces; ++i ) {
776 const struct libusb_interface* interface = &(m_impl->m_desc->interface[i]);
777 if( !interface->altsetting ) {
778 dout("ConfigDescriptor: empty altsetting");
779 // some devices are buggy and return a higher bNumInterfaces
780 // than the number of interfaces available... in this case
781 // we just skip and continue
782 continue;
784 for( int j = 0; j < interface->num_altsetting; ++j ) {
785 std::auto_ptr<InterfaceDescriptor> ptr(
786 new InterfaceDescriptor(*this, i, j));
787 (*this)[ptr->GetNumber()] = ptr.get();
788 ptr.release();
793 ConfigDescriptor::~ConfigDescriptor()
795 // Delete any pointers in the vector
796 std::for_each(begin(),
797 end(),
798 deleteMapPtr<int, InterfaceDescriptor>);
799 if( m_impl->m_desc ) {
800 libusb_free_config_descriptor(m_impl->m_desc);
801 m_impl->m_desc = NULL;
805 uint8_t ConfigDescriptor::GetNumber() const {
806 if( !m_impl->m_desc )
807 // Return an invalid config number
808 return 0;
809 return m_impl->m_desc->bConfigurationValue;
812 /////////////////////////////////////////////////////////////////////////
813 // InterfaceDescriptor
815 InterfaceDescriptor::InterfaceDescriptor(ConfigDescriptor& cfgdesc,
816 int interface, int altsetting)
817 : m_impl(new InterfaceDescriptorImpl())
819 m_impl->m_desc = NULL;
821 // Find the descriptor
822 m_impl->m_desc =
823 &(cfgdesc.m_impl->m_desc
824 ->interface[interface]
825 .altsetting[altsetting]);
826 dout(" interface_desc #" << std::dec << interface << " loaded"
827 << "\nbLength: " << std::dec << (unsigned) m_impl->m_desc->bLength
828 << "\nbDescriptorType: " << std::dec << (unsigned) m_impl->m_desc->bDescriptorType
829 << "\nbInterfaceNumber: " << std::dec << (unsigned) m_impl->m_desc->bInterfaceNumber
830 << "\nbAlternateSetting: " << std::dec << (unsigned) m_impl->m_desc->bAlternateSetting
831 << "\nbNumEndpoints: " << std::dec << (unsigned) m_impl->m_desc->bNumEndpoints
832 << "\nbInterfaceClass: " << std::dec << (unsigned) m_impl->m_desc->bInterfaceClass
833 << "\nbInterfaceSubClass: " << std::dec << (unsigned) m_impl->m_desc->bInterfaceSubClass
834 << "\nbInterfaceProtocol: " << std::dec << (unsigned) m_impl->m_desc->bInterfaceProtocol
835 << "\niInterface: " << std::dec << (unsigned) m_impl->m_desc->iInterface
836 << "\n"
839 if( !m_impl->m_desc->endpoint ) {
840 dout("InterfaceDescriptor: empty interface pointer");
841 return;
844 // Create all the endpoints
845 for( int i = 0; i < m_impl->m_desc->bNumEndpoints; ++i ) {
846 std::auto_ptr<EndpointDescriptor> ptr (
847 new EndpointDescriptor(*this, i));
848 push_back(ptr.get());
849 ptr.release();
852 // just for debugging purposes, check for extra descriptors, and
853 // dump them to dout if they exist
854 if( m_impl->m_desc->extra ) {
855 dout("while parsing interface descriptor, found a block of extra descriptors:");
856 Barry::Data data(m_impl->m_desc->extra, m_impl->m_desc->extra_length);
857 dout(data);
861 InterfaceDescriptor::~InterfaceDescriptor()
863 // Delete any pointers in the vector
864 std::for_each(begin(),
865 end(),
866 deletePtr<EndpointDescriptor>);
869 uint8_t InterfaceDescriptor::GetClass() const
871 return m_impl->m_desc->bInterfaceClass;
874 uint8_t InterfaceDescriptor::GetNumber() const
876 if( !m_impl->m_desc )
877 // Return an invalid interface number
878 return 0;
879 return m_impl->m_desc->bInterfaceNumber;
882 uint8_t InterfaceDescriptor::GetAltSetting() const
884 if( !m_impl->m_desc )
885 // Return an invalid setting number
886 return 0;
887 return m_impl->m_desc->bAlternateSetting;
890 /////////////////////////////////////////////////////////////////////////////////
891 // EndpointDescriptor
893 EndpointDescriptor::EndpointDescriptor(InterfaceDescriptor& intdesc, int endpoint)
894 : m_impl(new EndpointDescriptorImpl()),
895 m_read(false),
896 m_addr(0),
897 m_type(InvalidType)
899 // Copy the descriptor
900 m_impl->m_desc = &(intdesc.m_impl->m_desc->endpoint[endpoint]);
902 dout(" endpoint_desc #" << std::dec << endpoint << " loaded"
903 << "\nbLength: " << std::dec << (unsigned ) m_impl->m_desc->bLength
904 << "\nbDescriptorType: " << std::dec << (unsigned ) m_impl->m_desc->bDescriptorType
905 << "\nbEndpointAddress: 0x" << std::hex << (unsigned ) m_impl->m_desc->bEndpointAddress
906 << "\nbmAttributes: 0x" << std::hex << (unsigned ) m_impl->m_desc->bmAttributes
907 << "\nwMaxPacketSize: " << std::dec << (unsigned ) m_impl->m_desc->wMaxPacketSize
908 << "\nbInterval: " << std::dec << (unsigned ) m_impl->m_desc->bInterval
909 << "\nbRefresh: " << std::dec << (unsigned ) m_impl->m_desc->bRefresh
910 << "\nbSynchAddress: " << std::dec << (unsigned ) m_impl->m_desc->bSynchAddress
911 << "\n"
913 // Set up variables
914 m_read = ((m_impl->m_desc->bEndpointAddress & LIBUSB_ENDPOINT_DIR_MASK) ==
915 LIBUSB_ENDPOINT_IN);
916 m_addr = (m_impl->m_desc->bEndpointAddress & LIBUSB_ENDPOINT_ADDRESS_MASK);
917 int type = (m_impl->m_desc->bmAttributes & LIBUSB_TRANSFER_TYPE_MASK);
918 m_type = static_cast<Usb::EndpointDescriptor::EpType>(type);
920 // just for debugging purposes, check for extra descriptors, and
921 // dump them to dout if they exist
922 if( m_impl->m_desc->extra ) {
923 dout("while parsing endpoint descriptor, found a block of extra descriptors:");
924 Barry::Data data(m_impl->m_desc->extra, m_impl->m_desc->extra_length);
925 dout(data);
929 EndpointDescriptor::~EndpointDescriptor()
933 } // namespace Usb