VirtualBox

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

Last change on this file since 102788 was 98103, checked in by vboxsync, 20 months ago

Copyright year updates by scm.

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