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 m_lasterror
= usb_set_configuration(m_handle
, cfg
);
105 return m_lasterror
>= 0;
108 bool Device::ClearHalt(int ep
)
110 m_lasterror
= usb_clear_halt(m_handle
, ep
);
111 return m_lasterror
>= 0;
116 m_lasterror
= usb_reset(m_handle
);
117 return m_lasterror
== 0;
120 bool Device::BulkRead(int ep
, Barry::Data
&data
, int timeout
)
123 m_lasterror
= usb_bulk_read(m_handle
, ep
,
124 (char*) data
.GetBuffer(), data
.GetBufSize(),
125 timeout
== -1 ? m_timeout
: timeout
);
126 if( m_lasterror
< 0 && m_lasterror
!= -EINTR
&& m_lasterror
!= -EAGAIN
)
127 throw Error("Error in usb_bulk_read");
128 data
.ReleaseBuffer(m_lasterror
);
129 } while( m_lasterror
== -EINTR
|| m_lasterror
== -EAGAIN
);
131 return m_lasterror
>= 0;
134 bool Device::BulkWrite(int ep
, const Barry::Data
&data
, int timeout
)
136 ddout("BulkWrite to endpoint " << ep
<< ":\n" << data
);
138 m_lasterror
= usb_bulk_write(m_handle
, ep
,
139 (char*) data
.GetData(), data
.GetSize(),
140 timeout
== -1 ? m_timeout
: timeout
);
141 if( m_lasterror
< 0 && m_lasterror
!= -EINTR
&& m_lasterror
!= -EAGAIN
)
142 throw Error("Error in usb_bulk_write");
143 } while( m_lasterror
== -EINTR
|| m_lasterror
== -EAGAIN
);
145 return m_lasterror
>= 0;
148 bool Device::BulkWrite(int ep
, const void *data
, size_t size
, int timeout
)
150 #ifdef __DEBUG_MODE__
151 Barry::Data
dump(data
, size
);
152 ddout("BulkWrite to endpoint " << ep
<< ":\n" << dump
);
156 m_lasterror
= usb_bulk_write(m_handle
, ep
,
158 timeout
== -1 ? m_timeout
: timeout
);
159 if( m_lasterror
< 0 && m_lasterror
!= -EINTR
&& m_lasterror
!= -EAGAIN
)
160 throw Error("Error in usb_bulk_write");
161 } while( m_lasterror
== -EINTR
|| m_lasterror
== -EAGAIN
);
163 return m_lasterror
>= 0;
166 bool Device::InterruptRead(int ep
, Barry::Data
&data
, int timeout
)
169 m_lasterror
= usb_interrupt_read(m_handle
, ep
,
170 (char*) data
.GetBuffer(), data
.GetBufSize(),
171 timeout
== -1 ? m_timeout
: timeout
);
172 if( m_lasterror
< 0 && m_lasterror
!= -EINTR
&& m_lasterror
!= -EAGAIN
)
173 throw Error("Error in usb_interrupt_read");
174 data
.ReleaseBuffer(m_lasterror
);
175 } while( m_lasterror
== -EINTR
|| m_lasterror
== -EAGAIN
);
177 return m_lasterror
>= 0;
180 bool Device::InterruptWrite(int ep
, const Barry::Data
&data
, int timeout
)
182 ddout("InterruptWrite to endpoint " << ep
<< ":\n" << data
);
185 m_lasterror
= usb_interrupt_write(m_handle
, ep
,
186 (char*) data
.GetData(), data
.GetSize(),
187 timeout
== -1 ? m_timeout
: timeout
);
188 if( m_lasterror
< 0 && m_lasterror
!= -EINTR
&& m_lasterror
!= -EAGAIN
)
189 throw Error("Error in usb_interrupt_write");
190 } while( m_lasterror
== -EINTR
|| m_lasterror
== -EAGAIN
);
192 return m_lasterror
>= 0;
198 /// Reads anything available on the given endpoint, with a low timeout,
199 /// in order to clear any pending reads.
201 void Device::BulkDrain(int ep
)
205 while( BulkRead(ep
, data
, 100) )
208 catch( Usb::Error
& ) {}
213 ///////////////////////////////////////////////////////////////////////////////
216 bool EndpointDiscovery::Discover(struct usb_interface_descriptor
*interface
, int epcount
)
224 if( !interface
|| !interface
->endpoint
)
227 for( int i
= 0; i
< epcount
; i
++ ) {
229 usb_endpoint_descriptor desc
;
230 desc
= interface
->endpoint
[i
];
231 dout(" endpoint_desc #" << i
<< " loaded"
232 << "\nbLength: " << (unsigned ) desc
.bLength
233 << "\nbDescriptorType: " << (unsigned ) desc
.bDescriptorType
234 << "\nbEndpointAddress: " << (unsigned ) desc
.bEndpointAddress
235 << "\nbmAttributes: " << (unsigned ) desc
.bmAttributes
236 << "\nwMaxPacketSize: " << (unsigned ) desc
.wMaxPacketSize
237 << "\nbInterval: " << (unsigned ) desc
.bInterval
238 << "\nbRefresh: " << (unsigned ) desc
.bRefresh
239 << "\nbSynchAddress: " << (unsigned ) desc
.bSynchAddress
244 (*this)[desc
.bEndpointAddress
] = desc
;
245 dout(" endpoint added to map with bEndpointAddress: " << (unsigned int)desc
.bEndpointAddress
);
247 // parse the endpoint into read/write sets, if possible,
248 // going in discovery order...
250 // - endpoints of related utility will be grouped
251 // - endpoints with same type will be grouped
252 // - endpoints that do not meet the above assumptions
253 // do not belong in a pair
254 unsigned char type
= desc
.bmAttributes
& USB_ENDPOINT_TYPE_MASK
;
255 if( desc
.bEndpointAddress
& USB_ENDPOINT_DIR_MASK
) {
257 pair
.read
= desc
.bEndpointAddress
;
258 dout(" pair.read = " << (unsigned int)pair
.read
);
259 if( pair
.IsTypeSet() && pair
.type
!= type
) {
260 // if type is already set, we must start over
266 pair
.write
= desc
.bEndpointAddress
;
267 dout(" pair.write = " << (unsigned int)pair
.write
);
268 if( pair
.IsTypeSet() && pair
.type
!= type
) {
269 // if type is already set, we must start over
273 // save the type last
275 dout(" pair.type = " << (unsigned int)pair
.type
);
277 // if pair is complete, add to array
278 if( pair
.IsComplete() ) {
279 m_endpoints
.push_back(pair
);
280 dout(" pair added! ("
281 << "read: " << (unsigned int)pair
.read
<< ","
282 << "write: " << (unsigned int)pair
.write
<< ","
283 << "type: " << (unsigned int)pair
.type
<< ")");
284 pair
= EndpointPair(); // clear
288 return m_valid
= true;
292 ///////////////////////////////////////////////////////////////////////////////
293 // InterfaceDiscovery
295 bool InterfaceDiscovery::DiscoverInterface(struct usb_interface
*interface
)
297 if( !interface
->altsetting
)
300 for( int i
= 0; i
< interface
->num_altsetting
; i
++ ) {
303 desc
.desc
= interface
->altsetting
[i
];
304 dout(" interface_desc #" << i
<< " loaded"
305 << "\nbLength: " << (unsigned) desc
.desc
.bLength
306 << "\nbDescriptorType: " << (unsigned) desc
.desc
.bDescriptorType
307 << "\nbInterfaceNumber: " << (unsigned) desc
.desc
.bInterfaceNumber
308 << "\nbAlternateSetting: " << (unsigned) desc
.desc
.bAlternateSetting
309 << "\nbNumEndpoints: " << (unsigned) desc
.desc
.bNumEndpoints
310 << "\nbInterfaceClass: " << (unsigned) desc
.desc
.bInterfaceClass
311 << "\nbInterfaceSubClass: " << (unsigned) desc
.desc
.bInterfaceSubClass
312 << "\nbInterfaceProtocol: " << (unsigned) desc
.desc
.bInterfaceProtocol
313 << "\niInterface: " << (unsigned) desc
.desc
.iInterface
317 // load all endpoints on this interface
318 if( !desc
.endpoints
.Discover(&desc
.desc
, desc
.desc
.bNumEndpoints
) )
322 (*this)[desc
.desc
.bInterfaceNumber
] = desc
;
323 dout(" interface added to map with bInterfaceNumber: " << (unsigned int)desc
.desc
.bInterfaceNumber
);
328 bool InterfaceDiscovery::Discover(Usb::DeviceIDType devid
, int cfgidx
, int ifcount
)
334 if( !devid
|| !devid
->config
|| !devid
->config
[cfgidx
].interface
)
337 for( int i
= 0; i
< ifcount
; i
++ ) {
338 if( !DiscoverInterface(&devid
->config
[cfgidx
].interface
[i
]) )
342 return m_valid
= true;
346 ///////////////////////////////////////////////////////////////////////////////
349 bool ConfigDiscovery::Discover(Usb::DeviceIDType devid
, int cfgcount
)
355 for( int i
= 0; i
< cfgcount
; i
++ ) {
358 if( !devid
|| !devid
->config
)
360 desc
.desc
= devid
->config
[i
];
361 dout(" config_desc #" << i
<< " loaded"
362 << "\nbLength: " << (unsigned int) desc
.desc
.bLength
363 << "\nbDescriptorType: " << (unsigned int) desc
.desc
.bDescriptorType
364 << "\nwTotalLength: " << (unsigned int) desc
.desc
.wTotalLength
365 << "\nbNumInterfaces: " << (unsigned int) desc
.desc
.bNumInterfaces
366 << "\nbConfigurationValue: " << (unsigned int) desc
.desc
.bConfigurationValue
367 << "\niConfiguration: " << (unsigned int) desc
.desc
.iConfiguration
368 << "\nbmAttributes: " << (unsigned int) desc
.desc
.bmAttributes
369 << "\nMaxPower: " << (unsigned int) desc
.desc
.MaxPower
373 // load all interfaces on this configuration
374 if( !desc
.interfaces
.Discover(devid
, i
, desc
.desc
.bNumInterfaces
) )
378 (*this)[desc
.desc
.bConfigurationValue
] = desc
;
379 dout(" config added to map with bConfigurationValue: " << (unsigned int)desc
.desc
.bConfigurationValue
);
382 return m_valid
= true;
386 ///////////////////////////////////////////////////////////////////////////////
389 DeviceDiscovery::DeviceDiscovery(Usb::DeviceIDType devid
)
395 bool DeviceDiscovery::Discover(Usb::DeviceIDType devid
)
401 // copy the descriptor over to our memory
404 desc
= devid
->descriptor
;
405 dout("device_desc loaded"
406 << "\nbLength: " << (unsigned int) desc
.bLength
407 << "\nbDescriptorType: " << (unsigned int) desc
.bDescriptorType
408 << "\nbcdUSB: " << (unsigned int) desc
.bcdUSB
409 << "\nbDeviceClass: " << (unsigned int) desc
.bDeviceClass
410 << "\nbDeviceSubClass: " << (unsigned int) desc
.bDeviceSubClass
411 << "\nbDeviceProtocol: " << (unsigned int) desc
.bDeviceProtocol
412 << "\nbMaxPacketSize0: " << (unsigned int) desc
.bMaxPacketSize0
413 << "\nidVendor: " << (unsigned int) desc
.idVendor
414 << "\nidProduct: " << (unsigned int) desc
.idProduct
415 << "\nbcdDevice: " << (unsigned int) desc
.bcdDevice
416 << "\niManufacturer: " << (unsigned int) desc
.iManufacturer
417 << "\niProduct: " << (unsigned int) desc
.iProduct
418 << "\niSerialNumber: " << (unsigned int) desc
.iSerialNumber
419 << "\nbNumConfigurations: " << (unsigned int) desc
.bNumConfigurations
423 m_valid
= configs
.Discover(devid
, desc
.bNumConfigurations
);