OpenCores
URL https://opencores.org/ocsvn/w11/w11/trunk

Subversion Repositories w11

[/] [w11/] [tags/] [w11a_V0.7/] [tools/] [src/] [librlink/] [RlinkPortCuff.cpp] - Blame information for rev 27

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 27 wfjm
// $Id: RlinkPortCuff.cpp 584 2014-08-22 19:38:12Z mueller $
2 17 wfjm
//
3 27 wfjm
// Copyright 2012-2014 by Walter F.J. Mueller <W.F.J.Mueller@gsi.de>
4 17 wfjm
//
5
// This program is free software; you may redistribute and/or modify it under
6
// the terms of the GNU General Public License as published by the Free
7
// Software Foundation, either version 2, or at your option any later version.
8
//
9
// This program is distributed in the hope that it will be useful, but
10
// WITHOUT ANY WARRANTY, without even the implied warranty of MERCHANTABILITY
11
// or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
12
// for complete details.
13
// 
14
// Revision History: 
15
// Date         Rev Version  Comment
16 27 wfjm
// 2014-08-22   584   1.1.2  use nullptr
17 22 wfjm
// 2013-05-17   521   1.1.1  use Rtools::String2Long
18 19 wfjm
// 2013-02-23   492   1.1    use RparseUrl
19
// 2013-02-10   485   1.0.3  add static const defs
20
// 2013-02-03   481   1.0.2  use Rexception
21 17 wfjm
// 2013-01-02   467   1.0.1  get cleanup code right; add USBErrorName()
22
// 2012-12-26   465   1.0    Initial version
23
// ---------------------------------------------------------------------------
24
 
25
/*!
26
  \file
27 27 wfjm
  \version $Id: RlinkPortCuff.cpp 584 2014-08-22 19:38:12Z mueller $
28 17 wfjm
  \brief   Implemenation of RlinkPortCuff.
29
*/
30
 
31
#include <errno.h>
32
#include <unistd.h>
33
#include <sys/time.h>
34
#include <time.h>
35
#include <stdio.h>
36 19 wfjm
#include <string.h>
37 17 wfjm
 
38 19 wfjm
#include <iostream>
39
#include <sstream>
40 17 wfjm
 
41
#include "RlinkPortCuff.hpp"
42
 
43 19 wfjm
#include "librtools/Rexception.hpp"
44 22 wfjm
#include "librtools/Rtools.hpp"
45 19 wfjm
 
46 17 wfjm
using namespace std;
47
 
48
/*!
49
  \class Retro::RlinkPortCuff
50 19 wfjm
  \brief FIXME_docs
51 17 wfjm
*/
52
 
