usbwrap_libusb.cc

Go to the documentation of this file.
00001 ///
00002 /// \file       usbwrap_libusb.cc
00003 ///             USB API wrapper for libusb version 0.1
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 #include "usbwrap_libusb.h"
00024 
00025 #include "debug.h"
00026 #include "data.h"
00027 #include <errno.h>
00028 #include <string.h>
00029 #include <iostream>
00030 #include <sstream>
00031 #include <algorithm>
00032 
00033 #ifndef __DEBUG_MODE__
00034 #define __DEBUG_MODE__
00035 #endif
00036 #include "debug.h"
00037 
00038 namespace Usb {
00039 
00040 // helper function to make deleting pointers in maps and vectors easier
00041 template<typename T> static void deletePtr(T* ptr) {
00042         delete ptr;
00043 }
00044 
00045 template<typename K, typename T> static void deleteMapPtr(std::pair<K,T*> ptr) {
00046         delete ptr.second;
00047 }
00048 
00049 ///////////////////////////////////////////////////////////////////////////////
00050 // Static functions
00051 
00052 std::string LibraryInterface::GetLastErrorString(int /*libusb_errcode*/)
00053 {
00054         // Errcode is unused by libusb, so just call the last error
00055         return std::string(usb_strerror());
00056 }
00057 
00058 int LibraryInterface::TranslateErrcode(int libusb_errcode)
00059 {
00060         // libusb errcode == system errcode
00061         return libusb_errcode;
00062 }
00063 
00064 bool LibraryInterface::Init(int *libusb_errno)
00065 {
00066         // if the environment variable USB_DEBUG is set, that
00067         // level value will be used instead of our 9 below...
00068         // if you need to *force* this to 9, call SetDataDump(true)
00069         // after Init()
00070         usb_init();
00071         // Can never fail, so return success
00072         return true;
00073 }
00074 
00075 void LibraryInterface::Uninit()
00076 {
00077         // Nothing to do
00078 }
00079 
00080 void LibraryInterface::SetDataDump(bool data_dump_mode)
00081 {
00082         if( data_dump_mode )
00083                 usb_set_debug(9);
00084         else
00085                 usb_set_debug(0);
00086 }
00087 
00088 ///////////////////////////////////////////////////////////////////////////////
00089 // DeviceID
00090 
00091 DeviceID::DeviceID(DeviceIDImpl* impl)
00092         : m_impl(impl)
00093 {
00094 }
00095 
00096 DeviceID::~DeviceID()
00097 {
00098 }
00099 
00100 const char* DeviceID::GetBusName() const
00101 {
00102         return m_impl->m_dev->bus->dirname;
00103 }
00104 
00105 uint16_t DeviceID::GetNumber() const
00106 {
00107         return m_impl->m_dev->devnum;
00108 }
00109 
00110 const char* DeviceID::GetFilename() const
00111 {
00112         return m_impl->m_dev->filename;
00113 }
00114 
00115 uint16_t DeviceID::GetIdProduct() const
00116 {
00117         return m_impl->m_dev->descriptor.idProduct;
00118 }
00119 
00120 std::string DeviceID::GetUsbName() const
00121 {
00122         // for libusb 0.1, we need both the bus name and the filename
00123         // and we stay away from the product ID, since that requires
00124         // communication with the device, which may not be possible
00125         // in error conditions.
00126         std::ostringstream oss;
00127         oss << GetBusName() << ":" << GetFilename();
00128         return oss.str();
00129 }
00130 
00131 ///////////////////////////////////////////////////////////////////////////////
00132 // DeviceList
00133 
00134 DeviceList::DeviceList()
00135         : m_impl(new DeviceListImpl())
00136 {
00137         // Work out what devices are on the bus at the moment
00138         usb_find_busses();
00139         usb_find_devices();
00140         struct usb_bus* busses = usb_get_busses();
00141         for( ; busses; busses = busses->next ) {
00142                 struct usb_device* dev = busses->devices;
00143                 for( ; dev; dev = dev->next ) {
00144                         // Add the device to the list of devices
00145                         std::auto_ptr<DeviceIDImpl> impl( new DeviceIDImpl() );
00146                         impl->m_dev = dev;
00147                         DeviceID devID(impl.release());
00148                         m_impl->m_devices.push_back(devID);
00149                 }
00150         }
00151 }
00152 
00153 DeviceList::~DeviceList()
00154 {
00155 }
00156 
00157 
00158 static bool ToNum(const char *str, long &num)
00159 {
00160         char *end = 0;
00161         num = strtol(str, &end, 10);
00162         return  num >= 0 &&                     // no negative numbers
00163                 num != LONG_MIN && num != LONG_MAX &&   // no overflow
00164                 str != end && *end == '\0';     // whole string valid
00165 }
00166 
00167 //
00168 // Linux treats bus and device path names as numbers, sometimes left
00169 // padded with zeros.  Other platforms, such as Windows, use strings,
00170 // such as "bus-1" or similar.
00171 //
00172 // Here we try to convert each string to a number, and if successful,
00173 // compare them.  If unable to convert, then compare as strings.
00174 // This way, "3" == "003" and "bus-foobar" == "bus-foobar".
00175 //
00176 static bool NameCompare(const char *n1, const char *n2)
00177 {
00178         long l1, l2;
00179         if( ToNum(n1, l1) && ToNum(n2, l2) ) {
00180                 return l1 == l2;
00181         }
00182         else {
00183                 return strcmp(n1, n2) == 0;
00184         }
00185 }
00186 
00187 std::vector<DeviceID> DeviceList::MatchDevices(int vendor, int product,
00188                                             const char *busname, const char *devname)
00189 {
00190         std::vector<DeviceID> ret;
00191         
00192         std::vector<DeviceID>::iterator iter = m_impl->m_devices.begin();
00193 
00194         for( ; iter != m_impl->m_devices.end() ; ++iter ) {
00195                 struct usb_device* dev = iter->m_impl->m_dev;
00196                 
00197                 // only search on given bus
00198                 if( busname && !NameCompare(busname, dev->bus->dirname) )
00199                         continue;
00200                 
00201                 // search for specific device
00202                 if( devname && !NameCompare(devname, dev->filename) )
00203                         continue;
00204 
00205                 // is there a match?
00206                 if( dev->descriptor.idVendor == vendor &&
00207                     ( dev->descriptor.idProduct == product ||
00208                       product == PRODUCT_ANY )) {
00209                         ret.push_back(*iter);
00210                 }
00211         }
00212 
00213         return ret;
00214 }
00215 
00216 ///////////////////////////////////////////////////////////////////////////////
00217 // Device
00218 
00219 Device::Device(const Usb::DeviceID& id, int timeout)
00220         : m_id(id),
00221         m_timeout(timeout)
00222 {
00223         dout("usb_open(" << std::dec << id.m_impl.get() << ")");
00224         if( !id.m_impl.get() )
00225                 throw Error("invalid USB device ID");
00226         m_handle.reset(new DeviceHandle());
00227         m_handle->m_handle = usb_open(id.m_impl->m_dev);
00228         if( !m_handle->m_handle )
00229                 throw Error("Failed to open USB device.  Please check your system's USB device permissions.");
00230 }
00231 
00232 Device::~Device()
00233 {
00234         dout("usb_close(" << std::dec << m_handle->m_handle << ")");
00235         usb_close(m_handle->m_handle);
00236 }
00237 
00238 bool Device::SetConfiguration(unsigned char cfg)
00239 {
00240         dout("usb_set_configuration(" << std::dec << m_handle->m_handle << ", 0x" << std::hex << (unsigned int) cfg << ")");
00241         int ret = usb_set_configuration(m_handle->m_handle, cfg);
00242         m_lasterror = ret;
00243         return ret >= 0;
00244 }
00245 
00246 bool Device::ClearHalt(int ep)
00247 {
00248         dout("usb_clear_halt(" << std::dec << m_handle->m_handle << ", 0x" << std::hex << ep << ")");
00249         int ret = usb_clear_halt(m_handle->m_handle, ep);
00250         m_lasterror = ret;
00251         return ret >= 0;
00252 }
00253 
00254 bool Device::Reset()
00255 {
00256         dout("usb_reset(" << std::dec << m_handle->m_handle << ")");
00257         int ret = usb_reset(m_handle->m_handle);
00258         m_lasterror = ret;
00259         return ret == 0;
00260 }
00261 
00262 bool Device::BulkRead(int ep, Barry::Data &data, int timeout)
00263 {
00264         int ret;
00265         do {
00266                 data.QuickZap();
00267                 ret = usb_bulk_read(m_handle->m_handle, ep,
00268                         (char*) data.GetBuffer(), data.GetBufSize(),
00269                         timeout == -1 ? m_timeout : timeout);
00270                 if( ret < 0 && ret != -EINTR && ret != -EAGAIN ) {
00271                         m_lasterror = ret;
00272                         if( ret == -ETIMEDOUT )
00273                                 throw Timeout(ret, "Timeout in usb_bulk_read");
00274                         else {
00275                                 std::ostringstream oss;
00276                                 oss << "Error in usb_bulk_read("
00277                                     << m_handle->m_handle << ", "
00278                                     << ep << ", buf, "
00279                                     << data.GetBufSize() << ")";
00280                                 throw Error(ret, oss.str());
00281                         }
00282                 }
00283                 else if( ret > 0 )
00284                         data.ReleaseBuffer(ret);
00285         } while( ret == -EINTR || ret == -EAGAIN );
00286 
00287         return ret >= 0;
00288 }
00289 
00290 bool Device::BulkWrite(int ep, const Barry::Data &data, int timeout)
00291 {
00292         ddout("BulkWrite to endpoint 0x" << std::hex << ep << ":\n" << data);
00293         int ret;
00294         do {
00295                 ret = usb_bulk_write(m_handle->m_handle, ep,
00296                         (char*) data.GetData(), data.GetSize(),
00297                         timeout == -1 ? m_timeout : timeout);
00298                 if( ret < 0 && ret != -EINTR && ret != -EAGAIN ) {
00299                         m_lasterror = ret;
00300                         if( ret == -ETIMEDOUT )
00301                                 throw Timeout(ret, "Timeout in usb_bulk_write (1)");
00302                         else
00303                                 throw Error(ret, "Error in usb_bulk_write (1)");
00304                 }
00305         } while( ret == -EINTR || ret == -EAGAIN );
00306 
00307         return ret >= 0;
00308 }
00309 
00310 bool Device::BulkWrite(int ep, const void *data, size_t size, int timeout)
00311 {
00312 #ifdef __DEBUG_MODE__
00313         Barry::Data dump(data, size);
00314         ddout("BulkWrite to endpoint 0x" << std::hex << ep << ":\n" << dump);
00315 #endif
00316 
00317         int ret;
00318         do {
00319                 ret = usb_bulk_write(m_handle->m_handle, ep,
00320                         (char*) data, size,
00321                         timeout == -1 ? m_timeout : timeout);
00322                 if( ret < 0 && ret != -EINTR && ret != -EAGAIN ) {
00323                         m_lasterror = ret;
00324                         if( ret == -ETIMEDOUT )
00325                                 throw Timeout(ret, "Timeout in usb_bulk_write (2)");
00326                         else
00327                                 throw Error(ret, "Error in usb_bulk_write (2)");
00328                 }
00329         } while( ret == -EINTR || ret == -EAGAIN );
00330 
00331         return ret >= 0;
00332 }
00333 
00334 bool Device::InterruptRead(int ep, Barry::Data &data, int timeout)
00335 {
00336         int ret;
00337         do {
00338                 data.QuickZap();
00339                 ret = usb_interrupt_read(m_handle->m_handle, ep,
00340                         (char*) data.GetBuffer(), data.GetBufSize(),
00341                         timeout == -1 ? m_timeout : timeout);
00342                 if( ret < 0 && ret != -EINTR && ret != -EAGAIN ) {
00343                         m_lasterror = ret;
00344                         if( ret == -ETIMEDOUT )
00345                                 throw Timeout(ret, "Timeout in usb_interrupt_read");
00346                         else
00347                                 throw Error(ret, "Error in usb_interrupt_read");
00348                 }
00349                 else if( ret > 0 )
00350                         data.ReleaseBuffer(ret);
00351         } while( ret == -EINTR || ret == -EAGAIN );
00352 
00353         return ret >= 0;
00354 }
00355 
00356 bool Device::InterruptWrite(int ep, const Barry::Data &data, int timeout)
00357 {
00358         ddout("InterruptWrite to endpoint 0x" << std::hex << ep << ":\n" << data);
00359 
00360         int ret;
00361         do {
00362                 ret = usb_interrupt_write(m_handle->m_handle, ep,
00363                         (char*) data.GetData(), data.GetSize(),
00364                         timeout == -1 ? m_timeout : timeout);
00365                 if( ret < 0 && ret != -EINTR && ret != -EAGAIN ) {
00366                         m_lasterror = ret;
00367                         if( ret == -ETIMEDOUT )
00368                                 throw Timeout(ret, "Timeout in usb_interrupt_write");
00369                         else
00370                                 throw Error(ret, "Error in usb_interrupt_write");
00371                 }
00372         } while( ret == -EINTR || ret == -EAGAIN );
00373 
00374         return ret >= 0;
00375 }
00376 
00377 //
00378 // BulkDrain
00379 //
00380 /// Reads anything available on the given endpoint, with a low timeout,
00381 /// in order to clear any pending reads.
00382 ///
00383 void Device::BulkDrain(int ep, int timeout)
00384 {
00385         try {
00386                 Barry::Data data;
00387                 while( BulkRead(ep, data, timeout) )
00388                 ;
00389         }
00390         catch( Usb::Error & ) {}
00391 }
00392 
00393 //
00394 // GetConfiguration
00395 //
00396 /// Uses the GET_CONFIGURATION control message to determine the currently
00397 /// selected USB configuration, returning it in the cfg argument.
00398 /// If unsuccessful, returns false.
00399 ///
00400 bool Device::GetConfiguration(unsigned char &cfg)
00401 {
00402         int result = usb_control_msg(m_handle->m_handle, 0x80, USB_REQ_GET_CONFIGURATION, 0, 0,
00403                 (char*) &cfg, 1, m_timeout);
00404         m_lasterror = result;
00405         return result >= 0;
00406 }
00407 
00408 // Returns the current power level of the device, or 0 if unknown
00409 int Device::GetPowerLevel()
00410 {
00411         if( !m_id.m_impl->m_dev->config ||
00412             !m_id.m_impl->m_dev->descriptor.bNumConfigurations < 1 )
00413                 return 0;
00414 
00415         return m_id.m_impl->m_dev->config[0].MaxPower;
00416 }
00417 
00418 bool Device::IsAttachKernelDriver(int iface)
00419 {
00420         int ret;
00421         char buffer[64];
00422 
00423 #if LIBUSB_HAS_GET_DRIVER_NP
00424         ret = usb_get_driver_np(m_handle->m_handle, iface, buffer, sizeof(buffer));
00425         if (ret == 0) {
00426                 dout("interface (" << m_handle->m_handle << ", 0x" << std::hex << iface
00427                         << ") already claimed by driver \"" << buffer << "\"");
00428                 return true;
00429         }
00430         m_lasterror = ret;
00431 #else
00432         m_lasterror = -ENOSYS;
00433 #endif
00434 
00435         return false;
00436 }
00437 
00438 // Requests that the kernel driver is detached, returning false on failure
00439 bool Device::DetachKernelDriver(int iface)
00440 {
00441 #if LIBUSB_HAS_DETACH_KERNEL_DRIVER_NP
00442         int result = usb_detach_kernel_driver_np(m_handle->m_handle, iface);
00443         m_lasterror = result;
00444         return result >= 0;
00445 #else
00446         m_lasterror = -ENOSYS;
00447         return false;
00448 #endif
00449 }
00450 
00451 // Sends a control message to the device, returning false on failure
00452 bool Device::ControlMsg(int requesttype, int request, int value,
00453                         int index, char *bytes, int size, int timeout)
00454 {
00455         int result = usb_control_msg(m_handle->m_handle,
00456                                      requesttype, request, value, index,
00457                                      bytes, size, timeout);
00458         m_lasterror = result;
00459         return result >= 0;
00460 }
00461 
00462 
00463 int Device::FindInterface(int ifaceClass)
00464 {
00465         struct usb_config_descriptor *cfg = m_id.m_impl->m_dev->config;
00466 
00467         if( cfg ) {
00468 
00469                 for( unsigned i = 0; cfg->interface && i < cfg->bNumInterfaces; i++ ) {
00470                         struct usb_interface *iface = &cfg->interface[i];
00471                         for( int a = 0; iface->altsetting && a < iface->num_altsetting; a++ ) {
00472                                 struct usb_interface_descriptor *id = &iface->altsetting[a];
00473                                 if( id->bInterfaceClass == ifaceClass )
00474                                         return id->bInterfaceNumber;
00475                         }
00476                 }
00477         }
00478 
00479         return -1;
00480 }
00481 
00482 
00483 ///////////////////////////////////////////////////////////////////////////////
00484 // Interface
00485 
00486 Interface::Interface(Device &dev, int iface)
00487         : m_dev(dev), m_iface(iface)
00488 {
00489         dout("usb_claim_interface(" << dev.GetHandle()->m_handle << ", 0x" << std::hex << iface << ")");
00490         int ret = usb_claim_interface(dev.GetHandle()->m_handle, iface);
00491         if( ret < 0 )
00492                 throw Error(ret, "claim interface failed");
00493 }
00494 
00495 Interface::~Interface()
00496 {
00497         dout("usb_release_interface(" << m_dev.GetHandle()->m_handle << ", 0x" << std::hex << m_iface << ")");
00498         usb_release_interface(m_dev.GetHandle()->m_handle, m_iface);
00499 }
00500 
00501 //
00502 // SetAltInterface
00503 //
00504 /// Uses the usb_set_altinterface() function to set the currently
00505 /// selected USB alternate setting of the current interface.
00506 /// The iface parameter passed in should be a value specified
00507 /// in the bAlternateSetting descriptor field.
00508 /// If unsuccessful, returns false.
00509 ///
00510 bool Interface::SetAltInterface(int altSetting)
00511 {
00512         int result = usb_set_altinterface(m_dev.GetHandle()->m_handle, altSetting);
00513         m_dev.SetLastError(result);
00514         return result >= 0;
00515 }
00516 
00517 //////////////////////////////////////////////////////////////////
00518 // DeviceDescriptor
00519 
00520 DeviceDescriptor::DeviceDescriptor(DeviceID& devid)
00521         : m_impl(new DeviceDescriptorImpl())
00522 {
00523         if( !devid.m_impl.get() ) {
00524                 dout("DeviceDescriptor: empty devid");
00525                 return;
00526         }
00527         // Copy the descriptor over to our memory
00528         m_impl->m_dev = devid.m_impl->m_dev;
00529         m_impl->m_desc = devid.m_impl->m_dev->descriptor;
00530         dout("device_desc loaded"
00531              << "\nbLength: " << std::dec << (unsigned int) m_impl->m_desc.bLength
00532              << "\nbDescriptorType: " << std::dec << (unsigned int) m_impl->m_desc.bDescriptorType
00533              << "\nbcdUSB: 0x" << std::hex << (unsigned int) m_impl->m_desc.bcdUSB
00534              << "\nbDeviceClass: " << std::dec << (unsigned int) m_impl->m_desc.bDeviceClass
00535              << "\nbDeviceSubClass: " << std::dec << (unsigned int) m_impl->m_desc.bDeviceSubClass
00536              << "\nbDeviceProtocol: " << std::dec << (unsigned int) m_impl->m_desc.bDeviceProtocol
00537              << "\nbMaxPacketSize0: " << std::dec << (unsigned int) m_impl->m_desc.bMaxPacketSize0
00538              << "\nidVendor: 0x" << std::hex << (unsigned int) m_impl->m_desc.idVendor
00539              << "\nidProduct: 0x" << std::hex << (unsigned int) m_impl->m_desc.idProduct
00540              << "\nbcdDevice: 0x" << std::hex << (unsigned int) m_impl->m_desc.bcdDevice
00541              << "\niManufacturer: " << std::dec << (unsigned int) m_impl->m_desc.iManufacturer
00542              << "\niProduct: " << std::dec << (unsigned int) m_impl->m_desc.iProduct
00543              << "\niSerialNumber: " << std::dec << (unsigned int) m_impl->m_desc.iSerialNumber
00544              << "\nbNumConfigurations: " << std::dec << (unsigned int) m_impl->m_desc.bNumConfigurations
00545              << "\n"
00546         );
00547         
00548         // Create all the configs
00549         for( int i = 0; i < m_impl->m_desc.bNumConfigurations; ++i ) {
00550                 std::auto_ptr<ConfigDescriptor> ptr(new ConfigDescriptor(*this, i));
00551                 (*this)[ptr->GetNumber()] = ptr.get();
00552                 ptr.release();
00553         }
00554 }
00555 
00556 DeviceDescriptor::~DeviceDescriptor()
00557 {
00558         // Delete any pointers in the map
00559         std::for_each(begin(),
00560                       end(),
00561                       deleteMapPtr<int, ConfigDescriptor>);
00562 }
00563 
00564 ///////////////////////////////////////////////////////////////////
00565 // ConfigDescriptor
00566 
00567 ConfigDescriptor::ConfigDescriptor(DeviceDescriptor& dev, int cfgnumber)
00568         : m_impl(new ConfigDescriptorImpl())
00569 {
00570         // Copy the config descriptor locally
00571         m_impl->m_desc = dev.m_impl->m_dev->config[cfgnumber];
00572         dout("  config_desc #" << std::dec << cfgnumber << " loaded"
00573              << "\nbLength: " << std::dec << (unsigned int) m_impl->m_desc.bLength
00574              << "\nbDescriptorType: " << std::dec << (unsigned int) m_impl->m_desc.bDescriptorType
00575              << "\nwTotalLength: " << std::dec << (unsigned int) m_impl->m_desc.wTotalLength
00576              << "\nbNumInterfaces: " << std::dec << (unsigned int) m_impl->m_desc.bNumInterfaces
00577              << "\nbConfigurationValue: " << std::dec << (unsigned int) m_impl->m_desc.bConfigurationValue
00578              << "\niConfiguration: " << std::dec << (unsigned int) m_impl->m_desc.iConfiguration
00579              << "\nbmAttributes: 0x" << std::hex << (unsigned int) m_impl->m_desc.bmAttributes
00580              << "\nMaxPower: " << std::dec << (unsigned int) m_impl->m_desc.MaxPower
00581              << "\n"
00582                 );
00583 
00584         // just for debugging purposes, check for extra descriptors, and
00585         // dump them to dout if they exist
00586         if( m_impl->m_desc.extra ) {
00587                 dout("while parsing config descriptor, found a block of extra descriptors:");
00588                 Barry::Data data(m_impl->m_desc.extra, m_impl->m_desc.extralen);
00589                 dout(data);
00590         }
00591 
00592         // Create all the interfaces
00593         for( int i = 0; i < m_impl->m_desc.bNumInterfaces; ++i ) {
00594                 struct usb_interface* interface = &(m_impl->m_desc.interface[i]);
00595                 if( !interface->altsetting ) {
00596                         dout("ConfigDescriptor: empty altsetting");
00597                         // some devices are buggy and return a higher bNumInterfaces
00598                         // than the number of interfaces available... in this case
00599                         // we just skip and continue
00600                         continue;
00601                 }
00602                 for( int j = 0; j < interface->num_altsetting; ++j ) {
00603                         std::auto_ptr<InterfaceDescriptor> ptr(
00604                                 new InterfaceDescriptor(*this, i, j));
00605                         (*this)[ptr->GetNumber()] = ptr.get();
00606                         ptr.release();
00607                 }
00608         }
00609 }
00610 
00611 ConfigDescriptor::~ConfigDescriptor()
00612 {
00613         // Delete any pointers in the map
00614         std::for_each(begin(),
00615                       end(),
00616                       deleteMapPtr<int, InterfaceDescriptor>);
00617 }
00618 
00619 uint8_t ConfigDescriptor::GetNumber() const {
00620         return m_impl->m_desc.bConfigurationValue;
00621 }
00622 
00623 /////////////////////////////////////////////////////////////////////////
00624 // InterfaceDescriptor
00625 
00626 InterfaceDescriptor::InterfaceDescriptor(ConfigDescriptor& cfg,
00627                                          int interface, int altsetting)
00628         : m_impl(new InterfaceDescriptorImpl())
00629 {
00630         // Copy the descriptor
00631         m_impl->m_desc = cfg.m_impl->m_desc
00632                      .interface[interface]
00633                      .altsetting[altsetting];
00634         dout("    interface_desc #" << std::dec << interface << " loaded"
00635              << "\nbLength: " << std::dec << (unsigned) m_impl->m_desc.bLength
00636              << "\nbDescriptorType: " << std::dec << (unsigned) m_impl->m_desc.bDescriptorType
00637              << "\nbInterfaceNumber: " << std::dec << (unsigned) m_impl->m_desc.bInterfaceNumber
00638              << "\nbAlternateSetting: " << std::dec << (unsigned) m_impl->m_desc.bAlternateSetting
00639              << "\nbNumEndpoints: " << std::dec << (unsigned) m_impl->m_desc.bNumEndpoints
00640              << "\nbInterfaceClass: " << std::dec << (unsigned) m_impl->m_desc.bInterfaceClass
00641              << "\nbInterfaceSubClass: " << std::dec << (unsigned) m_impl->m_desc.bInterfaceSubClass
00642              << "\nbInterfaceProtocol: " << std::dec << (unsigned) m_impl->m_desc.bInterfaceProtocol
00643              << "\niInterface: " << std::dec << (unsigned) m_impl->m_desc.iInterface
00644              << "\n"
00645                 );
00646 
00647         if( !m_impl->m_desc.endpoint ) {
00648                 dout("InterfaceDescriptor: empty interface pointer");
00649                 return;
00650         }
00651 
00652         // Create all the endpoints
00653         for( int i = 0; i < m_impl->m_desc.bNumEndpoints; ++i ) {
00654                 std::auto_ptr<EndpointDescriptor> ptr (
00655                         new EndpointDescriptor(*this, i));
00656                 this->push_back(ptr.get());
00657                 ptr.release();
00658         }
00659 
00660         // just for debugging purposes, check for extra descriptors, and
00661         // dump them to dout if they exist
00662         if( m_impl->m_desc.extra ) {
00663                 dout("while parsing interface descriptor, found a block of extra descriptors:");
00664                 Barry::Data data(m_impl->m_desc.extra, m_impl->m_desc.extralen);
00665                 dout(data);
00666         }
00667 }
00668 
00669 InterfaceDescriptor::~InterfaceDescriptor()
00670 {
00671         // Delete any pointers in the vector
00672         std::for_each(begin(),
00673                       end(),
00674                       deletePtr<EndpointDescriptor>);
00675 }
00676 
00677 uint8_t InterfaceDescriptor::GetClass() const
00678 {
00679         return m_impl->m_desc.bInterfaceClass;
00680 }
00681 
00682 uint8_t InterfaceDescriptor::GetNumber() const
00683 {
00684         return m_impl->m_desc.bInterfaceNumber;
00685 }
00686 
00687 uint8_t InterfaceDescriptor::GetAltSetting() const
00688 {
00689         return m_impl->m_desc.bAlternateSetting;
00690 }
00691 
00692 /////////////////////////////////////////////////////////////////////////////////
00693 // EndpointDescriptor
00694 
00695 EndpointDescriptor::EndpointDescriptor(InterfaceDescriptor& interface, int endpoint)
00696         : m_impl(new EndpointDescriptorImpl()),
00697           m_read(false),
00698           m_addr(0),
00699           m_type(InvalidType)
00700 {
00701         // Copy the descriptor
00702         m_impl->m_desc = interface.m_impl->m_desc.endpoint[endpoint];
00703         dout("      endpoint_desc #" << std::dec << endpoint << " loaded"
00704              << "\nbLength: " << std::dec << (unsigned ) m_impl->m_desc.bLength
00705              << "\nbDescriptorType: " << std::dec << (unsigned ) m_impl->m_desc.bDescriptorType
00706              << "\nbEndpointAddress: 0x" << std::hex << (unsigned ) m_impl->m_desc.bEndpointAddress
00707              << "\nbmAttributes: 0x" << std::hex << (unsigned ) m_impl->m_desc.bmAttributes
00708              << "\nwMaxPacketSize: " << std::dec << (unsigned ) m_impl->m_desc.wMaxPacketSize
00709              << "\nbInterval: " << std::dec << (unsigned ) m_impl->m_desc.bInterval
00710              << "\nbRefresh: " << std::dec << (unsigned ) m_impl->m_desc.bRefresh
00711              << "\nbSynchAddress: " << std::dec << (unsigned ) m_impl->m_desc.bSynchAddress
00712              << "\n"
00713                 );
00714         // Set up variables
00715         m_read = ((m_impl->m_desc.bEndpointAddress & USB_ENDPOINT_DIR_MASK) != 0);
00716         m_addr = (m_impl->m_desc.bEndpointAddress & USB_ENDPOINT_ADDRESS_MASK);
00717         int type = (m_impl->m_desc.bmAttributes & USB_ENDPOINT_TYPE_MASK);
00718         m_type = static_cast<Usb::EndpointDescriptor::EpType>(type);
00719 
00720         // just for debugging purposes, check for extra descriptors, and
00721         // dump them to dout if they exist
00722         if( m_impl->m_desc.extra ) {
00723                 dout("while parsing endpoint descriptor, found a block of extra descriptors:");
00724                 Barry::Data data(m_impl->m_desc.extra, m_impl->m_desc.extralen);
00725                 dout(data);
00726         }
00727 }
00728 
00729 EndpointDescriptor::~EndpointDescriptor()
00730 {
00731 }
00732 
00733 } // namespace Usb
00734