VirtualBox

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

Last change on this file since 94342 was 94342, checked in by vboxsync, 3 years ago

Main,VMM/PDMUsb,Devices/USB,VRDP: Drop passing pointers through CFGM in favor of using VMM2USERMETHODS::pfnQueryGenericObject, bugref:10053

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 27.7 KB
Line 
1/* $Id: USBProxyDevice-os2.cpp 94342 2022-03-23 19:53:21Z vboxsync $ */
2/** @file
3 * USB device proxy - the Linux backend.
4 */
5
6/*
7 * Copyright (C) 2006-2022 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 */
431static int usbProxyOs2Open(PUSBPROXYDEV pProxyDev, const char *pszAddress)
432{
433 LogFlow(("usbProxyOs2Open: pProxyDev=%p pszAddress=%s\n", pProxyDev, pszAddress));
434 int rc;
435
436 /*
437 * Lazy init.
438 */
439#ifdef DYNAMIC_USBCALLS
440 if (!g_pfnUsbOpen)
441 {
442 rc = usbProxyOs2GlobalInit();
443 if (RT_FAILURE(rc))
444 return rc;
445 }
446#else
447static bool g_fInitialized = false;
448 if (!g_fInitialized)
449 {
450 rc = InitUsbCalls();
451 if (rc != NO_ERROR)
452 return RTErrConvertFromOS2(rc);
453 g_fInitialized = true;
454 }
455#endif
456
457 /*
458 * Parse out the open parameters from the address string.
459 */
460 uint16_t idProduct = 0;
461 uint16_t idVendor = 0;
462 uint16_t bcdDevice = 0;
463 uint32_t iEnum = 0;
464 const char *psz = pszAddress;
465 do
466 {
467 const char chValue = *psz;
468 AssertReleaseReturn(psz[1] == '=', VERR_INTERNAL_ERROR);
469 uint64_t u64Value;
470 int rc = RTStrToUInt64Ex(psz + 2, (char **)&psz, 0, &u64Value);
471 AssertReleaseRCReturn(rc, rc);
472 AssertReleaseReturn(!*psz || *psz == ';', rc);
473 switch (chValue)
474 {
475 case 'p': idProduct = (uint16_t)u64Value; break;
476 case 'v': idVendor = (uint16_t)u64Value; break;
477 case 'r': bcdDevice = (uint16_t)u64Value; break;
478 case 'e': iEnum = (uint16_t)u64Value; break;
479 default:
480 AssertReleaseMsgFailedReturn(("chValue=%#x\n", chValue), VERR_INTERNAL_ERROR);
481 }
482 if (*psz == ';')
483 psz++;
484 } while (*psz);
485
486
487 /*
488 * Try open (acquire) it.
489 */
490 USBHANDLE hDevice = 0;
491 int urc = rc = g_pfnUsbOpen(&hDevice, idVendor, idProduct, bcdDevice, iEnum);
492 if (!rc)
493 {
494 /*
495 * Allocate and initialize the OS/2 backend data.
496 */
497 PUSBPROXYDEVOS2 pDevOs2 = (PUSBPROXYDEVOS2)RTMemAllocZ(sizeof(*pDevOs2));
498 if (pDevOs2)
499 {
500 pDevOs2->hDevice = hDevice;
501 pDevOs2->fTerminate = false;
502 rc = RTCritSectInit(&pDevOs2->CritSect);
503 if (RT_SUCCESS(rc))
504 {
505 rc = RTSemEventCreate(&pDevOs2->EventSyncWait);
506 if (RT_SUCCESS(rc))
507 {
508 pProxyDev->Backend.pv = pDevOs2;
509
510 /** @todo
511 * Determine the active configuration.
512 */
513 //pProxyDev->cIgnoreSetConfigs = 1;
514 //pProxyDev->iActiveCfg = 1;
515 pProxyDev->cIgnoreSetConfigs = 0;
516 pProxyDev->iActiveCfg = -1;
517
518 /*
519 * Create the async worker thread and we're done.
520 */
521 rc = RTThreadCreate(&pDevOs2->Thread, usbProxyOs2AsyncThread, pProxyDev, 0, RTTHREADTYPE_IO, RTTHREADFLAGS_WAITABLE, "usbproxy");
522 if (RT_SUCCESS(rc))
523 {
524 LogFlow(("usbProxyOs2Open(%p, %s): returns successfully - iActiveCfg=%d\n",
525 pProxyDev, pszAddress, pProxyDev->iActiveCfg));
526 return VINF_SUCCESS;
527 }
528
529 /* failure */
530 RTSemEventDestroy(pDevOs2->EventSyncWait);
531 }
532 RTCritSectDelete(&pDevOs2->CritSect);
533 }
534 RTMemFree(pDevOs2);
535 }
536 else
537 rc = VERR_NO_MEMORY;
538 g_pfnUsbClose(hDevice);
539 }
540 else
541 rc = VERR_VUSB_USBFS_PERMISSION; /** @todo fix me */
542
543 Log(("usbProxyOs2Open(%p, %s) failed, rc=%Rrc! urc=%d\n", pProxyDev, pszAddress, rc, urc)); NOREF(urc);
544 pProxyDev->Backend.pv = NULL;
545
546 NOREF(pvBackend);
547 return rc;
548}
549
550
551/**
552 * Closes the proxy device.
553 */
554static void usbProxyOs2Close(PUSBPROXYDEV pProxyDev)
555{
556 LogFlow(("usbProxyOs2Close: pProxyDev=%s\n", pProxyDev->pUsbIns->pszName));
557 PUSBPROXYDEVOS2 pDevOs2 = (PUSBPROXYDEVOS2)pProxyDev->Backend.pv;
558 Assert(pDevOs2);
559 if (!pDevOs2)
560 return;
561
562 /*
563 * Tell the thread to terminate.
564 */
565 ASMAtomicXchgBool(&pDevOs2->fTerminate, true);
566 int rc = RTThreadUserSignal(pDevOs2->Thread); AssertRC(rc);
567 rc = RTThreadWait(pDevOs2->Thread, 60*1000 /* 1 min */, NULL); AssertRC(rc);
568
569 /*
570 * Now we can free all the resources and close the device.
571 */
572 RTCritSectDelete(&pDevOs2->CritSect);
573 RTSemEventDestroy(pDevOs2->EventSyncWait);
574
575 Assert(!pDevOs2->pInFlightHead);
576 Assert(!pDevOs2->pTodoHead);
577 Assert(!pDevOs2->pTodoTail);
578 Assert(!pDevOs2->pTaxingHead);
579 Assert(!pDevOs2->pTaxingTail);
580
581 PUSBPROXYURBOS2 pUrbOs2;
582 while ((pUrbOs2 = pDevOs2->pFreeHead) != NULL)
583 {
584 pDevOs2->pFreeHead = pUrbOs2->pNext;
585 RTMemFree(pUrbOs2);
586 }
587
588 g_pfnUsbClose(pDevOs2->hDevice);
589 pDevOs2->hDevice = 0;
590
591 RTMemFree(pDevOs2);
592 pProxyDev->Backend.pv = NULL;
593 LogFlow(("usbProxyOs2Close: returns\n"));
594}
595
596
597/** @interface_method_impl{USBPROXYBACK,pfnReset} */
598static int usbProxyOs2Reset(PUSBPROXYDEV pProxyDev, bool fResetOnLinux)
599{
600 return VINF_SUCCESS;
601}
602
603
604/**
605 * SET_CONFIGURATION.
606 *
607 * The caller makes sure that it's not called first time after open or reset
608 * with the active interface.
609 *
610 * @returns success indicator.
611 * @param pProxyDev The device instance data.
612 * @param iCfg The configuration to set.
613 */
614static int usbProxyOs2SetConfig(PUSBPROXYDEV pProxyDev, int iCfg)
615{
616 PUSBPROXYDEVOS2 pDevOs2 = (PUSBPROXYDEVOS2)pProxyDev->Backend.pv;
617 LogFlow(("usbProxyOs2SetConfig: pProxyDev=%s cfg=%#x\n",
618 pProxyDev->pUsbIns->pszName, iCfg));
619
620 /*
621 * This is sync - bad.
622 */
623 int rc = g_pfnUsbCtrlMessage(pDevOs2->hDevice,
624 0x00, /* bmRequestType - ?? */
625 0x09, /* bRequest - ?? */
626 iCfg, /* wValue - configuration */
627 0, /* wIndex*/
628 0, /* wLength */
629 NULL, /* pvData */
630 50 /* Timeout (ms) */);
631 if (rc)
632 LogFlow(("usbProxyOs2SetConfig: pProxyDev=%s cfg=%#X -> rc=%d\n", pProxyDev->pUsbIns->pszName, iCfg, rc));
633 return rc == 0;
634}
635
636
637/**
638 * Claims an interface.
639 * @returns success indicator.
640 */
641static int usbProxyOs2ClaimInterface(PUSBPROXYDEV pProxyDev, int iIf)
642{
643 LogFlow(("usbProxyOs2ClaimInterface: pProxyDev=%s ifnum=%#x\n", pProxyDev->pUsbIns->pszName, iIf));
644 return true;
645}
646
647
648/**
649 * Releases an interface.
650 * @returns success indicator.
651 */
652static int usbProxyOs2ReleaseInterface(PUSBPROXYDEV pProxyDev, int iIf)
653{
654 LogFlow(("usbProxyOs2ReleaseInterface: pProxyDev=%s ifnum=%#x\n", pProxyDev->pUsbIns->pszName, iIf));
655 return true;
656}
657
658
659/**
660 * SET_INTERFACE.
661 *
662 * @returns success indicator.
663 */
664static int usbProxyOs2SetInterface(PUSBPROXYDEV pProxyDev, int iIf, int iAlt)
665{
666 LogFlow(("usbProxyOs2SetInterface: pProxyDev=%p iIf=%#x iAlt=%#x\n", pProxyDev, iIf, iAlt));
667 return true;
668}
669
670
671/**
672 * Clears the halted endpoint 'EndPt'.
673 */
674static bool usbProxyOs2ClearHaltedEp(PUSBPROXYDEV pProxyDev, unsigned int EndPt)
675{
676 PUSBPROXYDEVOS2 pDevOs2 = (PUSBPROXYDEVOS2)pProxyDev->Backend.pv;
677 LogFlow(("usbProxyOs2ClearHaltedEp: pProxyDev=%s EndPt=%x\n", pProxyDev->pUsbIns->pszName, EndPt));
678
679 /*
680 * This is sync - bad.
681 */
682 int rc = g_pfnUsbCtrlMessage(pDevOs2->hDevice,
683 0x02, /* bmRequestType - ?? */
684 0x01, /* bRequest - ?? */
685 0, /* wValue - endpoint halt */
686 EndPt, /* wIndex - endpoint # */
687 0, /* wLength */
688 NULL, /* pvData */
689 50 /* Timeout (ms) */);
690 if (rc)
691 LogFlow(("usbProxyOs2ClearHaltedEp: pProxyDev=%s EndPt=%u -> rc=%d\n", pProxyDev->pUsbIns->pszName, EndPt, rc));
692 return rc == 0;
693}
694
695
696/**
697 * @interface_method_impl{USBPROXYBACK,pfnUrbQueue}
698 */
699static int usbProxyOs2UrbQueue(PUSBPROXYDEV pProxyDev, PVUSBURB pUrb)
700{
701 PUSBPROXYDEVOS2 pDevOs2 = (PUSBPROXYDEVOS2)pProxyDev->Backend.pv;
702 LogFlow(("usbProxyOs2UrbQueue: pProxyDev=%s pUrb=%p EndPt=%d cbData=%d\n",
703 pProxyDev->pUsbIns->pszName, pUrb, pUrb->EndPt, pUrb->cbData));
704
705 /*
706 * Quickly validate the input.
707 */
708 switch (pUrb->enmDir)
709 {
710 case VUSBDIRECTION_IN:
711 case VUSBDIRECTION_OUT:
712 break;
713 default:
714 AssertMsgFailed(("usbProxyOs2UrbQueue: Invalid direction %d\n", pUrb->enmDir));
715 return false;
716 }
717
718 switch (pUrb->enmType)
719 {
720 case VUSBXFERTYPE_MSG:
721 break;
722 case VUSBXFERTYPE_BULK:
723 break;
724/// @todo case VUSBXFERTYPE_INTR:
725// break;
726// case VUSBXFERTYPE_ISOC:
727// break;
728 default:
729 return false;
730 }
731
732 /*
733 * Allocate an OS/2 urb tracking structure, initialize it,
734 * add it to the todo list, and wake up the async thread.
735 */
736 PUSBPROXYURBOS2 pUrbOs2 = usbProxyOs2UrbAlloc(pProxyDev);
737 if (!pUrbOs2)
738 return false;
739
740 pUrbOs2->pUrb = pUrb;
741
742 RTCritSectEnter(&pDevOs2->CritSect);
743
744 pUrbOs2->pNext = NULL;
745 pUrbOs2->pPrev = pDevOs2->pTodoTail;
746 if (pDevOs2->pTodoTail)
747 pDevOs2->pTodoTail->pNext = pUrbOs2;
748 else
749 pDevOs2->pTodoHead = pUrbOs2;
750 pDevOs2->pTodoTail = pUrbOs2;
751
752 RTCritSectLeave(&pDevOs2->CritSect);
753
754 RTThreadUserSignal(pDevOs2->Thread);
755 return true;
756}
757
758
759/**
760 * Reap URBs in-flight on a device.
761 *
762 * @returns Pointer to a completed URB.
763 * @returns NULL if no URB was completed.
764 * @param pProxyDev The device.
765 * @param cMillies Number of milliseconds to wait. Use 0 to not wait at all.
766 */
767static PVUSBURB usbProxyOs2UrbReap(PUSBPROXYDEV pProxyDev, RTMSINTERVAL cMillies)
768{
769 PVUSBURB pUrb = NULL;
770 PUSBPROXYDEVOS2 pDevOs2 = (PUSBPROXYDEVOS2)pProxyDev->Backend.pv;
771
772 RTCritSectEnter(&pDevOs2->CritSect);
773 for (;;)
774 {
775 /*
776 * Any URBs pending delivery?
777 */
778 PUSBPROXYURBOS2 pUrbOs2 = pDevOs2->pTaxingHead;
779 if (pUrbOs2)
780 {
781 pUrb = pUrbOs2->pUrb;
782 usbProxyOs2UrbFree(pProxyDev, pUrbOs2);
783 break;
784 }
785
786 /*
787 * Block for something to completed, if requested and sensible.
788 */
789 if (!cMillies)
790 break;
791 if ( !pDevOs2->pInFlightHead
792 && !pDevOs2->pTodoHead)
793 break;
794
795 RTCritSectLeave(&pDevOs2->CritSect);
796
797 int rc = RTSemEventWait(pDevOs2->EventSyncWait, cMillies);
798 Assert(RT_SUCCESS(rc) || rc == VERR_TIMEOUT); NOREF(rc);
799 cMillies = 0;
800
801 RTCritSectEnter(&pDevOs2->CritSect);
802 }
803 RTCritSectLeave(&pDevOs2->CritSect);
804
805 LogFlow(("usbProxyOs2UrbReap: dev=%s returns %p\n", pProxyDev->pUsbIns->pszName, pUrb));
806 return pUrb;
807}
808
809
810/**
811 * Cancels the URB.
812 * The URB requires reaping, so we don't change its state.
813 */
814static void usbProxyOs2UrbCancel(PVUSBURB pUrb)
815{
816#if 0
817 PUSBPROXYDEV pProxyDev = (PUSBPROXYDEV)pUrb->pDev;
818 PUSBPROXYURBOS2 pUrbOs2 = (PUSBPROXYURBOS2)pUrb->Dev.pvProxyUrb;
819 if (pUrbOs2->pSplitHead)
820 {
821 /* split */
822 Assert(pUrbOs2 == pUrbOs2->pSplitHead);
823 for (PUSBPROXYURBOS2 pCur = pUrbOs2; pCur; pCur = pCur->pSplitNext)
824 {
825 if (pCur->fSplitElementReaped)
826 continue;
827 if ( !usbProxyOs2DoIoCtl(pProxyDev, USBDEVFS_DISCARDURB, &pCur->KUrb, true, UINT32_MAX)
828 || errno == ENOENT)
829 continue;
830 if (errno == ENODEV)
831 break;
832 Log(("usb-linux: Discard URB %p failed, errno=%d. pProxyDev=%s!!! (split)\n",
833 pUrb, errno, pProxyDev->pUsbIns->pszName));
834 }
835 }
836 else
837 {
838 /* unsplit */
839 if ( usbProxyOs2DoIoCtl(pProxyDev, USBDEVFS_DISCARDURB, &pUrbOs2->KUrb, true, UINT32_MAX)
840 && errno != ENODEV /* deal with elsewhere. */
841 && errno != ENOENT)
842 Log(("usb-linux: Discard URB %p failed, errno=%d. pProxyDev=%s!!!\n",
843 pUrb, errno, pProxyDev->pUsbIns->pszName));
844 }
845#endif
846}
847
848
849/**
850 * The Linux USB Proxy Backend.
851 */
852extern const USBPROXYBACK g_USBProxyDeviceHost =
853{
854 "host",
855 usbProxyOs2Open,
856 NULL,
857 usbProxyOs2Close,
858 usbProxyOs2Reset,
859 usbProxyOs2SetConfig,
860 usbProxyOs2ClaimInterface,
861 usbProxyOs2ReleaseInterface,
862 usbProxyOs2SetInterface,
863 usbProxyOs2ClearHaltedEp,
864 usbProxyOs2UrbQueue,
865 usbProxyOs2UrbCancel,
866 usbProxyOs2UrbReap,
867 0
868};
869
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