VirtualBox

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

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

eol style

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 20.5 KB
Line 
1/** $Id: DrvHostSerial.cpp 4749 2007-09-13 06:49:58Z 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#endif
456
457 rc = RTFileRead(pData->DeviceFile, abBuffer, sizeof(abBuffer), &cbRead);
458 if (VBOX_FAILURE(rc))
459 {
460 LogRel(("Host Serial Driver: Read failed with %Vrc, terminating the worker thread.\n", rc));
461 break;
462 }
463 Log(("Host Serial Driver: Read %d bytes.\n", cbRead));
464 cbRemaining = cbRead;
465 pbBuffer = abBuffer;
466 }
467 else
468 {
469 /* Send data to the guest. */
470 size_t cbProcessed = cbRemaining;
471 rc = pData->pDrvCharPort->pfnNotifyRead(pData->pDrvCharPort, pbBuffer, &cbProcessed);
472 if (VBOX_SUCCESS(rc))
473 {
474 Assert(cbProcessed); Assert(cbProcessed <= cbRemaining);
475 pbBuffer += cbProcessed;
476 cbRemaining -= cbProcessed;
477 STAM_COUNTER_ADD(&pData->StatBytesRead, cbProcessed);
478 }
479 else if (rc == VERR_TIMEOUT)
480 {
481 /* Normal case, just means that the guest didn't accept a new
482 * character before the timeout elapsed. Just retry. */
483 rc = VINF_SUCCESS;
484 }
485 else
486 {
487 LogRel(("Host Serial Driver: NotifyRead failed with %Vrc, terminating the worker thread.\n", rc));
488 break;
489 }
490 }
491 }
492
493 return VINF_SUCCESS;
494}
495
496
497/* -=-=-=-=- driver interface -=-=-=-=- */
498
499/**
500 * Construct a char driver instance.
501 *
502 * @returns VBox status.
503 * @param pDrvIns The driver instance data.
504 * If the registration structure is needed,
505 * pDrvIns->pDrvReg points to it.
506 * @param pCfgHandle Configuration node handle for the driver. Use this to
507 * obtain the configuration of the driver instance. It's
508 * also found in pDrvIns->pCfgHandle as it's expected to
509 * be used frequently in this function.
510 */
511static DECLCALLBACK(int) drvHostSerialConstruct(PPDMDRVINS pDrvIns, PCFGMNODE pCfgHandle)
512{
513 PDRVHOSTSERIAL pData = PDMINS2DATA(pDrvIns, PDRVHOSTSERIAL);
514 LogFlow(("%s: iInstance=%d\n", __FUNCTION__, pDrvIns->iInstance));
515
516 /*
517 * Init basic data members and interfaces.
518 */
519 pData->ReceiveThread = NIL_RTTHREAD;
520 pData->SendThread = NIL_RTTHREAD;
521 pData->fShutdown = false;
522 /* IBase. */
523 pDrvIns->IBase.pfnQueryInterface = drvHostSerialQueryInterface;
524 /* IChar. */
525 pData->IChar.pfnWrite = drvHostSerialWrite;
526 pData->IChar.pfnSetParameters = drvHostSerialSetParameters;
527
528 /*
529 * Query configuration.
530 */
531 /* Device */
532 int rc = CFGMR3QueryStringAlloc(pCfgHandle, "DevicePath", &pData->pszDevicePath);
533 if (VBOX_FAILURE(rc))
534 {
535 AssertMsgFailed(("Configuration error: query for \"DevicePath\" string returned %Vra.\n", rc));
536 return rc;
537 }
538
539 /*
540 * Open the device
541 */
542 rc = RTFileOpen(&pData->DeviceFile, pData->pszDevicePath, RTFILE_O_OPEN | RTFILE_O_READWRITE);
543
544 if (VBOX_FAILURE(rc)) {
545 pData->DeviceFile = NIL_RTFILE;
546 AssertMsgFailed(("Could not open host device %s, rc=%Vrc\n", pData->pszDevicePath, rc));
547 switch (rc) {
548 case VERR_ACCESS_DENIED:
549 return PDMDrvHlpVMSetError(pDrvIns, rc, RT_SRC_POS,
550#ifdef RT_OS_LINUX
551 N_("Cannot open host device '%s' for read/write access. Check the permissions "
552 "of that device ('/bin/ls -l %s'): Most probably you need to be member "
553 "of the device group. Make sure that you logout/login after changing "
554 "the group settings of the current user"),
555#else
556 N_("Cannot open host device '%s' for read/write access. Check the permissions "
557 "of that device"),
558#endif
559 pData->pszDevicePath, pData->pszDevicePath);
560 default:
561 return PDMDrvHlpVMSetError(pDrvIns, rc, RT_SRC_POS,
562 N_("Failed to open host device '%s'"),
563 pData->pszDevicePath);
564 }
565 }
566
567 /* Set to non blocking I/O */
568#ifdef RT_OS_LINUX
569 fcntl(pData->DeviceFile, F_SETFL, O_NONBLOCK);
570#elif defined(RT_OS_WINDOWS)
571 /* Set the COMMTIMEOUTS to get non blocking I/O */
572 COMMTIMEOUTS comTimeout;
573
574 comTimeout.ReadIntervalTimeout = MAXDWORD;
575 comTimeout.ReadTotalTimeoutMultiplier = 0;
576 comTimeout.ReadTotalTimeoutConstant = 10;
577 comTimeout.WriteTotalTimeoutMultiplier = 0;
578 comTimeout.WriteTotalTimeoutConstant = 0;
579
580 SetCommTimeouts((HANDLE)pData->DeviceFile, &comTimeout);
581#endif
582
583 /*
584 * Get the ICharPort interface of the above driver/device.
585 */
586 pData->pDrvCharPort = (PPDMICHARPORT)pDrvIns->pUpBase->pfnQueryInterface(pDrvIns->pUpBase, PDMINTERFACE_CHAR_PORT);
587 if (!pData->pDrvCharPort)
588 return PDMDrvHlpVMSetError(pDrvIns, VERR_PDM_MISSING_INTERFACE_ABOVE, RT_SRC_POS, N_("HostSerial#%d has no char port interface above"), pDrvIns->iInstance);
589
590 rc = RTThreadCreate(&pData->ReceiveThread, drvHostSerialReceiveLoop, (void *)pData, 0, RTTHREADTYPE_IO, RTTHREADFLAGS_WAITABLE, "Char Receive");
591 if (VBOX_FAILURE(rc))
592 return PDMDrvHlpVMSetError(pDrvIns, rc, RT_SRC_POS, N_("HostSerial#%d cannot create receive thread"), pDrvIns->iInstance);
593
594 rc = RTSemEventCreate(&pData->SendSem);
595 AssertRC(rc);
596
597 rc = RTThreadCreate(&pData->SendThread, drvHostSerialSendLoop, (void *)pData, 0, RTTHREADTYPE_IO, RTTHREADFLAGS_WAITABLE, "Serial Send");
598 if (VBOX_FAILURE(rc))
599 return PDMDrvHlpVMSetError(pDrvIns, rc, RT_SRC_POS, N_("HostSerial#%d cannot create send thread"), pDrvIns->iInstance);
600
601
602 PDMDrvHlpSTAMRegisterF(pDrvIns, &pData->StatBytesWritten, STAMTYPE_COUNTER, STAMVISIBILITY_USED, STAMUNIT_BYTES, "Nr of bytes written", "/Devices/HostSerial%d/Written", pDrvIns->iInstance);
603 PDMDrvHlpSTAMRegisterF(pDrvIns, &pData->StatBytesRead, STAMTYPE_COUNTER, STAMVISIBILITY_USED, STAMUNIT_BYTES, "Nr of bytes read", "/Devices/HostSerial%d/Read", pDrvIns->iInstance);
604
605 return VINF_SUCCESS;
606}
607
608
609/**
610 * Destruct a char driver instance.
611 *
612 * Most VM resources are freed by the VM. This callback is provided so that
613 * any non-VM resources can be freed correctly.
614 *
615 * @param pDrvIns The driver instance data.
616 */
617static DECLCALLBACK(void) drvHostSerialDestruct(PPDMDRVINS pDrvIns)
618{
619 PDRVHOSTSERIAL pData = PDMINS2DATA(pDrvIns, PDRVHOSTSERIAL);
620
621 LogFlow(("%s: iInstance=%d\n", __FUNCTION__, pDrvIns->iInstance));
622
623 ASMAtomicXchgBool(&pData->fShutdown, true);
624 if (pData->ReceiveThread != NIL_RTTHREAD)
625 {
626 int rc = RTThreadWait(pData->ReceiveThread, 15000, NULL);
627 if (RT_FAILURE(rc))
628 LogRel(("HostSerial%d: receive thread did not terminate (rc=%Rrc)\n", pDrvIns->iInstance, rc));
629 pData->ReceiveThread = NIL_RTTHREAD;
630 }
631
632 /* Empty the send queue */
633 pData->iSendQueueTail = pData->iSendQueueHead = 0;
634
635 RTSemEventSignal(pData->SendSem);
636 RTSemEventDestroy(pData->SendSem);
637 pData->SendSem = NIL_RTSEMEVENT;
638
639 if (pData->SendThread != NIL_RTTHREAD)
640 {
641 int rc = RTThreadWait(pData->SendThread, 15000, NULL);
642 if (RT_FAILURE(rc))
643 LogRel(("HostSerial%d: send thread did not terminate (rc=%Rrc)\n", pDrvIns->iInstance, rc));
644 pData->SendThread = NIL_RTTHREAD;
645 }
646}
647
648/**
649 * Char driver registration record.
650 */
651const PDMDRVREG g_DrvHostSerial =
652{
653 /* u32Version */
654 PDM_DRVREG_VERSION,
655 /* szDriverName */
656 "Host Serial",
657 /* pszDescription */
658 "Host serial driver.",
659 /* fFlags */
660 PDM_DRVREG_FLAGS_HOST_BITS_DEFAULT,
661 /* fClass. */
662 PDM_DRVREG_CLASS_CHAR,
663 /* cMaxInstances */
664 ~0,
665 /* cbInstance */
666 sizeof(DRVHOSTSERIAL),
667 /* pfnConstruct */
668 drvHostSerialConstruct,
669 /* pfnDestruct */
670 drvHostSerialDestruct,
671 /* pfnIOCtl */
672 NULL,
673 /* pfnPowerOn */
674 NULL,
675 /* pfnReset */
676 NULL,
677 /* pfnSuspend */
678 NULL,
679 /* pfnResume */
680 NULL,
681 /* pfnDetach */
682 NULL,
683 /** pfnPowerOff */
684 NULL
685};
686
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