- build system tweaks for opensync-plugin, and added a buildgen.sh for it
[barry.git] / src / usbwrap.cc
blob6079a6ddf3fec635d88db0738a9656187374f7e4
1 ///
2 /// \file usbwrap.cc
3 /// USB API wrapper
4 ///
6 /*
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.
23 #include "usbwrap.h"
24 #include "data.h"
25 #include "error.h"
26 #include "debug.h"
28 #include <iomanip>
29 #include <sstream>
30 #include <errno.h>
32 #ifndef __DEBUG_MODE__
33 #define __DEBUG_MODE__
34 #endif
35 #include "debug.h"
37 namespace Usb {
39 ///////////////////////////////////////////////////////////////////////////////
40 // Match
42 Match::Match(int vendor, int product)
43 : m_busses(0),
44 m_dev(0),
45 m_vendor(vendor),
46 m_product(product)
48 usb_find_busses();
49 usb_find_devices();
50 m_busses = usb_get_busses();
53 Match::~Match()
57 bool Match::next_device(Usb::DeviceIDType *devid)
59 for( ; m_busses; m_busses = m_busses->next ) {
61 if( !m_dev )
62 m_dev = m_busses->devices;
64 for( ; m_dev; m_dev = m_dev->next ) {
65 // is there a match?
66 if( m_dev->descriptor.idVendor == m_vendor &&
67 m_dev->descriptor.idProduct == m_product ) {
68 // found!
69 *devid = m_dev;
71 // advance for next time
72 m_dev = m_dev->next;
73 if( !m_dev )
74 m_busses = m_busses->next;
76 // done
77 return true;
81 return false;
85 ///////////////////////////////////////////////////////////////////////////////
86 // Device
88 Device::Device(Usb::DeviceIDType id, int timeout)
89 : m_id(id),
90 m_timeout(timeout)
92 m_handle = usb_open(id);
93 if( !m_handle )
94 throw Error("open failed");
97 Device::~Device()
99 usb_close(m_handle);
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;
114 bool Device::Reset()
116 m_lasterror = usb_reset(m_handle);
117 return m_lasterror == 0;
120 bool Device::BulkRead(int ep, Barry::Data &data, int timeout)
122 do {
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);
137 do {
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);
153 #endif
155 do {
156 m_lasterror = usb_bulk_write(m_handle, ep,
157 (char*) data, size,
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)
168 do {
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);
184 do {
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;
196 // BulkDrain
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)
203 try {
204 Barry::Data data;
205 while( BulkRead(ep, data, 100) )
208 catch( Usb::Error & ) {}
213 ///////////////////////////////////////////////////////////////////////////////
214 // EndpointDiscovery
216 bool EndpointDiscovery::Discover(struct usb_interface_descriptor *interface, int epcount)
218 // start fresh
219 clear();
220 m_valid = false;
222 EndpointPair pair;
224 if( !interface || !interface->endpoint )
225 return false;
227 for( int i = 0; i < epcount; i++ ) {
228 // load descriptor
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
240 << "\n"
243 // add to the map
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...
249 // Assumptions:
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 ) {
256 // read endpoint
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
261 pair.write = 0;
264 else {
265 // write endpoint
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
270 pair.read = 0;
273 // save the type last
274 pair.type = type;
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 )
298 return false;
300 for( int i = 0; i < interface->num_altsetting; i++ ) {
301 // load descriptor
302 InterfaceDesc desc;
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
314 << "\n"
317 // load all endpoints on this interface
318 if( !desc.endpoints.Discover(&desc.desc, desc.desc.bNumEndpoints) )
319 return false;
321 // add to the map
322 (*this)[desc.desc.bInterfaceNumber] = desc;
323 dout(" interface added to map with bInterfaceNumber: " << (unsigned int)desc.desc.bInterfaceNumber);
325 return true;
328 bool InterfaceDiscovery::Discover(Usb::DeviceIDType devid, int cfgidx, int ifcount)
330 // start fresh
331 clear();
332 m_valid = false;
334 if( !devid || !devid->config || !devid->config[cfgidx].interface )
335 return false;
337 for( int i = 0; i < ifcount; i++ ) {
338 if( !DiscoverInterface(&devid->config[cfgidx].interface[i]) )
339 return false;
342 return m_valid = true;
346 ///////////////////////////////////////////////////////////////////////////////
347 // ConfigDiscovery
349 bool ConfigDiscovery::Discover(Usb::DeviceIDType devid, int cfgcount)
351 // start fresh
352 clear();
353 m_valid = false;
355 for( int i = 0; i < cfgcount; i++ ) {
356 // load descriptor
357 ConfigDesc desc;
358 if( !devid || !devid->config )
359 return false;
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
370 << "\n"
373 // load all interfaces on this configuration
374 if( !desc.interfaces.Discover(devid, i, desc.desc.bNumInterfaces) )
375 return false;
377 // add to the map
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 ///////////////////////////////////////////////////////////////////////////////
387 // DeviceDiscovery
389 DeviceDiscovery::DeviceDiscovery(Usb::DeviceIDType devid)
390 : m_valid(false)
392 Discover(devid);
395 bool DeviceDiscovery::Discover(Usb::DeviceIDType devid)
397 // start fresh
398 configs.clear();
399 m_valid = false;
401 // copy the descriptor over to our memory
402 if( !devid )
403 return false;
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
420 << "\n"
423 m_valid = configs.Discover(devid, desc.bNumConfigurations);
424 return m_valid;
427 } // namespace Usb