53 19 wfjm
// all method definitions in namespace Retro
54
namespace Retro {
55
 
56 17 wfjm
//------------------------------------------+-----------------------------------
57 19 wfjm
// constants definitions
58
 
59
const size_t RlinkPortCuff::kUSBBufferSize;
60
const int    RlinkPortCuff::kUSBWriteEP;
61
const int    RlinkPortCuff::kUSBReadEP;
62
const size_t RlinkPortCuff::kUSBReadQueue;
63
 
64
//------------------------------------------+-----------------------------------
65 17 wfjm
//! Default constructor
66
 
67
RlinkPortCuff::RlinkPortCuff()
68
  : RlinkPort(),
69
    fFdReadDriver(-1),
70
    fFdWriteDriver(-1),
71
    fpUsbContext(0),
72
    fpUsbDevList(0),
73
    fUsbDevCount(0),
74
    fpUsbDevHdl(0),
75
    fLoopState(kLoopStateStopped)
76
{
77
  fStats.Define(kStatNPollAddCB,    "kStatNPollAddCB",    "USB poll add cb");
78
  fStats.Define(kStatNPollRemoveCB, "kStatNPollRemoveCB", "USB poll remove cb");
79
  fStats.Define(kStatNUSBWrite,     "kStatNUSBWrite",     "USB write done");
80
  fStats.Define(kStatNUSBRead,      "kStatNUSBRead",      "USB read done");
81
}
82
 
83
//------------------------------------------+-----------------------------------
84
//! Destructor
85
 
86
RlinkPortCuff::~RlinkPortCuff()
87
{
88
  if (IsOpen()) RlinkPortCuff::Close();
89
}
90
 
91
//------------------------------------------+-----------------------------------
92 19 wfjm
//! FIXME_docs
93 17 wfjm
 
94
bool RlinkPortCuff::Open(const std::string& url, RerrMsg& emsg)
95
{
96
  int irc;
97
 
98
  if (IsOpen()) Close();
99
 
100 19 wfjm
  if (!fUrl.Set(url, "|trace|", emsg)) return false;
101 17 wfjm
 
102
  // initialize USB context
103
  irc = libusb_init(&fpUsbContext);
104
  if (irc != 0) {
105
    emsg.Init("RlinkPortCuff::Open()",
106
              string("libusb_init() failed: ") +
107
              string(USBErrorName(irc)));
108
    Cleanup();
109
    return false;
110
  }
111
  // setup libusb level debug
112
  libusb_set_debug(fpUsbContext, 3);        // info->stdout, warn+err->stderr
113
 
114
  // check for internal timeout handling support
115
  if (libusb_pollfds_handle_timeouts(fpUsbContext) == 0) {
116
    emsg.Init("RlinkPortCuff::Open()",
117
              string("libusb_pollfds_handle_timeouts == 0 : "
118
                     "this program will not run on this legacy system"));
119
    Cleanup();
120
    return false;
121
  }
122
 
123
  // get USB device list
124
  fUsbDevCount = libusb_get_device_list(fpUsbContext, &fpUsbDevList);
125
 
126
  // determine USB path name
127 19 wfjm
  if (fUrl.Path().length() == 0) {
128
    char* env_vid = ::getenv("RETRO_FX2_VID");
129
    char* env_pid = ::getenv("RETRO_FX2_PID");
130
    if (env_vid && ::strlen(env_vid) == 4 &&
131
        env_pid && ::strlen(env_pid) == 4) {
132 21 wfjm
      fUrl.SetPath(string(env_vid) + ":" + string(env_pid));
133 17 wfjm
    } else {
134
      emsg.Init("RlinkPortCuff::Open()",
135 21 wfjm
                "RETRO_FX2_VID/PID not or ill defined");
136 17 wfjm
      Cleanup();
137
      return false;
138
    }
139
  }
140
 
141
  // connect to USB device
142
  libusb_device* mydev = 0;
143
  // path syntax: /bus/dev
144 19 wfjm
  if (fUrl.Path().length()==8 && fUrl.Path()[0]=='/' && fUrl.Path()[4]=='/') {
145
    string busnam = fUrl.Path().substr(1,3);
146
    string devnam = fUrl.Path().substr(5,3);
147 22 wfjm
    unsigned long busnum;
148
    unsigned long devnum;
149
    if (!Rtools::String2Long(busnam, busnum, emsg) ||
150
        !Rtools::String2Long(devnam, devnum, emsg)) {
151
      Cleanup();
152
      return false;
153
    }
154 17 wfjm
    for (ssize_t idev=0; idev<fUsbDevCount; idev++) {
155
      libusb_device* udev = fpUsbDevList[idev];
156
      if (libusb_get_bus_number(udev) == busnum &&
157
          libusb_get_device_address(udev) == devnum) {
158
        mydev = udev;
159
      }
160
    }
161
  // path syntax: vend:prod
162 19 wfjm
  } else if (fUrl.Path().length()==9 && fUrl.Path()[4]==':') {
163
    string vennam = fUrl.Path().substr(0,4);
164
    string pronam = fUrl.Path().substr(5,4);
165 22 wfjm
    unsigned long vennum;
166
    unsigned long pronum;
167
    if (!Rtools::String2Long(vennam, vennum, emsg, 16) ||
168
        !Rtools::String2Long(pronam, pronum, emsg, 16)) {
169
      Cleanup();
170
      return false;
171
    }
172 17 wfjm
    for (ssize_t idev=0; idev<fUsbDevCount; idev++) {
173
      libusb_device* udev = fpUsbDevList[idev];
174
      libusb_device_descriptor devdsc;
175
      libusb_get_device_descriptor(udev, &devdsc);
176
      if (devdsc.idVendor==vennum && devdsc.idProduct==pronum) {
177
        mydev = udev;
178
      }
179
    }
180
  } else {
181
    emsg.Init("RlinkPortCuff::Open()",
182 19 wfjm
              string("invalid usb path '") + fUrl.Path() +
183 17 wfjm
              "', not '/bus/dev' or 'vend:prod'");
184
    Cleanup();
185
    return false;
186
  }
187 22 wfjm
 
188 17 wfjm
  if (mydev == 0) {
189
    emsg.Init("RlinkPortCuff::Open()",
190 19 wfjm
              string("no usb device '") + fUrl.Path() + "', found'");
191 17 wfjm
    Cleanup();
192
    return false;
193
  }
194
 
195
  irc = libusb_open(mydev, &fpUsbDevHdl);
196
  if (irc) {
197
    fpUsbDevHdl = 0;
198
    emsg.Init("RlinkPortCuff::Open()",
199 19 wfjm
              string("opening usb device '") + fUrl.Path() + "', failed: " +
200 17 wfjm
              string(USBErrorName(irc)));
201
    Cleanup();
202
    return false;
203
  }
204 19 wfjm
  if (TraceOn()) cout << "libusb_open ok for '" << fUrl.Path() << "'" << endl;
205 17 wfjm
 
206
  // claim USB device
207
  irc = libusb_claim_interface(fpUsbDevHdl, 0);
208
  if (irc) {
209
    emsg.Init("RlinkPortCuff::Open()",
210 19 wfjm
              string("failed to claim '") + fUrl.Path() + "': " +
211 17 wfjm
              string(USBErrorName(irc)));
212
    Cleanup();
213
    return false;
214
  }
215
 
216
  // setup write pipe
217
  if (!OpenPipe(fFdWriteDriver, fFdWrite, emsg)) {
218
    Cleanup();
219
    return false;
220
  }
221
  // setup read pipe
222
  if (!OpenPipe(fFdRead, fFdReadDriver, emsg)) {
223
    Cleanup();
224
    return false;
225
  }
226
 
227
  // setup pollfd list
228
  fPollFds.clear();
229
 
230
  // 1. write pipe allert (is always 1st in list)
231
  PollfdAdd(fFdWriteDriver, POLLIN);
232
 
233
  // 2. libusb callbacks
234
  const libusb_pollfd** plist = libusb_get_pollfds(fpUsbContext);
235
  for (const libusb_pollfd** p = plist; *p !=0; p++) {
236
    PollfdAdd((*p)->fd, (*p)->events);
237
  }
238 19 wfjm
  ::free(plist);
239 17 wfjm
  libusb_set_pollfd_notifiers(fpUsbContext, ThunkPollfdAdd,
240
                              ThunkPollfdRemove, this);
241
 
242
  fDriverThread =  boost::thread(boost::bind(&RlinkPortCuff::Driver, this));
243
 
244
  fIsOpen  = true;
245
 
246
  return true;
247
}
248
 
249
//------------------------------------------+-----------------------------------
250 19 wfjm
//! FIXME_docs
251 17 wfjm
 
252
void RlinkPortCuff::Close()
253
{
254
  if (!IsOpen()) return;
255
 
256
  if (TraceOn()) cout << "Close() started" << endl;
257
  Cleanup();
258
  RlinkPort::Close();
259
 
260
  if (TraceOn()) cout << "Close() ended" << endl;
261
  return;
262
}
263
 
264
//------------------------------------------+-----------------------------------
265 19 wfjm
//! FIXME_docs
266 17 wfjm
 
267
void RlinkPortCuff::Cleanup()
268
{
269
  // close write pipe from user side -> causes event in driver and driver stop
270
  CloseFd(fFdWrite);
271
 
272
  // wait till driver thread terminates
273
  // use timed join, throw in case driver doesn't stop
274
  if (fDriverThread.get_id() != boost::thread::id()) {
275
    if (!fDriverThread.timed_join(boost::posix_time::milliseconds(500))) {
276 19 wfjm
      throw Rexception("RlinkPortCuff::Cleanup()",
277
                       "driver thread failed to stop");
278 17 wfjm
    }
279
  }
280
 
281
  // cleanup pipes
282
  CloseFd(fFdRead);
283
  CloseFd(fFdReadDriver);
284
  CloseFd(fFdWriteDriver);
285
 
286
  // cleanup USB context
287
  if (fpUsbContext) {
288
    if (fpUsbDevHdl) {
289
      libusb_release_interface(fpUsbDevHdl, 0);
290
      libusb_close(fpUsbDevHdl);
291
      fpUsbDevHdl = 0;
292
    }
293
    if (fpUsbDevList) {
294
      libusb_free_device_list(fpUsbDevList, 1);
295
      fpUsbDevList = 0;
296
    }
297 27 wfjm
    libusb_set_pollfd_notifiers(fpUsbContext, nullptr, nullptr, nullptr);
298 17 wfjm
    libusb_exit(fpUsbContext);
299
    fpUsbContext = 0;
300
  }
301
 
302
  fPollFds.clear();
303
 
304
  return;
305
}
306
 
307
//------------------------------------------+-----------------------------------
308 19 wfjm
//! FIXME_docs
309 17 wfjm
 
310
bool RlinkPortCuff::OpenPipe(int& fdread, int& fdwrite, RerrMsg& emsg)
311
{
312
  int irc;
313
  int pipefd[2];
314
 
315 19 wfjm
  irc = ::pipe(pipefd);
316 17 wfjm
  if (irc < 0) {
317 21 wfjm
    emsg.InitErrno("RlinkPortCuff::OpenPipe()", "pipe() failed: ", errno);
318 17 wfjm
    return false;
319
  }
320
 
321
  fdread  = pipefd[0];
322
  fdwrite = pipefd[1];
323
 
324
  return true;
325
}
326
 
327
//------------------------------------------+-----------------------------------
328 19 wfjm
//! FIXME_docs
329 17 wfjm
 
330
// executed in separate boost thread !!
331
void RlinkPortCuff::Driver()
332
{
333
  try {
334
 
335
    // setup USB read-ahead queue
336
    for (size_t nr=0; nr<kUSBReadQueue; nr++) {
337
      libusb_transfer* t = libusb_alloc_transfer(0);
338
 
339
      t->dev_handle = fpUsbDevHdl;
340
      t->flags      = LIBUSB_TRANSFER_FREE_BUFFER;
341
      t->endpoint   = (unsigned char) (kUSBReadEP|0x80);
342
      t->type       = LIBUSB_TRANSFER_TYPE_BULK;
343
      t->timeout    = 0;
344
      t->status     = LIBUSB_TRANSFER_COMPLETED;
345 22 wfjm
      t->buffer     = (unsigned char*) ::malloc(kUSBBufferSize);
346 17 wfjm
      t->length     = kUSBBufferSize;
347
      t->actual_length = 0;
348
      t->callback   = ThunkUSBReadDone;
349
      t->user_data  = this;
350
 
351
      int irc = libusb_submit_transfer(t);
352
      if (irc) BadUSBCall("RlinkPortCuff::Driver()",
353
                        "libusb_submit_transfer()", irc);
354
      fReadQueuePending.push_back(t);
355
    }
356
 
357
    // event loop
358
    if (TraceOn()) cout << "event loop started" << endl;
359
    fLoopState = kLoopStateRunning;
360
    while(fLoopState == kLoopStateRunning) {
361 22 wfjm
      int irc = ::poll(fPollFds.data(), fPollFds.size(), 1000);
362 17 wfjm
      if (irc==-1 && errno==EINTR) continue;
363
      if (irc!=0 && TraceOn()) {
364
        cout << "poll() -> " << irc << " :";
365
        for (size_t i=0; i<fPollFds.size(); i++)
366
          if (fPollFds[i].revents) cout << " (" << fPollFds[i].fd << ","
367
                                        << fPollFds[i].events << ","
368
                                        << fPollFds[i].revents << ")";
369
        cout << endl;
370
      }
371
 
372
      if (irc < 0) BadSysCall("RlinkPortCuff::Driver()", "poll()", irc);
373
 
374
      if (fPollFds[0].revents & POLLHUP) {        // write pipe close event
375
        fLoopState = kLoopStateStopping;
376
      } else if (fPollFds[0].revents & POLLIN) {  // write pipe data event
377
        DriverEventWritePipe();
378
      } else {                              // assume USB timeout events
379
        DriverEventUSB();
380
      }
381
    }
382
 
383
    if (TraceOn()) cout << "event loop ended, cleanup started" << endl;
384
 
385
    for (size_t i=0; i<fWriteQueuePending.size(); i++) {
386
      libusb_cancel_transfer(fWriteQueuePending[i]);
387
    }
388
    for (size_t i=0; i<fReadQueuePending.size(); i++) {
389
      libusb_cancel_transfer(fReadQueuePending[i]);
390
    }
391
 
392
    while(fLoopState == kLoopStateStopping &&
393
          fWriteQueuePending.size() + fReadQueuePending.size() > 0) {
394 22 wfjm
      int irc = ::poll(fPollFds.data()+1, fPollFds.size()-1, 1000);
395 17 wfjm
      if (irc==-1 && errno==EINTR) continue;
396
      if (irc==0) break;
397
      if (irc < 0) BadSysCall("RlinkPortCuff::Driver()", "poll()", irc);
398
      DriverEventUSB();
399
    }
400
    if (fWriteQueuePending.size() + fReadQueuePending.size())
401 19 wfjm
      throw Rexception("RlinkPortCuff::Driver()", "cleanup timeout");
402 17 wfjm
 
403
    fLoopState = kLoopStateStopped;
404
    if (TraceOn()) cout << "cleanup ended" << endl;
405
 
406
  } catch (exception& e) {
407
    cout << "exception caught in RlinkPortCuff::Driver(): '" << e.what()
408
         << "'" << endl;
409
    // close read pipe at driver end -> that causes main thread to respond
410 22 wfjm
    ::close(fFdReadDriver);
411 17 wfjm
    fFdReadDriver = -1;
412
  }
413
 
414
  return;
415
}
416
 
417
//------------------------------------------+-----------------------------------
418 19 wfjm
//! FIXME_docs
419 17 wfjm
 
420
void RlinkPortCuff::DriverEventWritePipe()
421
{
422
  libusb_transfer* t = NewWriteTransfer();
423
 
424 22 wfjm
  ssize_t ircs = ::read(fFdWriteDriver, t->buffer, kUSBBufferSize);
425 17 wfjm
  if (TraceOn()) cout << "write pipe read() -> " << ircs << endl;
426
  if (ircs < 0) BadSysCall("RlinkPortCuff::DriverEventWritePipe()",
427
                           "read()", ircs);
428
 
429
  // pipe closed... end driver event loop
430
  if (ircs == 0) {
431
    fLoopState = kLoopStateStopping;
432
    return;
433
  }
434
 
435
  t->length = (int) ircs;
436
  int irc = libusb_submit_transfer(t);
437
  if (irc) BadUSBCall("RlinkPortCuff::DriverEventWritePipe()",
438
                      "libusb_submit_transfer()", irc);
439
  fWriteQueuePending.push_back(t);
440
 
441
  return;
442
}
443
 
444
//------------------------------------------+-----------------------------------
445 19 wfjm
//! FIXME_docs
446 17 wfjm
 
447
void RlinkPortCuff::DriverEventUSB()
448
{
449
  struct timeval tv;
450
  tv.tv_sec  = 0;
451
  tv.tv_usec = 0;
452
  int irc = libusb_handle_events_timeout(fpUsbContext, &tv);
453 27 wfjm
  //setting the timeval pointer to nullptr should work, but doesn't (in 1.0.6)
454 17 wfjm
  //rc = libusb_handle_events_timeout(pUsbContext, 0);
455
  if (irc) BadUSBCall("RlinkPortCuff::DriverEventUSB()",
456
                      "libusb_handle_events_timeout()", irc);
457
  return;
458
}
459
 
460
//------------------------------------------+-----------------------------------
461 19 wfjm
//! FIXME_docs
462 17 wfjm
 
463
libusb_transfer* RlinkPortCuff::NewWriteTransfer()
464
{
465
  libusb_transfer* t = 0;
466
  if (!fWriteQueueFree.empty()) {
467
    t = fWriteQueueFree.front();
468
    fWriteQueueFree.pop_front();
469
  } else {
470
    t = libusb_alloc_transfer(0);
471
    t->dev_handle = fpUsbDevHdl;
472
    t->flags      = LIBUSB_TRANSFER_FREE_BUFFER;
473
    t->endpoint   = (unsigned char) (kUSBWriteEP);
474
    t->type       = LIBUSB_TRANSFER_TYPE_BULK;
475
    t->timeout    = 1000;
476 22 wfjm
    t->buffer     = (unsigned char*) ::malloc(kUSBBufferSize);
477 17 wfjm
    t->callback   = ThunkUSBWriteDone;
478
    t->user_data  = this;
479
  }
480
 
481
  t->status        = LIBUSB_TRANSFER_COMPLETED;
482
  t->length        = 0;
483
  t->actual_length = 0;
484
 
485
  return t;
486
}
487
 
488
//------------------------------------------+-----------------------------------
489 19 wfjm
//! FIXME_docs
490 17 wfjm
 
491
bool RlinkPortCuff::TraceOn()
492
{
493 19 wfjm
  if (!fUrl.FindOpt("trace")) return false;
494 17 wfjm
  struct timeval tv;
495
  struct timezone tz;
496
  struct tm tmval;
497
 
498 19 wfjm
  ::gettimeofday(&tv, &tz);
499
  ::localtime_r(&tv.tv_sec, &tmval);
500 17 wfjm
  char buf[20];
501 19 wfjm
  ::snprintf(buf, 20, "%02d:%02d:%02d.%06d: ",
502
             tmval.tm_hour, tmval.tm_min, tmval.tm_sec, (int) tv.tv_usec);
503 17 wfjm
  cout << buf;
504
  return true;
505
}
506
 
507
//------------------------------------------+-----------------------------------
508 19 wfjm
//! FIXME_docs
509 17 wfjm
 
510
void RlinkPortCuff::BadSysCall(const char* meth, const char* text, int rc)
511
{
512 19 wfjm
  stringstream ss;
513
  ss << rc;
514 21 wfjm
  throw Rexception(meth, string(text) + " failed with rc=" + ss.str(),
515 19 wfjm
                   errno);
516 17 wfjm
}
517
 
518
//------------------------------------------+-----------------------------------
519 19 wfjm
//! FIXME_docs
520 17 wfjm
 
521
void RlinkPortCuff::BadUSBCall(const char* meth, const char* text, int rc)
522
{
523 19 wfjm
  stringstream ss;
524
  ss << rc;
525 21 wfjm
  throw Rexception(meth, string(text) + " failed with rc=" + ss.str() +
526
                   " : " + string(USBErrorName(rc)));
527 17 wfjm
}
528
 
529
//------------------------------------------+-----------------------------------
530 19 wfjm
//! FIXME_docs
531 17 wfjm
 
532
void RlinkPortCuff::CheckUSBTransfer(const char* meth, libusb_transfer *t)
533
{
534
  const char* etext = 0;
535
 
536
  if (t->status == LIBUSB_TRANSFER_ERROR)     etext = "ERROR";
537
  if (t->status == LIBUSB_TRANSFER_STALL)     etext = "STALL";
538
  if (t->status == LIBUSB_TRANSFER_NO_DEVICE) etext = "NO_DEVICE";
539
  if (t->status == LIBUSB_TRANSFER_OVERFLOW)  etext = "OVERFLOW";
540
 
541
  if (etext == 0) return;
542
 
543
  char buf[1024];
544 19 wfjm
  ::snprintf(buf, 1024, "%s : transfer failure on ep=%d: %s",
545
             meth, (int)(t->endpoint&(~0x80)), etext);
546
  throw Rexception(meth, buf);
547 17 wfjm
}
548
 
549
//------------------------------------------+-----------------------------------
550 19 wfjm
//! FIXME_docs
551 17 wfjm
 
552
const char* RlinkPortCuff::USBErrorName(int rc)
553
{
554
  // Code taken verbatim from libusb-1.0.9.tar.bz2 function libusb_error_name
555
  // The libusb_error_name() function was added rather late in V1.0.9.
556
  // To allow usage with V1.0.8 and earlier this function is include here
557
 
558
  switch (rc) {
559
  case LIBUSB_SUCCESS:
560
    return "LIBUSB_SUCCESS";
561
  case LIBUSB_ERROR_IO:
562
    return "LIBUSB_ERROR_IO";
563
  case LIBUSB_ERROR_INVALID_PARAM:
564
    return "LIBUSB_ERROR_INVALID_PARAM";
565
  case LIBUSB_ERROR_ACCESS:
566
    return "LIBUSB_ERROR_ACCESS";
567
  case LIBUSB_ERROR_NO_DEVICE:
568
    return "LIBUSB_ERROR_NO_DEVICE";
569
  case LIBUSB_ERROR_NOT_FOUND:
570
    return "LIBUSB_ERROR_NOT_FOUND";
571
  case LIBUSB_ERROR_BUSY:
572
    return "LIBUSB_ERROR_BUSY";
573
  case LIBUSB_ERROR_TIMEOUT:
574
    return "LIBUSB_ERROR_TIMEOUT";
575
  case LIBUSB_ERROR_OVERFLOW:
576
    return "LIBUSB_ERROR_OVERFLOW";
577
  case LIBUSB_ERROR_PIPE:
578
    return "LIBUSB_ERROR_PIPE";
579
  case LIBUSB_ERROR_INTERRUPTED:
580
    return "LIBUSB_ERROR_INTERRUPTED";
581
  case LIBUSB_ERROR_NO_MEM:
582
    return "LIBUSB_ERROR_NO_MEM";
583
  case LIBUSB_ERROR_NOT_SUPPORTED:
584
    return "LIBUSB_ERROR_NOT_SUPPORTED";
585
  case LIBUSB_ERROR_OTHER:
586
    return "LIBUSB_ERROR_OTHER";
587
  }
588
  return "**UNKNOWN**";
589
}
590
 
591
//------------------------------------------+-----------------------------------
592 19 wfjm
//! FIXME_docs
593 17 wfjm
 
594
void RlinkPortCuff::PollfdAdd(int fd, short events)
595
{
596
  fStats.Inc(kStatNPollAddCB);
597
  pollfd pfd;
598
  pfd.fd      = fd;
599
  pfd.events  = events;
600
  pfd.revents = 0;
601
  fPollFds.push_back(pfd);
602
  return;
603
}
604
 
605
//------------------------------------------+-----------------------------------
606 19 wfjm
//! FIXME_docs
607 17 wfjm
 
608
void RlinkPortCuff::PollfdRemove(int fd)
609
{
610
  fStats.Inc(kStatNPollRemoveCB);
611
  for (size_t i=0; i<fPollFds.size(); ) {
612
    if (fPollFds[i].fd == fd) {
613
      fPollFds.erase(fPollFds.begin()+i);
614
    } else {
615
      i++;
616
    }
617
  }
618
  return;
619
}
620
 
621
//------------------------------------------+-----------------------------------
622 19 wfjm
//! FIXME_docs
623 17 wfjm
 
624
void RlinkPortCuff::USBWriteDone(libusb_transfer* t)
625
{
626
  if (TraceOn()) cout << "USB write done -> " << t->actual_length << endl;
627
 
628
  if (fWriteQueuePending.size() && t == fWriteQueuePending.front())
629
    fWriteQueuePending.pop_front();
630
  else
631 19 wfjm
    throw Rexception("RlinkPortCuff::USBWriteDone()",
632
                     "BugCheck: fWriteQueuePending disordered");
633 17 wfjm
 
634
  if (fLoopState == kLoopStateRunning) {
635
    CheckUSBTransfer("RlinkPortCuff::USBWriteDone()", t);
636
    fStats.Inc(kStatNUSBWrite);
637
    fWriteQueueFree.push_back(t);
638
 
639
  } else {
640
    libusb_free_transfer(t);
641
  }
642
  return;
643
}
644
 
645
//------------------------------------------+-----------------------------------
646 19 wfjm
//! FIXME_docs
647 17 wfjm
 
648
void RlinkPortCuff::USBReadDone(libusb_transfer* t)
649
{
650
  if (TraceOn()) cout << "USB read done -> " << t->actual_length << endl;
651
 
652
  if (fReadQueuePending.size() && t == fReadQueuePending.front())
653
    fReadQueuePending.pop_front();
654
  else
655 19 wfjm
    throw Rexception("RlinkPortCuff::USBReadDone()",
656
                     "BugCheck: fReadQueuePending disordered");
657 17 wfjm
 
658
  if (fLoopState == kLoopStateRunning) {
659
    CheckUSBTransfer("RlinkPortCuff::USBReadDone()", t);
660
    fStats.Inc(kStatNUSBRead);
661
    if (t->actual_length>0) {
662 22 wfjm
      ssize_t ircs = ::write(fFdReadDriver, t->buffer,
663
                             (size_t) t->actual_length);
664 17 wfjm
      if (ircs < 0) BadSysCall("RlinkPortCuff::USBReadDone()",
665
                               "write()", ircs);
666
    }
667
 
668
    t->status        = LIBUSB_TRANSFER_COMPLETED;
669
    t->actual_length = 0;
670
    int irc = libusb_submit_transfer(t);
671
    if (irc) BadUSBCall("RlinkPortCuff::USBReadDone()",
672
                        "libusb_submit_transfer()", irc);
673
    fReadQueuePending.push_back(t);
674
 
675
  } else {
676
    libusb_free_transfer(t);
677
  }
678
 
679
  return;
680
}
681
 
682
//------------------------------------------+-----------------------------------
683 19 wfjm
//! FIXME_docs
684 17 wfjm
 
685
void RlinkPortCuff::ThunkPollfdAdd(int fd, short events, void* udata)
686
{
687
  RlinkPortCuff* pcntx = (RlinkPortCuff*) udata;
688
  pcntx->PollfdAdd(fd, events);
689
  return;
690
}
691
 
692
//------------------------------------------+-----------------------------------
693 19 wfjm
//! FIXME_docs
694 17 wfjm
 
695
void RlinkPortCuff::ThunkPollfdRemove(int fd, void* udata)
696
{
697
  RlinkPortCuff* pcntx = (RlinkPortCuff*) udata;
698
  pcntx->PollfdRemove(fd);
699
  return;
700
}
701
 
702
//------------------------------------------+-----------------------------------
703 19 wfjm
//! FIXME_docs
704 17 wfjm
 
705
void RlinkPortCuff::ThunkUSBWriteDone(libusb_transfer* t)
706
{
707
  RlinkPortCuff* pcntx = (RlinkPortCuff*) t->user_data;
708
  pcntx->USBWriteDone(t);
709
  return;
710
}
711
 
712
//------------------------------------------+-----------------------------------
713 19 wfjm
//! FIXME_docs
714 17 wfjm
 
715
void RlinkPortCuff::ThunkUSBReadDone(libusb_transfer* t)
716
{
717
  RlinkPortCuff* pcntx = (RlinkPortCuff*) t->user_data;
718
  pcntx->USBReadDone(t);
719
  return;
720
}
721
 
722 19 wfjm
} // end namespace Retro

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.