# usbwrap.cc

Go to the documentation of this file.

    00001 ///
    00002 /// \file       usbwrap.cc
    00003 ///             USB API wrapper
    00004 ///
    00005
    00006 /*
    00007     Copyright (C) 2005-2011, Chris Frey
    00008
    00009     This program is free software; you can redistribute it and/or modify
    00010     it under the terms of the GNU General Public License as published by
    00011     the Free Software Foundation; either version 2 of the License, or
    00012     (at your option) any later version.
    00013
    00014     This program is distributed in the hope that it will be useful,
    00015     but WITHOUT ANY WARRANTY; without even the implied warranty of
    00016     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
    00017
    00018     See the GNU General Public License in the COPYING file at the
    00019     root directory of this project for more details.
    00020 */
    00021
    00022
    00023 #include "usbwrap.h"
    00024 #include "data.h"
    00025 #include "error.h"
    00026 #include "debug.h"
    00027
    00028 #include <iomanip>
    00029 #include <sstream>
    00030 #include <errno.h>
    00031 #include <string.h>
    00032 #include <limits.h>
    00033
    00034 #ifndef __DEBUG_MODE__
    00035 #define __DEBUG_MODE__
    00036 #endif
    00037 #include "debug.h"
    00038
    00039 namespace Usb {
    00040
    00041 ///////////////////////////////////////////////////////////////////////////////
    00042 // Usb::Error exception class
    00043
    00044 static std::string GetErrorString(int libusb_errcode, const std::string &str)
    00045 {
    00046         std::ostringstream oss;
    00047         oss << "(";
    00048
    00049         if( libusb_errcode ) {
    00050                 oss << std::setbase(10) << libusb_errcode << ", ";
    00051         }
    00052
    00053 //      oss << strerror(-libusb_errno) << "): "
    00054         oss << usb_strerror() << "): ";
    00055         oss << str;
    00056         return oss.str();
    00057 }
    00058
    00059 Error::Error(const std::string &str)
    00060         : Barry::Error(GetErrorString(0, str))
    00061         , m_libusb_errcode(0)
    00062 {
    00063 }
    00064
    00065 Error::Error(int libusb_errcode, const std::string &str)
    00066         : Barry::Error(GetErrorString(libusb_errcode, str))
    00067         , m_libusb_errcode(libusb_errcode)
    00068 {
    00069 }
    00070
    00071
    00072 ///////////////////////////////////////////////////////////////////////////////
    00073 // Match
    00074
    00075 Match::Match(int vendor, int product,
    00076                 const char *busname, const char *devname)
    00077         : m_busses(0)
    00078         , m_dev(0)
    00079         , m_vendor(vendor)
    00080         , m_product(product)
    00081         , m_busname(busname)
    00082         , m_devname(devname)
    00083 {
    00084         usb_find_busses();
    00085         usb_find_devices();
    00086         m_busses = usb_get_busses();
    00087 }
    00088
    00089 Match::~Match()
    00090 {
    00091 }
    00092
    00093 bool Match::ToNum(const char *str, long &num)
    00094 {
    00095         char *end = 0;
    00096         num = strtol(str, &end, 10);
    00097         return  num >= 0 &&                     // no negative numbers
    00098                 num != LONG_MIN && num != LONG_MAX &&   // no overflow
    00099                 str != end && *end == '\0';     // whole string valid
    00100 }
    00101
    00102 //
    00103 // Linux treats bus and device path names as numbers, sometimes left
    00104 // padded with zeros.  Other platforms, such as Windows, use strings,
    00105 // such as "bus-1" or similar.
    00106 //
    00107 // Here we try to convert each string to a number, and if successful,
    00108 // compare them.  If unable to convert, then compare as strings.
    00109 // This way, "3" == "003" and "bus-foobar" == "bus-foobar".
    00110 //
    00111 bool Match::NameCompare(const char *n1, const char *n2)
    00112 {
    00113         long l1, l2;
    00114         if( ToNum(n1, l1) && ToNum(n2, l2) ) {
    00115                 return l1 == l2;
    00116         }
    00117         else {
    00118                 return strcmp(n1, n2) == 0;
    00119         }
    00120 }
    00121
    00122 bool Match::next_device(Usb::DeviceIDType *devid)
    00123 {
    00124         for( ; m_busses; m_busses = m_busses->next ) {
    00125
    00126                 // only search on given bus
    00127                 if( m_busname && !NameCompare(m_busname, m_busses->dirname) )
    00128                         continue;
    00129
    00130                 if( !m_dev )
    00131                         m_dev = m_busses->devices;
    00132
    00133                 for( ; m_dev; m_dev = m_dev->next ) {
    00134
    00135                         // search for specific device
    00136                         if( m_devname && !NameCompare(m_devname, m_dev->filename) )
    00137                                 continue;
    00138
    00139                         // is there a match?
    00140                         if( m_dev->descriptor.idVendor == m_vendor &&
    00141                             m_dev->descriptor.idProduct == m_product ) {
    00142                                 // found!
    00143                                 *devid = m_dev;
    00144
    00145                                 // advance for next time
    00146                                 m_dev = m_dev->next;
    00147                                 if( !m_dev )
    00148                                         m_busses = m_busses->next;
    00149
    00150                                 // done
    00151                                 return true;
    00152                         }
    00153                 }
    00154         }
    00155         return false;
    00156 }
    00157
    00158
    00159 ///////////////////////////////////////////////////////////////////////////////
    00160 // Device
    00161
    00162 Device::Device(Usb::DeviceIDType id, int timeout)
    00163         : m_id(id),
    00164         m_timeout(timeout)
    00165 {
    00166         dout("usb_open(" << std::dec << id << ")");
    00167         if( !id )
    00168                 throw Error("invalid USB device ID");
    00169         m_handle = usb_open(id);
    00170         if( !m_handle )
    00171                 throw Error("open failed");
    00172 }
    00173
    00174 Device::~Device()
    00175 {
    00176         dout("usb_close(" << std::dec << m_handle << ")");
    00177         usb_close(m_handle);
    00178 }
    00179
    00180 bool Device::SetConfiguration(unsigned char cfg)
    00181 {
    00182         dout("usb_set_configuration(" << std::dec << m_handle << ", 0x" << std::hex << (unsigned int) cfg << ")");
    00183         int ret = usb_set_configuration(m_handle, cfg);
    00184         m_lasterror = ret;
    00185         return ret >= 0;
    00186 }
    00187
    00188 bool Device::ClearHalt(int ep)
    00189 {
    00190         dout("usb_clear_halt(" << std::dec << m_handle << ", 0x" << std::hex << ep << ")");
    00191         int ret = usb_clear_halt(m_handle, ep);
    00192         m_lasterror = ret;
    00193         return ret >= 0;
    00194 }
    00195
    00196 bool Device::Reset()
    00197 {
    00198         dout("usb_reset(" << std::dec << m_handle << ")");
    00199         int ret = usb_reset(m_handle);
    00200         m_lasterror = ret;
    00201         return ret == 0;
    00202 }
    00203
    00204 bool Device::BulkRead(int ep, Barry::Data &data, int timeout)
    00205 {
    00206         int ret;
    00207         do {
    00208                 data.QuickZap();
    00209                 ret = usb_bulk_read(m_handle, ep,
    00210                         (char*) data.GetBuffer(), data.GetBufSize(),
    00211                         timeout == -1 ? m_timeout : timeout);
    00212                 if( ret < 0 && ret != -EINTR && ret != -EAGAIN ) {
    00213                         m_lasterror = ret;
    00214                         if( ret == -ETIMEDOUT )
    00215                                 throw Timeout(ret, "Timeout in usb_bulk_read");
    00216                         else
    00217                                 throw Error(ret, "Error in usb_bulk_read");
    00218                 }
    00219                 else if( ret > 0 )
    00220                         data.ReleaseBuffer(ret);
    00221         } while( ret == -EINTR || ret == -EAGAIN );
    00222
    00223         return ret >= 0;
    00224 }
    00225
    00226 bool Device::BulkWrite(int ep, const Barry::Data &data, int timeout)
    00227 {
    00228         ddout("BulkWrite to endpoint 0x" << std::hex << ep << ":\n" << data);
    00229         int ret;
    00230         do {
    00231                 ret = usb_bulk_write(m_handle, ep,
    00232                         (char*) data.GetData(), data.GetSize(),
    00233                         timeout == -1 ? m_timeout : timeout);
    00234                 if( ret < 0 && ret != -EINTR && ret != -EAGAIN ) {
    00235                         m_lasterror = ret;
    00236                         if( ret == -ETIMEDOUT )
    00237                                 throw Timeout(ret, "Timeout in usb_bulk_write (1)");
    00238                         else
    00239                                 throw Error(ret, "Error in usb_bulk_write (1)");
    00240                 }
    00241         } while( ret == -EINTR || ret == -EAGAIN );
    00242
    00243         return ret >= 0;
    00244 }
    00245
    00246 bool Device::BulkWrite(int ep, const void *data, size_t size, int timeout)
    00247 {
    00248 #ifdef __DEBUG_MODE__
    00249         Barry::Data dump(data, size);
    00250         ddout("BulkWrite to endpoint 0x" << std::hex << ep << ":\n" << dump);
    00251 #endif
    00252
    00253         int ret;
    00254         do {
    00255                 ret = usb_bulk_write(m_handle, ep,
    00256                         (char*) data, size,
    00257                         timeout == -1 ? m_timeout : timeout);
    00258                 if( ret < 0 && ret != -EINTR && ret != -EAGAIN ) {
    00259                         m_lasterror = ret;
    00260                         if( ret == -ETIMEDOUT )
    00261                                 throw Timeout(ret, "Timeout in usb_bulk_write (2)");
    00262                         else
    00263                                 throw Error(ret, "Error in usb_bulk_write (2)");
    00264                 }
    00265         } while( ret == -EINTR || ret == -EAGAIN );
    00266
    00267         return ret >= 0;
    00268 }
    00269
    00270 bool Device::InterruptRead(int ep, Barry::Data &data, int timeout)
    00271 {
    00272         int ret;
    00273         do {
    00274                 data.QuickZap();
    00275                 ret = usb_interrupt_read(m_handle, ep,
    00276                         (char*) data.GetBuffer(), data.GetBufSize(),
    00277                         timeout == -1 ? m_timeout : timeout);
    00278                 if( ret < 0 && ret != -EINTR && ret != -EAGAIN ) {
    00279                         m_lasterror = ret;
    00280                         if( ret == -ETIMEDOUT )
    00281                                 throw Timeout(ret, "Timeout in usb_interrupt_read");
    00282                         else
    00283                                 throw Error(ret, "Error in usb_interrupt_read");
    00284                 }
    00285                 else if( ret > 0 )
    00286                         data.ReleaseBuffer(ret);
    00287         } while( ret == -EINTR || ret == -EAGAIN );
    00288
    00289         return ret >= 0;
    00290 }
    00291
    00292 bool Device::InterruptWrite(int ep, const Barry::Data &data, int timeout)
    00293 {
    00294         ddout("InterruptWrite to endpoint 0x" << std::hex << ep << ":\n" << data);
    00295
    00296         int ret;
    00297         do {
    00298                 ret = usb_interrupt_write(m_handle, ep,
    00299                         (char*) data.GetData(), data.GetSize(),
    00300                         timeout == -1 ? m_timeout : timeout);
    00301                 if( ret < 0 && ret != -EINTR && ret != -EAGAIN ) {
    00302                         m_lasterror = ret;
    00303                         if( ret == -ETIMEDOUT )
    00304                                 throw Timeout(ret, "Timeout in usb_interrupt_write");
    00305                         else
    00306                                 throw Error(ret, "Error in usb_interrupt_write");
    00307                 }
    00308         } while( ret == -EINTR || ret == -EAGAIN );
    00309
    00310         return ret >= 0;
    00311 }
    00312
    00313 //
    00314 // BulkDrain
    00315 //
    00316 /// Reads anything available on the given endpoint, with a low timeout,
    00317 /// in order to clear any pending reads.
    00318 ///
    00319 void Device::BulkDrain(int ep, int timeout)
    00320 {
    00321         try {
    00322                 Barry::Data data;
    00323                 while( BulkRead(ep, data, timeout) )
    00324                 ;
    00325         }
    00326         catch( Usb::Error & ) {}
    00327 }
    00328
    00329 //
    00330 // GetConfiguration
    00331 //
    00332 /// Uses the GET_CONFIGURATION control message to determine the currently
    00333 /// selected USB configuration, returning it in the cfg argument.
    00334 /// If unsuccessful, returns false.
    00335 ///
    00336 bool Device::GetConfiguration(unsigned char &cfg)
    00337 {
    00338         int result = usb_control_msg(m_handle, 0x80, USB_REQ_GET_CONFIGURATION, 0, 0,
    00339                 (char*) &cfg, 1, m_timeout);
    00340         m_lasterror = result;
    00341         return result >= 0;
    00342 }
    00343
    00344 //
    00345 // SetAltInterface
    00346 //
    00347 /// Uses the usb_set_altinterface() function to set the currently
    00348 /// selected USB alternate setting of the current interface.
    00349 /// The iface parameter passed in should be a value specified
    00350 /// in the bAlternateSetting descriptor field.
    00351 /// If unsuccessful, returns false.
    00352 ///
    00353 bool Device::SetAltInterface(int iface)
    00354 {
    00355         int result = usb_set_altinterface(m_handle, iface);
    00356         m_lasterror = result;
    00357         return result >= 0;
    00358 }
    00359
    00360
    00361
    00362 ///////////////////////////////////////////////////////////////////////////////
    00363 // Interface
    00364
    00365 Interface::Interface(Device &dev, int iface)
    00366         : m_dev(dev), m_iface(iface)
    00367 {
    00368         dout("usb_claim_interface(" << dev.GetHandle() << ", 0x" << std::hex << iface << ")");
    00369         int ret = usb_claim_interface(dev.GetHandle(), iface);
    00370         if( ret < 0 )
    00371                 throw Error(ret, "claim interface failed");
    00372 }
    00373
    00374 Interface::~Interface()
    00375 {
    00376         dout("usb_release_interface(" << m_dev.GetHandle() << ", 0x" << std::hex << m_iface << ")");
    00377         usb_release_interface(m_dev.GetHandle(), m_iface);
    00378 }
    00379
    00380
    00381
    00382 ///////////////////////////////////////////////////////////////////////////////
    00383 // EndpointDiscovery
    00384
    00385 bool EndpointDiscovery::Discover(struct usb_interface_descriptor *interface, int epcount)
    00386 {
    00387         // start fresh
    00388         clear();
    00389         m_valid = false;
    00390
    00391         EndpointPair pair;
    00392
    00393         if( !interface || !interface->endpoint ) {
    00394                 dout("EndpointDiscovery::Discover: empty interface pointer");
    00395                 return false;
    00396         }
    00397
    00398         for( int i = 0; i < epcount; i++ ) {
    00399                 // load descriptor
    00400                 usb_endpoint_descriptor desc;
    00401                 desc = interface->endpoint[i];
    00402                 dout("      endpoint_desc #" << std::dec << i << " loaded"
    00403                         << "\nbLength: " << std::dec << (unsigned ) desc.bLength
    00404                         << "\nbDescriptorType: " << std::dec << (unsigned ) desc.bDescriptorType
    00405                         << "\nbEndpointAddress: 0x" << std::hex << (unsigned ) desc.bEndpointAddress
    00406                         << "\nbmAttributes: 0x" << std::hex << (unsigned ) desc.bmAttributes
    00407                         << "\nwMaxPacketSize: " << std::dec << (unsigned ) desc.wMaxPacketSize
    00408                         << "\nbInterval: " << std::dec << (unsigned ) desc.bInterval
    00409                         << "\nbRefresh: " << std::dec << (unsigned ) desc.bRefresh
    00410                         << "\nbSynchAddress: " << std::dec << (unsigned ) desc.bSynchAddress
    00411                         << "\n"
    00412                         );
    00413
    00414                 // add to the map
    00415                 (*this)[desc.bEndpointAddress] = desc;
    00416                 dout("      endpoint added to map with bEndpointAddress: 0x" << std::hex << (unsigned int)desc.bEndpointAddress);
    00417
    00418                 // parse the endpoint into read/write sets, if possible,
    00419                 // going in discovery order...
    00420                 // Assumptions:
    00421                 //      - endpoints of related utility will be grouped
    00422                 //      - endpoints with same type will be grouped
    00423                 //      - endpoints that do not meet the above assumptions
    00424                 //              do not belong in a pair
    00425                 unsigned char type = desc.bmAttributes & USB_ENDPOINT_TYPE_MASK;
    00426                 if( desc.bEndpointAddress & USB_ENDPOINT_DIR_MASK ) {
    00427                         // read endpoint
    00428                         pair.read = desc.bEndpointAddress;
    00429                         dout("        pair.read = 0x" << std::hex << (unsigned int)pair.read);
    00430                         if( pair.IsTypeSet() && pair.type != type ) {
    00431                                 // if type is already set, we must start over
    00432                                 pair.write = 0;
    00433                         }
    00434                 }
    00435                 else {
    00436                         // write endpoint
    00437                         pair.write = desc.bEndpointAddress;
    00438                         dout("        pair.write = 0x" << std::hex << (unsigned int)pair.write);
    00439                         if( pair.IsTypeSet() && pair.type != type ) {
    00440                                 // if type is already set, we must start over
    00441                                 pair.read = 0;
    00442                         }
    00443                 }
    00444                 // save the type last
    00445                 pair.type = type;
    00446                 dout("        pair.type = 0x" << std::hex << (unsigned int)pair.type);
    00447
    00448                 // if pair is complete, add to array
    00449                 if( pair.IsComplete() ) {
    00450                         m_endpoints.push_back(pair);
    00451                         dout("        pair added! ("
    00452                                 << "read: 0x" << std::hex << (unsigned int)pair.read << ","
    00453                                 << "write: 0x" << std::hex << (unsigned int)pair.write << ","
    00454                                 << "type: 0x" << std::hex << (unsigned int)pair.type << ")");
    00455                         pair = EndpointPair();  // clear
    00456                 }
    00457         }
    00458
    00459         // just for debugging purposes, check for extra descriptors, and
    00460         // dump them to dout if they exist
    00461         if( interface->extra ) {
    00462                 dout("while parsing endpoints, found a block of extra descriptors:");
    00463                 Barry::Data data(interface->extra, interface->extralen);
    00464                 dout(data);
    00465         }
    00466
    00467         return m_valid = true;
    00468 }
    00469
    00470
    00471 ///////////////////////////////////////////////////////////////////////////////
    00472 // InterfaceDiscovery
    00473
    00474 bool InterfaceDiscovery::DiscoverInterface(struct usb_interface *interface)
    00475 {
    00476         if( !interface->altsetting ) {
    00477                 dout("InterfaceDiscovery::DiscoverIterface: empty altsetting");
    00478                 // some devices are buggy and return a higher bNumInterfaces
    00479                 // than the number of interfaces available... in this case
    00480                 // we just skip and continue
    00481                 return true;
    00482         }
    00483
    00484         for( int i = 0; i < interface->num_altsetting; i++ ) {
    00485                 // load descriptor
    00486                 InterfaceDesc desc;
    00487                 desc.desc = interface->altsetting[i];
    00488                 dout("    interface_desc #" << std::dec << i << " loaded"
    00489                         << "\nbLength: " << std::dec << (unsigned) desc.desc.bLength
    00490                         << "\nbDescriptorType: " << std::dec << (unsigned) desc.desc.bDescriptorType
    00491                         << "\nbInterfaceNumber: " << std::dec << (unsigned) desc.desc.bInterfaceNumber
    00492                         << "\nbAlternateSetting: " << std::dec << (unsigned) desc.desc.bAlternateSetting
    00493                         << "\nbNumEndpoints: " << std::dec << (unsigned) desc.desc.bNumEndpoints
    00494                         << "\nbInterfaceClass: " << std::dec << (unsigned) desc.desc.bInterfaceClass
    00495                         << "\nbInterfaceSubClass: " << std::dec << (unsigned) desc.desc.bInterfaceSubClass
    00496                         << "\nbInterfaceProtocol: " << std::dec << (unsigned) desc.desc.bInterfaceProtocol
    00497                         << "\niInterface: " << std::dec << (unsigned) desc.desc.iInterface
    00498                         << "\n"
    00499                         );
    00500
    00501                 // load all endpoints on this interface
    00502                 if( !desc.endpoints.Discover(&desc.desc, desc.desc.bNumEndpoints) ) {
    00503                         dout("    endpoint discovery failed for bInterfaceNumber: " << std::dec << (unsigned int)desc.desc.bInterfaceNumber << ", not added to map.");
    00504                         return false;
    00505                 }
    00506
    00507                 // add to the map
    00508                 (*this)[desc.desc.bInterfaceNumber] = desc;
    00509                 dout("    interface added to map with bInterfaceNumber: " << std::dec << (unsigned int)desc.desc.bInterfaceNumber);
    00510         }
    00511         return true;
    00512 }
    00513
    00514 bool InterfaceDiscovery::Discover(Usb::DeviceIDType devid, int cfgidx, int ifcount)
    00515 {
    00516         // start fresh
    00517         clear();
    00518         m_valid = false;
    00519
    00520         if( !devid || !devid->config || !devid->config[cfgidx].interface ) {
    00521                 dout("InterfaceDiscovery::Discover: empty devid/config/interface");
    00522                 return false;
    00523         }
    00524
    00525         for( int i = 0; i < ifcount; i++ ) {
    00526                 if( !DiscoverInterface(&devid->config[cfgidx].interface[i]) )
    00527                         return false;
    00528         }
    00529
    00530         return m_valid = true;
    00531 }
    00532
    00533
    00534 ///////////////////////////////////////////////////////////////////////////////
    00535 // ConfigDiscovery
    00536
    00537 bool ConfigDiscovery::Discover(Usb::DeviceIDType devid, int cfgcount)
    00538 {
    00539         // start fresh
    00540         clear();
    00541         m_valid = false;
    00542
    00543         for( int i = 0; i < cfgcount; i++ ) {
    00544                 // load descriptor
    00545                 ConfigDesc desc;
    00546                 if( !devid || !devid->config ) {
    00547                         dout("ConfigDiscovery::Discover: empty devid or config");
    00548                         return false;
    00549                 }
    00550                 desc.desc = devid->config[i];
    00551                 dout("  config_desc #" << std::dec << i << " loaded"
    00552                         << "\nbLength: " << std::dec << (unsigned int) desc.desc.bLength
    00553                         << "\nbDescriptorType: " << std::dec << (unsigned int) desc.desc.bDescriptorType
    00554                         << "\nwTotalLength: " << std::dec << (unsigned int) desc.desc.wTotalLength
    00555                         << "\nbNumInterfaces: " << std::dec << (unsigned int) desc.desc.bNumInterfaces
    00556                         << "\nbConfigurationValue: " << std::dec << (unsigned int) desc.desc.bConfigurationValue
    00557                         << "\niConfiguration: " << std::dec << (unsigned int) desc.desc.iConfiguration
    00558                         << "\nbmAttributes: 0x" << std::hex << (unsigned int) desc.desc.bmAttributes
    00559                         << "\nMaxPower: " << std::dec << (unsigned int) desc.desc.MaxPower
    00560                         << "\n"
    00561                         );
    00562
    00563                 // just for debugging purposes, check for extra descriptors, and
    00564                 // dump them to dout if they exist
    00565                 if( desc.desc.extra ) {
    00566                         dout("while parsing config descriptor, found a block of extra descriptors:");
    00567                         Barry::Data data(desc.desc.extra, desc.desc.extralen);
    00568                         dout(data);
    00569                 }
    00570
    00571                 // load all interfaces on this configuration
    00572                 if( !desc.interfaces.Discover(devid, i, desc.desc.bNumInterfaces) ) {
    00573                         dout("  config discovery failed for bConfigurationValue: " << std::dec << (unsigned int)desc.desc.bConfigurationValue << ", not added to map.");
    00574                         return false;
    00575                 }
    00576
    00577                 // add to the map
    00578                 (*this)[desc.desc.bConfigurationValue] = desc;
    00579                 dout("  config added to map with bConfigurationValue: " << std::dec << (unsigned int)desc.desc.bConfigurationValue);
    00580         }
    00581
    00582         return m_valid = true;
    00583 }
    00584
    00585
    00586 ///////////////////////////////////////////////////////////////////////////////
    00587 // DeviceDiscovery
    00588
    00589 DeviceDiscovery::DeviceDiscovery(Usb::DeviceIDType devid)
    00590         : m_valid(false)
    00591 {
    00592         Discover(devid);
    00593 }
    00594
    00595 bool DeviceDiscovery::Discover(Usb::DeviceIDType devid)
    00596 {
    00597         // start fresh
    00598         configs.clear();
    00599         m_valid = false;
    00600
    00601         // copy the descriptor over to our memory
    00602         if( !devid ) {
    00603                 dout("DeviceDiscovery::Discover: empty devid");
    00604                 return false;
    00605         }
    00606
    00607         desc = devid->descriptor;
    00608         dout("device_desc loaded"
    00609                 << "\nbLength: " << std::dec << (unsigned int) desc.bLength
    00610                 << "\nbDescriptorType: " << std::dec << (unsigned int) desc.bDescriptorType
    00611                 << "\nbcdUSB: 0x" << std::hex << (unsigned int) desc.bcdUSB
    00612                 << "\nbDeviceClass: " << std::dec << (unsigned int) desc.bDeviceClass
    00613                 << "\nbDeviceSubClass: " << std::dec << (unsigned int) desc.bDeviceSubClass
    00614                 << "\nbDeviceProtocol: " << std::dec << (unsigned int) desc.bDeviceProtocol
    00615                 << "\nbMaxPacketSize0: " << std::dec << (unsigned int) desc.bMaxPacketSize0
    00616                 << "\nidVendor: 0x" << std::hex << (unsigned int) desc.idVendor
    00617                 << "\nidProduct: 0x" << std::hex << (unsigned int) desc.idProduct
    00618                 << "\nbcdDevice: 0x" << std::hex << (unsigned int) desc.bcdDevice
    00619                 << "\niManufacturer: " << std::dec << (unsigned int) desc.iManufacturer
    00620                 << "\niProduct: " << std::dec << (unsigned int) desc.iProduct
    00621                 << "\niSerialNumber: " << std::dec << (unsigned int) desc.iSerialNumber
    00622                 << "\nbNumConfigurations: " << std::dec << (unsigned int) desc.bNumConfigurations
    00623                 << "\n"
    00624         );
    00625
    00626         m_valid = configs.Discover(devid, desc.bNumConfigurations);
    00627         return m_valid;
    00628 }
    00629
    00630 } // namespace Usb
    00631