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 

Generated on Tue Mar 1 17:50:16 2011 for Barry by  doxygen 1.5.6