VirtualBox

source: vbox/trunk/src/VBox/Devices/Serial/DrvHostSerial.cpp@ 4928

Last change on this file since 4928 was 4928, checked in by vboxsync, 17 years ago

Lower the cpu usage pf the serial port on windows hosts

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 20.9 KB
Line 
1/** $Id: DrvHostSerial.cpp 4928 2007-09-20 13:09:14Z vboxsync $ */
2/** @file
3 * VBox stream I/O devices: Host serial driver
4 *
5 * Contributed by: Alexander Eichner
6 */
7
8/*
9 * Copyright (C) 2006-2007 innotek GmbH
10 *
11 * This file is part of VirtualBox Open Source Edition (OSE), as
12 * available from http://www.virtualbox.org. This file is free software;
13 * you can redistribute it and/or modify it under the terms of the GNU
14 * General Public License as published by the Free Software Foundation,
15 * in version 2 as it comes in the "COPYING" file of the VirtualBox OSE
16 * distribution. VirtualBox OSE is distributed in the hope that it will
17 * be useful, but WITHOUT ANY WARRANTY of any kind.
18 *
19 * If you received this file as part of a commercial VirtualBox
20 * distribution, then only the terms of your commercial VirtualBox
21 * license agreement apply instead of the previous paragraph.
22 */
23
24
25
26/*******************************************************************************
27* Header Files *
28*******************************************************************************/
29#define LOG_GROUP LOG_GROUP_DRV_HOST_SERIAL
30#include <VBox/pdm.h>
31#include <VBox/err.h>
32
33#include <VBox/log.h>
34#include <iprt/asm.h>
35#include <iprt/assert.h>
36#include <iprt/stream.h>
37#include <iprt/semaphore.h>
38#include <iprt/file.h>
39#include <iprt/alloc.h>
40
41#ifdef RT_OS_LINUX
42# include <termios.h>
43# include <sys/types.h>
44# include <fcntl.h>
45# include <string.h>
46# include <unistd.h>
47# include <sys/poll.h>
48#elif defined(RT_OS_WINDOWS)
49# include <windows.h>
50#endif
51
52#include "Builtins.h"
53
54
55/** Size of the send fifo queue (in bytes) */
56#define CHAR_MAX_SEND_QUEUE 0x80
57#define CHAR_MAX_SEND_QUEUE_MASK 0x7f
58
59/*******************************************************************************
60* Structures and Typedefs *
61*******************************************************************************/
62
63/**
64 * Char driver instance data.
65 */
66typedef struct DRVHOSTSERIAL
67{
68 /** Pointer to the driver instance structure. */
69 PPDMDRVINS pDrvIns;
70 /** Pointer to the char port interface of the driver/device above us. */
71 PPDMICHARPORT pDrvCharPort;
72 /** Our char interface. */
73 PDMICHAR IChar;
74 /** Flag to notify the receive thread it should terminate. */
75 volatile bool fShutdown;
76 /** Receive thread ID. */
77 RTTHREAD ReceiveThread;
78 /** Send thread ID. */
79 RTTHREAD SendThread;
80 /** Send event semephore */
81 RTSEMEVENT SendSem;
82
83 /** the device path */
84 char *pszDevicePath;
85 /** the device handle */
86 RTFILE DeviceFile;
87
88 /** Internal send FIFO queue */
89 uint8_t aSendQueue[CHAR_MAX_SEND_QUEUE];
90 uint32_t iSendQueueHead;
91 uint32_t iSendQueueTail;
92
93 /** Read/write statistics */
94 STAMCOUNTER StatBytesRead;
95 STAMCOUNTER StatBytesWritten;
96} DRVHOSTSERIAL, *PDRVHOSTSERIAL;
97
98
99/** Converts a pointer to DRVCHAR::IChar to a PDRVHOSTSERIAL. */
100#define PDMICHAR_2_DRVHOSTSERIAL(pInterface) ( (PDRVHOSTSERIAL)((uintptr_t)pInterface - RT_OFFSETOF(DRVHOSTSERIAL, IChar)) )
101
102
103/* -=-=-=-=- IBase -=-=-=-=- */
104
105/**
106 * Queries an interface to the driver.
107 *
108 * @returns Pointer to interface.
109 * @returns NULL if the interface was not supported by the driver.
110 * @param pInterface Pointer to this interface structure.
111 * @param enmInterface The requested interface identification.
112 */
113static DECLCALLBACK(void *) drvHostSerialQueryInterface(PPDMIBASE pInterface, PDMINTERFACE enmInterface)
114{
115 PPDMDRVINS pDrvIns = PDMIBASE_2_PDMDRV(pInterface);
116 PDRVHOSTSERIAL pData = PDMINS2DATA(pDrvIns, PDRVHOSTSERIAL);
117 switch (enmInterface)
118 {
119 case PDMINTERFACE_BASE:
120 return &pDrvIns->IBase;
121 case PDMINTERFACE_CHAR:
122 return &pData->IChar;
123 default:
124 return NULL;
125 }
126}
127
128
129/* -=-=-=-=- IChar -=-=-=-=- */
130
131/** @copydoc PDMICHAR::pfnWrite */
132static DECLCALLBACK(int) drvHostSerialWrite(PPDMICHAR pInterface, const void *pvBuf, size_t cbWrite)
133{
134 PDRVHOSTSERIAL pData = PDMICHAR_2_DRVHOSTSERIAL(pInterface);
135 const uint8_t *pbBuffer = (const uint8_t *)pvBuf;
136
137 LogFlow(("%s: pvBuf=%#p cbWrite=%d\n", __FUNCTION__, pvBuf, cbWrite));
138
139 for (uint32_t i=0;i<cbWrite;i++)
140 {
141 uint32_t idx = pData->iSendQueueHead;
142
143 pData->aSendQueue[idx] = pbBuffer[i];
144 idx = (idx + 1) & CHAR_MAX_SEND_QUEUE_MASK;
145
146 STAM_COUNTER_INC(&pData->StatBytesWritten);
147 ASMAtomicXchgU32(&pData->iSendQueueHead, idx);
148 }
149 RTSemEventSignal(pData->SendSem);
150 return VINF_SUCCESS;
151}
152
153static DECLCALLBACK(int) drvHostSerialSetParameters(PPDMICHAR pInterface, unsigned Bps, char chParity, unsigned cDataBits, unsigned cStopBits)
154{
155 PDRVHOSTSERIAL pData = PDMICHAR_2_DRVHOSTSERIAL(pInterface);
156#ifdef RT_OS_LINUX
157 struct termios *termiosSetup;
158 int baud_rate;
159#elif defined(RT_OS_WINDOWS)
160 LPDCB comSetup;
161#endif
162
163 LogFlow(("%s: Bps=%u chParity=%c cDataBits=%u cStopBits=%u\n", __FUNCTION__, Bps, chParity, cDataBits, cStopBits));
164
165#ifdef RT_OS_LINUX
166 termiosSetup = (struct termios *)RTMemTmpAllocZ(sizeof(struct termios));
167
168 /* Enable receiver */
169 termiosSetup->c_cflag |= (CLOCAL | CREAD);
170
171 switch (Bps) {
172 case 50:
173 baud_rate = B50;
174 break;
175 case 75:
176 baud_rate = B75;
177 break;
178 case 110:
179 baud_rate = B110;
180 break;
181 case 134:
182 baud_rate = B134;
183 break;
184 case 150:
185 baud_rate = B150;
186 break;
187 case 200:
188 baud_rate = B200;
189 break;
190 case 300:
191 baud_rate = B300;
192 break;
193 case 600:
194 baud_rate = B600;
195 break;
196 case 1200:
197 baud_rate = B1200;
198 break;
199 case 1800:
200 baud_rate = B1800;
201 break;
202 case 2400:
203 baud_rate = B2400;
204 break;
205 case 4800:
206 baud_rate = B4800;
207 break;
208 case 9600:
209 baud_rate = B9600;
210 break;
211 case 19200:
212 baud_rate = B19200;
213 break;
214 case 38400:
215 baud_rate = B38400;
216 break;
217 case 57600:
218 baud_rate = B57600;
219 break;
220 case 115200:
221 baud_rate = B115200;
222 break;
223 default:
224 baud_rate = B9600;
225 }
226
227 cfsetispeed(termiosSetup, baud_rate);
228 cfsetospeed(termiosSetup, baud_rate);
229
230 switch (chParity) {
231 case 'E':
232 termiosSetup->c_cflag |= PARENB;
233 break;
234 case 'O':
235 termiosSetup->c_cflag |= (PARENB | PARODD);
236 break;
237 case 'N':
238 break;
239 default:
240 break;
241 }
242
243 switch (cDataBits) {
244 case 5:
245 termiosSetup->c_cflag |= CS5;
246 break;
247 case 6:
248 termiosSetup->c_cflag |= CS6;
249 break;
250 case 7:
251 termiosSetup->c_cflag |= CS7;
252 break;
253 case 8:
254 termiosSetup->c_cflag |= CS8;
255 break;
256 default:
257 break;
258 }
259
260 switch (cStopBits) {
261 case 2:
262 termiosSetup->c_cflag |= CSTOPB;
263 default:
264 break;
265 }
266
267 /* set serial port to raw input */
268 termiosSetup->c_lflag = ~(ICANON | ECHO | ECHOE | ISIG);
269
270 tcsetattr(pData->DeviceFile, TCSANOW, termiosSetup);
271 RTMemFree(termiosSetup);
272#elif defined(RT_OS_WINDOWS)
273 comSetup = (LPDCB)RTMemTmpAllocZ(sizeof(DCB));
274
275 comSetup->DCBlength = sizeof(DCB);
276
277 switch (Bps) {
278 case 110:
279 comSetup->BaudRate = CBR_110;
280 break;
281 case 300:
282 comSetup->BaudRate = CBR_300;
283 break;
284 case 600:
285 comSetup->BaudRate = CBR_600;
286 break;
287 case 1200:
288 comSetup->BaudRate = CBR_1200;
289 break;
290 case 2400:
291 comSetup->BaudRate = CBR_2400;
292 break;
293 case 4800:
294 comSetup->BaudRate = CBR_4800;
295 break;
296 case 9600:
297 comSetup->BaudRate = CBR_9600;
298 break;
299 case 14400:
300 comSetup->BaudRate = CBR_14400;
301 break;
302 case 19200:
303 comSetup->BaudRate = CBR_19200;
304 break;
305 case 38400:
306 comSetup->BaudRate = CBR_38400;
307 break;
308 case 57600:
309 comSetup->BaudRate = CBR_57600;
310 break;
311 case 115200:
312 comSetup->BaudRate = CBR_115200;
313 break;
314 default:
315 comSetup->BaudRate = CBR_9600;
316 }
317
318 comSetup->fBinary = TRUE;
319 comSetup->fOutxCtsFlow = FALSE;
320 comSetup->fOutxDsrFlow = FALSE;
321 comSetup->fDtrControl = DTR_CONTROL_DISABLE;
322 comSetup->fDsrSensitivity = FALSE;
323 comSetup->fTXContinueOnXoff = TRUE;
324 comSetup->fOutX = FALSE;
325 comSetup->fInX = FALSE;
326 comSetup->fErrorChar = FALSE;
327 comSetup->fNull = FALSE;
328 comSetup->fRtsControl = RTS_CONTROL_DISABLE;
329 comSetup->fAbortOnError = FALSE;
330 comSetup->wReserved = 0;
331 comSetup->XonLim = 5;
332 comSetup->XoffLim = 5;
333 comSetup->ByteSize = cDataBits;
334
335 switch (chParity) {
336 case 'E':
337 comSetup->Parity = EVENPARITY;
338 break;
339 case 'O':
340 comSetup->Parity = ODDPARITY;
341 break;
342 case 'N':
343 comSetup->Parity = NOPARITY;
344 break;
345 default:
346 break;
347 }
348
349 switch (cStopBits) {
350 case 1:
351 comSetup->StopBits = ONESTOPBIT;
352 break;
353 case 2:
354 comSetup->StopBits = TWOSTOPBITS;
355 break;
356 default:
357 break;
358 }
359
360 comSetup->XonChar = 0;
361 comSetup->XoffChar = 0;
362 comSetup->ErrorChar = 0;
363 comSetup->EofChar = 0;
364 comSetup->EvtChar = 0;
365
366 SetCommState((HANDLE)pData->DeviceFile, comSetup);
367 RTMemFree(comSetup);
368#endif /* RT_OS_WINDOWS */
369
370 return VINF_SUCCESS;
371}
372
373/* -=-=-=-=- receive thread -=-=-=-=- */
374
375/**
376 * Send thread loop.
377 *
378 * @returns VINF_SUCCESS.
379 * @param ThreadSelf Thread handle to this thread.
380 * @param pvUser User argument.
381 */
382static DECLCALLBACK(int) drvHostSerialSendLoop(RTTHREAD ThreadSelf, void *pvUser)
383{
384 PDRVHOSTSERIAL pData = (PDRVHOSTSERIAL)pvUser;
385
386 while (!pData->fShutdown)
387 {
388 int rc = RTSemEventWait(pData->SendSem, RT_INDEFINITE_WAIT);
389 if (VBOX_FAILURE(rc))
390 break;
391
392 /*
393 * Write the character to the host device.
394 */
395 while ( !pData->fShutdown
396 && pData->iSendQueueTail != pData->iSendQueueHead)
397 {
398 unsigned cbProcessed = 1;
399
400 rc = RTFileWrite(pData->DeviceFile, &pData->aSendQueue[pData->iSendQueueTail], cbProcessed, NULL);
401 if (VBOX_SUCCESS(rc))
402 {
403 Assert(cbProcessed);
404 pData->iSendQueueTail++;
405 pData->iSendQueueTail &= CHAR_MAX_SEND_QUEUE_MASK;
406 }
407 else if (VBOX_FAILURE(rc))
408 {
409 LogFlow(("Write failed with %Vrc; skipping\n", rc));
410 break;
411 }
412 }
413 }
414
415 return VINF_SUCCESS;
416}
417
418
419/* -=-=-=-=- receive thread -=-=-=-=- */
420
421/**
422 * Receive thread loop.
423 *
424 * This thread pushes data from the host serial device up the driver
425 * chain toward the serial device.
426 *
427 * @returns VINF_SUCCESS.
428 * @param ThreadSelf Thread handle to this thread.
429 * @param pvUser User argument.
430 */
431static DECLCALLBACK(int) drvHostSerialReceiveLoop(RTTHREAD ThreadSelf, void *pvUser)
432{
433 PDRVHOSTSERIAL pData = (PDRVHOSTSERIAL)pvUser;
434 uint8_t abBuffer[256];
435 uint8_t *pbBuffer = NULL;
436 size_t cbRemaining = 0; /* start by reading host data */
437 int rc = VINF_SUCCESS;
438
439 while (!pData->fShutdown)
440 {
441 if (!cbRemaining)
442 {
443 /* Get a block of data from the host serial device. */
444 size_t cbRead;
445
446#ifdef RT_OS_LINUX
447 struct pollfd pfd;
448
449 pfd.fd = pData->DeviceFile;
450 pfd.events = POLLIN;
451
452 rc = poll(&pfd, 1, -1);
453 if (rc < 0)
454 break;
455#elif defined(RT_OS_WINDOWS)
456 BOOL retval;
457 DWORD dwEventMask = EV_RXCHAR;
458
459 retval = WaitCommEvent((HANDLE)pData->DeviceFile, &dwEventMask, NULL);
460
461 if (!retval)
462 {
463 LogRel(("Host Serial Driver: WaitCommEvent failed, terminating the worker thread.\n"));
464 break;
465 }
466#endif
467
468 rc = RTFileRead(pData->DeviceFile, abBuffer, sizeof(abBuffer), &cbRead);
469 if (VBOX_FAILURE(rc))
470 {
471 LogRel(("Host Serial Driver: Read failed with %Vrc, terminating the worker thread.\n", rc));
472 break;
473 }
474 Log(("Host Serial Driver: Read %d bytes.\n", cbRead));
475 cbRemaining = cbRead;
476 pbBuffer = abBuffer;
477 }
478 else
479 {
480 /* Send data to the guest. */
481 size_t cbProcessed = cbRemaining;
482 rc = pData->pDrvCharPort->pfnNotifyRead(pData->pDrvCharPort, pbBuffer, &cbProcessed);
483 if (VBOX_SUCCESS(rc))
484 {
485 Assert(cbProcessed); Assert(cbProcessed <= cbRemaining);
486 pbBuffer += cbProcessed;
487 cbRemaining -= cbProcessed;
488 STAM_COUNTER_ADD(&pData->StatBytesRead, cbProcessed);
489 }
490 else if (rc == VERR_TIMEOUT)
491 {
492 /* Normal case, just means that the guest didn't accept a new
493 * character before the timeout elapsed. Just retry. */
494 rc = VINF_SUCCESS;
495 }
496 else
497 {
498 LogRel(("Host Serial Driver: NotifyRead failed with %Vrc, terminating the worker thread.\n", rc));
499 break;
500 }
501 }
502 }
503
504 return VINF_SUCCESS;
505}
506
507
508/* -=-=-=-=- driver interface -=-=-=-=- */
509
510/**
511 * Construct a char driver instance.
512 *
513 * @returns VBox status.
514 * @param pDrvIns The driver instance data.
515 * If the registration structure is needed,
516 * pDrvIns->pDrvReg points to it.
517 * @param pCfgHandle Configuration node handle for the driver. Use this to
518 * obtain the configuration of the driver instance. It's
519 * also found in pDrvIns->pCfgHandle as it's expected to
520 * be used frequently in this function.
521 */
522static DECLCALLBACK(int) drvHostSerialConstruct(PPDMDRVINS pDrvIns, PCFGMNODE pCfgHandle)
523{
524 PDRVHOSTSERIAL pData = PDMINS2DATA(pDrvIns, PDRVHOSTSERIAL);
525 LogFlow(("%s: iInstance=%d\n", __FUNCTION__, pDrvIns->iInstance));
526
527 /*
528 * Init basic data members and interfaces.
529 */
530 pData->ReceiveThread = NIL_RTTHREAD;
531 pData->SendThread = NIL_RTTHREAD;
532 pData->fShutdown = false;
533 /* IBase. */
534 pDrvIns->IBase.pfnQueryInterface = drvHostSerialQueryInterface;
535 /* IChar. */
536 pData->IChar.pfnWrite = drvHostSerialWrite;
537 pData->IChar.pfnSetParameters = drvHostSerialSetParameters;
538
539 /*
540 * Query configuration.
541 */
542 /* Device */
543 int rc = CFGMR3QueryStringAlloc(pCfgHandle, "DevicePath", &pData->pszDevicePath);
544 if (VBOX_FAILURE(rc))
545 {
546 AssertMsgFailed(("Configuration error: query for \"DevicePath\" string returned %Vra.\n", rc));
547 return rc;
548 }
549
550 /*
551 * Open the device
552 */
553 rc = RTFileOpen(&pData->DeviceFile, pData->pszDevicePath, RTFILE_O_OPEN | RTFILE_O_READWRITE);
554
555 if (VBOX_FAILURE(rc)) {
556 pData->DeviceFile = NIL_RTFILE;
557 AssertMsgFailed(("Could not open host device %s, rc=%Vrc\n", pData->pszDevicePath, rc));
558 switch (rc) {
559 case VERR_ACCESS_DENIED:
560 return PDMDrvHlpVMSetError(pDrvIns, rc, RT_SRC_POS,
561#ifdef RT_OS_LINUX
562 N_("Cannot open host device '%s' for read/write access. Check the permissions "
563 "of that device ('/bin/ls -l %s'): Most probably you need to be member "
564 "of the device group. Make sure that you logout/login after changing "
565 "the group settings of the current user"),
566#else
567 N_("Cannot open host device '%s' for read/write access. Check the permissions "
568 "of that device"),
569#endif
570 pData->pszDevicePath, pData->pszDevicePath);
571 default:
572 return PDMDrvHlpVMSetError(pDrvIns, rc, RT_SRC_POS,
573 N_("Failed to open host device '%s'"),
574 pData->pszDevicePath);
575 }
576 }
577
578 /* Set to non blocking I/O */
579#ifdef RT_OS_LINUX
580 fcntl(pData->DeviceFile, F_SETFL, O_NONBLOCK);
581#elif defined(RT_OS_WINDOWS)
582 /* Set the COMMTIMEOUTS to get non blocking I/O */
583 COMMTIMEOUTS comTimeout;
584
585 comTimeout.ReadIntervalTimeout = MAXDWORD;
586 comTimeout.ReadTotalTimeoutMultiplier = 0;
587 comTimeout.ReadTotalTimeoutConstant = 0;
588 comTimeout.WriteTotalTimeoutMultiplier = 0;
589 comTimeout.WriteTotalTimeoutConstant = 0;
590
591 SetCommTimeouts((HANDLE)pData->DeviceFile, &comTimeout);
592#endif
593
594 /*
595 * Get the ICharPort interface of the above driver/device.
596 */
597 pData->pDrvCharPort = (PPDMICHARPORT)pDrvIns->pUpBase->pfnQueryInterface(pDrvIns->pUpBase, PDMINTERFACE_CHAR_PORT);
598 if (!pData->pDrvCharPort)
599 return PDMDrvHlpVMSetError(pDrvIns, VERR_PDM_MISSING_INTERFACE_ABOVE, RT_SRC_POS, N_("HostSerial#%d has no char port interface above"), pDrvIns->iInstance);
600
601 rc = RTThreadCreate(&pData->ReceiveThread, drvHostSerialReceiveLoop, (void *)pData, 0, RTTHREADTYPE_IO, RTTHREADFLAGS_WAITABLE, "Char Receive");
602 if (VBOX_FAILURE(rc))
603 return PDMDrvHlpVMSetError(pDrvIns, rc, RT_SRC_POS, N_("HostSerial#%d cannot create receive thread"), pDrvIns->iInstance);
604
605 rc = RTSemEventCreate(&pData->SendSem);
606 AssertRC(rc);
607
608 rc = RTThreadCreate(&pData->SendThread, drvHostSerialSendLoop, (void *)pData, 0, RTTHREADTYPE_IO, RTTHREADFLAGS_WAITABLE, "Serial Send");
609 if (VBOX_FAILURE(rc))
610 return PDMDrvHlpVMSetError(pDrvIns, rc, RT_SRC_POS, N_("HostSerial#%d cannot create send thread"), pDrvIns->iInstance);
611
612
613 PDMDrvHlpSTAMRegisterF(pDrvIns, &pData->StatBytesWritten, STAMTYPE_COUNTER, STAMVISIBILITY_USED, STAMUNIT_BYTES, "Nr of bytes written", "/Devices/HostSerial%d/Written", pDrvIns->iInstance);
614 PDMDrvHlpSTAMRegisterF(pDrvIns, &pData->StatBytesRead, STAMTYPE_COUNTER, STAMVISIBILITY_USED, STAMUNIT_BYTES, "Nr of bytes read", "/Devices/HostSerial%d/Read", pDrvIns->iInstance);
615
616 return VINF_SUCCESS;
617}
618
619
620/**
621 * Destruct a char driver instance.
622 *
623 * Most VM resources are freed by the VM. This callback is provided so that
624 * any non-VM resources can be freed correctly.
625 *
626 * @param pDrvIns The driver instance data.
627 */
628static DECLCALLBACK(void) drvHostSerialDestruct(PPDMDRVINS pDrvIns)
629{
630 PDRVHOSTSERIAL pData = PDMINS2DATA(pDrvIns, PDRVHOSTSERIAL);
631
632 LogFlow(("%s: iInstance=%d\n", __FUNCTION__, pDrvIns->iInstance));
633
634 ASMAtomicXchgBool(&pData->fShutdown, true);
635 if (pData->ReceiveThread != NIL_RTTHREAD)
636 {
637 int rc = RTThreadWait(pData->ReceiveThread, 15000, NULL);
638 if (RT_FAILURE(rc))
639 LogRel(("HostSerial%d: receive thread did not terminate (rc=%Rrc)\n", pDrvIns->iInstance, rc));
640 pData->ReceiveThread = NIL_RTTHREAD;
641 }
642
643 /* Empty the send queue */
644 pData->iSendQueueTail = pData->iSendQueueHead = 0;
645
646 RTSemEventSignal(pData->SendSem);
647 RTSemEventDestroy(pData->SendSem);
648 pData->SendSem = NIL_RTSEMEVENT;
649
650 if (pData->SendThread != NIL_RTTHREAD)
651 {
652 int rc = RTThreadWait(pData->SendThread, 15000, NULL);
653 if (RT_FAILURE(rc))
654 LogRel(("HostSerial%d: send thread did not terminate (rc=%Rrc)\n", pDrvIns->iInstance, rc));
655 pData->SendThread = NIL_RTTHREAD;
656 }
657}
658
659/**
660 * Char driver registration record.
661 */
662const PDMDRVREG g_DrvHostSerial =
663{
664 /* u32Version */
665 PDM_DRVREG_VERSION,
666 /* szDriverName */
667 "Host Serial",
668 /* pszDescription */
669 "Host serial driver.",
670 /* fFlags */
671 PDM_DRVREG_FLAGS_HOST_BITS_DEFAULT,
672 /* fClass. */
673 PDM_DRVREG_CLASS_CHAR,
674 /* cMaxInstances */
675 ~0,
676 /* cbInstance */
677 sizeof(DRVHOSTSERIAL),
678 /* pfnConstruct */
679 drvHostSerialConstruct,
680 /* pfnDestruct */
681 drvHostSerialDestruct,
682 /* pfnIOCtl */
683 NULL,
684 /* pfnPowerOn */
685 NULL,
686 /* pfnReset */
687 NULL,
688 /* pfnSuspend */
689 NULL,
690 /* pfnResume */
691 NULL,
692 /* pfnDetach */
693 NULL,
694 /** pfnPowerOff */
695 NULL
696};
697
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