libusbemu_internal.h
Go to the documentation of this file.
1 /*
2 * This file is part of the OpenKinect Project. http://www.openkinect.org
3 *
4 * Copyright (c) 2010 individual OpenKinect contributors. See the CONTRIB file
5 * for details.
6 *
7 * This code is licensed to you under the terms of the Apache License, version
8 * 2.0, or, at your option, the terms of the GNU General Public License,
9 * version 2.0. See the APACHE20 and GPL2 files for the text of the licenses,
10 * or the following URLs:
11 * http://www.apache.org/licenses/LICENSE-2.0
12 * http://www.gnu.org/licenses/gpl-2.0.txt
13 *
14 * If you redistribute this file in source form, modified or unmodified, you
15 * may:
16 * 1) Leave this header intact and distribute it under the same terms,
17 * accompanying it with the APACHE20 and GPL20 files, or
18 * 2) Delete the Apache 2.0 clause and accompany it with the GPL2 file, or
19 * 3) Delete the GPL v2 clause and accompany it with the APACHE20 file
20 * In all cases you must keep the copyright notice intact and include a copy
21 * of the CONTRIB file.
22 *
23 * Binary distributions must follow the binary distribution requirements of
24 * either License.
25 */
26 
27 #pragma once
28 
29 #include "libusbemu_threads.h"
30 #include <lusb0_usb.h>
31 #include <map>
32 #include <cassert>
33 
34 namespace libusbemu {
35 
36 template<typename T>
37 inline T*& SAFE_DELETE(T*& p)
38 {
39  if(NULL != p)
40  delete(p);
41  p = NULL;
42  return(p);
43 }
44 
45 template<typename T>
46 inline T MIN(const T& v1, const T& v2)
47 {
48  return((v1<v2) ? v1 : v2);
49 }
50 
51 template<typename T>
52 struct QuickList
53 {
54  T ini;
55  T end;
57  {
58  memset(&ini, 0, sizeof(T));
59  memset(&end, 0, sizeof(T));
60  ini.prev = NULL;
61  ini.next = &end;
62  end.prev = &ini;
63  end.next = NULL;
64  }
65  // copy-constructor is required to be safely used as a plain std::map value
66  QuickList(const QuickList& rhs)
67  {
68  if (!rhs.Empty())
69  {
70  fprintf(stdout, "WARNING: Copy-constructin from a non-empty QuickList!\n");
71  return;
72  }
73  memset(&ini, 0, sizeof(T));
74  memset(&end, 0, sizeof(T));
75  ini.prev = NULL;
76  ini.next = &end;
77  end.prev = &ini;
78  end.next = NULL;
79  }
80  ~QuickList() {};
81  const bool Empty() const
82  {
83  return(ini.next == &end); // could also be (end.prev == &ini)
84  }
85  void Append(T* node)
86  {
87  if (!Orphan(node))
88  {
89  fprintf(stdout, "WARNING: Appending non-orphan node to list...\n");
90  Remove(node);
91  }
92  end.prev->next = node;
93  node->prev = end.prev;
94  node->next = &end;
95  end.prev = node;
96  node->list = this;
97  }
98  T* Head() const
99  {
100  T* head (NULL);
101  if (!Empty())
102  head = ini.next;
103  return(head);
104  }
105  T* Last() const
106  {
107  T* last (NULL);
108  if (!Empty())
109  last = end.prev;
110  return(last);
111  }
112  const bool Member(T* node) const
113  {
114  return(this == node->list);
115  }
116  static T* Prev(T* node)
117  {
118  T* prev (NULL);
119  if (NULL != node->prev->prev)
120  prev = node->prev;
121  return(prev);
122  }
123  static T* Next(T* node)
124  {
125  T* next (NULL);
126  if (NULL != node->next->next)
127  next = node->next;
128  return(next);
129  }
130  const bool Remove (T* node)
131  {
132  if (!Member(node))
133  return(false);
134  node->prev->next = node->next;
135  node->next->prev = node->prev;
136  node->prev = NULL;
137  node->next = NULL;
138  node->list = NULL;
139  return(true);
140  }
141  static void RemoveNode(T* node)
142  {
143  if (Orphan(node))
144  return;
145  node->list->Remove(node);
146  }
147  static const bool Orphan(T* node)
148  {
149  return(NULL == node->list);
150  }
151 };
152 
153 template<typename T>
155 {
156 protected:
157  // 'mutable' required to allow operations within 'const methods'
158  mutable QuickMutex mutex;
159  mutable QuickEvent chomp; // signals whether there is (or not) transfers in the list
160 
161 public:
163  QuickListMutexed(const QuickListMutexed& rhs) : QuickList<T>(rhs) {};
164  ~QuickListMutexed() { /*this->~QuickListMutexed()*/ mutex.Enter(); mutex.Leave(); };
165  const bool Empty() const
166  {
167  mutex.Enter();
168  const bool empty = QuickList<T>::Empty();
169  mutex.Leave();
170  return(empty);
171  }
172  void Append(T* node)
173  {
174  mutex.Enter();
175  const bool empty = QuickList<T>::Empty();
176  QuickList<T>::Append(node);
177  if (empty)
178  chomp.Signal();
179  mutex.Leave();
180  }
181  T* Head() const
182  {
183  mutex.Enter();
184  T* head = QuickList<T>::Head();
185  mutex.Leave();
186  return(head);
187  }
188  T* Last() const
189  {
190  mutex.Enter();
191  T* last = QuickList<T>::Last();
192  mutex.Leave();
193  return(last);
194  }
195  const bool Member(T* node) const
196  {
197  mutex.Enter();
198  const bool member = QuickList<T>::Member(node);
199  mutex.Leave();
200  return(member);
201  }
202  const bool Remove(T* node)
203  {
204  mutex.Enter();
205  const bool removed = QuickList<T>::Remove(node);
206  if (QuickList<T>::Empty())
207  chomp.Reset();
208  mutex.Leave();
209  return(removed);
210  }
211  static const bool Orphan(T* node)
212  {
213  //node->list->mutex.Enter();
214  const bool orphan = QuickList<T>::Orphan(node);
215  //node->list->mutex.Leave();
216  return(orphan);
217  }
218 
219  const bool WaitUntilTimeout(unsigned int milliseconds) const
220  {
221  return(chomp.WaitUntilTimeout(milliseconds));
222  }
223  void Wait() const
224  {
225  chomp.Wait();
226  }
227  const bool Check() const
228  {
229  return(chomp.Check());
230  }
231 };
232 
233 } // end of 'namespace libusbemu'
234 
235 
236 
237 using namespace libusbemu;
238 
240 {
244  void* usb;
246 };
247 
249 {
251  usb_dev_handle* handle;
252 };
253 
255 {
257  struct usb_device* device;
258  int refcount;
260  struct isoc_handle
261  {
262  TListTransfers listTransfers;
264  };
265  typedef std::map<int, isoc_handle> TMapIsocTransfers;
266  TMapIsocTransfers* isoTransfers;
267  typedef std::map<usb_dev_handle*, libusb_device_handle> TMapHandles;
268  TMapHandles* handles;
269 };
270 
272 {
273  typedef std::map<struct usb_device*, libusb_device> TMapDevices;
274  TMapDevices devices;
276 
281 };
282 
283 
284 
285 #define LIBUSBEMU_ERROR(msg) libusbemu_report_error(__FILE__, __LINE__, msg)
286 #define LIBUSBEMU_ERROR_LIBUSBWIN32() LIBUSBEMU_ERROR(usb_strerror())
287 
288 namespace libusbemu {
289 
290 void libusbemu_report_error(const char* file, const int line, const char* msg)
291 {
292  // remove source file path:
293  int i = strlen(file);
294  while (-1 != --i)
295  if ((file[i] == '/') || (file[i] == '\\'))
296  break;
297  file = &file[++i];
298 
299  fprintf(stderr, "ERROR in libusbemu -- source file '%s' at line %d -- %s\n", file, line, msg);
300 }
301 
303 {
304  char* raw_address ((char*)transfer);
305  char* off_address (raw_address - sizeof(void*) - 2*sizeof(transfer_wrapper*) - sizeof(QuickList<transfer_wrapper>*));
306  return((transfer_wrapper*)off_address);
307 }
308 
310 {
311  RAIIMutex lock (ctx->mutex);
312  // register the device (if not already there) ...
313  libusb_device dummy = { ctx, dev, 0, NULL, NULL };
314  libusb_context::TMapDevices::iterator it = ctx->devices.insert(std::make_pair(dev,dummy)).first;
315  // ... and increment the reference count
316  libusb_device& record (it->second);
317  record.refcount++;
318  // might as well do some paranoid checkings...
319  assert(record.ctx == ctx);
320  assert(record.device == dev);
321  return(&(it->second));
322 }
323 
325 {
326  libusb_context* ctx (dev->ctx);
327  RAIIMutex lock (ctx->mutex);
328  // decrement the reference count of the device ...
329  --(dev->refcount);
330  // ... and unregister device if the reference count reaches zero
331  if (0 == dev->refcount)
332  {
333  SAFE_DELETE(dev->handles);
334  // prior to device deletion, all of its transfer lists must be deleted
335  if (NULL != dev->isoTransfers)
336  {
337  libusb_device::TMapIsocTransfers& allTransfers (*(dev->isoTransfers));
338  while (!allTransfers.empty())
339  {
340  libusb_device::TMapIsocTransfers::iterator it (allTransfers.begin());
341  libusb_device::TListTransfers& listTransfers (it->second.listTransfers);
342  while (!listTransfers.Empty())
343  {
344  transfer_wrapper* transfer (listTransfers.Head());
345  // make it orphan so that it can be deleted:
346  listTransfers.Remove(transfer);
347  // the following will free the wrapper object as well:
348  libusb_free_transfer(&transfer->libusb);
349  }
350  allTransfers.erase(it);
351  }
353  }
354  ctx->devices.erase(dev->device);
355  }
356 }
357 
359 {
360  void*& context = wrapper->usb;
361  // paranoid check...
362  if (NULL != context)
363  return(LIBUSB_ERROR_OTHER);
364 
365  RAIIMutex lock (wrapper->libusb.dev_handle->dev->ctx->mutex);
366 
367  int ret (LIBUSB_ERROR_OTHER);
368  libusb_transfer* transfer (&wrapper->libusb);
369  usb_dev_handle* handle (transfer->dev_handle->handle);
370  switch(transfer->type)
371  {
373  ret = usb_isochronous_setup_async(handle, &context, transfer->endpoint, transfer->iso_packet_desc[0].length);
374  break;
376  // libusb-0.1 does not actually support asynchronous control transfers, but this should be
377  // very easy to emulate if necessary: just stick the transfer in a special list and then
378  // libusb_handle_events() check if the list is empty or not; if it is not empty, a thread
379  // is created temporarily just to deal with such control transfer requests until the list
380  // becomes eventually empty again and the thread terminates.
383  // these transfer types are not being used by libfreenect. they should be fairly simple to
384  // emulate with libusb-0.1 since it already provides support for them.
385  // usb_bulk_setup_async(translate(transfer->dev_handle), &context, transfer->endpoint);
386  // usb_interrupt_setup_async(translate(transfer->dev_handle), &context, transfer->endpoint);
387  default :
389  }
390 
391  if (ret < 0)
392  {
393  // TODO: better error handling...
394  // what do the functions usb_***_setup_async() actually return on error?
396  return(ret);
397  }
398 
399  return(LIBUSB_SUCCESS);
400 }
401 
403 {
404  libusb_transfer* transfer (&wrapper->libusb);
405  if (transfer->actual_length > 0)
406  {
407  transfer->actual_length = 0;
408  memset(transfer->buffer, 0, transfer->length);
409  for (int i=0; i<transfer->num_iso_packets; ++i)
410  transfer->iso_packet_desc[i].actual_length = 0;
411  }
412 }
413 
414 } // end of 'namespace libusbemu'
struct usb_device * device
const bool Remove(T *node)
std::map< struct usb_device *, libusb_device > TMapDevices
transfer_wrapper * prev
#define LIBUSBEMU_ERROR_LIBUSBWIN32()
QuickList(const QuickList &rhs)
unsigned char * buffer
Definition: libusb.h:168
void libusbemu_unregister_device(libusb_device *dev)
QuickList< transfer_wrapper > TListTransfers
EventList hDoneDeliveringPool
const bool Member(T *node) const
void libusbemu_report_error(const char *file, const int line, const char *msg)
QuickMutex mutDeliveryPool
static T * Next(T *node)
const bool WaitUntilTimeout(const unsigned int milliseconds)
TMapHandles * handles
unsigned int actual_length
Definition: libusb.h:176
void libusbemu_clear_transfer(transfer_wrapper *wrapper)
libusb_device * libusbemu_register_device(libusb_context *ctx, struct usb_device *dev)
EventList hAllowDeliveryPool
const bool WaitUntilTimeout(unsigned int milliseconds) const
std::map< usb_dev_handle *, libusb_device_handle > TMapHandles
T *& SAFE_DELETE(T *&p)
void libusb_free_transfer(struct libusb_transfer *transfer)
Definition: libusbemu.cpp:451
QuickListMutexed(const QuickListMutexed &rhs)
struct libusb_iso_packet_descriptor * iso_packet_desc
Definition: libusb.h:170
transfer_wrapper * next
libusb_device_handle * dev_handle
Definition: libusb.h:158
int libusbemu_setup_transfer(transfer_wrapper *wrapper)
int num_iso_packets
Definition: libusb.h:169
static freenect_context * ctx
static const bool Orphan(T *node)
int actual_length
Definition: libusb.h:165
const bool Empty() const
T MIN(const T &v1, const T &v2)
transfer_wrapper * libusbemu_get_transfer_wrapper(libusb_transfer *transfer)
const bool Member(T *node) const
EventList hWantToDeliverPool
QuickList< transfer_wrapper > * list
unsigned char endpoint
Definition: libusb.h:160
TMapIsocTransfers * isoTransfers
static T * Prev(T *node)
libusb_transfer libusb
std::map< int, isoc_handle > TMapIsocTransfers
libusb_context * ctx
static const bool Orphan(T *node)
unsigned char type
Definition: libusb.h:161
static void RemoveNode(T *node)


libfreenect
Author(s): Hector Martin, Josh Blake, Kyle Machulis, OpenKinect community
autogenerated on Thu Jun 6 2019 19:25:38