- updated time conversion calls to match opensync's latest SVN
[barry.git] / src / usbwrap.cc
blobb57323d486a4ef99baaaea81d99788560c51737a
1 ///
2 /// \file usbwrap.cc
3 /// USB API wrapper
4 ///
6 /*
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.
23 #include "usbwrap.h"
24 #include "data.h"
25 #include "error.h"
26 #include "debug.h"
28 #include <iomanip>
29 #include <sstream>
31 #define __DEBUG_MODE__
32 #include "debug.h"
34 namespace Usb {
36 IO::IO(Device *dev, libusb_io_handle_t *handle)
37 : m_dev(dev),
38 m_handle(handle)
40 if( m_handle )
41 dout("IO::IO handle: " << m_handle);
44 IO::IO(Device &dev, libusb_io_handle_t *handle)
45 : m_dev(&dev),
46 m_handle(handle)
48 if( m_handle )
49 dout("IO::IO handle: " << m_handle);
52 IO::IO(const IO &other)
53 : m_dev(other.m_dev),
54 m_handle(0)
56 operator=(other);
59 // only one IO object can ever hold a handle to an io operation
60 IO& IO::operator=(const IO &other)
62 if( this == &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.");
69 cleanup();
70 m_handle = other.m_handle;
71 other.m_handle = 0;
72 return *this;
75 // cleans up the io handle, making this IO object invalid
76 void IO::cleanup()
78 if( IsValid() ) {
79 dout("IO::cleanup handle: " << m_handle);
81 std::ostringstream oss;
82 oss << "cleanup: " << GetEndpoint() << " ";
83 if( !IsCompleted() ) {
84 // not complete yet, cancel
85 oss << " cancel ";
86 libusb_io_cancel(m_handle);
88 oss << " free";
89 dout(oss.str());
90 libusb_io_free(m_handle);
91 m_handle = 0;
95 // will cancel if not complete, and will always free if valid
96 IO::~IO()
98 cleanup();
101 // API wrappers
102 bool IO::IsCompleted() const
104 if( !IsValid() )
105 return true;
107 return libusb_is_io_completed(m_handle) != 0;
110 void IO::Wait()
112 if( !IsValid() )
113 return; // nothing to wait on
114 libusb_io_wait(m_handle);
116 #ifdef __DEBUG_MODE__
117 ddout("IO::Wait(): Endpoint " << GetEndpoint()
118 << " Status "
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());
124 ddout(dump);
126 #endif
129 void IO::Cancel()
131 if( !IsValid() )
132 return;
133 if( !IsCompleted() ) {
134 // not complete yet, cancel
135 libusb_io_cancel(m_handle);
139 int IO::GetStatus() const
141 if( !IsValid() )
142 return -1;
143 return libusb_io_comp_status(m_handle);
146 int IO::GetSize() const
148 if( !IsValid() )
149 return 0;
150 return libusb_io_xfer_size(m_handle);
153 int IO::GetReqSize() const
155 if( !IsValid() )
156 return 0;
157 return libusb_io_req_size(m_handle);
160 int IO::GetEndpoint() const
162 if( !IsValid() )
163 return 0;
164 return libusb_io_ep_addr(m_handle);
167 unsigned char * IO::GetData()
169 if( !IsValid() )
170 return 0;
171 return libusb_io_data(m_handle);
174 const unsigned char * IO::GetData() const
176 if( !IsValid() )
177 return 0;
178 return libusb_io_data(m_handle);
183 ///////////////////////////////////////////////////////////////////////////////
184 // Device
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;
198 bool Device::Reset()
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();
231 if( !done )
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++ ) {
237 if( *b == done ) {
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);
249 else {
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);
264 if( !rd )
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);
275 if( !wr )
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);
286 #endif
288 libusb_io_handle_t *wr = libusb_submit_bulk_write(GetHandle(), ep,
289 data, size, m_timeout, NULL);
290 if( !wr )
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);
300 if( !rd )
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);
311 if( !wr )
312 throw UsbError("Error in libusb_submit_interrupt_write");
314 return IO(*this, wr);
319 ///////////////////////////////////////////////////////////////////////////////
320 // EndpointDiscovery
322 bool EndpointDiscovery::Discover(libusb_device_id_t devid, int cfgidx, int ifcidx, int epcount)
324 // start fresh
325 clear();
326 m_valid = false;
328 EndpointPair pair;
330 for( int i = 0; i < epcount; i++ ) {
331 // load descriptor
332 usb_endpoint_desc desc;
333 if( libusb_get_endpoint_desc(devid, cfgidx, ifcidx, i, &desc) < 0 )
334 return false;
335 dout(" endpoint_desc #" << i << " loaded");
337 // add to the map
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...
343 // Assumptions:
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 ) {
350 // read endpoint
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
355 pair.write = 0;
358 else {
359 // write endpoint
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
364 pair.read = 0;
367 // save the type last
368 pair.type = type;
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)
391 // start fresh
392 clear();
393 m_valid = false;
395 for( int i = 0; i < ifcount; i++ ) {
396 // load descriptor
397 InterfaceDesc desc;
398 if( libusb_get_interface_desc(devid, cfgidx, i, &desc.desc) < 0 )
399 return false;
400 dout(" interface_desc #" << i << " loaded");
402 // load all endpoints on this interface
403 if( !desc.endpoints.Discover(devid, cfgidx, i, desc.desc.bNumEndpoints) )
404 return false;
406 // add to the map
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 ///////////////////////////////////////////////////////////////////////////////
416 // ConfigDiscovery
418 bool ConfigDiscovery::Discover(libusb_device_id_t devid, int cfgcount)
420 // start fresh
421 clear();
422 m_valid = false;
424 for( int i = 0; i < cfgcount; i++ ) {
425 // load descriptor
426 ConfigDesc desc;
427 if( libusb_get_config_desc(devid, i, &desc.desc) < 0 )
428 return false;
429 dout(" config_desc #" << i << " loaded");
431 // load all interfaces on this configuration
432 if( !desc.interfaces.Discover(devid, i, desc.desc.bNumInterfaces) )
433 return false;
435 // add to the map
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 ///////////////////////////////////////////////////////////////////////////////
445 // DeviceDiscovery
447 DeviceDiscovery::DeviceDiscovery(libusb_device_id_t devid)
448 : m_valid(false)
450 Discover(devid);
453 bool DeviceDiscovery::Discover(libusb_device_id_t devid)
455 // start fresh
456 configs.clear();
457 m_valid = false;
459 if( libusb_get_device_desc(devid, &desc) < 0 )
460 return false;
461 dout("device_desc loaded");
463 m_valid = configs.Discover(devid, desc.bNumConfigurations);
464 return m_valid;
467 } // namespace Usb