7 Copyright (C) 2005-2007, Chris Frey
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
18 See the GNU General Public License in the COPYING file at the
19 root directory of this project for more details.
32 #ifndef __DEBUG_MODE__
33 #define __DEBUG_MODE__
39 ///////////////////////////////////////////////////////////////////////////////
40 // Usb::Error exception class
42 static std::string
GetErrorString(int libusb_errcode
, const std::string
&str
)
44 std::ostringstream oss
;
47 if( libusb_errcode
) {
48 oss
<< std::setbase(10) << libusb_errcode
<< ", ";
51 // oss << strerror(-libusb_errno) << "): "
52 oss
<< usb_strerror() << "): ";
57 Error::Error(const std::string
&str
)
58 : Barry::Error(GetErrorString(0, str
))
63 Error::Error(int libusb_errcode
, const std::string
&str
)
64 : Barry::Error(GetErrorString(libusb_errcode
, str
))
65 , m_libusb_errcode(libusb_errcode
)
70 ///////////////////////////////////////////////////////////////////////////////
73 Match::Match(int vendor
, int product
)
81 m_busses
= usb_get_busses();
88 bool Match::next_device(Usb::DeviceIDType
*devid
)
90 for( ; m_busses
; m_busses
= m_busses
->next
) {
93 m_dev
= m_busses
->devices
;
95 for( ; m_dev
; m_dev
= m_dev
->next
) {
97 if( m_dev
->descriptor
.idVendor
== m_vendor
&&
98 m_dev
->descriptor
.idProduct
== m_product
) {
102 // advance for next time
105 m_busses
= m_busses
->next
;
116 ///////////////////////////////////////////////////////////////////////////////
119 Device::Device(Usb::DeviceIDType id
, int timeout
)
123 dout("usb_open(" << std::dec
<< id
<< ")");
124 m_handle
= usb_open(id
);
126 throw Error("open failed");
131 dout("usb_close(" << std::dec
<< m_handle
<< ")");
135 bool Device::SetConfiguration(unsigned char cfg
)
137 dout("usb_set_configuration(" << std::dec
<< m_handle
<< "," << std::dec
<< (unsigned int) cfg
<< ")");
138 int ret
= usb_set_configuration(m_handle
, cfg
);
143 bool Device::ClearHalt(int ep
)
145 dout("usb_clear_halt(" << std::dec
<< m_handle
<< "," << std::dec
<< ep
<< ")");
146 int ret
= usb_clear_halt(m_handle
, ep
);
153 dout("usb_reset(" << std::dec
<< m_handle
<< ")");
154 int ret
= usb_reset(m_handle
);
159 bool Device::BulkRead(int ep
, Barry::Data
&data
, int timeout
)
163 ret
= usb_bulk_read(m_handle
, ep
,
164 (char*) data
.GetBuffer(), data
.GetBufSize(),
165 timeout
== -1 ? m_timeout
: timeout
);
166 if( ret
< 0 && ret
!= -EINTR
&& ret
!= -EAGAIN
) {
168 if( ret
== -ETIMEDOUT
)
169 throw Timeout(ret
, "Timeout in usb_bulk_read");
171 throw Error(ret
, "Error in usb_bulk_read");
173 data
.ReleaseBuffer(ret
);
174 } while( ret
== -EINTR
|| ret
== -EAGAIN
);
179 bool Device::BulkWrite(int ep
, const Barry::Data
&data
, int timeout
)
181 ddout("BulkWrite to endpoint " << std::dec
<< ep
<< ":\n" << data
);
184 ret
= usb_bulk_write(m_handle
, ep
,
185 (char*) data
.GetData(), data
.GetSize(),
186 timeout
== -1 ? m_timeout
: timeout
);
187 if( ret
< 0 && ret
!= -EINTR
&& ret
!= -EAGAIN
) {
189 if( ret
== -ETIMEDOUT
)
190 throw Timeout(ret
, "Timeout in usb_bulk_read");
192 throw Error(ret
, "Error in usb_bulk_read");
194 } while( ret
== -EINTR
|| ret
== -EAGAIN
);
199 bool Device::BulkWrite(int ep
, const void *data
, size_t size
, int timeout
)
201 #ifdef __DEBUG_MODE__
202 Barry::Data
dump(data
, size
);
203 ddout("BulkWrite to endpoint " << std::dec
<< ep
<< ":\n" << dump
);
208 ret
= usb_bulk_write(m_handle
, ep
,
210 timeout
== -1 ? m_timeout
: timeout
);
211 if( ret
< 0 && ret
!= -EINTR
&& ret
!= -EAGAIN
) {
213 if( ret
== -ETIMEDOUT
)
214 throw Timeout(ret
, "Timeout in usb_bulk_read");
216 throw Error(ret
, "Error in usb_bulk_read");
218 } while( ret
== -EINTR
|| ret
== -EAGAIN
);
223 bool Device::InterruptRead(int ep
, Barry::Data
&data
, int timeout
)
227 ret
= usb_interrupt_read(m_handle
, ep
,
228 (char*) data
.GetBuffer(), data
.GetBufSize(),
229 timeout
== -1 ? m_timeout
: timeout
);
230 if( ret
< 0 && ret
!= -EINTR
&& ret
!= -EAGAIN
) {
232 if( ret
== -ETIMEDOUT
)
233 throw Timeout(ret
, "Timeout in usb_bulk_read");
235 throw Error(ret
, "Error in usb_bulk_read");
237 data
.ReleaseBuffer(ret
);
238 } while( ret
== -EINTR
|| ret
== -EAGAIN
);
243 bool Device::InterruptWrite(int ep
, const Barry::Data
&data
, int timeout
)
245 ddout("InterruptWrite to endpoint " << std::dec
<< ep
<< ":\n" << data
);
249 ret
= usb_interrupt_write(m_handle
, ep
,
250 (char*) data
.GetData(), data
.GetSize(),
251 timeout
== -1 ? m_timeout
: timeout
);
252 if( ret
< 0 && ret
!= -EINTR
&& ret
!= -EAGAIN
) {
254 if( ret
== -ETIMEDOUT
)
255 throw Timeout(ret
, "Timeout in usb_bulk_read");
257 throw Error(ret
, "Error in usb_bulk_read");
259 } while( ret
== -EINTR
|| ret
== -EAGAIN
);
267 /// Reads anything available on the given endpoint, with a low timeout,
268 /// in order to clear any pending reads.
270 void Device::BulkDrain(int ep
)
274 while( BulkRead(ep
, data
, 100) )
277 catch( Usb::Error
& ) {}
282 ///////////////////////////////////////////////////////////////////////////////
285 Interface::Interface(Device
&dev
, int iface
)
286 : m_dev(dev
), m_iface(iface
)
288 dout("usb_claim_interface(" << dev
.GetHandle() << "," << std::dec
<< iface
<< ")");
289 int ret
= usb_claim_interface(dev
.GetHandle(), iface
);
291 throw Error(ret
, "claim interface failed");
294 Interface::~Interface()
296 dout("usb_release_interface(" << m_dev
.GetHandle() << "," << std::dec
<< m_iface
<< ")");
297 usb_release_interface(m_dev
.GetHandle(), m_iface
);
302 ///////////////////////////////////////////////////////////////////////////////
305 bool EndpointDiscovery::Discover(struct usb_interface_descriptor
*interface
, int epcount
)
313 if( !interface
|| !interface
->endpoint
) {
314 dout("EndpointDiscovery::Discover: empty interface pointer");
318 for( int i
= 0; i
< epcount
; i
++ ) {
320 usb_endpoint_descriptor desc
;
321 desc
= interface
->endpoint
[i
];
322 dout(" endpoint_desc #" << i
<< " loaded"
323 << "\nbLength: " << (unsigned ) desc
.bLength
324 << "\nbDescriptorType: " << (unsigned ) desc
.bDescriptorType
325 << "\nbEndpointAddress: " << (unsigned ) desc
.bEndpointAddress
326 << "\nbmAttributes: " << (unsigned ) desc
.bmAttributes
327 << "\nwMaxPacketSize: " << (unsigned ) desc
.wMaxPacketSize
328 << "\nbInterval: " << (unsigned ) desc
.bInterval
329 << "\nbRefresh: " << (unsigned ) desc
.bRefresh
330 << "\nbSynchAddress: " << (unsigned ) desc
.bSynchAddress
335 (*this)[desc
.bEndpointAddress
] = desc
;
336 dout(" endpoint added to map with bEndpointAddress: " << (unsigned int)desc
.bEndpointAddress
);
338 // parse the endpoint into read/write sets, if possible,
339 // going in discovery order...
341 // - endpoints of related utility will be grouped
342 // - endpoints with same type will be grouped
343 // - endpoints that do not meet the above assumptions
344 // do not belong in a pair
345 unsigned char type
= desc
.bmAttributes
& USB_ENDPOINT_TYPE_MASK
;
346 if( desc
.bEndpointAddress
& USB_ENDPOINT_DIR_MASK
) {
348 pair
.read
= desc
.bEndpointAddress
;
349 dout(" pair.read = " << (unsigned int)pair
.read
);
350 if( pair
.IsTypeSet() && pair
.type
!= type
) {
351 // if type is already set, we must start over
357 pair
.write
= desc
.bEndpointAddress
;
358 dout(" pair.write = " << (unsigned int)pair
.write
);
359 if( pair
.IsTypeSet() && pair
.type
!= type
) {
360 // if type is already set, we must start over
364 // save the type last
366 dout(" pair.type = " << (unsigned int)pair
.type
);
368 // if pair is complete, add to array
369 if( pair
.IsComplete() ) {
370 m_endpoints
.push_back(pair
);
371 dout(" pair added! ("
372 << "read: " << (unsigned int)pair
.read
<< ","
373 << "write: " << (unsigned int)pair
.write
<< ","
374 << "type: " << (unsigned int)pair
.type
<< ")");
375 pair
= EndpointPair(); // clear
379 // just for debugging purposes, check for extra descriptors, and
380 // dump them to dout if they exist
381 if( interface
->extra
) {
382 dout("while parsing endpoints, found a block of extra descriptors:");
383 Barry::Data
data(interface
->extra
, interface
->extralen
);
387 return m_valid
= true;
391 ///////////////////////////////////////////////////////////////////////////////
392 // InterfaceDiscovery
394 bool InterfaceDiscovery::DiscoverInterface(struct usb_interface
*interface
)
396 if( !interface
->altsetting
) {
397 dout("InterfaceDiscovery::DiscoverIterface: empty altsetting");
398 // some devices are buggy and return a higher bNumInterfaces
399 // than the number of interfaces available... in this case
400 // we just skip and continue
404 for( int i
= 0; i
< interface
->num_altsetting
; i
++ ) {
407 desc
.desc
= interface
->altsetting
[i
];
408 dout(" interface_desc #" << i
<< " loaded"
409 << "\nbLength: " << (unsigned) desc
.desc
.bLength
410 << "\nbDescriptorType: " << (unsigned) desc
.desc
.bDescriptorType
411 << "\nbInterfaceNumber: " << (unsigned) desc
.desc
.bInterfaceNumber
412 << "\nbAlternateSetting: " << (unsigned) desc
.desc
.bAlternateSetting
413 << "\nbNumEndpoints: " << (unsigned) desc
.desc
.bNumEndpoints
414 << "\nbInterfaceClass: " << (unsigned) desc
.desc
.bInterfaceClass
415 << "\nbInterfaceSubClass: " << (unsigned) desc
.desc
.bInterfaceSubClass
416 << "\nbInterfaceProtocol: " << (unsigned) desc
.desc
.bInterfaceProtocol
417 << "\niInterface: " << (unsigned) desc
.desc
.iInterface
421 // load all endpoints on this interface
422 if( !desc
.endpoints
.Discover(&desc
.desc
, desc
.desc
.bNumEndpoints
) ) {
423 dout(" endpoint discovery failed for bInterfaceNumber: " << (unsigned int)desc
.desc
.bInterfaceNumber
<< ", not added to map.");
428 (*this)[desc
.desc
.bInterfaceNumber
] = desc
;
429 dout(" interface added to map with bInterfaceNumber: " << (unsigned int)desc
.desc
.bInterfaceNumber
);
434 bool InterfaceDiscovery::Discover(Usb::DeviceIDType devid
, int cfgidx
, int ifcount
)
440 if( !devid
|| !devid
->config
|| !devid
->config
[cfgidx
].interface
) {
441 dout("InterfaceDiscovery::Discover: empty devid/config/interface");
445 for( int i
= 0; i
< ifcount
; i
++ ) {
446 if( !DiscoverInterface(&devid
->config
[cfgidx
].interface
[i
]) )
450 return m_valid
= true;
454 ///////////////////////////////////////////////////////////////////////////////
457 bool ConfigDiscovery::Discover(Usb::DeviceIDType devid
, int cfgcount
)
463 for( int i
= 0; i
< cfgcount
; i
++ ) {
466 if( !devid
|| !devid
->config
) {
467 dout("ConfigDiscovery::Discover: empty devid or config");
470 desc
.desc
= devid
->config
[i
];
471 dout(" config_desc #" << i
<< " loaded"
472 << "\nbLength: " << (unsigned int) desc
.desc
.bLength
473 << "\nbDescriptorType: " << (unsigned int) desc
.desc
.bDescriptorType
474 << "\nwTotalLength: " << (unsigned int) desc
.desc
.wTotalLength
475 << "\nbNumInterfaces: " << (unsigned int) desc
.desc
.bNumInterfaces
476 << "\nbConfigurationValue: " << (unsigned int) desc
.desc
.bConfigurationValue
477 << "\niConfiguration: " << (unsigned int) desc
.desc
.iConfiguration
478 << "\nbmAttributes: " << (unsigned int) desc
.desc
.bmAttributes
479 << "\nMaxPower: " << (unsigned int) desc
.desc
.MaxPower
483 // just for debugging purposes, check for extra descriptors, and
484 // dump them to dout if they exist
485 if( desc
.desc
.extra
) {
486 dout("while parsing config descriptor, found a block of extra descriptors:");
487 Barry::Data
data(desc
.desc
.extra
, desc
.desc
.extralen
);
491 // load all interfaces on this configuration
492 if( !desc
.interfaces
.Discover(devid
, i
, desc
.desc
.bNumInterfaces
) ) {
493 dout(" config discovery failed for bConfigurationValue: " << (unsigned int)desc
.desc
.bConfigurationValue
<< ", not added to map.");
498 (*this)[desc
.desc
.bConfigurationValue
] = desc
;
499 dout(" config added to map with bConfigurationValue: " << (unsigned int)desc
.desc
.bConfigurationValue
);
502 return m_valid
= true;
506 ///////////////////////////////////////////////////////////////////////////////
509 DeviceDiscovery::DeviceDiscovery(Usb::DeviceIDType devid
)
515 bool DeviceDiscovery::Discover(Usb::DeviceIDType devid
)
521 // copy the descriptor over to our memory
523 dout("DeviceDiscovery::Discover: empty devid");
527 desc
= devid
->descriptor
;
528 dout("device_desc loaded"
529 << "\nbLength: " << (unsigned int) desc
.bLength
530 << "\nbDescriptorType: " << (unsigned int) desc
.bDescriptorType
531 << "\nbcdUSB: " << (unsigned int) desc
.bcdUSB
532 << "\nbDeviceClass: " << (unsigned int) desc
.bDeviceClass
533 << "\nbDeviceSubClass: " << (unsigned int) desc
.bDeviceSubClass
534 << "\nbDeviceProtocol: " << (unsigned int) desc
.bDeviceProtocol
535 << "\nbMaxPacketSize0: " << (unsigned int) desc
.bMaxPacketSize0
536 << "\nidVendor: " << (unsigned int) desc
.idVendor
537 << "\nidProduct: " << (unsigned int) desc
.idProduct
538 << "\nbcdDevice: " << (unsigned int) desc
.bcdDevice
539 << "\niManufacturer: " << (unsigned int) desc
.iManufacturer
540 << "\niProduct: " << (unsigned int) desc
.iProduct
541 << "\niSerialNumber: " << (unsigned int) desc
.iSerialNumber
542 << "\nbNumConfigurations: " << (unsigned int) desc
.bNumConfigurations
546 m_valid
= configs
.Discover(devid
, desc
.bNumConfigurations
);