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 30

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

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