usbwrap_libusb_1_0.cc

Go to the documentation of this file.
00001 ///
00002 /// \file       usbwrap_libusb_1_0.cc
00003 ///             USB API wrapper for libusb version 1.0
00004 ///
00005 
00006 /*
00007     Copyright (C) 2005-2012, Chris Frey
00008     Portions Copyright (C) 2011, RealVNC Ltd.
00009 
00010     This program is free software; you can redistribute it and/or modify
00011     it under the terms of the GNU General Public License as published by
00012     the Free Software Foundation; either version 2 of the License, or
00013     (at your option) any later version.
00014 
00015     This program is distributed in the hope that it will be useful,
00016     but WITHOUT ANY WARRANTY; without even the implied warranty of
00017     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
00018 
00019     See the GNU General Public License in the COPYING file at the
00020     root directory of this project for more details.
00021 */
00022 
00023 
00024 
00025 #include "usbwrap_libusb_1_0.h"
00026 
00027 #include "debug.h"
00028 #include "data.h"
00029 #include <errno.h>
00030 #include <sstream>
00031 #include <iostream>
00032 #include <sstream>
00033 #include <algorithm>
00034 
00035 #ifndef __DEBUG_MODE__
00036 #define __DEBUG_MODE__
00037 #endif
00038 #include "debug.h"
00039 
00040 namespace Usb {
00041 
00042 // helper functions to make deleting pointers in maps and vectors easier
00043 template<typename T> static void deletePtr(T* ptr)
00044 {
00045         delete ptr;
00046 }
00047 
00048 template<typename K, typename T> static void deleteMapPtr(std::pair<K,T*> ptr)
00049 {
00050         delete ptr.second;
00051 }
00052 
00053 // lookup table translating LIBUSB errors to standard Linux errors
00054 static const struct {
00055         int libusb;
00056         int system;
00057 } errorCodes[] = {
00058         { LIBUSB_SUCCESS, 0 },
00059         { LIBUSB_ERROR_IO, -EIO },
00060         { LIBUSB_ERROR_INVALID_PARAM, -EINVAL },
00061         { LIBUSB_ERROR_ACCESS, -EACCES },
00062         { LIBUSB_ERROR_NO_DEVICE, -ENODEV },
00063         { LIBUSB_ERROR_NOT_FOUND, -ENOENT },
00064         { LIBUSB_ERROR_BUSY, -EBUSY },
00065         { LIBUSB_ERROR_TIMEOUT, -ETIMEDOUT },
00066         { LIBUSB_ERROR_OVERFLOW, -EOVERFLOW },
00067         { LIBUSB_ERROR_PIPE, -EPIPE },
00068         { LIBUSB_ERROR_INTERRUPTED, -EINTR },
00069         { LIBUSB_ERROR_NO_MEM, -ENOMEM },
00070         { LIBUSB_ERROR_NOT_SUPPORTED, -ENOSYS },
00071         // There isn't an errno.h value for generic errors, so
00072         // return success, which, for TranslateErrcode(), means error.
00073         { LIBUSB_ERROR_OTHER, 0 }
00074 };
00075 
00076 static const int errorCodeCnt = sizeof(errorCodes) / sizeof(errorCodes[0]);
00077 
00078 
00079 ///////////////////////////////////////////////////////////////////////////////
00080 // Global libusb library context
00081 static libusb_context* libusbctx;
00082 
00083 ///////////////////////////////////////////////////////////////////////////////
00084 // Static functions
00085 
00086 std::string LibraryInterface::GetLastErrorString(int libusb_errcode)
00087 {
00088         switch( libusb_errcode )
00089         {
00090         case LIBUSB_SUCCESS:
00091                 return "Success";
00092         case LIBUSB_ERROR_IO:
00093                 return "IO Error";
00094         case LIBUSB_ERROR_INVALID_PARAM:
00095                 return "Invalid parameter";
00096         case LIBUSB_ERROR_ACCESS:
00097                 return "Access";
00098         case LIBUSB_ERROR_NO_DEVICE:
00099                 return "No device";
00100         case LIBUSB_ERROR_NOT_FOUND:
00101                 return "Not found";
00102         case LIBUSB_ERROR_BUSY:
00103                 return "Busy";
00104         case LIBUSB_ERROR_TIMEOUT:
00105                 return "Timeout";
00106         case LIBUSB_ERROR_OVERFLOW:
00107                 return "Overflow";
00108         case LIBUSB_ERROR_PIPE:
00109                 return "Pipe";
00110         case LIBUSB_ERROR_INTERRUPTED:
00111                 return "Interrupted";
00112         case LIBUSB_ERROR_NO_MEM:
00113                 return "No memory";
00114         case LIBUSB_ERROR_NOT_SUPPORTED:
00115                 return "Not supported";
00116         case LIBUSB_ERROR_OTHER:
00117                 return "Other";
00118         default:
00119                 return "Unknown LIBUSB error code";
00120         }
00121 }
00122 
00123 // Helper function to translate libusb error codes into more useful values
00124 //
00125 // Note that this function assumes that libusb_errcode contains an error.
00126 // It is helpful enough to return 0 if libusb_errcode contains 0, but
00127 // if it is a positive success value (such as for a read or write)
00128 // it will still return 0, since it won't find a corresponding errno code.
00129 //
00130 // Since this function assumes that libusb_errcode is already an error,
00131 // it also assumes the caller already *knows* that it is an error, and
00132 // therefore a return of success is an "error" for this function. :-)
00133 //
00134 int LibraryInterface::TranslateErrcode(int libusb_errcode)
00135 {
00136         for( int i = 0; i < errorCodeCnt; ++i ) {
00137                 if( errorCodes[i].libusb == libusb_errcode )
00138                         return errorCodes[i].system;
00139         }
00140 
00141         // default to 0 if unknown
00142         eout("Failed to translate libusb errorcode: " << libusb_errcode);
00143         return 0;
00144 }
00145 
00146 bool LibraryInterface::Init(int *libusb_errno)
00147 {
00148         // if the environment variable LIBUSB_DEBUG is set, that
00149         // level value will be used instead of our 3 above...
00150         // if you need to *force* this to 3, call SetDataDump(true)
00151         // after Init()
00152         if( !libusbctx ) {
00153                 int ret = libusb_init(&libusbctx);
00154 
00155                 // store errno for user if possible
00156                 if( libusb_errno )
00157                         *libusb_errno = ret;
00158 
00159                 // true on success
00160                 return ret >= 0;
00161         }
00162         return true;
00163 }
00164 
00165 void LibraryInterface::Uninit()
00166 {
00167         libusb_exit(libusbctx);
00168         libusbctx = NULL;
00169 }
00170 
00171 void LibraryInterface::SetDataDump(bool data_dump_mode)
00172 {
00173         if( !libusbctx ) {
00174                 Init();
00175         }
00176         if( !libusbctx ) {
00177                 // Failed to init, can't do much but return
00178                 dout("SetDataDump: Failed to initialise libusb");
00179                 return;
00180         }
00181         if( data_dump_mode )
00182                 libusb_set_debug(libusbctx, 3);
00183         else
00184                 libusb_set_debug(libusbctx, 0);
00185 }
00186 
00187 ///////////////////////////////////////////////////////////////////////////////
00188 // DeviceIDImpl
00189 
00190 DeviceIDImpl::DeviceIDImpl(libusb_device *dev)
00191         : m_dev(dev)
00192 {
00193         libusb_ref_device(m_dev);
00194 
00195         // Libusb 1.0 doesn't provide busnames or filenames
00196         // so it's necessary to make some up.
00197         std::ostringstream formatter;
00198         formatter << "libusb1-"
00199                   << static_cast<int>(libusb_get_bus_number(m_dev));
00200         m_busname = formatter.str();
00201 
00202         formatter << "-"
00203                   << static_cast<int>(libusb_get_device_address(m_dev));
00204         m_filename = formatter.str();
00205 }
00206 
00207 DeviceIDImpl::~DeviceIDImpl()
00208 {
00209         libusb_unref_device(m_dev);
00210 }
00211 
00212 ///////////////////////////////////////////////////////////////////////////////
00213 // DeviceID
00214 
00215 DeviceID::DeviceID(DeviceIDImpl* impl)
00216         : m_impl(impl)
00217 {
00218 }
00219 
00220 DeviceID::~DeviceID()
00221 {
00222 }
00223 
00224 
00225 const char* DeviceID::GetBusName() const
00226 {
00227         return m_impl->m_busname.c_str();
00228 }
00229 
00230 uint16_t DeviceID::GetNumber() const
00231 {
00232         return libusb_get_device_address(m_impl->m_dev);
00233 }
00234 
00235 const char* DeviceID::GetFilename() const
00236 {
00237         return m_impl->m_filename.c_str();
00238 }
00239 
00240 uint16_t DeviceID::GetIdProduct() const
00241 {
00242         int ret = PRODUCT_UNKNOWN;
00243         struct libusb_device_descriptor desc;
00244         int err = libusb_get_device_descriptor(m_impl->m_dev, &desc);
00245         if( err == 0 )
00246                 ret = desc.idProduct;
00247         return ret;
00248 }
00249 
00250 std::string DeviceID::GetUsbName() const
00251 {
00252         // for libusb 1.0, we can use bus name and number...
00253         // and we stay away from the product ID, since that requires
00254         // communication with the device, which may not be possible
00255         // in error conditions.
00256         std::ostringstream oss;
00257         oss << GetBusName() << ":" << GetNumber();
00258         return oss.str();
00259 }
00260 
00261 ///////////////////////////////////////////////////////////////////////////////
00262 // DeviceList
00263 
00264 DeviceList::DeviceList()
00265         : m_impl(new DeviceListImpl())
00266 {
00267         m_impl->m_list = NULL;
00268         m_impl->m_listcnt = 0;
00269 
00270         m_impl->m_listcnt = libusb_get_device_list(libusbctx, &m_impl->m_list);
00271         if( m_impl->m_listcnt < 0 ) {
00272                 throw Error(m_impl->m_listcnt, "Failed to get device list");
00273         }
00274 
00275         for( int i = 0; i < m_impl->m_listcnt; ++i ) {
00276                 // Add the device to the list of devices
00277                 DeviceID devID(new DeviceIDImpl(m_impl->m_list[i]));
00278                 m_impl->m_devices.push_back(devID);
00279         }
00280 }
00281 
00282 DeviceList::~DeviceList()
00283 {
00284         if( m_impl->m_list ) {
00285                 libusb_free_device_list(m_impl->m_list, 1);
00286         }
00287 }
00288 
00289 std::vector<DeviceID> DeviceList::MatchDevices(int vendor, int product,
00290                                             const char *busname, const char *devname)
00291 {
00292         std::vector<DeviceID> ret;
00293         int err;
00294 
00295         std::vector<DeviceID>::iterator iter = m_impl->m_devices.begin();
00296 
00297         for( ; iter != m_impl->m_devices.end() ; ++iter ) {
00298                 struct libusb_device* dev = iter->m_impl->m_dev;
00299 
00300                 // only search on given bus
00301                 if( busname && atoi(busname) != libusb_get_bus_number(dev) )
00302                         continue;
00303 
00304                 // search for specific device
00305                 if( devname && atoi(devname) != libusb_get_device_address(dev) )
00306                         continue;
00307 
00308                 struct libusb_device_descriptor desc;
00309                 err = libusb_get_device_descriptor(dev, &desc);
00310                 if( err ) {
00311                         dout("Failed to get device descriptor: " << err);
00312                         continue;
00313                 }
00314 
00315                 // is there a match?
00316                 if( desc.idVendor == vendor &&
00317                     ( desc.idProduct == product || 
00318                       product == PRODUCT_ANY )) {
00319                         ret.push_back(*iter);
00320                 }
00321         }
00322 
00323         return ret;
00324 }
00325 
00326 ///////////////////////////////////////////////////////////////////////////////
00327 // Device
00328 
00329 Device::Device(const Usb::DeviceID& id, int timeout)
00330         : m_id(id),
00331         m_timeout(timeout)
00332 {
00333         dout("libusb_open(" << std::dec << id.m_impl.get() << ")");
00334         if( !&(*id.m_impl) )
00335                 throw Error("invalid USB device ID");
00336         m_handle.reset(new DeviceHandle());
00337         int err = libusb_open(id.m_impl->m_dev, &(m_handle->m_handle));
00338         m_lasterror = err;
00339         if( err )
00340                 throw Error(err, "Failed to open USB device.  Please check your system's USB device permissions.");
00341 }
00342 
00343 Device::~Device()
00344 {
00345         dout("libusb_close(" << std::dec << m_handle->m_handle << ")");
00346         libusb_close(m_handle->m_handle);
00347 }
00348 
00349 bool Device::SetConfiguration(unsigned char cfg)
00350 {
00351         dout("libusb_set_configuration(" << std::dec << m_handle->m_handle << ", 0x" << std::hex << (unsigned int) cfg << ")");
00352         int ret = libusb_set_configuration(m_handle->m_handle, cfg);
00353         m_lasterror = ret;
00354         return ret >= 0;
00355 }
00356 
00357 bool Device::ClearHalt(int ep)
00358 {
00359         dout("libusb_clear_halt(" << std::dec << m_handle->m_handle << ", 0x" << std::hex << ep << ")");
00360         int ret = libusb_clear_halt(m_handle->m_handle, ep);
00361         m_lasterror = ret;
00362         return ret >= 0;
00363 }
00364 
00365 bool Device::Reset()
00366 {
00367         dout("libusb_reset_device(" << std::dec << m_handle->m_handle << ")");
00368         int ret = libusb_reset_device(m_handle->m_handle);
00369         m_lasterror = ret;
00370         return ret == 0;
00371 }
00372 
00373 bool Device::BulkRead(int ep, Barry::Data &data, int timeout)
00374 {
00375         ddout("BulkRead to endpoint 0x" << std::hex << ep << ":\n" << data);
00376         int ret;
00377         do {
00378                 int transferred = 0;
00379                 data.QuickZap();
00380                 ret = libusb_bulk_transfer(m_handle->m_handle,
00381                         ep |= LIBUSB_ENDPOINT_IN,
00382                         data.GetBuffer(), data.GetBufSize(),
00383                         &transferred,
00384                         timeout == -1 ? m_timeout : timeout);
00385                 if( ret < 0 && ret != LIBUSB_ERROR_INTERRUPTED ) {
00386                         m_lasterror = ret;
00387                         // only notify of a timeout if no data was transferred,
00388                         // otherwise treat it as success.
00389                         if( ret == LIBUSB_ERROR_TIMEOUT ) {
00390                                 if( transferred == 0 )
00391                                         throw Timeout(ret, "Timeout in BulkRead");
00392                                 else
00393                                         dout("Read timed out with some data transferred... possible partial read");
00394                         }
00395                         else if( ret != LIBUSB_ERROR_TIMEOUT ) {
00396                                 std::ostringstream oss;
00397                                 oss << "Error in libusb_bulk_tranfer("
00398                                     << m_handle->m_handle << ", "
00399                                     << ep << ", buf, "
00400                                     << data.GetBufSize() << ", "
00401                                     << transferred << ", "
00402                                     << (timeout == -1 ? m_timeout : timeout)
00403                                     << ")";
00404                                 throw Error(ret, oss.str());
00405                         }
00406                 }
00407                 if( transferred != 0 )
00408                         data.ReleaseBuffer(transferred);
00409 
00410         } while( ret == -LIBUSB_ERROR_INTERRUPTED );
00411 
00412         return ret >= 0;
00413 }
00414 
00415 bool Device::BulkWrite(int ep, const Barry::Data &data, int timeout)
00416 {
00417         ddout("BulkWrite to endpoint 0x" << std::hex << ep << ":\n" << data);
00418         int ret;
00419         do {
00420                 int transferred;
00421                 ret = libusb_bulk_transfer(m_handle->m_handle,
00422                         ep | LIBUSB_ENDPOINT_OUT,
00423                         const_cast<unsigned char*>(data.GetData()),
00424                         data.GetSize(),
00425                         &transferred,
00426                         timeout == -1 ? m_timeout : timeout);
00427                 if( ret < 0 && ret != LIBUSB_ERROR_INTERRUPTED ) {
00428                         m_lasterror = ret;
00429                         // only notify of a timeout if no data was transferred,
00430                         // otherwise treat it as success.
00431                         if( ret == LIBUSB_ERROR_TIMEOUT && transferred == 0 )
00432                                 throw Timeout(ret, "Timeout in BulkWrite");
00433                         else if( ret != LIBUSB_ERROR_TIMEOUT )
00434                                 throw Error(ret, "Error in BulkWrite");
00435                 }
00436                 if( ret >= 0 &&
00437                     (unsigned int)transferred != data.GetSize() ) {
00438                         dout("Failed to write all data on ep: " << ep <<
00439                              " attempted to write: " << data.GetSize() << 
00440                              " but only wrote: " << transferred);
00441                         throw Error("Failed to perform a complete write");
00442                 }
00443 
00444         } while( ret == -LIBUSB_ERROR_INTERRUPTED );
00445 
00446         return ret >= 0;
00447 }
00448 
00449 bool Device::BulkWrite(int ep, const void *data, size_t size, int timeout)
00450 {
00451 #ifdef __DEBUG_MODE__
00452         Barry::Data dump(data, size);
00453         ddout("BulkWrite to endpoint 0x" << std::hex << ep << ":\n" << dump);
00454 #endif  
00455         int ret;
00456         do {
00457                 int transferred;
00458                 ret = libusb_bulk_transfer(m_handle->m_handle,
00459                         ep | LIBUSB_ENDPOINT_OUT,
00460                         (unsigned char*)const_cast<void*>(data),
00461                         size,
00462                         &transferred,
00463                         timeout == -1 ? m_timeout : timeout);
00464                 if( ret < 0 && ret != LIBUSB_ERROR_INTERRUPTED ) {
00465                         m_lasterror = ret;
00466                         // only notify of a timeout if no data was transferred,
00467                         // otherwise treat it as success.
00468                         if( ret == LIBUSB_ERROR_TIMEOUT && transferred == 0 )
00469                                 throw Timeout(ret, "Timeout in BulkWrite (2)");
00470                         else if( ret != LIBUSB_ERROR_TIMEOUT )
00471                                 throw Error(ret, "Error in BulkWrite (2)");
00472                 }
00473                 if( ret >= 0 && (unsigned int)transferred != size ) {
00474                         dout("Failed to write all data on ep: " << ep <<
00475                              " attempted to write: " << size << 
00476                              " but only wrote: " << transferred);
00477                         throw Error("Failed to perform a complete write");
00478                 }
00479 
00480         } while( ret == -LIBUSB_ERROR_INTERRUPTED );
00481 
00482         return ret >= 0;
00483 }
00484 
00485 bool Device::InterruptRead(int ep, Barry::Data &data, int timeout)
00486 {
00487         ddout("InterruptRead to endpoint 0x" << std::hex << ep << ":\n" << data);
00488         int ret;
00489         do {
00490                 int transferred = 0;
00491                 data.QuickZap();
00492                 ret = libusb_interrupt_transfer(m_handle->m_handle,
00493                         ep | LIBUSB_ENDPOINT_IN,
00494                         data.GetBuffer(), data.GetBufSize(),
00495                         &transferred,
00496                         timeout == -1 ? m_timeout : timeout);
00497                 if( ret < 0 && ret != LIBUSB_ERROR_INTERRUPTED ) {
00498                         m_lasterror = ret;
00499                         // only notify of a timeout if no data was transferred,
00500                         // otherwise treat it as success.
00501                         if( ret == LIBUSB_ERROR_TIMEOUT ) {
00502                                 if( transferred == 0 )
00503                                         throw Timeout(ret, "Timeout in InterruptRead");
00504                                 else
00505                                         dout("Read timed out with some data transferred... possible partial read");
00506                         }
00507                         else if( ret != LIBUSB_ERROR_TIMEOUT )
00508                                 throw Error(ret, "Error in InterruptRead");
00509                 }
00510                 if( transferred != 0 )
00511                         data.ReleaseBuffer(transferred);
00512 
00513         } while( ret == -LIBUSB_ERROR_INTERRUPTED );
00514 
00515         return ret >= 0;
00516 
00517 }
00518 
00519 bool Device::InterruptWrite(int ep, const Barry::Data &data, int timeout)
00520 {
00521         ddout("InterruptWrite to endpoint 0x" << std::hex << ep << ":\n" << data);
00522         int ret;
00523         do {
00524                 int transferred;
00525                 ret = libusb_interrupt_transfer(m_handle->m_handle,
00526                         ep | LIBUSB_ENDPOINT_OUT,
00527                         const_cast<unsigned char*>(data.GetData()),
00528                         data.GetSize(),
00529                         &transferred,
00530                         timeout == -1 ? m_timeout : timeout);
00531                 if( ret < 0 && ret != LIBUSB_ERROR_INTERRUPTED ) {
00532                         m_lasterror = ret;
00533                         // only notify of a timeout if no data was transferred,
00534                         // otherwise treat it as success.
00535                         if( ret == LIBUSB_ERROR_TIMEOUT && transferred == 0 )
00536                                 throw Timeout(ret, "Timeout in InterruptWrite");
00537                         else if( ret != LIBUSB_ERROR_TIMEOUT )
00538                                 throw Error(ret, "Error in InterruptWrite");
00539                 }
00540                 if( ret >= 0 && 
00541                     (unsigned int)transferred != data.GetSize() ) {
00542                         dout("Failed to write all data on ep: " << ep <<
00543                              " attempted to write: " << data.GetSize() << 
00544                              " but only wrote: " << transferred);
00545                         throw Error("Failed to perform a complete write");
00546                 }
00547 
00548         } while( ret == -LIBUSB_ERROR_INTERRUPTED );
00549 
00550         return ret >= 0;
00551 }
00552 
00553 //
00554 // BulkDrain
00555 //
00556 /// Reads anything available on the given endpoint, with a low timeout,
00557 /// in order to clear any pending reads.
00558 ///
00559 void Device::BulkDrain(int ep, int timeout)
00560 {
00561         try {
00562                 Barry::Data data;
00563                 while( BulkRead(ep, data, timeout) )
00564                 ;
00565         }
00566         catch( Usb::Error & ) {}
00567 }
00568 
00569 //
00570 // GetConfiguration
00571 //
00572 /// Determines the currently selected USB configuration, returning it
00573 /// in the cfg argument.
00574 /// If unsuccessful, returns false.
00575 ///
00576 bool Device::GetConfiguration(unsigned char &cfg)
00577 {
00578         int config = 0;
00579         int result = libusb_get_configuration(m_handle->m_handle, &config);
00580         if( result >= 0 )
00581                 cfg = config;
00582         m_lasterror = result;
00583         return result >= 0;
00584 }
00585 
00586 // Returns the current power level of the device, or 0 if unknown
00587 int Device::GetPowerLevel()
00588 {
00589         struct libusb_config_descriptor* cfg = NULL;
00590         int ret = 0;
00591         int result = libusb_get_active_config_descriptor(m_id.m_impl->m_dev, &cfg);
00592         m_lasterror = result;
00593         if( result == 0 ) {
00594                 ret = cfg->MaxPower;
00595         }
00596 
00597         if( cfg )
00598                 libusb_free_config_descriptor(cfg);
00599 
00600         return ret;
00601 }
00602 
00603 bool Device::IsAttachKernelDriver(int iface)
00604 {
00605         int ret;
00606 
00607         ret = libusb_kernel_driver_active(m_handle->m_handle, iface);
00608         if (ret == 0) {
00609                 dout("interface (" << m_handle->m_handle << ", 0x" << std::hex << iface
00610                         << ") already claimed by a driver of unknown name.");
00611                 return true;
00612         }
00613 
00614         return false;
00615 }
00616 
00617 // Requests that the kernel driver is detached, returning false on failure
00618 bool Device::DetachKernelDriver(int iface)
00619 {
00620         int result = libusb_detach_kernel_driver(m_handle->m_handle, iface);
00621         m_lasterror = result;
00622         return result >= 0;
00623 }
00624 
00625 // Sends a control message to the device, returning false on failure
00626 bool Device::ControlMsg(int requesttype, int request, int value,
00627                         int index, char *bytes, int size, int timeout)
00628 {
00629         int result = libusb_control_transfer(m_handle->m_handle,
00630                                              requesttype, request, value, index,
00631                                              (unsigned char*)bytes, size, timeout);
00632         m_lasterror = result;
00633         return result >= 0;
00634 }
00635 
00636 int Device::FindInterface(int ifaceClass)
00637 {
00638         struct libusb_config_descriptor* cfg = NULL;
00639         int ret = libusb_get_active_config_descriptor(m_id.m_impl->m_dev, &cfg);
00640         if( ret == 0 ) {
00641                 for( int i = 0; cfg->interface && i < cfg->bNumInterfaces; ++i ) {
00642                         const struct libusb_interface& iface = cfg->interface[i];
00643                         for( int j = 0;
00644                              iface.altsetting && j < iface.num_altsetting;
00645                              ++j ) {
00646                                 const struct libusb_interface_descriptor& id = 
00647                                         iface.altsetting[j];
00648                                 if( id.bInterfaceClass == ifaceClass )
00649                                         return id.bInterfaceNumber;
00650                         }
00651                 }
00652         }
00653 
00654         if( cfg )
00655                 libusb_free_config_descriptor(cfg);
00656 
00657         return ret;
00658 }
00659 
00660 ///////////////////////////////////////////////////////////////////////////////
00661 // Interface
00662 
00663 Interface::Interface(Device &dev, int iface)
00664         : m_dev(dev), m_iface(iface)
00665 {
00666         dout("libusb_claim_interface(" << dev.GetHandle()->m_handle << ", 0x" << std::hex << iface << ")");
00667         int ret = libusb_claim_interface(dev.GetHandle()->m_handle, iface);
00668         if( ret < 0 )
00669                 throw Error(ret, "claim interface failed");
00670 }
00671 
00672 Interface::~Interface()
00673 {
00674         dout("libusb_release_interface(" << m_dev.GetHandle()->m_handle << ", 0x" << std::hex << m_iface << ")");
00675         libusb_release_interface(m_dev.GetHandle()->m_handle, m_iface);
00676 }
00677 
00678 
00679 //
00680 // SetAltInterface
00681 //
00682 /// Sets the currently selected USB alternate setting of the current interface.
00683 /// The iface parameter passed in should be a value specified
00684 /// in the bAlternateSetting descriptor field.
00685 /// If unsuccessful, returns false.
00686 ///
00687 bool Interface::SetAltInterface(int altSetting)
00688 {
00689         int result = libusb_set_interface_alt_setting(
00690                 m_dev.GetHandle()->m_handle,
00691                 m_iface,
00692                 altSetting);
00693         m_dev.SetLastError(result);
00694         return result >= 0;
00695 }
00696 
00697 
00698 
00699 //////////////////////////////////////////////////////////////////
00700 // DeviceDescriptor
00701 
00702 DeviceDescriptor::DeviceDescriptor(DeviceID& devid)
00703         : m_impl(new DeviceDescriptorImpl())
00704 {
00705         if( !devid.m_impl.get() ) {
00706                 dout("DeviceDescriptor: empty devid");
00707                 return;
00708         }
00709         m_impl->m_devid = devid;
00710         int ret = libusb_get_device_descriptor(devid.m_impl->m_dev, &m_impl->m_desc);
00711         if( ret != 0 ) {
00712                 dout("Failed to read device descriptor with err: " << ret);
00713                 return;
00714         }
00715         dout("device_desc loaded"
00716              << "\nbLength: " << std::dec << (unsigned int) m_impl->m_desc.bLength
00717              << "\nbDescriptorType: " << std::dec << (unsigned int) m_impl->m_desc.bDescriptorType
00718              << "\nbcdUSB: 0x" << std::hex << (unsigned int) m_impl->m_desc.bcdUSB
00719              << "\nbDeviceClass: " << std::dec << (unsigned int) m_impl->m_desc.bDeviceClass
00720              << "\nbDeviceSubClass: " << std::dec << (unsigned int) m_impl->m_desc.bDeviceSubClass
00721              << "\nbDeviceProtocol: " << std::dec << (unsigned int) m_impl->m_desc.bDeviceProtocol
00722              << "\nbMaxPacketSize0: " << std::dec << (unsigned int) m_impl->m_desc.bMaxPacketSize0
00723              << "\nidVendor: 0x" << std::hex << (unsigned int) m_impl->m_desc.idVendor
00724              << "\nidProduct: 0x" << std::hex << (unsigned int) m_impl->m_desc.idProduct
00725              << "\nbcdDevice: 0x" << std::hex << (unsigned int) m_impl->m_desc.bcdDevice
00726              << "\niManufacturer: " << std::dec << (unsigned int) m_impl->m_desc.iManufacturer
00727              << "\niProduct: " << std::dec << (unsigned int) m_impl->m_desc.iProduct
00728              << "\niSerialNumber: " << std::dec << (unsigned int) m_impl->m_desc.iSerialNumber
00729              << "\nbNumConfigurations: " << std::dec << (unsigned int) m_impl->m_desc.bNumConfigurations
00730              << "\n"
00731         );
00732 
00733         // Create all the configs
00734         for( int i = 0; i < m_impl->m_desc.bNumConfigurations; ++i ) {
00735                 std::auto_ptr<ConfigDescriptor> ptr(new ConfigDescriptor(*this, i));
00736                 (*this)[ptr->GetNumber()] = ptr.get();
00737                 ptr.release();
00738         }
00739 }
00740 
00741 DeviceDescriptor::~DeviceDescriptor()
00742 {
00743         // Delete any pointers in the vector
00744         std::for_each(begin(),
00745                       end(),
00746                       deleteMapPtr<int, ConfigDescriptor>);
00747 }
00748 
00749 ///////////////////////////////////////////////////////////////////
00750 // ConfigDescriptor
00751 
00752 ConfigDescriptor::ConfigDescriptor(DeviceDescriptor& dev, int cfgnumber)
00753         : m_impl(new ConfigDescriptorImpl())
00754 {
00755         m_impl->m_desc = NULL;
00756         int ret = libusb_get_config_descriptor(dev.m_impl->m_devid.m_impl->m_dev,
00757                                                cfgnumber, &(m_impl->m_desc));
00758         if( ret != 0 ) {
00759                 dout("Failed to read config descriptor with err: " << ret);
00760                 return;
00761         }
00762 
00763         dout("  config_desc #" << std::dec << cfgnumber << " loaded"
00764              << "\nbLength: " << std::dec << (unsigned int) m_impl->m_desc->bLength
00765              << "\nbDescriptorType: " << std::dec << (unsigned int) m_impl->m_desc->bDescriptorType
00766              << "\nwTotalLength: " << std::dec << (unsigned int) m_impl->m_desc->wTotalLength
00767              << "\nbNumInterfaces: " << std::dec << (unsigned int) m_impl->m_desc->bNumInterfaces
00768              << "\nbConfigurationValue: " << std::dec << (unsigned int) m_impl->m_desc->bConfigurationValue
00769              << "\niConfiguration: " << std::dec << (unsigned int) m_impl->m_desc->iConfiguration
00770              << "\nbmAttributes: 0x" << std::hex << (unsigned int) m_impl->m_desc->bmAttributes
00771              << "\nMaxPower: " << std::dec << (unsigned int) m_impl->m_desc->MaxPower
00772              << "\n"
00773                 );
00774 
00775         // just for debugging purposes, check for extra descriptors, and
00776         // dump them to dout if they exist
00777         if( m_impl->m_desc->extra ) {
00778                 dout("while parsing config descriptor, found a block of extra descriptors:");
00779                 Barry::Data data(m_impl->m_desc->extra, m_impl->m_desc->extra_length);
00780                 dout(data);
00781         }
00782 
00783         // Create all the interfaces
00784         for( int i = 0; i < m_impl->m_desc->bNumInterfaces; ++i ) {
00785                 const struct libusb_interface* interface = &(m_impl->m_desc->interface[i]);
00786                 if( !interface->altsetting ) {
00787                         dout("ConfigDescriptor: empty altsetting");
00788                         // some devices are buggy and return a higher bNumInterfaces
00789                         // than the number of interfaces available... in this case
00790                         // we just skip and continue
00791                         continue;
00792                 }
00793                 for( int j = 0; j < interface->num_altsetting; ++j ) {
00794                         std::auto_ptr<InterfaceDescriptor> ptr(
00795                                 new InterfaceDescriptor(*this, i, j));
00796                         (*this)[ptr->GetNumber()] = ptr.get();
00797                         ptr.release();
00798                 }
00799         }
00800 }
00801 
00802 ConfigDescriptor::~ConfigDescriptor()
00803 {
00804         // Delete any pointers in the vector
00805         std::for_each(begin(),
00806                       end(),
00807                       deleteMapPtr<int, InterfaceDescriptor>);
00808         if( m_impl->m_desc ) {
00809                 libusb_free_config_descriptor(m_impl->m_desc);
00810                 m_impl->m_desc = NULL;
00811         }
00812 }
00813 
00814 uint8_t ConfigDescriptor::GetNumber() const {
00815         if( !m_impl->m_desc )
00816                 // Return an invalid config number
00817                 return 0;
00818         return m_impl->m_desc->bConfigurationValue;
00819 }
00820 
00821 /////////////////////////////////////////////////////////////////////////
00822 // InterfaceDescriptor
00823 
00824 InterfaceDescriptor::InterfaceDescriptor(ConfigDescriptor& cfgdesc,
00825                                          int interface, int altsetting)
00826         : m_impl(new InterfaceDescriptorImpl())
00827 {
00828         m_impl->m_desc = NULL;
00829 
00830         // Find the descriptor
00831         m_impl->m_desc =
00832                 &(cfgdesc.m_impl->m_desc
00833                      ->interface[interface]
00834                   .altsetting[altsetting]);
00835         dout("    interface_desc #" << std::dec << interface << " loaded"
00836              << "\nbLength: " << std::dec << (unsigned) m_impl->m_desc->bLength
00837              << "\nbDescriptorType: " << std::dec << (unsigned) m_impl->m_desc->bDescriptorType
00838              << "\nbInterfaceNumber: " << std::dec << (unsigned) m_impl->m_desc->bInterfaceNumber
00839              << "\nbAlternateSetting: " << std::dec << (unsigned) m_impl->m_desc->bAlternateSetting
00840              << "\nbNumEndpoints: " << std::dec << (unsigned) m_impl->m_desc->bNumEndpoints
00841              << "\nbInterfaceClass: " << std::dec << (unsigned) m_impl->m_desc->bInterfaceClass
00842              << "\nbInterfaceSubClass: " << std::dec << (unsigned) m_impl->m_desc->bInterfaceSubClass
00843              << "\nbInterfaceProtocol: " << std::dec << (unsigned) m_impl->m_desc->bInterfaceProtocol
00844              << "\niInterface: " << std::dec << (unsigned) m_impl->m_desc->iInterface
00845              << "\n"
00846                 );
00847 
00848         if( !m_impl->m_desc->endpoint ) {
00849                 dout("InterfaceDescriptor: empty interface pointer");
00850                 return;
00851         }
00852 
00853         // Create all the endpoints
00854         for( int i = 0; i < m_impl->m_desc->bNumEndpoints; ++i ) {
00855                 std::auto_ptr<EndpointDescriptor> ptr (
00856                         new EndpointDescriptor(*this, i));
00857                 push_back(ptr.get());
00858                 ptr.release();
00859         }
00860 
00861         // just for debugging purposes, check for extra descriptors, and
00862         // dump them to dout if they exist
00863         if( m_impl->m_desc->extra ) {
00864                 dout("while parsing interface descriptor, found a block of extra descriptors:");
00865                 Barry::Data data(m_impl->m_desc->extra, m_impl->m_desc->extra_length);
00866                 dout(data);
00867         }
00868 }
00869 
00870 InterfaceDescriptor::~InterfaceDescriptor()
00871 {
00872         // Delete any pointers in the vector
00873         std::for_each(begin(),
00874                       end(),
00875                       deletePtr<EndpointDescriptor>);
00876 }
00877 
00878 uint8_t InterfaceDescriptor::GetClass() const
00879 {
00880         return m_impl->m_desc->bInterfaceClass;
00881 }
00882 
00883 uint8_t InterfaceDescriptor::GetNumber() const
00884 {
00885         if( !m_impl->m_desc )
00886                 // Return an invalid interface number
00887                 return 0;
00888         return m_impl->m_desc->bInterfaceNumber;
00889 }
00890 
00891 uint8_t InterfaceDescriptor::GetAltSetting() const
00892 {
00893         if( !m_impl->m_desc )
00894                 // Return an invalid setting number
00895                 return 0;
00896         return m_impl->m_desc->bAlternateSetting;
00897 }
00898 
00899 /////////////////////////////////////////////////////////////////////////////////
00900 // EndpointDescriptor
00901 
00902 EndpointDescriptor::EndpointDescriptor(InterfaceDescriptor& intdesc, int endpoint)
00903         : m_impl(new EndpointDescriptorImpl()),
00904           m_read(false),
00905           m_addr(0),
00906           m_type(InvalidType)
00907 {
00908         // Copy the descriptor
00909         m_impl->m_desc = &(intdesc.m_impl->m_desc->endpoint[endpoint]);
00910 
00911         dout("      endpoint_desc #" << std::dec << endpoint << " loaded"
00912              << "\nbLength: " << std::dec << (unsigned ) m_impl->m_desc->bLength
00913              << "\nbDescriptorType: " << std::dec << (unsigned ) m_impl->m_desc->bDescriptorType
00914              << "\nbEndpointAddress: 0x" << std::hex << (unsigned ) m_impl->m_desc->bEndpointAddress
00915              << "\nbmAttributes: 0x" << std::hex << (unsigned ) m_impl->m_desc->bmAttributes
00916              << "\nwMaxPacketSize: " << std::dec << (unsigned ) m_impl->m_desc->wMaxPacketSize
00917              << "\nbInterval: " << std::dec << (unsigned ) m_impl->m_desc->bInterval
00918              << "\nbRefresh: " << std::dec << (unsigned ) m_impl->m_desc->bRefresh
00919              << "\nbSynchAddress: " << std::dec << (unsigned ) m_impl->m_desc->bSynchAddress
00920              << "\n"
00921                 );
00922         // Set up variables
00923         m_read = ((m_impl->m_desc->bEndpointAddress & LIBUSB_ENDPOINT_DIR_MASK) == 
00924                 LIBUSB_ENDPOINT_IN);
00925         m_addr = (m_impl->m_desc->bEndpointAddress & LIBUSB_ENDPOINT_ADDRESS_MASK);
00926         int type = (m_impl->m_desc->bmAttributes & LIBUSB_TRANSFER_TYPE_MASK);
00927         m_type = static_cast<Usb::EndpointDescriptor::EpType>(type);
00928 
00929         // just for debugging purposes, check for extra descriptors, and
00930         // dump them to dout if they exist
00931         if( m_impl->m_desc->extra ) {
00932                 dout("while parsing endpoint descriptor, found a block of extra descriptors:");
00933                 Barry::Data data(m_impl->m_desc->extra, m_impl->m_desc->extra_length);
00934                 dout(data);
00935         }
00936 }
00937 
00938 EndpointDescriptor::~EndpointDescriptor()
00939 {
00940 }
00941 
00942 } // namespace Usb
00943