1// -*- C++;indent-tabs-mode: t; tab-width: 4; c-basic-offset: 4; -*-
2/*
3 * USB C++ bindings
4 *
5 * Copyright (C) 2003 Brad Hards <bradh@frogmouth.net>
6 *
7 * This library is covered by the LGPL, read LICENSE for details.
8 */
9
10#include <errno.h>
11#include <cstdlib>
12#include <stdio.h>
13
14//remove after debugging
15#include <iostream>
16
17#include "usbpp.h"
18
19namespace USB {
20  Busses::Busses(void)
21  {
22    usb_init();
23    rescan();
24  }
25
26  void Busses::rescan(void)
27  {
28    struct usb_bus *bus;
29    struct usb_device *dev;
30    Bus *this_Bus;
31    Device *this_Device;
32    Configuration *this_Configuration;
33    Interface *this_Interface;
34    AltSetting *this_AltSetting;
35    Endpoint *this_Endpoint;
36    int i, j, k, l;
37
38    usb_find_busses();
39    usb_find_devices();
40
41    for (bus = usb_get_busses(); bus; bus = bus->next) {
42      std::string dirName(bus->dirname);
43
44      this_Bus = new Bus;
45      this_Bus->setDirectoryName(dirName);
46      push_back(this_Bus);
47
48      for (dev = bus->devices; dev; dev = dev->next) {
49	std::string buf, fileName(dev->filename);
50	usb_dev_handle *dev_handle;
51	int ret;
52
53	this_Device = new Device;
54	this_Device->setFileName(fileName);
55	this_Device->setDescriptor(dev->descriptor);
56
57	dev_handle = usb_open(dev);
58
59	if (dev_handle) {
60	  this_Device->setDevHandle(dev_handle);
61
62	  if (dev->descriptor.iManufacturer) {
63	    ret = this_Device->string(buf, dev->descriptor.iManufacturer);
64	    if (ret > 0)
65	      this_Device->setVendor(buf);
66	  }
67
68	  if (dev->descriptor.iProduct) {
69	    ret = this_Device->string(buf, dev->descriptor.iProduct);
70	    if (ret > 0)
71	      this_Device->setProduct(buf);
72	  }
73
74	  if (dev->descriptor.iSerialNumber) {
75	    ret = this_Device->string(buf, dev->descriptor.iSerialNumber);
76	    if (ret > 0)
77	      this_Device->setSerialNumber(buf);
78	  }
79	}
80
81	this_Bus->push_back(this_Device);
82
83	for (i = 0; i < this_Device->numConfigurations(); i++) {
84	  this_Configuration = new Configuration;
85	  this_Configuration->setDescriptor(dev->config[i]);
86	  this_Device->push_back(this_Configuration);
87
88	  for (j = 0; j < this_Configuration->numInterfaces(); j ++) {
89	    this_Interface = new Interface;
90	    this_Interface->setNumAltSettings(dev->config[i].interface[j].num_altsetting);
91	    this_Interface->setParent(this_Device);
92	    this_Interface->setInterfaceNumber(j);
93	    this_Configuration->push_back(this_Interface);
94
95	    for (k = 0; k < this_Interface->numAltSettings(); k ++) {
96	      this_AltSetting = new AltSetting;
97	      this_AltSetting->setDescriptor(dev->config[i].interface[j].altsetting[k]);
98	      this_Interface->push_back(this_AltSetting);
99
100	      for (l = 0; l < this_AltSetting->numEndpoints(); l++) {
101		this_Endpoint = new Endpoint;
102		this_Endpoint->setDescriptor(dev->config[i].interface[j].altsetting[k].endpoint[l]);
103		this_Endpoint->setParent(this_Device);
104		this_AltSetting->push_back(this_Endpoint);
105	      }
106	    }
107	  }
108	}
109      }
110    }
111  }
112
113  std::list<Device *> Busses::match(u_int8_t class_code)
114  {
115    std::list<Device *> match_list;
116    USB::Bus *bus;
117    std::list<USB::Bus *>::const_iterator biter;
118
119    for (biter = begin(); biter != end(); biter++) {
120      USB::Device *device;
121      std::list<USB::Device *>::const_iterator diter;
122      bus = *biter;
123
124      for (diter = bus->begin(); diter != bus->end(); diter++) {
125        device = *diter;
126	if (device->devClass() == class_code)
127	  match_list.push_back(device);
128      }
129    }
130    return match_list;
131  }
132
133  std::list<Device *> Busses::match(DeviceIDList devList)
134  {
135    std::list<Device *> match_list;
136    USB::Bus *bus;
137    std::list<USB::Bus *>::const_iterator biter;
138
139    for (biter = begin(); biter != end(); biter++) {
140      USB::Device *device;
141      std::list<USB::Device *>::const_iterator diter;
142
143      bus = *biter;
144      for (diter = bus->begin(); diter != bus->end(); diter++) {
145	DeviceIDList::iterator it;
146
147        device = *diter;
148
149	for (it = devList.begin(); it != devList.end(); it++) {
150	  if (device->idVendor() == (*it).vendor() &&
151	      device->idProduct() == (*it).product())
152	    match_list.push_back(device);
153	}
154      }
155    }
156    return match_list;
157  }
158
159  std::string Bus::directoryName(void)
160  {
161    return m_directoryName;
162  }
163
164  void Bus::setDirectoryName(std::string directoryName)
165  {
166    m_directoryName = directoryName;
167  }
168
169  Device::~Device(void)
170  {
171    usb_close(m_handle);
172  }
173
174  std::string Device::fileName(void)
175  {
176    return m_fileName;
177  }
178
179  int Device::string(std::string &buf, int index, u_int16_t langID)
180  {
181    int retval;
182    char tmpBuff[256];
183
184    if (0 == langID) {
185      /* we want the first lang ID available, so find out what it is */
186      retval = usb_get_string(m_handle, 0, 0, tmpBuff, sizeof(tmpBuff));
187      if (retval < 0)
188	return retval;
189
190      if (retval < 4 || tmpBuff[1] != USB_DT_STRING)
191	return -EIO;
192
193      langID = tmpBuff[2] | (tmpBuff[3] << 8);
194    }
195
196    retval = usb_get_string(m_handle, index, langID, tmpBuff, sizeof(tmpBuff));
197
198    if (retval < 0)
199      return retval;
200
201    if (tmpBuff[1] != USB_DT_STRING)
202      return -EIO;
203
204    if (tmpBuff[0] > retval)
205      return -EFBIG;
206
207    /* FIXME: Handle unicode? */
208#if 0
209    if (retval > 0) {
210      std::string.setUnicode((unsigned char *)&tmpBuff[2], tmpBuff[0] / 2 - 1);
211    }
212#endif
213    return retval;
214  }
215
216  struct usb_dev_handle *Device::handle(void)
217  {
218    return m_handle;
219  }
220
221#ifdef USE_UNTESTED_LIBUSBPP_METHODS
222  int Device::reset(void)
223  {
224    return usb_reset(handle());
225  }
226
227  int Device::setConfiguration(int configurationNumber)
228  {
229    return usb_set_configuration(handle(), configurationNumber);
230  }
231#endif /* USE_UNTESTED_LIBUSBPP_METHODS */
232
233  u_int16_t Device::idVendor(void)
234  {
235    return m_descriptor.idVendor;
236  }
237
238  u_int16_t Device::idProduct(void)
239  {
240    return m_descriptor.idProduct;
241  }
242
243  u_int16_t Device::idRevision(void)
244  {
245    return m_descriptor.bcdDevice;
246  }
247
248  u_int8_t Device::devClass(void)
249  {
250    return m_descriptor.bDeviceClass;
251  }
252
253  u_int8_t Device::devSubClass(void)
254  {
255    return m_descriptor.bDeviceSubClass;
256  }
257
258  u_int8_t Device::devProtocol(void)
259  {
260    return m_descriptor.bDeviceProtocol;
261  }
262
263  std::string Device::Vendor(void)
264  {
265    return m_Vendor;
266  }
267
268  std::string Device::Product(void)
269  {
270    return m_Product;
271  }
272
273  std::string Device::SerialNumber(void)
274  {
275    return m_SerialNumber;
276  }
277
278  void Device::setVendor(std::string vendor)
279  {
280    m_Vendor = vendor;
281  }
282
283  void Device::setDevHandle(struct usb_dev_handle *device)
284  {
285    m_handle = device;
286  }
287
288  void Device::setProduct(std::string product)
289  {
290    m_Product = product;
291  }
292
293  void Device::setSerialNumber(std::string serialnumber)
294  {
295    m_SerialNumber = serialnumber;
296  }
297
298  u_int8_t Device::numConfigurations(void)
299  {
300    return m_descriptor.bNumConfigurations;
301  }
302
303  void Device::setFileName(std::string fileName)
304  {
305    m_fileName = fileName;
306  }
307
308  void Device::setDescriptor(struct usb_device_descriptor descriptor)
309  {
310    m_descriptor = descriptor;
311  }
312
313  Configuration *Device::firstConfiguration(void)
314  {
315    iter = begin();
316    return *iter++;
317  }
318
319  Configuration *Device::nextConfiguration(void)
320  {
321    if (iter == end())
322      return NULL;
323
324    return *iter++;
325  }
326
327  Configuration *Device::lastConfiguration(void)
328  {
329    return back();
330  }
331
332  int Device::controlTransfer(u_int8_t requestType, u_int8_t request,
333			       u_int16_t value, u_int16_t index, u_int16_t length,
334			       unsigned char *payload, int timeout)
335  {
336    return usb_control_msg(m_handle, requestType, request, value, index, (char *)payload, length, timeout);
337  }
338
339  u_int8_t Configuration::numInterfaces(void)
340  {
341    return m_NumInterfaces;
342  }
343
344  void Configuration::setDescriptor(struct usb_config_descriptor descriptor)
345  {
346    m_Length = descriptor.bLength;
347    m_DescriptorType = descriptor.bDescriptorType;
348    m_TotalLength = descriptor.wTotalLength;
349    m_NumInterfaces = descriptor.bNumInterfaces;
350    m_ConfigurationValue = descriptor.bConfigurationValue;
351    m_Configuration = descriptor.iConfiguration;
352    m_Attributes = descriptor.bmAttributes;
353    m_MaxPower = descriptor.MaxPower;
354  }
355
356  void Configuration::dumpDescriptor(void)
357  {
358    printf("  wTotalLength:         %d\n", m_TotalLength);
359    printf("  bNumInterfaces:       %d\n", m_NumInterfaces);
360    printf("  bConfigurationValue:  %d\n", m_ConfigurationValue);
361    printf("  iConfiguration:       %d\n", m_Configuration);
362    printf("  bmAttributes:         %02xh\n", m_Attributes);
363    printf("  MaxPower:             %d\n", m_MaxPower);
364  }
365
366  Interface *Configuration::firstInterface(void)
367  {
368    iter = begin();
369    return *iter++;
370  }
371
372  Interface *Configuration::nextInterface(void)
373  {
374    if (iter == end())
375      return NULL;
376
377    return *iter++;
378  }
379
380  Interface *Configuration::lastInterface(void)
381  {
382    return back();
383  }
384
385#ifdef LIBUSB_HAS_GET_DRIVER_NP
386  int Interface::driverName(std::string &driver)
387  {
388    int retval;
389    char tmpString[256];
390
391    retval = usb_get_driver_np(m_parent->handle(), m_interfaceNumber, tmpString, sizeof(tmpString));
392    if (retval == 0) {
393      std::string buf(tmpString);
394
395      driver = buf;
396    }
397    return retval;
398  }
399#endif
400
401#ifdef USE_UNTESTED_LIBUSBPP_METHODS
402  int Interface::claim(void)
403  {
404    return usb_claim_interface(m_parent->handle(), m_interfaceNumber);
405  }
406
407  int Interface::release(void)
408  {
409    return usb_claim_interface(m_parent->handle(), m_interfaceNumber);
410  }
411
412  int Interface::setAltSetting(int altSettingNumber)
413  {
414    return usb_set_altinterface(m_parent->handle(), altSettingNumber);
415  }
416#endif /* USE_UNTESTED_LIBUSBPP_METHODS */
417
418  u_int8_t Interface::numAltSettings(void)
419  {
420    return m_numAltSettings;
421  }
422
423  void Interface::setNumAltSettings(u_int8_t num_altsetting)
424  {
425    m_numAltSettings = num_altsetting;
426  }
427
428  void Interface::setInterfaceNumber(int interfaceNumber)
429  {
430    m_interfaceNumber = interfaceNumber;
431  }
432
433  void Interface::setParent(Device *parent)
434  {
435    m_parent = parent;
436  }
437
438  AltSetting *Interface::firstAltSetting(void)
439  {
440    iter = begin();
441    return *iter++;
442  }
443
444  AltSetting *Interface::nextAltSetting(void)
445  {
446    if (iter == end())
447      return NULL;
448
449    return *iter++;
450  }
451
452  AltSetting *Interface::lastAltSetting(void)
453  {
454    return back();
455  }
456
457  void AltSetting::setDescriptor(struct usb_interface_descriptor descriptor)
458  {
459    m_Length = descriptor.bLength;
460    m_DescriptorType = descriptor.bDescriptorType;
461    m_InterfaceNumber = descriptor.bInterfaceNumber;
462    m_AlternateSetting = descriptor.bAlternateSetting;
463    m_NumEndpoints = descriptor.bNumEndpoints;
464    m_InterfaceClass = descriptor.bInterfaceClass;
465    m_InterfaceSubClass = descriptor.bInterfaceSubClass;
466    m_InterfaceProtocol = descriptor.bInterfaceProtocol;
467    m_Interface = descriptor.iInterface;
468  }
469
470  void AltSetting::dumpDescriptor(void)
471  {
472    printf("    bInterfaceNumber:   %d\n", m_InterfaceNumber);
473    printf("    bAlternateSetting:  %d\n", m_AlternateSetting);
474    printf("    bNumEndpoints:      %d\n", m_NumEndpoints);
475    printf("    bInterfaceClass:    %d\n", m_InterfaceClass);
476    printf("    bInterfaceSubClass: %d\n", m_InterfaceSubClass);
477    printf("    bInterfaceProtocol: %d\n", m_InterfaceProtocol);
478    printf("    iInterface:         %d\n", m_Interface);
479  }
480
481  Endpoint *AltSetting::firstEndpoint(void)
482  {
483    iter = begin();
484    return *iter++;
485  }
486
487  Endpoint *AltSetting::nextEndpoint(void)
488  {
489    if (iter == end())
490      return NULL;
491
492    return *iter++;
493  }
494
495  Endpoint *AltSetting::lastEndpoint(void)
496  {
497    return back();
498  }
499
500  u_int8_t AltSetting::numEndpoints(void)
501  {
502    return m_NumEndpoints;
503  }
504
505  void Endpoint::setDescriptor(struct usb_endpoint_descriptor descriptor)
506  {
507    m_EndpointAddress = descriptor.bEndpointAddress;
508    m_Attributes = descriptor.bmAttributes;
509    m_MaxPacketSize = descriptor.wMaxPacketSize;
510    m_Interval = descriptor.bInterval;
511    m_Refresh = descriptor.bRefresh;
512    m_SynchAddress = descriptor.bSynchAddress;
513  }
514
515  void Endpoint::setParent(Device *parent)
516  {
517    m_parent = parent;
518  }
519
520#ifdef USE_UNTESTED_LIBUSBPP_METHODS
521  int Endpoint::bulkWrite(unsigned char *message, int timeout)
522  {
523    return usb_bulk_write(m_parent->handle(), m_EndpointAddress, message.data(),
524			  message.size(), timeout);
525  }
526
527  int Endpoint::bulkRead(int length, unsigned char *message, int timeout)
528  {
529    char *buf;
530    int res;
531
532    buf = (char *)malloc(length);
533    res = usb_bulk_read(m_parent->handle(), m_EndpointAddress, buf, length, timeout);
534
535    if (res > 0) {
536      message.resize(length);
537      message.duplicate(buf, res);
538    }
539
540    return res;
541  }
542
543  int Endpoint::reset(void)
544  {
545    return usb_resetep(m_parent->handle(), m_EndpointAddress);
546  }
547
548  int Endpoint::clearHalt(void)
549  {
550    return usb_clear_halt(m_parent->handle(), m_EndpointAddress);
551  }
552
553#endif /* USE_UNTESTED_LIBUSBPP_METHODS */
554
555  void Endpoint::dumpDescriptor(void)
556  {
557    printf("      bEndpointAddress: %02xh\n", m_EndpointAddress);
558    printf("      bmAttributes:     %02xh\n", m_Attributes);
559    printf("      wMaxPacketSize:   %d\n", m_MaxPacketSize);
560    printf("      bInterval:        %d\n", m_Interval);
561    printf("      bRefresh:         %d\n", m_Refresh);
562    printf("      bSynchAddress:    %d\n", m_SynchAddress);
563  }
564
565  DeviceID::DeviceID(u_int16_t vendor, u_int16_t product)
566  {
567    m_vendor = vendor;
568    m_product = product;
569  }
570
571  u_int16_t DeviceID::vendor(void)
572  {
573    return m_vendor;
574  }
575
576  u_int16_t DeviceID::product(void)
577  {
578    return m_product;
579  }
580}
581
582