7 Copyright (C) 2005-2006, 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.
31 #define __DEBUG_MODE__
36 IO::IO(Device
*dev
, libusb_io_handle_t
*handle
)
41 dout("IO::IO handle: " << m_handle
);
44 IO::IO(Device
&dev
, libusb_io_handle_t
*handle
)
49 dout("IO::IO handle: " << m_handle
);
52 IO::IO(const IO
&other
)
59 // only one IO object can ever hold a handle to an io operation
60 IO
& IO::operator=(const IO
&other
)
63 return *this; // nothing to do
65 if( m_dev
&& m_dev
!= other
.m_dev
)
66 throw UsbError("Copying IO objects that are not "
67 "related to the same device.");
70 m_handle
= other
.m_handle
;
75 // cleans up the io handle, making this IO object invalid
79 dout("IO::cleanup handle: " << m_handle
);
81 std::ostringstream oss
;
82 oss
<< "cleanup: " << GetEndpoint() << " ";
83 if( !IsCompleted() ) {
84 // not complete yet, cancel
86 libusb_io_cancel(m_handle
);
90 libusb_io_free(m_handle
);
95 // will cancel if not complete, and will always free if valid
102 bool IO::IsCompleted() const
107 return libusb_is_io_completed(m_handle
) != 0;
113 return; // nothing to wait on
114 libusb_io_wait(m_handle
);
116 #ifdef __DEBUG_MODE__
117 ddout("IO::Wait(): Endpoint " << GetEndpoint()
119 << std::setbase(10) << GetStatus() << std::setbase(16));
121 // only dump read endpoints that are successful
122 if( (GetEndpoint() & USB_ENDPOINT_DIR_MASK
) && GetStatus() >= 0 ) {
123 Data
dump(GetData(), GetSize());
133 if( !IsCompleted() ) {
134 // not complete yet, cancel
135 libusb_io_cancel(m_handle
);
139 int IO::GetStatus() const
143 return libusb_io_comp_status(m_handle
);
146 int IO::GetSize() const
150 return libusb_io_xfer_size(m_handle
);
153 int IO::GetReqSize() const
157 return libusb_io_req_size(m_handle
);
160 int IO::GetEndpoint() const
164 return libusb_io_ep_addr(m_handle
);
167 unsigned char * IO::GetData()
171 return libusb_io_data(m_handle
);
174 const unsigned char * IO::GetData() const
178 return libusb_io_data(m_handle
);
183 ///////////////////////////////////////////////////////////////////////////////
186 bool Device::SetConfiguration(unsigned char cfg
)
188 m_lasterror
= libusb_set_configuration(m_handle
, cfg
);
189 return m_lasterror
>= 0;
192 bool Device::ClearHalt(int ep
)
194 m_lasterror
= libusb_clear_halt(m_handle
, ep
);
195 return m_lasterror
>= 0;
200 m_lasterror
= libusb_reset(m_handle
);
201 return m_lasterror
== 0;
204 void Device::TrackBulkRead(int ep
, Data
&data
)
206 m_ios
.push_back(ABulkRead(ep
, data
));
209 void Device::TrackBulkWrite(int ep
, const Data
&data
)
211 m_ios
.push_back(ABulkWrite(ep
, data
));
214 void Device::TrackInterruptRead(int ep
, Data
&data
)
216 m_ios
.push_back(AInterruptRead(ep
, data
));
219 void Device::TrackInterruptWrite(int ep
, const Data
&data
)
221 m_ios
.push_back(AInterruptWrite(ep
, data
));
224 // extracts the next completed IO handle, and returns it as an IO object
225 // The Device object no longer tracks this handle, and if the IO object
226 // goes out of scope, the handle will be freed.
227 IO
Device::PollCompletions()
229 // get next completed libusb IO handle
230 libusb_io_handle_t
*done
= libusb_io_poll_completions();
232 return IO::InvalidIO();
234 // search for it in our list
235 io_list_type::iterator b
= m_ios
.begin();
236 for( ; b
!= m_ios
.end(); b
++ ) {
238 IO io
= *b
; // make copy to return
239 m_ios
.erase(b
); // remove forgotten placeholder
240 return io
; // return so user can deal with it
244 // not found in our tracked list
245 if( libusb_io_dev(done
) == m_handle
) {
246 // this is an event for our device handle, so ok to return it
247 return IO(*this, done
);
250 // not our device, ignore it
251 return IO::InvalidIO();
255 void Device::ClearIO(int index
)
257 m_ios
.erase(m_ios
.begin() + index
);
260 IO
Device::ABulkRead(int ep
, Data
&data
)
262 libusb_io_handle_t
*rd
= libusb_submit_bulk_read( GetHandle(), ep
,
263 data
.GetBuffer(), data
.GetBufSize(), m_timeout
, NULL
);
265 throw UsbError("Error in libusb_submit_bulk_read");
267 return IO(*this, rd
);
270 IO
Device::ABulkWrite(int ep
, const Data
&data
)
272 ddout("ABulkWrite to endpoint " << ep
<< ":\n" << data
);
273 libusb_io_handle_t
*wr
= libusb_submit_bulk_write(GetHandle(), ep
,
274 data
.GetData(), data
.GetSize(), m_timeout
, NULL
);
276 throw UsbError("Error in libusb_submit_bulk_write");
278 return IO(*this, wr
);
281 IO
Device::ABulkWrite(int ep
, const void *data
, size_t size
)
283 #ifdef __DEBUG_MODE__
284 Data
dump(data
, size
);
285 ddout("ABulkWrite to endpoint " << ep
<< ":\n" << dump
);
288 libusb_io_handle_t
*wr
= libusb_submit_bulk_write(GetHandle(), ep
,
289 data
, size
, m_timeout
, NULL
);
291 throw UsbError("Error in libusb_submit_bulk_write");
293 return IO(*this, wr
);
296 IO
Device::AInterruptRead(int ep
, Data
&data
)
298 libusb_io_handle_t
*rd
= libusb_submit_interrupt_read( GetHandle(), ep
,
299 data
.GetBuffer(), data
.GetBufSize(), m_timeout
, NULL
);
301 throw UsbError("Error in libusb_submit_interrupt_read");
303 return IO(*this, rd
);
306 IO
Device::AInterruptWrite(int ep
, const Data
&data
)
308 ddout("AInterruptWrite to endpoint " << ep
<< ":\n" << data
);
309 libusb_io_handle_t
*wr
= libusb_submit_interrupt_write(GetHandle(), ep
,
310 data
.GetData(), data
.GetSize(), m_timeout
, NULL
);
312 throw UsbError("Error in libusb_submit_interrupt_write");
314 return IO(*this, wr
);
319 ///////////////////////////////////////////////////////////////////////////////
322 bool EndpointDiscovery::Discover(libusb_device_id_t devid
, int cfgidx
, int ifcidx
, int epcount
)
330 for( int i
= 0; i
< epcount
; i
++ ) {
332 usb_endpoint_desc desc
;
333 if( libusb_get_endpoint_desc(devid
, cfgidx
, ifcidx
, i
, &desc
) < 0 )
335 dout(" endpoint_desc #" << i
<< " loaded");
338 (*this)[desc
.bEndpointAddress
] = desc
;
339 dout(" endpoint added to map with bEndpointAddress: " << (unsigned int)desc
.bEndpointAddress
);
341 // parse the endpoint into read/write sets, if possible,
342 // going in discovery order...
344 // - endpoints of related utility will be grouped
345 // - endpoints with same type will be grouped
346 // - endpoints that do not meet the above assumptions
347 // do not belong in a pair
348 unsigned char type
= desc
.bmAttributes
& USB_ENDPOINT_TYPE_MASK
;
349 if( desc
.bEndpointAddress
& USB_ENDPOINT_DIR_MASK
) {
351 pair
.read
= desc
.bEndpointAddress
;
352 dout(" pair.read = " << (unsigned int)pair
.read
);
353 if( pair
.IsTypeSet() && pair
.type
!= type
) {
354 // if type is already set, we must start over
360 pair
.write
= desc
.bEndpointAddress
;
361 dout(" pair.write = " << (unsigned int)pair
.write
);
362 if( pair
.IsTypeSet() && pair
.type
!= type
) {
363 // if type is already set, we must start over
367 // save the type last
369 dout(" pair.type = " << (unsigned int)pair
.type
);
371 // if pair is complete, add to array
372 if( pair
.IsComplete() ) {
373 m_endpoints
.push_back(pair
);
374 dout(" pair added! ("
375 << (unsigned int)pair
.read
<< ","
376 << (unsigned int)pair
.write
<< ","
377 << (unsigned int)pair
.type
<< ")");
378 pair
= EndpointPair(); // clear
382 return m_valid
= true;
386 ///////////////////////////////////////////////////////////////////////////////
387 // InterfaceDiscovery
389 bool InterfaceDiscovery::Discover(libusb_device_id_t devid
, int cfgidx
, int ifcount
)
395 for( int i
= 0; i
< ifcount
; i
++ ) {
398 if( libusb_get_interface_desc(devid
, cfgidx
, i
, &desc
.desc
) < 0 )
400 dout(" interface_desc #" << i
<< " loaded");
402 // load all endpoints on this interface
403 if( !desc
.endpoints
.Discover(devid
, cfgidx
, i
, desc
.desc
.bNumEndpoints
) )
407 (*this)[desc
.desc
.bInterfaceNumber
] = desc
;
408 dout(" interface added to map with bInterfaceNumber: " << (unsigned int)desc
.desc
.bInterfaceNumber
);
411 return m_valid
= true;
415 ///////////////////////////////////////////////////////////////////////////////
418 bool ConfigDiscovery::Discover(libusb_device_id_t devid
, int cfgcount
)
424 for( int i
= 0; i
< cfgcount
; i
++ ) {
427 if( libusb_get_config_desc(devid
, i
, &desc
.desc
) < 0 )
429 dout(" config_desc #" << i
<< " loaded");
431 // load all interfaces on this configuration
432 if( !desc
.interfaces
.Discover(devid
, i
, desc
.desc
.bNumInterfaces
) )
436 (*this)[desc
.desc
.bConfigurationValue
] = desc
;
437 dout(" config added to map with bConfigurationValue: " << (unsigned int)desc
.desc
.bConfigurationValue
);
440 return m_valid
= true;
444 ///////////////////////////////////////////////////////////////////////////////
447 DeviceDiscovery::DeviceDiscovery(libusb_device_id_t devid
)
453 bool DeviceDiscovery::Discover(libusb_device_id_t devid
)
459 if( libusb_get_device_desc(devid
, &desc
) < 0 )
461 dout("device_desc loaded");
463 m_valid
= configs
.Discover(devid
, desc
.bNumConfigurations
);