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

Subversion Repositories w11

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

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

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

powered by: WebSVN 2.1.0

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