VirtualBox

source: vbox/trunk/src/VBox/Devices/USB/os2/USBProxyDevice-os2.cpp@ 76553

Last change on this file since 76553 was 76553, checked in by vboxsync, 6 years ago

scm --update-copyright-year

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 27.8 KB
Line 
1/* $Id: USBProxyDevice-os2.cpp 76553 2019-01-01 01:45:53Z vboxsync $ */
2/** @file
3 * USB device proxy - the Linux backend.
4 */
5
6/*
7 * Copyright (C) 2006-2019 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17
18
19/*********************************************************************************************************************************
20* Defined Constants And Macros *
21*********************************************************************************************************************************/
22
23
24/*********************************************************************************************************************************
25* Header Files *
26*********************************************************************************************************************************/
27#define LOG_GROUP LOG_GROUP_DRV_USBPROXY
28#include <VBox/vmm/pdm.h>
29#include <VBox/err.h>
30#include <VBox/log.h>
31#include <iprt/assert.h>
32#include <iprt/stream.h>
33#include <iprt/alloc.h>
34#include <iprt/thread.h>
35#include <iprt/time.h>
36#include <iprt/asm.h>
37#include <iprt/string.h>
38#include <iprt/semaphore.h>
39#include <iprt/file.h>
40#include "../USBProxyDevice.h"
41
42#define INCL_BASE
43#define INCL_ERRORS
44#include <os2.h>
45#include <usbcalls.h>
46
47
48/*********************************************************************************************************************************
49* Structures and Typedefs *
50*********************************************************************************************************************************/
51/**
52 * Structure for keeping track of the URBs for a device.
53 */
54typedef struct USBPROXYURBOS2
55{
56 /** Pointer to the virtual URB. */
57 PVUSBURB pUrb;
58 /** Pointer to the next OS/2 URB. */
59 struct USBPROXYURBOS2 *pNext;
60 /** Pointer to the previous OS/2 URB. */
61 struct USBPROXYURBOS2 *pPrev;
62} USBPROXYURBOS2, *PUSBPROXYURBOS2;
63
64/**
65 * Data for the OS/2 usb proxy backend.
66 */
67typedef struct USBPROXYDEVOS2
68{
69 /** The async thread for this device.
70 * Currently only one thread is used, but this might have to change... */
71 RTTHREAD Thread;
72 /** Thread termination indicator. */
73 bool volatile fTerminate;
74 /** The USB handle. */
75 USBHANDLE hDevice;
76 /** Critical section protecting the lists. */
77 RTCRITSECT CritSect;
78 /** For blocking reap calls. */
79 RTSEMEVENT EventSyncWait;
80 /** List of URBs to process. Doubly linked. */
81 PUSBPROXYURBOS2 pTodoHead;
82 /** The tail pointer. */
83 PUSBPROXYURBOS2 pTodoTail;
84 /** The list of free linux URBs. Singly linked. */
85 PUSBPROXYURBOS2 pFreeHead;
86 /** The list of active linux URBs. Doubly linked.
87 * We must maintain this so we can properly reap URBs of a detached device.
88 * Only the split head will appear in this list. */
89 PUSBPROXYURBOS2 pInFlightHead;
90 /** The list of landed linux URBs. Doubly linked.
91 * Only the split head will appear in this list. */
92 PUSBPROXYURBOS2 pTaxingHead;
93 /** The tail of the landed linux URBs. */
94 PUSBPROXYURBOS2 pTaxingTail;
95} USBPROXYDEVOS2, *PUSBPROXYDEVOS2;
96
97
98/*********************************************************************************************************************************
99* Internal Functions *
100*********************************************************************************************************************************/
101#ifdef DYNAMIC_USBCALLS
102static int usbProxyOs2GlobalInit(void);
103#endif
104static PUSBPROXYURBOS2 usbProxyOs2UrbAlloc(PUSBPROXYDEV pProxyDev);
105static void usbProxyOs2UrbFree(PUSBPROXYDEV pProxyDev, PUSBPROXYURBOS2 pUrbOs2);
106static DECLCALLBACK(int) usbProxyOs2AsyncThread(RTTHREAD Thread, void *pvProxyDev);
107
108
109/*********************************************************************************************************************************
110* Global Variables *
111*********************************************************************************************************************************/
112#ifdef DYNAMIC_USBCALLS
113static HMODULE g_hmod;
114static APIRET (APIENTRY *g_pfnUsbOpen)(PUSBHANDLE, USHORT, USHORT, USHORT, USHORT);
115static APIRET (APIENTRY *g_pfnUsbClose)(USBHANDLE);
116static APIRET (APIENTRY *g_pfnUsbCtrlMessage)(USBHANDLE, UCHAR, UCHAR, USHORT, USHORT, USHORT, void *, ULONG);
117static APIRET (APIENTRY *g_pfnUsbBulkRead2)(USBHANDLE, UCHAR, UCHAR, BOOL, PULONG, void *, ULONG);
118static APIRET (APIENTRY *g_pfnUsbBulkWrite2)(USBHANDLE, UCHAR, UCHAR, BOOL, ULONG, void *, ULONG);
119#else
120# define g_pfnUsbOpen UsbOpen
121# define g_pfnUsbClose UsbClose
122# define g_pfnUsbCtrlMessage UsbCtrlMessage
123# define g_pfnUsbBulkRead2 UsbBulkRead2
124# define g_pfnUsbBulkWrite2 UsbBulkWrite2
125#endif
126
127
128
129#ifdef DYNAMIC_USBCALLS
130/**
131 * Loads usbcalls.dll and resolves the symbols we need.
132 *
133 * The usbcalls.dll will not be unloaded.
134 *
135 * @returns VBox status code.
136 */
137static int usbProxyOs2GlobalInit(void)
138{
139 int rc = DosLoadModule(NULL, 0, (PCSZ)"usbcalls", &g_hmod);
140 rc = RTErrConvertFromOS2(rc);
141 if (RT_SUCCESS(rc))
142 {
143 if ( (rc = DosQueryProcAddr(g_hmod, 0, (PCSZ)"UsbOpen", (PPFN)&g_pfnUsbOpen)) == NO_ERROR
144 && (rc = DosQueryProcAddr(g_hmod, 0, (PCSZ)"UsbClose", (PPFN)&g_pfnUsbClose)) == NO_ERROR
145 && (rc = DosQueryProcAddr(g_hmod, 0, (PCSZ)"UsbCtrlMessage", (PPFN)&g_pfnUsbCtrlMessage)) == NO_ERROR
146 && (rc = DosQueryProcAddr(g_hmod, 0, (PCSZ)"UsbBulkRead", (PPFN)&g_pfnUsbBulkRead)) == NO_ERROR
147 && (rc = DosQueryProcAddr(g_hmod, 0, (PCSZ)"UsbBulkWrite", (PPFN)&g_pfnUsbBulkWrite)) == NO_ERROR
148 )
149 {
150
151 return VINF_SUCCESS;
152 }
153
154 g_pfnUsbOpen = NULL;
155 g_pfnUsbClose = NULL;
156 g_pfnUsbCtrlMessage = NULL;
157 g_pfnUsbBulkRead = NULL;
158 g_pfnUsbBulkWrite = NULL;
159 DosFreeModule(g_hmod);
160 }
161
162 g_hmod = NULLHANDLE;
163 return rc;
164}
165#endif
166
167
168
169/**
170 * Allocates a OS/2 URB request structure.
171 * @returns Pointer to an active URB request.
172 * @returns NULL on failure.
173 * @param pProxyDev The proxy device instance.
174 */
175static PUSBPROXYURBOS2 usbProxyOs2UrbAlloc(PUSBPROXYDEV pProxyDev)
176{
177 PUSBPROXYDEVOS2 pDevOs2 = (PUSBPROXYDEVOS2)pProxyDev->Backend.pv;
178 PUSBPROXYURBOS2 pUrbOs2;
179
180 RTCritSectEnter(&pDevOs2->CritSect);
181
182 /*
183 * Try remove a linux URB from the free list, if none there allocate a new one.
184 */
185 pUrbOs2 = pDevOs2->pFreeHead;
186 if (pUrbOs2)
187 pDevOs2->pFreeHead = pUrbOs2->pNext;
188 else
189 {
190 RTCritSectLeave(&pDevOs2->CritSect);
191 pUrbOs2 = (PUSBPROXYURBOS2)RTMemAlloc(sizeof(*pUrbOs2));
192 if (!pUrbOs2)
193 return NULL;
194 RTCritSectEnter(&pDevOs2->CritSect);
195 }
196
197 /*
198 * Link it into the active list
199 */
200 pUrbOs2->pPrev = NULL;
201 pUrbOs2->pNext = pDevOs2->pInFlightHead;
202 if (pUrbOs2->pNext)
203 pUrbOs2->pNext->pPrev = pUrbOs2;
204 pDevOs2->pInFlightHead = pUrbOs2;
205
206 RTCritSectLeave(&pDevOs2->CritSect);
207 return pUrbOs2;
208}
209
210
211/**
212 * Frees a linux URB request structure.
213 *
214 * @param pProxyDev The proxy device instance.
215 * @param pUrbOs2 The linux URB to free.
216 */
217static void usbProxyOs2UrbFree(PUSBPROXYDEV pProxyDev, PUSBPROXYURBOS2 pUrbOs2)
218{
219 PUSBPROXYDEVOS2 pDevOs2 = (PUSBPROXYDEVOS2)pProxyDev->Backend.pv;
220
221 RTCritSectEnter(&pDevOs2->CritSect);
222
223 /*
224 * Remove from the active list.
225 */
226 if (pUrbOs2->pNext)
227 pUrbOs2->pNext->pPrev = pUrbOs2->pPrev;
228 else if (pDevOs2->pTaxingTail == pUrbOs2)
229 pDevOs2->pTaxingTail = pUrbOs2->pPrev;
230 else if (pDevOs2->pTodoTail == pUrbOs2)
231 pDevOs2->pTodoTail = pUrbOs2->pPrev;
232
233 if (pUrbOs2->pPrev)
234 pUrbOs2->pPrev->pNext = pUrbOs2->pNext;
235 else if (pDevOs2->pTaxingHead == pUrbOs2)
236 pDevOs2->pTaxingHead = pUrbOs2->pNext;
237 else if (pDevOs2->pInFlightHead == pUrbOs2)
238 pDevOs2->pInFlightHead = pUrbOs2->pNext;
239 else if (pDevOs2->pTodoHead == pUrbOs2)
240 pDevOs2->pTodoHead = pUrbOs2->pNext;
241
242 /*
243 * Link it into the free list.
244 */
245 pUrbOs2->pPrev = NULL;
246 pUrbOs2->pNext = pDevOs2->pFreeHead;
247 pDevOs2->pFreeHead = pUrbOs2;
248
249 RTCritSectLeave(&pDevOs2->CritSect);
250}
251
252
253/**
254 * Thread for executing the URBs asynchronously.
255 *
256 * @returns VINF_SUCCESS.
257 * @param Thread Thread handle (IPRT).
258 * @param pvProxyDev Pointer to the proxy device we're servicing.
259 */
260static DECLCALLBACK(int) usbProxyOs2AsyncThread(RTTHREAD Thread, void *pvProxyDev)
261{
262 PUSBPROXYDEV pProxyDev = (PUSBPROXYDEV)pvProxyDev;
263 PUSBPROXYDEVOS2 pDevOs2 = (PUSBPROXYDEVOS2)pProxyDev->Backend.pv;
264 size_t cbLow = 0;
265 void *pvLow = NULL;
266
267
268 /*
269 * The main loop.
270 *
271 * We're always in the critsect, except when waiting or submitting a URB.
272 */
273 int rc = RTCritSectEnter(&pDevOs2->CritSect); AssertRC(rc);
274
275 while (!pDevOs2->fTerminate)
276 {
277 /*
278 * Anything to do?
279 */
280 PUSBPROXYURBOS2 pUrbOs2 = pDevOs2->pTodoHead;
281 if (pUrbOs2)
282 {
283 pDevOs2->pTodoHead = pUrbOs2->pNext;
284 if (pUrbOs2->pNext)
285 pUrbOs2->pNext->pPrev = NULL;
286 else
287 pDevOs2->pTodoTail = NULL;
288
289 /*
290 * Move it to the in-flight list and submit it.
291 */
292 pUrbOs2->pPrev = NULL;
293 pUrbOs2->pNext = pDevOs2->pInFlightHead;
294 if (pDevOs2->pInFlightHead)
295 pDevOs2->pInFlightHead->pPrev = pUrbOs2;
296 //else
297 // pDevOs2->pInFlightTail = pUrbOs2;
298 Log3(("%s: usbProxyOs2AsyncThread: pPickup\n", pUrbOs2->pUrb->pszDesc));
299
300 RTCritSectLeave(&pDevOs2->CritSect);
301
302 /*
303 * Process the URB.
304 */
305 PVUSBURB pUrb = pUrbOs2->pUrb;
306 uint8_t *pbData = &pUrb->abData[0];
307 ULONG cbData = pUrb->cbData;
308 if ( (uintptr_t)pbData >= 0x20000000
309 || ((uintptr_t)pbData & 0xfff))
310 {
311 if (cbData > cbLow)
312 {
313 if (pvLow)
314 DosFreeMem(pvLow);
315 cbLow = (cbData + 0xffff) & ~0xffff;
316 rc = DosAllocMem(&pvLow, cbLow, PAG_WRITE | PAG_READ | OBJ_TILE | PAG_COMMIT);
317 if (rc)
318 {
319 cbLow = 0;
320 pvLow = NULL;
321 }
322 }
323 if (pvLow)
324 pbData = (uint8_t *)memcpy(pvLow, pbData, cbData);
325 }
326
327 switch (pUrb->enmType)
328 {
329 case VUSBXFERTYPE_MSG:
330 {
331 PVUSBSETUP pSetup = (PVUSBSETUP)&pbData[0];
332 Log2(("%s: usbProxyOs2AsyncThread: CtlrMsg\n", pUrb->pszDesc));
333 rc = g_pfnUsbCtrlMessage(pDevOs2->hDevice, /** @todo this API must take a endpoint number! */
334 pSetup->bmRequestType,
335 pSetup->bRequest,
336 pSetup->wValue,
337 pSetup->wIndex,
338 pSetup->wLength,
339 pSetup + 1,
340 5*60000 /* min */);
341 break;
342 }
343
344 case VUSBXFERTYPE_BULK:
345 {
346 /* there is a thing with altnative interface thing here... */
347
348 if (pUrb->enmDir == VUSBDIRECTION_IN)
349 {
350 Log2(("%s: usbProxyOs2AsyncThread: BulkRead %d\n", pUrb->pszDesc, cbData));
351 rc = g_pfnUsbBulkRead2(pDevOs2->hDevice, pUrb->EndPt | 0x80, 0, !pUrb->fShortNotOk, &cbData, pbData, 500);//5*6000);
352 }
353 else
354 {
355 Log2(("%s: usbProxyOs2AsyncThread: BulkWrite %d\n", pUrb->pszDesc, cbData));
356 rc = g_pfnUsbBulkWrite2(pDevOs2->hDevice, pUrb->EndPt, 0, !pUrb->fShortNotOk, cbData, pbData, 500);//5*6000);
357 }
358 break;
359 }
360
361 case VUSBXFERTYPE_INTR:
362 case VUSBXFERTYPE_ISOC:
363 default:
364 Log2(("%s: usbProxyOs2AsyncThread: Unsupported\n", pUrb->pszDesc));
365 rc = USB_IORB_FAILED;
366 break;
367 }
368
369 /* unbuffer */
370 if (pbData == pvLow)
371 memcpy(pUrb->abData, pbData, pUrb->cbData);
372
373 /* Convert rc to USB status code. */
374 int orc = rc;
375 if (!rc)
376 pUrb->enmStatus = VUSBSTATUS_OK;
377 else if (rc == USB_ERROR_LESSTRANSFERED && !pUrb->fShortNotOk)
378 {
379 Assert(pUrb->cbData >= cbData);
380 pUrb->cbData = cbData;
381 pUrb->enmStatus = VUSBSTATUS_DATA_UNDERRUN;
382 }
383 else
384 pUrb->enmStatus = VUSBSTATUS_STALL;
385 Log2(("%s: usbProxyOs2AsyncThread: orc=%d enmStatus=%d cbData=%d \n", pUrb->pszDesc, orc, pUrb->enmStatus, pUrb->cbData)); NOREF(orc);
386
387 /*
388 * Retire it to the completed list
389 */
390 RTCritSectEnter(&pDevOs2->CritSect);
391
392 pUrbOs2->pNext = NULL;
393 pUrbOs2->pPrev = pDevOs2->pTaxingTail;
394 if (pDevOs2->pTaxingTail)
395 pDevOs2->pTaxingTail->pNext = pUrbOs2;
396 else
397 pDevOs2->pTaxingHead = pUrbOs2;
398 pDevOs2->pTaxingTail = pUrbOs2;
399
400 RTSemEventSignal(pDevOs2->EventSyncWait);
401 Log2(("%s: usbProxyOs2AsyncThread: orc=%d enmStatus=%d cbData=%d!\n", pUrb->pszDesc, orc, pUrb->enmStatus, pUrb->cbData)); NOREF(orc);
402 }
403 else
404 {
405 RTThreadUserReset(Thread);
406 RTCritSectLeave(&pDevOs2->CritSect);
407
408 /*
409 * Wait for something to do.
410 */
411 RTThreadUserWait(Thread, 30*1000 /* 30 sec */);
412
413 RTCritSectEnter(&pDevOs2->CritSect);
414 }
415 }
416
417 RTCritSectLeave(&pDevOs2->CritSect);
418 if (pvLow)
419 DosFreeMem(pvLow);
420 return VINF_SUCCESS;
421}
422
423
424/**
425 * Opens the /proc/bus/usb/bus/addr file.
426 *
427 * @returns VBox status code.
428 * @param pProxyDev The device instance.
429 * @param pszAddress The path to the device.
430 * @param pvBackend Backend specific pointer, unused for the linux backend.
431 */
432static int usbProxyOs2Open(PUSBPROXYDEV pProxyDev, const char *pszAddress, void *pvBackend)
433{
434 LogFlow(("usbProxyOs2Open: pProxyDev=%p pszAddress=%s\n", pProxyDev, pszAddress));
435 int rc;
436
437 /*
438 * Lazy init.
439 */
440#ifdef DYNAMIC_USBCALLS
441 if (!g_pfnUsbOpen)
442 {
443 rc = usbProxyOs2GlobalInit();
444 if (RT_FAILURE(rc))
445 return rc;
446 }
447#else
448static bool g_fInitialized = false;
449 if (!g_fInitialized)
450 {
451 rc = InitUsbCalls();
452 if (rc != NO_ERROR)
453 return RTErrConvertFromOS2(rc);
454 g_fInitialized = true;
455 }
456#endif
457
458 /*
459 * Parse out the open parameters from the address string.
460 */
461 uint16_t idProduct = 0;
462 uint16_t idVendor = 0;
463 uint16_t bcdDevice = 0;
464 uint32_t iEnum = 0;
465 const char *psz = pszAddress;
466 do
467 {
468 const char chValue = *psz;
469 AssertReleaseReturn(psz[1] == '=', VERR_INTERNAL_ERROR);
470 uint64_t u64Value;
471 int rc = RTStrToUInt64Ex(psz + 2, (char **)&psz, 0, &u64Value);
472 AssertReleaseRCReturn(rc, rc);
473 AssertReleaseReturn(!*psz || *psz == ';', rc);
474 switch (chValue)
475 {
476 case 'p': idProduct = (uint16_t)u64Value; break;
477 case 'v': idVendor = (uint16_t)u64Value; break;
478 case 'r': bcdDevice = (uint16_t)u64Value; break;
479 case 'e': iEnum = (uint16_t)u64Value; break;
480 default:
481 AssertReleaseMsgFailedReturn(("chValue=%#x\n", chValue), VERR_INTERNAL_ERROR);
482 }
483 if (*psz == ';')
484 psz++;
485 } while (*psz);
486
487
488 /*
489 * Try open (acquire) it.
490 */
491 USBHANDLE hDevice = 0;
492 int urc = rc = g_pfnUsbOpen(&hDevice, idVendor, idProduct, bcdDevice, iEnum);
493 if (!rc)
494 {
495 /*
496 * Allocate and initialize the OS/2 backend data.
497 */
498 PUSBPROXYDEVOS2 pDevOs2 = (PUSBPROXYDEVOS2)RTMemAllocZ(sizeof(*pDevOs2));
499 if (pDevOs2)
500 {
501 pDevOs2->hDevice = hDevice;
502 pDevOs2->fTerminate = false;
503 rc = RTCritSectInit(&pDevOs2->CritSect);
504 if (RT_SUCCESS(rc))
505 {
506 rc = RTSemEventCreate(&pDevOs2->EventSyncWait);
507 if (RT_SUCCESS(rc))
508 {
509 pProxyDev->Backend.pv = pDevOs2;
510
511 /** @todo
512 * Determine the active configuration.
513 */
514 //pProxyDev->cIgnoreSetConfigs = 1;
515 //pProxyDev->iActiveCfg = 1;
516 pProxyDev->cIgnoreSetConfigs = 0;
517 pProxyDev->iActiveCfg = -1;
518
519 /*
520 * Create the async worker thread and we're done.
521 */
522 rc = RTThreadCreate(&pDevOs2->Thread, usbProxyOs2AsyncThread, pProxyDev, 0, RTTHREADTYPE_IO, RTTHREADFLAGS_WAITABLE, "usbproxy");
523 if (RT_SUCCESS(rc))
524 {
525 LogFlow(("usbProxyOs2Open(%p, %s): returns successfully - iActiveCfg=%d\n",
526 pProxyDev, pszAddress, pProxyDev->iActiveCfg));
527 return VINF_SUCCESS;
528 }
529
530 /* failure */
531 RTSemEventDestroy(pDevOs2->EventSyncWait);
532 }
533 RTCritSectDelete(&pDevOs2->CritSect);
534 }
535 RTMemFree(pDevOs2);
536 }
537 else
538 rc = VERR_NO_MEMORY;
539 g_pfnUsbClose(hDevice);
540 }
541 else
542 rc = VERR_VUSB_USBFS_PERMISSION; /** @todo fix me */
543
544 Log(("usbProxyOs2Open(%p, %s) failed, rc=%Rrc! urc=%d\n", pProxyDev, pszAddress, rc, urc)); NOREF(urc);
545 pProxyDev->Backend.pv = NULL;
546
547 NOREF(pvBackend);
548 return rc;
549}
550
551
552/**
553 * Closes the proxy device.
554 */
555static void usbProxyOs2Close(PUSBPROXYDEV pProxyDev)
556{
557 LogFlow(("usbProxyOs2Close: pProxyDev=%s\n", pProxyDev->pUsbIns->pszName));
558 PUSBPROXYDEVOS2 pDevOs2 = (PUSBPROXYDEVOS2)pProxyDev->Backend.pv;
559 Assert(pDevOs2);
560 if (!pDevOs2)
561 return;
562
563 /*
564 * Tell the thread to terminate.
565 */
566 ASMAtomicXchgBool(&pDevOs2->fTerminate, true);
567 int rc = RTThreadUserSignal(pDevOs2->Thread); AssertRC(rc);
568 rc = RTThreadWait(pDevOs2->Thread, 60*1000 /* 1 min */, NULL); AssertRC(rc);
569
570 /*
571 * Now we can free all the resources and close the device.
572 */
573 RTCritSectDelete(&pDevOs2->CritSect);
574 RTSemEventDestroy(pDevOs2->EventSyncWait);
575
576 Assert(!pDevOs2->pInFlightHead);
577 Assert(!pDevOs2->pTodoHead);
578 Assert(!pDevOs2->pTodoTail);
579 Assert(!pDevOs2->pTaxingHead);
580 Assert(!pDevOs2->pTaxingTail);
581
582 PUSBPROXYURBOS2 pUrbOs2;
583 while ((pUrbOs2 = pDevOs2->pFreeHead) != NULL)
584 {
585 pDevOs2->pFreeHead = pUrbOs2->pNext;
586 RTMemFree(pUrbOs2);
587 }
588
589 g_pfnUsbClose(pDevOs2->hDevice);
590 pDevOs2->hDevice = 0;
591
592 RTMemFree(pDevOs2);
593 pProxyDev->Backend.pv = NULL;
594 LogFlow(("usbProxyOs2Close: returns\n"));
595}
596
597
598/** @interface_method_impl{USBPROXYBACK,pfnReset} */
599static int usbProxyOs2Reset(PUSBPROXYDEV pProxyDev, bool fResetOnLinux)
600{
601 return VINF_SUCCESS;
602}
603
604
605/**
606 * SET_CONFIGURATION.
607 *
608 * The caller makes sure that it's not called first time after open or reset
609 * with the active interface.
610 *
611 * @returns success indicator.
612 * @param pProxyDev The device instance data.
613 * @param iCfg The configuration to set.
614 */
615static int usbProxyOs2SetConfig(PUSBPROXYDEV pProxyDev, int iCfg)
616{
617 PUSBPROXYDEVOS2 pDevOs2 = (PUSBPROXYDEVOS2)pProxyDev->Backend.pv;
618 LogFlow(("usbProxyOs2SetConfig: pProxyDev=%s cfg=%#x\n",
619 pProxyDev->pUsbIns->pszName, iCfg));
620
621 /*
622 * This is sync - bad.
623 */
624 int rc = g_pfnUsbCtrlMessage(pDevOs2->hDevice,
625 0x00, /* bmRequestType - ?? */
626 0x09, /* bRequest - ?? */
627 iCfg, /* wValue - configuration */
628 0, /* wIndex*/
629 0, /* wLength */
630 NULL, /* pvData */
631 50 /* Timeout (ms) */);
632 if (rc)
633 LogFlow(("usbProxyOs2SetConfig: pProxyDev=%s cfg=%#X -> rc=%d\n", pProxyDev->pUsbIns->pszName, iCfg, rc));
634 return rc == 0;
635}
636
637
638/**
639 * Claims an interface.
640 * @returns success indicator.
641 */
642static int usbProxyOs2ClaimInterface(PUSBPROXYDEV pProxyDev, int iIf)
643{
644 LogFlow(("usbProxyOs2ClaimInterface: pProxyDev=%s ifnum=%#x\n", pProxyDev->pUsbIns->pszName, iIf));
645 return true;
646}
647
648
649/**
650 * Releases an interface.
651 * @returns success indicator.
652 */
653static int usbProxyOs2ReleaseInterface(PUSBPROXYDEV pProxyDev, int iIf)
654{
655 LogFlow(("usbProxyOs2ReleaseInterface: pProxyDev=%s ifnum=%#x\n", pProxyDev->pUsbIns->pszName, iIf));
656 return true;
657}
658
659
660/**
661 * SET_INTERFACE.
662 *
663 * @returns success indicator.
664 */
665static int usbProxyOs2SetInterface(PUSBPROXYDEV pProxyDev, int iIf, int iAlt)
666{
667 LogFlow(("usbProxyOs2SetInterface: pProxyDev=%p iIf=%#x iAlt=%#x\n", pProxyDev, iIf, iAlt));
668 return true;
669}
670
671
672/**
673 * Clears the halted endpoint 'EndPt'.
674 */
675static bool usbProxyOs2ClearHaltedEp(PUSBPROXYDEV pProxyDev, unsigned int EndPt)
676{
677 PUSBPROXYDEVOS2 pDevOs2 = (PUSBPROXYDEVOS2)pProxyDev->Backend.pv;
678 LogFlow(("usbProxyOs2ClearHaltedEp: pProxyDev=%s EndPt=%x\n", pProxyDev->pUsbIns->pszName, EndPt));
679
680 /*
681 * This is sync - bad.
682 */
683 int rc = g_pfnUsbCtrlMessage(pDevOs2->hDevice,
684 0x02, /* bmRequestType - ?? */
685 0x01, /* bRequest - ?? */
686 0, /* wValue - endpoint halt */
687 EndPt, /* wIndex - endpoint # */
688 0, /* wLength */
689 NULL, /* pvData */
690 50 /* Timeout (ms) */);
691 if (rc)
692 LogFlow(("usbProxyOs2ClearHaltedEp: pProxyDev=%s EndPt=%u -> rc=%d\n", pProxyDev->pUsbIns->pszName, EndPt, rc));
693 return rc == 0;
694}
695
696
697/**
698 * @interface_method_impl{USBPROXYBACK,pfnUrbQueue}
699 */
700static int usbProxyOs2UrbQueue(PUSBPROXYDEV pProxyDev, PVUSBURB pUrb)
701{
702 PUSBPROXYDEVOS2 pDevOs2 = (PUSBPROXYDEVOS2)pProxyDev->Backend.pv;
703 LogFlow(("usbProxyOs2UrbQueue: pProxyDev=%s pUrb=%p EndPt=%d cbData=%d\n",
704 pProxyDev->pUsbIns->pszName, pUrb, pUrb->EndPt, pUrb->cbData));
705
706 /*
707 * Quickly validate the input.
708 */
709 switch (pUrb->enmDir)
710 {
711 case VUSBDIRECTION_IN:
712 case VUSBDIRECTION_OUT:
713 break;
714 default:
715 AssertMsgFailed(("usbProxyOs2UrbQueue: Invalid direction %d\n", pUrb->enmDir));
716 return false;
717 }
718
719 switch (pUrb->enmType)
720 {
721 case VUSBXFERTYPE_MSG:
722 break;
723 case VUSBXFERTYPE_BULK:
724 break;
725/// @todo case VUSBXFERTYPE_INTR:
726// break;
727// case VUSBXFERTYPE_ISOC:
728// break;
729 default:
730 return false;
731 }
732
733 /*
734 * Allocate an OS/2 urb tracking structure, initialize it,
735 * add it to the todo list, and wake up the async thread.
736 */
737 PUSBPROXYURBOS2 pUrbOs2 = usbProxyOs2UrbAlloc(pProxyDev);
738 if (!pUrbOs2)
739 return false;
740
741 pUrbOs2->pUrb = pUrb;
742
743 RTCritSectEnter(&pDevOs2->CritSect);
744
745 pUrbOs2->pNext = NULL;
746 pUrbOs2->pPrev = pDevOs2->pTodoTail;
747 if (pDevOs2->pTodoTail)
748 pDevOs2->pTodoTail->pNext = pUrbOs2;
749 else
750 pDevOs2->pTodoHead = pUrbOs2;
751 pDevOs2->pTodoTail = pUrbOs2;
752
753 RTCritSectLeave(&pDevOs2->CritSect);
754
755 RTThreadUserSignal(pDevOs2->Thread);
756 return true;
757}
758
759
760/**
761 * Reap URBs in-flight on a device.
762 *
763 * @returns Pointer to a completed URB.
764 * @returns NULL if no URB was completed.
765 * @param pProxyDev The device.
766 * @param cMillies Number of milliseconds to wait. Use 0 to not wait at all.
767 */
768static PVUSBURB usbProxyOs2UrbReap(PUSBPROXYDEV pProxyDev, RTMSINTERVAL cMillies)
769{
770 PVUSBURB pUrb = NULL;
771 PUSBPROXYDEVOS2 pDevOs2 = (PUSBPROXYDEVOS2)pProxyDev->Backend.pv;
772
773 RTCritSectEnter(&pDevOs2->CritSect);
774 for (;;)
775 {
776 /*
777 * Any URBs pending delivery?
778 */
779 PUSBPROXYURBOS2 pUrbOs2 = pDevOs2->pTaxingHead;
780 if (pUrbOs2)
781 {
782 pUrb = pUrbOs2->pUrb;
783 usbProxyOs2UrbFree(pProxyDev, pUrbOs2);
784 break;
785 }
786
787 /*
788 * Block for something to completed, if requested and sensible.
789 */
790 if (!cMillies)
791 break;
792 if ( !pDevOs2->pInFlightHead
793 && !pDevOs2->pTodoHead)
794 break;
795
796 RTCritSectLeave(&pDevOs2->CritSect);
797
798 int rc = RTSemEventWait(pDevOs2->EventSyncWait, cMillies);
799 Assert(RT_SUCCESS(rc) || rc == VERR_TIMEOUT); NOREF(rc);
800 cMillies = 0;
801
802 RTCritSectEnter(&pDevOs2->CritSect);
803 }
804 RTCritSectLeave(&pDevOs2->CritSect);
805
806 LogFlow(("usbProxyOs2UrbReap: dev=%s returns %p\n", pProxyDev->pUsbIns->pszName, pUrb));
807 return pUrb;
808}
809
810
811/**
812 * Cancels the URB.
813 * The URB requires reaping, so we don't change its state.
814 */
815static void usbProxyOs2UrbCancel(PVUSBURB pUrb)
816{
817#if 0
818 PUSBPROXYDEV pProxyDev = (PUSBPROXYDEV)pUrb->pDev;
819 PUSBPROXYURBOS2 pUrbOs2 = (PUSBPROXYURBOS2)pUrb->Dev.pvProxyUrb;
820 if (pUrbOs2->pSplitHead)
821 {
822 /* split */
823 Assert(pUrbOs2 == pUrbOs2->pSplitHead);
824 for (PUSBPROXYURBOS2 pCur = pUrbOs2; pCur; pCur = pCur->pSplitNext)
825 {
826 if (pCur->fSplitElementReaped)
827 continue;
828 if ( !usbProxyOs2DoIoCtl(pProxyDev, USBDEVFS_DISCARDURB, &pCur->KUrb, true, UINT32_MAX)
829 || errno == ENOENT)
830 continue;
831 if (errno == ENODEV)
832 break;
833 Log(("usb-linux: Discard URB %p failed, errno=%d. pProxyDev=%s!!! (split)\n",
834 pUrb, errno, pProxyDev->pUsbIns->pszName));
835 }
836 }
837 else
838 {
839 /* unsplit */
840 if ( usbProxyOs2DoIoCtl(pProxyDev, USBDEVFS_DISCARDURB, &pUrbOs2->KUrb, true, UINT32_MAX)
841 && errno != ENODEV /* deal with elsewhere. */
842 && errno != ENOENT)
843 Log(("usb-linux: Discard URB %p failed, errno=%d. pProxyDev=%s!!!\n",
844 pUrb, errno, pProxyDev->pUsbIns->pszName));
845 }
846#endif
847}
848
849
850/**
851 * The Linux USB Proxy Backend.
852 */
853extern const USBPROXYBACK g_USBProxyDeviceHost =
854{
855 "host",
856 usbProxyOs2Open,
857 NULL,
858 usbProxyOs2Close,
859 usbProxyOs2Reset,
860 usbProxyOs2SetConfig,
861 usbProxyOs2ClaimInterface,
862 usbProxyOs2ReleaseInterface,
863 usbProxyOs2SetInterface,
864 usbProxyOs2ClearHaltedEp,
865 usbProxyOs2UrbQueue,
866 usbProxyOs2UrbCancel,
867 usbProxyOs2UrbReap,
868 0
869};
870
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette