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 ///////////////////////////////////////////////////////////////////////////////
42 Match::Match(int vendor
, int product
)
50 m_busses
= usb_get_busses();
57 bool Match::next_device(Usb::DeviceIDType
*devid
)
59 for( ; m_busses
; m_busses
= m_busses
->next
) {
62 m_dev
= m_busses
->devices
;
64 for( ; m_dev
; m_dev
= m_dev
->next
) {
66 if( m_dev
->descriptor
.idVendor
== m_vendor
&&
67 m_dev
->descriptor
.idProduct
== m_product
) {
71 // advance for next time
74 m_busses
= m_busses
->next
;
85 ///////////////////////////////////////////////////////////////////////////////
88 Device::Device(Usb::DeviceIDType id
, int timeout
)
92 m_handle
= usb_open(id
);
94 throw Error("open failed");
102 bool Device::SetConfiguration(unsigned char cfg
)
104 int ret
= usb_set_configuration(m_handle
, cfg
);
109 bool Device::ClearHalt(int ep
)
111 int ret
= usb_clear_halt(m_handle
, ep
);
118 int ret
= usb_reset(m_handle
);
123 bool Device::BulkRead(int ep
, Barry::Data
&data
, int timeout
)
127 ret
= usb_bulk_read(m_handle
, ep
,
128 (char*) data
.GetBuffer(), data
.GetBufSize(),
129 timeout
== -1 ? m_timeout
: timeout
);
130 if( ret
< 0 && ret
!= -EINTR
&& ret
!= -EAGAIN
) {
132 if( ret
== -ETIMEDOUT
)
133 throw Timeout("Timeout in usb_bulk_read");
135 throw Error("Error in usb_bulk_read");
137 data
.ReleaseBuffer(ret
);
138 } while( ret
== -EINTR
|| ret
== -EAGAIN
);
143 bool Device::BulkWrite(int ep
, const Barry::Data
&data
, int timeout
)
145 ddout("BulkWrite to endpoint " << ep
<< ":\n" << data
);
148 ret
= usb_bulk_write(m_handle
, ep
,
149 (char*) data
.GetData(), data
.GetSize(),
150 timeout
== -1 ? m_timeout
: timeout
);
151 if( ret
< 0 && ret
!= -EINTR
&& ret
!= -EAGAIN
) {
153 if( ret
== -ETIMEDOUT
)
154 throw Timeout("Timeout in usb_bulk_read");
156 throw Error("Error in usb_bulk_read");
158 } while( ret
== -EINTR
|| ret
== -EAGAIN
);
163 bool Device::BulkWrite(int ep
, const void *data
, size_t size
, int timeout
)
165 #ifdef __DEBUG_MODE__
166 Barry::Data
dump(data
, size
);
167 ddout("BulkWrite to endpoint " << ep
<< ":\n" << dump
);
172 ret
= usb_bulk_write(m_handle
, ep
,
174 timeout
== -1 ? m_timeout
: timeout
);
175 if( ret
< 0 && ret
!= -EINTR
&& ret
!= -EAGAIN
) {
177 if( ret
== -ETIMEDOUT
)
178 throw Timeout("Timeout in usb_bulk_read");
180 throw Error("Error in usb_bulk_read");
182 } while( ret
== -EINTR
|| ret
== -EAGAIN
);
187 bool Device::InterruptRead(int ep
, Barry::Data
&data
, int timeout
)
191 ret
= usb_interrupt_read(m_handle
, ep
,
192 (char*) data
.GetBuffer(), data
.GetBufSize(),
193 timeout
== -1 ? m_timeout
: timeout
);
194 if( ret
< 0 && ret
!= -EINTR
&& ret
!= -EAGAIN
) {
196 if( ret
== -ETIMEDOUT
)
197 throw Timeout("Timeout in usb_bulk_read");
199 throw Error("Error in usb_bulk_read");
201 data
.ReleaseBuffer(ret
);
202 } while( ret
== -EINTR
|| ret
== -EAGAIN
);
207 bool Device::InterruptWrite(int ep
, const Barry::Data
&data
, int timeout
)
209 ddout("InterruptWrite to endpoint " << ep
<< ":\n" << data
);
213 ret
= usb_interrupt_write(m_handle
, ep
,
214 (char*) data
.GetData(), data
.GetSize(),
215 timeout
== -1 ? m_timeout
: timeout
);
216 if( ret
< 0 && ret
!= -EINTR
&& ret
!= -EAGAIN
) {
218 if( ret
== -ETIMEDOUT
)
219 throw Timeout("Timeout in usb_bulk_read");
221 throw Error("Error in usb_bulk_read");
223 } while( ret
== -EINTR
|| ret
== -EAGAIN
);
231 /// Reads anything available on the given endpoint, with a low timeout,
232 /// in order to clear any pending reads.
234 void Device::BulkDrain(int ep
)
238 while( BulkRead(ep
, data
, 100) )
241 catch( Usb::Error
& ) {}
246 ///////////////////////////////////////////////////////////////////////////////
249 bool EndpointDiscovery::Discover(struct usb_interface_descriptor
*interface
, int epcount
)
257 if( !interface
|| !interface
->endpoint
) {
258 dout("EndpointDiscovery::Discover: empty interface pointer");
262 for( int i
= 0; i
< epcount
; i
++ ) {
264 usb_endpoint_descriptor desc
;
265 desc
= interface
->endpoint
[i
];
266 dout(" endpoint_desc #" << i
<< " loaded"
267 << "\nbLength: " << (unsigned ) desc
.bLength
268 << "\nbDescriptorType: " << (unsigned ) desc
.bDescriptorType
269 << "\nbEndpointAddress: " << (unsigned ) desc
.bEndpointAddress
270 << "\nbmAttributes: " << (unsigned ) desc
.bmAttributes
271 << "\nwMaxPacketSize: " << (unsigned ) desc
.wMaxPacketSize
272 << "\nbInterval: " << (unsigned ) desc
.bInterval
273 << "\nbRefresh: " << (unsigned ) desc
.bRefresh
274 << "\nbSynchAddress: " << (unsigned ) desc
.bSynchAddress
279 (*this)[desc
.bEndpointAddress
] = desc
;
280 dout(" endpoint added to map with bEndpointAddress: " << (unsigned int)desc
.bEndpointAddress
);
282 // parse the endpoint into read/write sets, if possible,
283 // going in discovery order...
285 // - endpoints of related utility will be grouped
286 // - endpoints with same type will be grouped
287 // - endpoints that do not meet the above assumptions
288 // do not belong in a pair
289 unsigned char type
= desc
.bmAttributes
& USB_ENDPOINT_TYPE_MASK
;
290 if( desc
.bEndpointAddress
& USB_ENDPOINT_DIR_MASK
) {
292 pair
.read
= desc
.bEndpointAddress
;
293 dout(" pair.read = " << (unsigned int)pair
.read
);
294 if( pair
.IsTypeSet() && pair
.type
!= type
) {
295 // if type is already set, we must start over
301 pair
.write
= desc
.bEndpointAddress
;
302 dout(" pair.write = " << (unsigned int)pair
.write
);
303 if( pair
.IsTypeSet() && pair
.type
!= type
) {
304 // if type is already set, we must start over
308 // save the type last
310 dout(" pair.type = " << (unsigned int)pair
.type
);
312 // if pair is complete, add to array
313 if( pair
.IsComplete() ) {
314 m_endpoints
.push_back(pair
);
315 dout(" pair added! ("
316 << "read: " << (unsigned int)pair
.read
<< ","
317 << "write: " << (unsigned int)pair
.write
<< ","
318 << "type: " << (unsigned int)pair
.type
<< ")");
319 pair
= EndpointPair(); // clear
323 // just for debugging purposes, check for extra descriptors, and
324 // dump them to dout if they exist
325 if( interface
->extra
) {
326 dout("while parsing endpoints, found a block of extra descriptors:");
327 Barry::Data
data(interface
->extra
, interface
->extralen
);
331 return m_valid
= true;
335 ///////////////////////////////////////////////////////////////////////////////
336 // InterfaceDiscovery
338 bool InterfaceDiscovery::DiscoverInterface(struct usb_interface
*interface
)
340 if( !interface
->altsetting
) {
341 dout("InterfaceDiscovery::DiscoverIterface: empty altsetting");
342 // some devices are buggy and return a higher bNumInterfaces
343 // than the number of interfaces available... in this case
344 // we just skip and continue
348 for( int i
= 0; i
< interface
->num_altsetting
; i
++ ) {
351 desc
.desc
= interface
->altsetting
[i
];
352 dout(" interface_desc #" << i
<< " loaded"
353 << "\nbLength: " << (unsigned) desc
.desc
.bLength
354 << "\nbDescriptorType: " << (unsigned) desc
.desc
.bDescriptorType
355 << "\nbInterfaceNumber: " << (unsigned) desc
.desc
.bInterfaceNumber
356 << "\nbAlternateSetting: " << (unsigned) desc
.desc
.bAlternateSetting
357 << "\nbNumEndpoints: " << (unsigned) desc
.desc
.bNumEndpoints
358 << "\nbInterfaceClass: " << (unsigned) desc
.desc
.bInterfaceClass
359 << "\nbInterfaceSubClass: " << (unsigned) desc
.desc
.bInterfaceSubClass
360 << "\nbInterfaceProtocol: " << (unsigned) desc
.desc
.bInterfaceProtocol
361 << "\niInterface: " << (unsigned) desc
.desc
.iInterface
365 // load all endpoints on this interface
366 if( !desc
.endpoints
.Discover(&desc
.desc
, desc
.desc
.bNumEndpoints
) ) {
367 dout(" endpoint discovery failed for bInterfaceNumber: " << (unsigned int)desc
.desc
.bInterfaceNumber
<< ", not added to map.");
372 (*this)[desc
.desc
.bInterfaceNumber
] = desc
;
373 dout(" interface added to map with bInterfaceNumber: " << (unsigned int)desc
.desc
.bInterfaceNumber
);
378 bool InterfaceDiscovery::Discover(Usb::DeviceIDType devid
, int cfgidx
, int ifcount
)
384 if( !devid
|| !devid
->config
|| !devid
->config
[cfgidx
].interface
) {
385 dout("InterfaceDiscovery::Discover: empty devid/config/interface");
389 for( int i
= 0; i
< ifcount
; i
++ ) {
390 if( !DiscoverInterface(&devid
->config
[cfgidx
].interface
[i
]) )
394 return m_valid
= true;
398 ///////////////////////////////////////////////////////////////////////////////
401 bool ConfigDiscovery::Discover(Usb::DeviceIDType devid
, int cfgcount
)
407 for( int i
= 0; i
< cfgcount
; i
++ ) {
410 if( !devid
|| !devid
->config
) {
411 dout("ConfigDiscovery::Discover: empty devid or config");
414 desc
.desc
= devid
->config
[i
];
415 dout(" config_desc #" << i
<< " loaded"
416 << "\nbLength: " << (unsigned int) desc
.desc
.bLength
417 << "\nbDescriptorType: " << (unsigned int) desc
.desc
.bDescriptorType
418 << "\nwTotalLength: " << (unsigned int) desc
.desc
.wTotalLength
419 << "\nbNumInterfaces: " << (unsigned int) desc
.desc
.bNumInterfaces
420 << "\nbConfigurationValue: " << (unsigned int) desc
.desc
.bConfigurationValue
421 << "\niConfiguration: " << (unsigned int) desc
.desc
.iConfiguration
422 << "\nbmAttributes: " << (unsigned int) desc
.desc
.bmAttributes
423 << "\nMaxPower: " << (unsigned int) desc
.desc
.MaxPower
427 // just for debugging purposes, check for extra descriptors, and
428 // dump them to dout if they exist
429 if( desc
.desc
.extra
) {
430 dout("while parsing config descriptor, found a block of extra descriptors:");
431 Barry::Data
data(desc
.desc
.extra
, desc
.desc
.extralen
);
435 // load all interfaces on this configuration
436 if( !desc
.interfaces
.Discover(devid
, i
, desc
.desc
.bNumInterfaces
) ) {
437 dout(" config discovery failed for bConfigurationValue: " << (unsigned int)desc
.desc
.bConfigurationValue
<< ", not added to map.");
442 (*this)[desc
.desc
.bConfigurationValue
] = desc
;
443 dout(" config added to map with bConfigurationValue: " << (unsigned int)desc
.desc
.bConfigurationValue
);
446 return m_valid
= true;
450 ///////////////////////////////////////////////////////////////////////////////
453 DeviceDiscovery::DeviceDiscovery(Usb::DeviceIDType devid
)
459 bool DeviceDiscovery::Discover(Usb::DeviceIDType devid
)
465 // copy the descriptor over to our memory
467 dout("DeviceDiscovery::Discover: empty devid");
471 desc
= devid
->descriptor
;
472 dout("device_desc loaded"
473 << "\nbLength: " << (unsigned int) desc
.bLength
474 << "\nbDescriptorType: " << (unsigned int) desc
.bDescriptorType
475 << "\nbcdUSB: " << (unsigned int) desc
.bcdUSB
476 << "\nbDeviceClass: " << (unsigned int) desc
.bDeviceClass
477 << "\nbDeviceSubClass: " << (unsigned int) desc
.bDeviceSubClass
478 << "\nbDeviceProtocol: " << (unsigned int) desc
.bDeviceProtocol
479 << "\nbMaxPacketSize0: " << (unsigned int) desc
.bMaxPacketSize0
480 << "\nidVendor: " << (unsigned int) desc
.idVendor
481 << "\nidProduct: " << (unsigned int) desc
.idProduct
482 << "\nbcdDevice: " << (unsigned int) desc
.bcdDevice
483 << "\niManufacturer: " << (unsigned int) desc
.iManufacturer
484 << "\niProduct: " << (unsigned int) desc
.iProduct
485 << "\niSerialNumber: " << (unsigned int) desc
.iSerialNumber
486 << "\nbNumConfigurations: " << (unsigned int) desc
.bNumConfigurations
490 m_valid
= configs
.Discover(devid
, desc
.bNumConfigurations
);