VirtualBox

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

Last change on this file since 35753 was 35346, checked in by vboxsync, 14 years ago

VMM reorg: Moving the public include files from include/VBox to include/VBox/vmm.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 27.1 KB
Line 
1/* $Id: USBProxyDevice-os2.cpp 35346 2010-12-27 16:13:13Z vboxsync $ */
2/** @file
3 * USB device proxy - the Linux backend.
4 */
5
6/*
7 * Copyright (C) 2006-2007 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/**
599 * Reset a device.
600 *
601 * @returns VBox status code.
602 * @param pDev The device to reset.
603 */
604static int usbProxyOs2Reset(PUSBPROXYDEV pProxyDev, bool fResetOnLinux)
605{
606 return VINF_SUCCESS;
607}
608
609
610/**
611 * SET_CONFIGURATION.
612 *
613 * The caller makes sure that it's not called first time after open or reset
614 * with the active interface.
615 *
616 * @returns success indicator.
617 * @param pProxyDev The device instance data.
618 * @param iCfg The configuration to set.
619 */
620static int usbProxyOs2SetConfig(PUSBPROXYDEV pProxyDev, int iCfg)
621{
622 PUSBPROXYDEVOS2 pDevOs2 = (PUSBPROXYDEVOS2)pProxyDev->Backend.pv;
623 LogFlow(("usbProxyOs2SetConfig: pProxyDev=%s cfg=%#x\n",
624 pProxyDev->pUsbIns->pszName, iCfg));
625
626 /*
627 * This is sync - bad.
628 */
629 int rc = g_pfnUsbCtrlMessage(pDevOs2->hDevice,
630 0x00, /* bmRequestType - ?? */
631 0x09, /* bRequest - ?? */
632 iCfg, /* wValue - configuration */
633 0, /* wIndex*/
634 0, /* wLength */
635 NULL, /* pvData */
636 50 /* Timeout (ms) */);
637 if (rc)
638 LogFlow(("usbProxyOs2SetConfig: pProxyDev=%s cfg=%#X -> rc=%d\n", pProxyDev->pUsbIns->pszName, iCfg, rc));
639 return rc == 0;
640}
641
642
643/**
644 * Claims an interface.
645 * @returns success indicator.
646 */
647static int usbProxyOs2ClaimInterface(PUSBPROXYDEV pProxyDev, int iIf)
648{
649 LogFlow(("usbProxyOs2ClaimInterface: pProxyDev=%s ifnum=%#x\n", pProxyDev->pUsbIns->pszName, iIf));
650 return true;
651}
652
653
654/**
655 * Releases an interface.
656 * @returns success indicator.
657 */
658static int usbProxyOs2ReleaseInterface(PUSBPROXYDEV pProxyDev, int iIf)
659{
660 LogFlow(("usbProxyOs2ReleaseInterface: pProxyDev=%s ifnum=%#x\n", pProxyDev->pUsbIns->pszName, iIf));
661 return true;
662}
663
664
665/**
666 * SET_INTERFACE.
667 *
668 * @returns success indicator.
669 */
670static int usbProxyOs2SetInterface(PUSBPROXYDEV pProxyDev, int iIf, int iAlt)
671{
672 LogFlow(("usbProxyOs2SetInterface: pProxyDev=%p iIf=%#x iAlt=%#x\n", pProxyDev, iIf, iAlt));
673 return true;
674}
675
676
677/**
678 * Clears the halted endpoint 'EndPt'.
679 */
680static bool usbProxyOs2ClearHaltedEp(PUSBPROXYDEV pProxyDev, unsigned int EndPt)
681{
682 PUSBPROXYDEVOS2 pDevOs2 = (PUSBPROXYDEVOS2)pProxyDev->Backend.pv;
683 LogFlow(("usbProxyOs2ClearHaltedEp: pProxyDev=%s EndPt=%x\n", pProxyDev->pUsbIns->pszName, EndPt));
684
685 /*
686 * This is sync - bad.
687 */
688 int rc = g_pfnUsbCtrlMessage(pDevOs2->hDevice,
689 0x02, /* bmRequestType - ?? */
690 0x01, /* bRequest - ?? */
691 0, /* wValue - endpoint halt */
692 EndPt, /* wIndex - endpoint # */
693 0, /* wLength */
694 NULL, /* pvData */
695 50 /* Timeout (ms) */);
696 if (rc)
697 LogFlow(("usbProxyOs2ClearHaltedEp: pProxyDev=%s EndPt=%u -> rc=%d\n", pProxyDev->pUsbIns->pszName, EndPt, rc));
698 return rc == 0;
699}
700
701
702/**
703 * @copydoc USBPROXYBACK::pfnUrbQueue
704 */
705static int usbProxyOs2UrbQueue(PVUSBURB pUrb)
706{
707 PUSBPROXYDEV pProxyDev = (PUSBPROXYDEV)pUrb->pDev;
708 PUSBPROXYDEVOS2 pDevOs2 = (PUSBPROXYDEVOS2)pProxyDev->Backend.pv;
709 LogFlow(("usbProxyOs2UrbQueue: pProxyDev=%s pUrb=%p EndPt=%d cbData=%d\n",
710 pProxyDev->pUsbIns->pszName, pUrb, pUrb->EndPt, pUrb->cbData));
711
712 /*
713 * Quickly validate the input.
714 */
715 switch (pUrb->enmDir)
716 {
717 case VUSBDIRECTION_IN:
718 case VUSBDIRECTION_OUT:
719 break;
720 default:
721 AssertMsgFailed(("usbProxyOs2UrbQueue: Invalid direction %d\n", pUrb->enmDir));
722 return false;
723 }
724
725 switch (pUrb->enmType)
726 {
727 case VUSBXFERTYPE_MSG:
728 break;
729 case VUSBXFERTYPE_BULK:
730 break;
731///@todo case VUSBXFERTYPE_INTR:
732// break;
733// case VUSBXFERTYPE_ISOC:
734// break;
735 default:
736 return false;
737 }
738
739 /*
740 * Allocate an OS/2 urb tracking structure, initialize it,
741 * add it to the todo list, and wake up the async thread.
742 */
743 PUSBPROXYURBOS2 pUrbOs2 = usbProxyOs2UrbAlloc(pProxyDev);
744 if (!pUrbOs2)
745 return false;
746
747 pUrbOs2->pUrb = pUrb;
748
749 RTCritSectEnter(&pDevOs2->CritSect);
750
751 pUrbOs2->pNext = NULL;
752 pUrbOs2->pPrev = pDevOs2->pTodoTail;
753 if (pDevOs2->pTodoTail)
754 pDevOs2->pTodoTail->pNext = pUrbOs2;
755 else
756 pDevOs2->pTodoHead = pUrbOs2;
757 pDevOs2->pTodoTail = pUrbOs2;
758
759 RTCritSectLeave(&pDevOs2->CritSect);
760
761 RTThreadUserSignal(pDevOs2->Thread);
762 return true;
763}
764
765
766/**
767 * Reap URBs in-flight on a device.
768 *
769 * @returns Pointer to a completed URB.
770 * @returns NULL if no URB was completed.
771 * @param pProxyDev The device.
772 * @param cMillies Number of milliseconds to wait. Use 0 to not wait at all.
773 */
774static PVUSBURB usbProxyOs2UrbReap(PUSBPROXYDEV pProxyDev, RTMSINTERVAL cMillies)
775{
776 PVUSBURB pUrb = NULL;
777 PUSBPROXYDEVOS2 pDevOs2 = (PUSBPROXYDEVOS2)pProxyDev->Backend.pv;
778
779 RTCritSectEnter(&pDevOs2->CritSect);
780 for (;;)
781 {
782 /*
783 * Any URBs pending delivery?
784 */
785 PUSBPROXYURBOS2 pUrbOs2 = pDevOs2->pTaxingHead;
786 if (pUrbOs2)
787 {
788 pUrb = pUrbOs2->pUrb;
789 usbProxyOs2UrbFree(pProxyDev, pUrbOs2);
790 break;
791 }
792
793 /*
794 * Block for something to completed, if requested and sensible.
795 */
796 if (!cMillies)
797 break;
798 if ( !pDevOs2->pInFlightHead
799 && !pDevOs2->pTodoHead)
800 break;
801
802 RTCritSectLeave(&pDevOs2->CritSect);
803
804 int rc = RTSemEventWait(pDevOs2->EventSyncWait, cMillies);
805 Assert(RT_SUCCESS(rc) || rc == VERR_TIMEOUT); NOREF(rc);
806 cMillies = 0;
807
808 RTCritSectEnter(&pDevOs2->CritSect);
809 }
810 RTCritSectLeave(&pDevOs2->CritSect);
811
812 LogFlow(("usbProxyOs2UrbReap: dev=%s returns %p\n", pProxyDev->pUsbIns->pszName, pUrb));
813 return pUrb;
814}
815
816
817/**
818 * Cancels the URB.
819 * The URB requires reaping, so we don't change its state.
820 */
821static void usbProxyOs2UrbCancel(PVUSBURB pUrb)
822{
823#if 0
824 PUSBPROXYDEV pProxyDev = (PUSBPROXYDEV)pUrb->pDev;
825 PUSBPROXYURBOS2 pUrbOs2 = (PUSBPROXYURBOS2)pUrb->Dev.pvProxyUrb;
826 if (pUrbOs2->pSplitHead)
827 {
828 /* split */
829 Assert(pUrbOs2 == pUrbOs2->pSplitHead);
830 for (PUSBPROXYURBOS2 pCur = pUrbOs2; pCur; pCur = pCur->pSplitNext)
831 {
832 if (pCur->fSplitElementReaped)
833 continue;
834 if ( !usbProxyOs2DoIoCtl(pProxyDev, USBDEVFS_DISCARDURB, &pCur->KUrb, true, UINT32_MAX)
835 || errno == ENOENT)
836 continue;
837 if (errno == ENODEV)
838 break;
839 Log(("usb-linux: Discard URB %p failed, errno=%d. pProxyDev=%s!!! (split)\n",
840 pUrb, errno, pProxyDev->pUsbIns->pszName));
841 }
842 }
843 else
844 {
845 /* unsplit */
846 if ( usbProxyOs2DoIoCtl(pProxyDev, USBDEVFS_DISCARDURB, &pUrbOs2->KUrb, true, UINT32_MAX)
847 && errno != ENODEV /* deal with elsewhere. */
848 && errno != ENOENT)
849 Log(("usb-linux: Discard URB %p failed, errno=%d. pProxyDev=%s!!!\n",
850 pUrb, errno, pProxyDev->pUsbIns->pszName));
851 }
852#endif
853}
854
855
856/**
857 * The Linux USB Proxy Backend.
858 */
859extern const USBPROXYBACK g_USBProxyDeviceHost =
860{
861 "host",
862 usbProxyOs2Open,
863 NULL,
864 usbProxyOs2Close,
865 usbProxyOs2Reset,
866 usbProxyOs2SetConfig,
867 usbProxyOs2ClaimInterface,
868 usbProxyOs2ReleaseInterface,
869 usbProxyOs2SetInterface,
870 usbProxyOs2ClearHaltedEp,
871 usbProxyOs2UrbQueue,
872 usbProxyOs2UrbCancel,
873 usbProxyOs2UrbReap,
874 0
875};
876
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