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 21

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

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