Changeset 70800 in vbox for trunk/src/VBox
- Timestamp:
- Jan 29, 2018 8:55:29 PM (7 years ago)
- Location:
- trunk/src/VBox/Devices
- Files:
-
- 1 edited
- 1 copied
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Devices/Makefile.kmk
r70434 r70800 813 813 endif 814 814 815 if defined(VBOX_WITH_NEW_DRVHOSTSERIAL) 816 VBoxDD_SOURCES.linux := \ 817 $(filter-out Serial/DrvHostSerial.cpp, $(VBoxDD_SOURCES.linux)) \ 818 Serial/DrvHostSerialNew.cpp 819 820 VBoxDD_SOURCES.darwin := \ 821 $(filter-out Serial/DrvHostSerial.cpp, $(VBoxDD_SOURCES.darwin)) \ 822 Serial/DrvHostSerialNew.cpp 823 824 VBoxDD_SOURCES.win := \ 825 $(filter-out Serial/DrvHostSerial.cpp, $(VBoxDD_SOURCES.win)) \ 826 Serial/DrvHostSerialNew.cpp 827 828 VBoxDD_SOURCES.freebsd := \ 829 $(filter-out Serial/DrvHostSerial.cpp, $(VBoxDD_SOURCES.freebsd)) \ 830 Serial/DrvHostSerialNew.cpp 831 832 VBoxDD_SOURCES.solaris := \ 833 $(filter-out Serial/DrvHostSerial.cpp, $(VBoxDD_SOURCES.solaris)) \ 834 Serial/DrvHostSerialNew.cpp 835 endif 815 836 816 837 # --- Final bits, mostly libraries for order dependant linkers. --- -
trunk/src/VBox/Devices/Serial/DrvHostSerialNew.cpp
r70762 r70800 33 33 #include <iprt/semaphore.h> 34 34 #include <iprt/uuid.h> 35 36 #if defined(RT_OS_LINUX) || defined(RT_OS_DARWIN) || defined(RT_OS_SOLARIS) || defined(RT_OS_FREEBSD) 37 # include <errno.h> 38 # ifdef RT_OS_SOLARIS 39 # include <sys/termios.h> 40 # else 41 # include <termios.h> 42 # endif 43 # include <sys/types.h> 44 # include <fcntl.h> 45 # include <string.h> 46 # include <unistd.h> 47 # ifdef RT_OS_DARWIN 48 # include <sys/select.h> 49 # else 50 # include <sys/poll.h> 51 # endif 52 # include <sys/ioctl.h> 53 # include <pthread.h> 54 55 # ifdef RT_OS_LINUX 56 /* 57 * TIOCM_LOOP is not defined in the above header files for some reason but in asm/termios.h. 58 * But inclusion of this file however leads to compilation errors because of redefinition of some 59 * structs. That's why it is defined here until a better solution is found. 60 */ 61 # ifndef TIOCM_LOOP 62 # define TIOCM_LOOP 0x8000 63 # endif 64 /* For linux custom baudrate code we also need serial_struct */ 65 # include <linux/serial.h> 66 # endif /* linux */ 67 68 #elif defined(RT_OS_WINDOWS) 69 # include <iprt/win/windows.h> 70 #endif 35 #include <iprt/serialport.h> 71 36 72 37 #include "VBoxDD.h" … … 90 55 /** Our char interface. */ 91 56 PDMICHARCONNECTOR ICharConnector; 92 /** Receive thread. */ 93 PPDMTHREAD pRecvThread; 94 /** Send thread. */ 95 PPDMTHREAD pSendThread; 96 /** Status lines monitor thread. */ 97 PPDMTHREAD pMonitorThread; 98 /** Send event semaphore */ 99 RTSEMEVENT SendSem; 100 57 /** I/O thread. */ 58 PPDMTHREAD pIoThrd; 59 /** The serial port handle. */ 60 RTSERIALPORT hSerialPort; 101 61 /** the device path */ 102 62 char *pszDevicePath; 103 63 104 #if defined(RT_OS_LINUX) || defined(RT_OS_DARWIN) || defined(RT_OS_SOLARIS) || defined(RT_OS_FREEBSD)105 /** the device handle */106 RTFILE hDeviceFile;107 # ifdef RT_OS_DARWIN108 /** The device handle used for reading.109 * Used to prevent the read select from blocking the writes. */110 RTFILE hDeviceFileR;111 # endif112 /** The read end of the control pipe */113 RTPIPE hWakeupPipeR;114 /** The write end of the control pipe */115 RTPIPE hWakeupPipeW;116 /** The current line status.117 * Used by the polling version of drvHostSerialMonitorThread. */118 int fStatusLines;119 #elif defined(RT_OS_WINDOWS)120 /** the device handle */121 HANDLE hDeviceFile;122 /** The event semaphore for waking up the receive thread */123 HANDLE hHaltEventSem;124 /** The event semaphore for overlapped receiving */125 HANDLE hEventRecv;126 /** For overlapped receiving */127 OVERLAPPED overlappedRecv;128 /** The event semaphore for overlapped sending */129 HANDLE hEventSend;130 /** For overlapped sending */131 OVERLAPPED overlappedSend;132 #endif133 64 134 65 /** Internal send FIFO queue */ … … 137 68 uint8_t Alignment[2]; 138 69 70 /** The read queue. */ 71 uint8_t abReadBuf[256]; 72 /** Read buffer currently used. */ 73 size_t cbReadBufUsed; 74 /** Current offset into the read buffer. */ 75 uint32_t offReadBuf; 76 139 77 /** Read/write statistics */ 140 78 STAMCOUNTER StatBytesRead; 141 79 STAMCOUNTER StatBytesWritten; 142 #ifdef RT_OS_DARWIN143 /** The number of bytes we've dropped because the send queue144 * was full. */145 STAMCOUNTER StatSendOverflows;146 #endif147 80 } DRVHOSTSERIAL, *PDRVHOSTSERIAL; 148 81 149 150 /** Converts a pointer to DRVCHAR::ICharConnector to a PDRVHOSTSERIAL. */151 #define PDMICHAR_2_DRVHOSTSERIAL(pInterface) RT_FROM_MEMBER(pInterface, DRVHOSTSERIAL, ICharConnector)152 82 153 83 … … 173 103 static DECLCALLBACK(int) drvHostSerialWrite(PPDMICHARCONNECTOR pInterface, const void *pvBuf, size_t cbWrite) 174 104 { 175 PDRVHOSTSERIAL pThis = PDMICHAR_2_DRVHOSTSERIAL(pInterface);105 PDRVHOSTSERIAL pThis = RT_FROM_MEMBER(pInterface, DRVHOSTSERIAL, ICharConnector); 176 106 const uint8_t *pbBuffer = (const uint8_t *)pvBuf; 177 107 … … 184 114 185 115 pThis->u8SendByte = pbBuffer[i]; 186 RTSe mEventSignal(pThis->SendSem);116 RTSerialPortEvtPollInterrupt(pThis->hSerialPort); 187 117 STAM_COUNTER_INC(&pThis->StatBytesWritten); 188 118 } … … 190 120 } 191 121 122 192 123 static DECLCALLBACK(int) drvHostSerialSetParameters(PPDMICHARCONNECTOR pInterface, unsigned Bps, char chParity, unsigned cDataBits, unsigned cStopBits) 193 124 { 194 PDRVHOSTSERIAL pThis = PDMICHAR_2_DRVHOSTSERIAL(pInterface); 195 #if defined(RT_OS_LINUX) || defined(RT_OS_DARWIN) || defined(RT_OS_SOLARIS) || defined(RT_OS_FREEBSD) 196 struct termios *termiosSetup; 197 int baud_rate; 198 #elif defined(RT_OS_WINDOWS) 199 LPDCB comSetup; 200 #endif 201 202 LogFlow(("%s: Bps=%u chParity=%c cDataBits=%u cStopBits=%u\n", __FUNCTION__, Bps, chParity, cDataBits, cStopBits)); 203 204 #if defined(RT_OS_LINUX) || defined(RT_OS_DARWIN) || defined(RT_OS_SOLARIS) || defined(RT_OS_FREEBSD) 205 termiosSetup = (struct termios *)RTMemTmpAllocZ(sizeof(struct termios)); 206 207 /* Enable receiver */ 208 termiosSetup->c_cflag |= (CLOCAL | CREAD); 209 210 switch (Bps) 211 { 212 case 50: 213 baud_rate = B50; 214 break; 215 case 75: 216 baud_rate = B75; 217 break; 218 case 110: 219 baud_rate = B110; 220 break; 221 case 134: 222 baud_rate = B134; 223 break; 224 case 150: 225 baud_rate = B150; 226 break; 227 case 200: 228 baud_rate = B200; 229 break; 230 case 300: 231 baud_rate = B300; 232 break; 233 case 600: 234 baud_rate = B600; 235 break; 236 case 1200: 237 baud_rate = B1200; 238 break; 239 case 1800: 240 baud_rate = B1800; 241 break; 242 case 2400: 243 baud_rate = B2400; 244 break; 245 case 4800: 246 baud_rate = B4800; 247 break; 248 case 9600: 249 baud_rate = B9600; 250 break; 251 case 19200: 252 baud_rate = B19200; 253 break; 254 case 38400: 255 baud_rate = B38400; 256 break; 257 case 57600: 258 baud_rate = B57600; 259 break; 260 case 115200: 261 baud_rate = B115200; 125 PDRVHOSTSERIAL pThis = RT_FROM_MEMBER(pInterface, DRVHOSTSERIAL, ICharConnector); 126 RTSERIALPORTCFG Cfg; 127 128 Cfg.uBaudRate = Bps; 129 130 switch (chParity) 131 { 132 case 'E': 133 Cfg.enmParity = RTSERIALPORTPARITY_EVEN; 134 break; 135 case 'O': 136 Cfg.enmParity = RTSERIALPORTPARITY_ODD; 137 break; 138 case 'N': 139 Cfg.enmParity = RTSERIALPORTPARITY_NONE; 262 140 break; 263 141 default: 264 #ifdef RT_OS_LINUX 265 struct serial_struct serialStruct; 266 if (ioctl(RTFileToNative(pThis->hDeviceFile), TIOCGSERIAL, &serialStruct) != -1) 267 { 268 serialStruct.custom_divisor = serialStruct.baud_base / Bps; 269 if (!serialStruct.custom_divisor) 270 serialStruct.custom_divisor = 1; 271 serialStruct.flags &= ~ASYNC_SPD_MASK; 272 serialStruct.flags |= ASYNC_SPD_CUST; 273 ioctl(RTFileToNative(pThis->hDeviceFile), TIOCSSERIAL, &serialStruct); 274 baud_rate = B38400; 275 } 276 else 277 baud_rate = B9600; 278 #else /* !RT_OS_LINUX */ 279 baud_rate = B9600; 280 #endif /* !RT_OS_LINUX */ 281 } 282 283 cfsetispeed(termiosSetup, baud_rate); 284 cfsetospeed(termiosSetup, baud_rate); 285 286 switch (chParity) 287 { 288 case 'E': 289 termiosSetup->c_cflag |= PARENB; 290 break; 291 case 'O': 292 termiosSetup->c_cflag |= (PARENB | PARODD); 293 break; 294 case 'N': 142 AssertMsgFailed(("Unsupported parity setting %c\n", chParity)); /* Should not happen. */ 143 Cfg.enmParity = RTSERIALPORTPARITY_NONE; 144 } 145 146 switch (cDataBits) 147 { 148 case 5: 149 Cfg.enmDataBitCount = RTSERIALPORTDATABITS_5BITS; 150 break; 151 case 6: 152 Cfg.enmDataBitCount = RTSERIALPORTDATABITS_6BITS; 153 break; 154 case 7: 155 Cfg.enmDataBitCount = RTSERIALPORTDATABITS_7BITS; 156 break; 157 case 8: 158 Cfg.enmDataBitCount = RTSERIALPORTDATABITS_8BITS; 295 159 break; 296 160 default: 297 break; 298 } 299 300 switch (cDataBits) 301 { 302 case 5: 303 termiosSetup->c_cflag |= CS5; 304 break; 305 case 6: 306 termiosSetup->c_cflag |= CS6; 307 break; 308 case 7: 309 termiosSetup->c_cflag |= CS7; 310 break; 311 case 8: 312 termiosSetup->c_cflag |= CS8; 313 break; 314 default: 315 break; 316 } 317 318 switch (cStopBits) 319 { 320 case 2: 321 termiosSetup->c_cflag |= CSTOPB; 322 default: 323 break; 324 } 325 326 /* set serial port to raw input */ 327 termiosSetup->c_lflag &= ~(ICANON | ECHO | ECHOE | ECHONL | ECHOK | ISIG | IEXTEN); 328 329 tcsetattr(RTFileToNative(pThis->hDeviceFile), TCSANOW, termiosSetup); 330 RTMemTmpFree(termiosSetup); 331 332 #ifdef RT_OS_LINUX 333 /* 334 * XXX In Linux, if a thread calls tcsetattr while the monitor thread is 335 * waiting in ioctl for a modem status change then 8250.c wrongly disables 336 * modem irqs and so the monitor thread never gets released. The workaround 337 * is to send a signal after each tcsetattr. 338 */ 339 if (RT_LIKELY(pThis->pMonitorThread != NULL)) 340 RTThreadPoke(pThis->pMonitorThread->Thread); 341 #endif 342 343 #elif defined(RT_OS_WINDOWS) 344 comSetup = (LPDCB)RTMemTmpAllocZ(sizeof(DCB)); 345 346 comSetup->DCBlength = sizeof(DCB); 347 348 switch (Bps) 349 { 350 case 110: 351 comSetup->BaudRate = CBR_110; 352 break; 353 case 300: 354 comSetup->BaudRate = CBR_300; 355 break; 356 case 600: 357 comSetup->BaudRate = CBR_600; 358 break; 359 case 1200: 360 comSetup->BaudRate = CBR_1200; 361 break; 362 case 2400: 363 comSetup->BaudRate = CBR_2400; 364 break; 365 case 4800: 366 comSetup->BaudRate = CBR_4800; 367 break; 368 case 9600: 369 comSetup->BaudRate = CBR_9600; 370 break; 371 case 14400: 372 comSetup->BaudRate = CBR_14400; 373 break; 374 case 19200: 375 comSetup->BaudRate = CBR_19200; 376 break; 377 case 38400: 378 comSetup->BaudRate = CBR_38400; 379 break; 380 case 57600: 381 comSetup->BaudRate = CBR_57600; 382 break; 383 case 115200: 384 comSetup->BaudRate = CBR_115200; 385 break; 386 default: 387 comSetup->BaudRate = CBR_9600; 388 } 389 390 comSetup->fBinary = TRUE; 391 comSetup->fOutxCtsFlow = FALSE; 392 comSetup->fOutxDsrFlow = FALSE; 393 comSetup->fDtrControl = DTR_CONTROL_DISABLE; 394 comSetup->fDsrSensitivity = FALSE; 395 comSetup->fTXContinueOnXoff = TRUE; 396 comSetup->fOutX = FALSE; 397 comSetup->fInX = FALSE; 398 comSetup->fErrorChar = FALSE; 399 comSetup->fNull = FALSE; 400 comSetup->fRtsControl = RTS_CONTROL_DISABLE; 401 comSetup->fAbortOnError = FALSE; 402 comSetup->wReserved = 0; 403 comSetup->XonLim = 5; 404 comSetup->XoffLim = 5; 405 comSetup->ByteSize = cDataBits; 406 407 switch (chParity) 408 { 409 case 'E': 410 comSetup->Parity = EVENPARITY; 411 break; 412 case 'O': 413 comSetup->Parity = ODDPARITY; 414 break; 415 case 'N': 416 comSetup->Parity = NOPARITY; 417 break; 418 default: 419 break; 420 } 421 422 switch (cStopBits) 423 { 424 case 1: 425 comSetup->StopBits = ONESTOPBIT; 426 break; 427 case 2: 428 comSetup->StopBits = TWOSTOPBITS; 429 break; 430 default: 431 break; 432 } 433 434 comSetup->XonChar = 0; 435 comSetup->XoffChar = 0; 436 comSetup->ErrorChar = 0; 437 comSetup->EofChar = 0; 438 comSetup->EvtChar = 0; 439 440 SetCommState(pThis->hDeviceFile, comSetup); 441 RTMemTmpFree(comSetup); 442 #endif /* RT_OS_WINDOWS */ 443 444 return VINF_SUCCESS; 161 AssertMsgFailed(("Unsupported data bit count %u\n", cDataBits)); /* Should not happen. */ 162 Cfg.enmDataBitCount = RTSERIALPORTDATABITS_8BITS; 163 } 164 165 if (cStopBits == 2) 166 Cfg.enmStopBitCount = RTSERIALPORTSTOPBITS_TWO; 167 else 168 Cfg.enmStopBitCount = RTSERIALPORTSTOPBITS_ONE; 169 170 int rc = RTSerialPortCfgSet(pThis->hSerialPort, &Cfg, NULL); 171 if (RT_FAILURE(rc)) 172 LogRelMax(10, ("HostSerial#%u: Failed to change settings to %u:%u%c%u (rc=%Rrc)\n", 173 pThis->pDrvIns->iInstance, Bps, cDataBits, chParity, cStopBits, rc)); 174 return rc; 445 175 } 446 176 … … 448 178 449 179 /** 450 * Sendthread loop.180 * I/O thread loop. 451 181 * 452 182 * @returns VINF_SUCCESS. … … 454 184 * @param pThread The PDM thread data. 455 185 */ 456 static DECLCALLBACK(int) drvHostSerial SendThread(PPDMDRVINS pDrvIns, PPDMTHREAD pThread)186 static DECLCALLBACK(int) drvHostSerialIoThread(PPDMDRVINS pDrvIns, PPDMTHREAD pThread) 457 187 { 458 188 PDRVHOSTSERIAL pThis = PDMINS_2_DATA(pDrvIns, PDRVHOSTSERIAL); … … 461 191 return VINF_SUCCESS; 462 192 463 #ifdef RT_OS_WINDOWS464 /* Make sure that the halt event semaphore is reset. */465 DWORD dwRet = WaitForSingleObject(pThis->hHaltEventSem, 0);466 467 HANDLE haWait[2];468 haWait[0] = pThis->hEventSend;469 haWait[1] = pThis->hHaltEventSem;470 #endif471 472 193 while (pThread->enmState == PDMTHREADSTATE_RUNNING) 473 194 { 474 int rc = RTSemEventWait(pThis->SendSem, RT_INDEFINITE_WAIT); 475 AssertRCBreak(rc); 476 477 /* 478 * Write the character to the host device. 479 */ 480 while (pThread->enmState == PDMTHREADSTATE_RUNNING) 195 if (pThis->offReadBuf < pThis->cbReadBufUsed) 481 196 { 482 /* copy the send queue so we get a linear buffer with the maximal size. */ 483 uint8_t ch = pThis->u8SendByte; 484 #if defined(RT_OS_LINUX) || defined(RT_OS_DARWIN) || defined(RT_OS_SOLARIS) || defined(RT_OS_FREEBSD) 485 486 size_t cbWritten; 487 rc = RTFileWrite(pThis->hDeviceFile, &ch, 1, &cbWritten); 488 if (rc == VERR_TRY_AGAIN) 489 cbWritten = 0; 490 if (cbWritten < 1 && (RT_SUCCESS(rc) || rc == VERR_TRY_AGAIN)) 197 /* Try to send data to the guest. */ 198 size_t cbProcessed = pThis->cbReadBufUsed - pThis->offReadBuf; 199 int rc = pThis->pDrvCharPort->pfnNotifyRead(pThis->pDrvCharPort, &pThis->abReadBuf[pThis->offReadBuf], &cbProcessed); 200 if (RT_SUCCESS(rc)) 491 201 { 492 /* ok, block till the device is ready for more (O_NONBLOCK) effect. */ 493 rc = VINF_SUCCESS; 494 while (pThread->enmState == PDMTHREADSTATE_RUNNING) 202 Assert(cbProcessed); Assert(cbProcessed <= pThis->cbReadBufUsed); 203 pThis->offReadBuf += cbProcessed; 204 STAM_COUNTER_ADD(&pThis->StatBytesRead, cbProcessed); 205 } 206 else if (rc != VERR_TIMEOUT) 207 LogRelMax(10, ("HostSerial#%d: NotifyRead failed with %Rrc, expect errorneous device behavior.\n", 208 pDrvIns->iInstance, rc)); 209 } 210 211 uint32_t fEvtFlags = RTSERIALPORT_EVT_F_STATUS_LINE_CHANGED | RTSERIALPORT_EVT_F_BREAK_DETECTED; 212 213 /* Wait until there is room again if there is anyting to send. */ 214 if (pThis->fSending) 215 fEvtFlags |= RTSERIALPORT_EVT_F_DATA_TX; 216 217 /* Try to receive more if there is still room. */ 218 if (pThis->cbReadBufUsed < sizeof(pThis->abReadBuf)) 219 fEvtFlags |= RTSERIALPORT_EVT_F_DATA_RX; 220 221 uint32_t fEvtsRecv = 0; 222 int rc = RTSerialPortEvtPoll(pThis->hSerialPort, fEvtFlags, &fEvtsRecv, 223 pThis->offReadBuf < pThis->cbReadBufUsed ? 100 : RT_INDEFINITE_WAIT); 224 if (RT_SUCCESS(rc)) 225 { 226 if (fEvtsRecv & RTSERIALPORT_EVT_F_DATA_TX) 227 { 228 Assert(pThis->fSending); 229 size_t cbWritten = 0; 230 uint8_t bSend = pThis->u8SendByte; 231 rc = RTSerialPortWriteNB(pThis->hSerialPort, &bSend, 1, &cbWritten); 232 if (RT_SUCCESS(rc)) 495 233 { 496 /* wait */ 497 fd_set WrSet; 498 FD_ZERO(&WrSet); 499 FD_SET(RTFileToNative(pThis->hDeviceFile), &WrSet); 500 fd_set XcptSet; 501 FD_ZERO(&XcptSet); 502 FD_SET(RTFileToNative(pThis->hDeviceFile), &XcptSet); 503 # ifdef DEBUG 504 uint64_t u64Now = RTTimeMilliTS(); 505 # endif 506 rc = select(RTFileToNative(pThis->hDeviceFile) + 1, NULL, &WrSet, &XcptSet, NULL); 507 /** @todo check rc? */ 508 509 # ifdef DEBUG 510 Log2(("select wait for %dms\n", RTTimeMilliTS() - u64Now)); 511 # endif 512 /* try write more */ 513 rc = RTFileWrite(pThis->hDeviceFile, &ch, 1, &cbWritten); 514 if (rc == VERR_TRY_AGAIN) 515 cbWritten = 0; 516 else if (RT_FAILURE(rc)) 517 break; 518 else if (cbWritten >= 1) 519 break; 520 rc = VINF_SUCCESS; 521 } /* wait/write loop */ 234 Assert(cbWritten == 1); 235 ASMAtomicXchgBool(&pThis->fSending, false); 236 } 237 else 238 LogRelMax(10, ("HostSerial#%d: Sending data failed even though the serial port is marked as writeable (rc=%Rrc)\n", 239 pThis->pDrvIns->iInstance, rc)); 522 240 } 523 241 524 #elif defined(RT_OS_WINDOWS) 525 /* perform an overlapped write operation. */ 526 DWORD cbWritten; 527 memset(&pThis->overlappedSend, 0, sizeof(pThis->overlappedSend)); 528 pThis->overlappedSend.hEvent = pThis->hEventSend; 529 if (!WriteFile(pThis->hDeviceFile, &ch, 1, &cbWritten, &pThis->overlappedSend)) 242 if (fEvtsRecv & RTSERIALPORT_EVT_F_DATA_RX) 530 243 { 531 dwRet = GetLastError();532 if ( dwRet == ERROR_IO_PENDING)244 /* Move all remaining data in the buffer to the front to make up as much room as possible. */ 245 if (pThis->offReadBuf) 533 246 { 534 /* 535 * write blocked, wait for completion or wakeup... 536 */ 537 dwRet = WaitForMultipleObjects(2, haWait, FALSE, INFINITE); 538 if (dwRet != WAIT_OBJECT_0) 247 memmove(&pThis->abReadBuf[0], &pThis->abReadBuf[pThis->offReadBuf], pThis->cbReadBufUsed - pThis->offReadBuf); 248 pThis->cbReadBufUsed -= pThis->offReadBuf; 249 pThis->offReadBuf = 0; 250 } 251 size_t cbToRead = sizeof(pThis->abReadBuf) - pThis->cbReadBufUsed; 252 size_t cbRead = 0; 253 rc = RTSerialPortReadNB(pThis->hSerialPort, &pThis->abReadBuf[pThis->cbReadBufUsed], cbToRead, &cbRead); 254 if (RT_SUCCESS(rc)) 255 pThis->cbReadBufUsed += cbRead; 256 else 257 LogRelMax(10, ("HostSerial#%d: Reading data failed even though the serial port is marked as readable (rc=%Rrc)\n", 258 pThis->pDrvIns->iInstance, rc)); 259 } 260 261 if (fEvtsRecv & RTSERIALPORT_EVT_F_BREAK_DETECTED) 262 pThis->pDrvCharPort->pfnNotifyBreak(pThis->pDrvCharPort); 263 264 if (fEvtsRecv & RTSERIALPORT_EVT_F_STATUS_LINE_CHANGED) 265 { 266 /* The status lines have changed. Notify the device. */ 267 uint32_t fStsLines = 0; 268 rc = RTSerialPortQueryStatusLines(pThis->hSerialPort, &fStsLines); 269 if (RT_SUCCESS(rc)) 270 { 271 uint32_t fPdmStsLines = 0; 272 273 if (fStsLines & RTSERIALPORT_STS_LINE_DCD) 274 fPdmStsLines |= PDMICHARPORT_STATUS_LINES_DCD; 275 if (fStsLines & RTSERIALPORT_STS_LINE_RI) 276 fPdmStsLines |= PDMICHARPORT_STATUS_LINES_RI; 277 if (fStsLines & RTSERIALPORT_STS_LINE_DSR) 278 fPdmStsLines |= PDMICHARPORT_STATUS_LINES_DSR; 279 if (fStsLines & RTSERIALPORT_STS_LINE_CTS) 280 fPdmStsLines |= PDMICHARPORT_STATUS_LINES_CTS; 281 282 rc = pThis->pDrvCharPort->pfnNotifyStatusLinesChanged(pThis->pDrvCharPort, fPdmStsLines); 283 if (RT_FAILURE(rc)) 539 284 { 540 AssertMsg(pThread->enmState != PDMTHREADSTATE_RUNNING, ("The halt event semaphore is set but the thread is still in running state\n")); 541 break; 285 /* Notifying device failed, continue but log it */ 286 LogRelMax(10, ("HostSerial#%d: Notifying device about changed status lines failed with error %Rrc; continuing.\n", 287 pDrvIns->iInstance, rc)); 542 288 } 543 289 } 544 290 else 545 rc = RTErrConvertFromWin32(dwRet);291 LogRelMax(10, ("HostSerial#%d: Getting status lines state failed with error %Rrc; continuing.\n", pDrvIns->iInstance, rc)); 546 292 } 547 293 548 #endif /* RT_OS_WINDOWS */ 549 if (RT_FAILURE(rc)) 550 { 551 LogRel(("HostSerial#%d: Serial Write failed with %Rrc; terminating send thread\n", pDrvIns->iInstance, rc)); 552 return rc; 553 } 554 ASMAtomicXchgBool(&pThis->fSending, false); 555 break; 556 } /* write loop */ 294 if (fEvtsRecv & RTSERIALPORT_EVT_F_STATUS_LINE_MONITOR_FAILED) 295 LogRel(("HostSerial#%d: Status line monitoring failed at a lower level and is disabled\n", pDrvIns->iInstance)); 296 } 297 else if (rc == VERR_TIMEOUT || rc == VERR_INTERRUPTED) 298 { 299 /* Getting interrupted or running into a timeout are no error conditions. */ 300 rc = VINF_SUCCESS; 301 } 557 302 } 558 303 559 304 return VINF_SUCCESS; 560 305 } 306 561 307 562 308 /** … … 567 313 * @param pThread The send thread. 568 314 */ 569 static DECLCALLBACK(int) drvHostSerialWakeup SendThread(PPDMDRVINS pDrvIns, PPDMTHREAD pThread)315 static DECLCALLBACK(int) drvHostSerialWakeupIoThread(PPDMDRVINS pDrvIns, PPDMTHREAD pThread) 570 316 { 571 317 RT_NOREF(pThread); 572 318 PDRVHOSTSERIAL pThis = PDMINS_2_DATA(pDrvIns, PDRVHOSTSERIAL); 573 int rc; 574 575 rc = RTSemEventSignal(pThis->SendSem); 576 if (RT_FAILURE(rc)) 577 return rc; 578 579 #ifdef RT_OS_WINDOWS 580 if (!SetEvent(pThis->hHaltEventSem)) 581 return RTErrConvertFromWin32(GetLastError()); 582 #endif 583 584 return VINF_SUCCESS; 585 } 586 587 /* -=-=-=-=- receive thread -=-=-=-=- */ 588 589 /** 590 * Receive thread loop. 591 * 592 * This thread pushes data from the host serial device up the driver 593 * chain toward the serial device. 594 * 595 * @returns VINF_SUCCESS. 596 * @param pDrvIns PDM driver instance data. 597 * @param pThread The PDM thread data. 598 */ 599 static DECLCALLBACK(int) drvHostSerialRecvThread(PPDMDRVINS pDrvIns, PPDMTHREAD pThread) 600 { 601 PDRVHOSTSERIAL pThis = PDMINS_2_DATA(pDrvIns, PDRVHOSTSERIAL); 602 uint8_t abBuffer[256]; 603 uint8_t *pbBuffer = NULL; 604 size_t cbRemaining = 0; /* start by reading host data */ 605 int rc = VINF_SUCCESS; 606 int rcThread = VINF_SUCCESS; 607 608 if (pThread->enmState == PDMTHREADSTATE_INITIALIZING) 609 return VINF_SUCCESS; 610 611 #ifdef RT_OS_WINDOWS 612 /* Make sure that the halt event semaphore is reset. */ 613 DWORD dwRet = WaitForSingleObject(pThis->hHaltEventSem, 0); 614 615 HANDLE ahWait[2]; 616 ahWait[0] = pThis->hEventRecv; 617 ahWait[1] = pThis->hHaltEventSem; 618 #endif 619 620 while (pThread->enmState == PDMTHREADSTATE_RUNNING) 621 { 622 if (!cbRemaining) 623 { 624 /* Get a block of data from the host serial device. */ 625 626 #if defined(RT_OS_DARWIN) /* poll is broken on x86 darwin, returns POLLNVAL. */ 627 fd_set RdSet; 628 FD_ZERO(&RdSet); 629 FD_SET(RTFileToNative(pThis->hDeviceFileR), &RdSet); 630 FD_SET(RTPipeToNative(pThis->hWakeupPipeR), &RdSet); 631 fd_set XcptSet; 632 FD_ZERO(&XcptSet); 633 FD_SET(RTFileToNative(pThis->hDeviceFile), &XcptSet); 634 FD_SET(RTPipeToNative(pThis->hWakeupPipeR), &XcptSet); 635 # if 1 /* it seems like this select is blocking the write... */ 636 rc = select(RT_MAX(RTPipeToNative(pThis->hWakeupPipeR), RTFileToNative(pThis->hDeviceFileR)) + 1, 637 &RdSet, NULL, &XcptSet, NULL); 638 # else 639 struct timeval tv = { 0, 1000 }; 640 rc = select(RTPipeToNative(pThis->hWakeupPipeR), RTFileToNative(pThis->hDeviceFileR) + 1, 641 &RdSet, NULL, &XcptSet, &tv); 642 # endif 643 if (rc == -1) 644 { 645 int err = errno; 646 rcThread = RTErrConvertFromErrno(err); 647 LogRel(("HostSerial#%d: select failed with errno=%d / %Rrc, terminating the worker thread.\n", pDrvIns->iInstance, err, rcThread)); 648 break; 649 } 650 651 /* this might have changed in the meantime */ 652 if (pThread->enmState != PDMTHREADSTATE_RUNNING) 653 break; 654 if (rc == 0) 655 continue; 656 657 /* drain the wakeup pipe */ 658 size_t cbRead; 659 if ( FD_ISSET(RTPipeToNative(pThis->hWakeupPipeR), &RdSet) 660 || FD_ISSET(RTPipeToNative(pThis->hWakeupPipeR), &XcptSet)) 661 { 662 rc = RTPipeRead(pThis->hWakeupPipeR, abBuffer, 1, &cbRead); 663 if (RT_FAILURE(rc)) 664 { 665 LogRel(("HostSerial#%d: draining the wakeup pipe failed with %Rrc, terminating the worker thread.\n", pDrvIns->iInstance, rc)); 666 rcThread = rc; 667 break; 668 } 669 continue; 670 } 671 672 /* read data from the serial port. */ 673 rc = RTFileRead(pThis->hDeviceFileR, abBuffer, sizeof(abBuffer), &cbRead); 674 if (RT_FAILURE(rc)) 675 { 676 LogRel(("HostSerial#%d: (1) Read failed with %Rrc, terminating the worker thread.\n", pDrvIns->iInstance, rc)); 677 rcThread = rc; 678 break; 679 } 680 cbRemaining = cbRead; 681 682 #elif defined(RT_OS_LINUX) || defined(RT_OS_SOLARIS) || defined(RT_OS_FREEBSD) 683 684 size_t cbRead; 685 struct pollfd aFDs[2]; 686 aFDs[0].fd = RTFileToNative(pThis->hDeviceFile); 687 aFDs[0].events = POLLIN; 688 aFDs[0].revents = 0; 689 aFDs[1].fd = RTPipeToNative(pThis->hWakeupPipeR); 690 aFDs[1].events = POLLIN | POLLERR | POLLHUP; 691 aFDs[1].revents = 0; 692 rc = poll(aFDs, RT_ELEMENTS(aFDs), -1); 693 if (rc < 0) 694 { 695 int err = errno; 696 if (err == EINTR) 697 { 698 /* 699 * EINTR errors should be harmless, even if they are not supposed to occur in our setup. 700 */ 701 Log(("rc=%d revents=%#x,%#x errno=%p %s\n", rc, aFDs[0].revents, aFDs[1].revents, err, strerror(err))); 702 RTThreadYield(); 703 continue; 704 } 705 706 rcThread = RTErrConvertFromErrno(err); 707 LogRel(("HostSerial#%d: poll failed with errno=%d / %Rrc, terminating the worker thread.\n", pDrvIns->iInstance, err, rcThread)); 708 break; 709 } 710 /* this might have changed in the meantime */ 711 if (pThread->enmState != PDMTHREADSTATE_RUNNING) 712 break; 713 if (rc > 0 && aFDs[1].revents) 714 { 715 if (aFDs[1].revents & (POLLHUP | POLLERR | POLLNVAL)) 716 break; 717 /* notification to terminate -- drain the pipe */ 718 RTPipeRead(pThis->hWakeupPipeR, &abBuffer, 1, &cbRead); 719 continue; 720 } 721 rc = RTFileRead(pThis->hDeviceFile, abBuffer, sizeof(abBuffer), &cbRead); 722 if (RT_FAILURE(rc)) 723 { 724 /* don't terminate worker thread when data unavailable */ 725 if (rc == VERR_TRY_AGAIN) 726 continue; 727 728 LogRel(("HostSerial#%d: (2) Read failed with %Rrc, terminating the worker thread.\n", pDrvIns->iInstance, rc)); 729 rcThread = rc; 730 break; 731 } 732 cbRemaining = cbRead; 733 734 #elif defined(RT_OS_WINDOWS) 735 736 DWORD dwEventMask = 0; 737 DWORD dwNumberOfBytesTransferred; 738 739 memset(&pThis->overlappedRecv, 0, sizeof(pThis->overlappedRecv)); 740 pThis->overlappedRecv.hEvent = pThis->hEventRecv; 741 742 if (!WaitCommEvent(pThis->hDeviceFile, &dwEventMask, &pThis->overlappedRecv)) 743 { 744 dwRet = GetLastError(); 745 if (dwRet == ERROR_IO_PENDING) 746 { 747 dwRet = WaitForMultipleObjects(2, ahWait, FALSE, INFINITE); 748 if (dwRet != WAIT_OBJECT_0) 749 { 750 /* notification to terminate */ 751 AssertMsg(pThread->enmState != PDMTHREADSTATE_RUNNING, ("The halt event semaphore is set but the thread is still in running state\n")); 752 break; 753 } 754 } 755 else 756 { 757 rcThread = RTErrConvertFromWin32(dwRet); 758 LogRel(("HostSerial#%d: Wait failed with error %Rrc; terminating the worker thread.\n", pDrvIns->iInstance, rcThread)); 759 break; 760 } 761 } 762 /* this might have changed in the meantime */ 763 if (pThread->enmState != PDMTHREADSTATE_RUNNING) 764 break; 765 766 /* Check the event */ 767 if (dwEventMask & EV_RXCHAR) 768 { 769 if (!ReadFile(pThis->hDeviceFile, abBuffer, sizeof(abBuffer), &dwNumberOfBytesTransferred, &pThis->overlappedRecv)) 770 { 771 dwRet = GetLastError(); 772 if (dwRet == ERROR_IO_PENDING) 773 { 774 if (GetOverlappedResult(pThis->hDeviceFile, &pThis->overlappedRecv, &dwNumberOfBytesTransferred, TRUE)) 775 dwRet = NO_ERROR; 776 else 777 dwRet = GetLastError(); 778 } 779 if (dwRet != NO_ERROR) 780 { 781 rcThread = RTErrConvertFromWin32(dwRet); 782 LogRel(("HostSerial#%d: Read failed with error %Rrc; terminating the worker thread.\n", pDrvIns->iInstance, rcThread)); 783 break; 784 } 785 } 786 cbRemaining = dwNumberOfBytesTransferred; 787 } 788 else if (dwEventMask & EV_BREAK) 789 { 790 Log(("HostSerial#%d: Detected break\n")); 791 rc = pThis->pDrvCharPort->pfnNotifyBreak(pThis->pDrvCharPort); 792 } 793 else 794 { 795 /* The status lines have changed. Notify the device. */ 796 DWORD dwNewStatusLinesState = 0; 797 uint32_t uNewStatusLinesState = 0; 798 799 /* Get the new state */ 800 if (GetCommModemStatus(pThis->hDeviceFile, &dwNewStatusLinesState)) 801 { 802 if (dwNewStatusLinesState & MS_RLSD_ON) 803 uNewStatusLinesState |= PDMICHARPORT_STATUS_LINES_DCD; 804 if (dwNewStatusLinesState & MS_RING_ON) 805 uNewStatusLinesState |= PDMICHARPORT_STATUS_LINES_RI; 806 if (dwNewStatusLinesState & MS_DSR_ON) 807 uNewStatusLinesState |= PDMICHARPORT_STATUS_LINES_DSR; 808 if (dwNewStatusLinesState & MS_CTS_ON) 809 uNewStatusLinesState |= PDMICHARPORT_STATUS_LINES_CTS; 810 rc = pThis->pDrvCharPort->pfnNotifyStatusLinesChanged(pThis->pDrvCharPort, uNewStatusLinesState); 811 if (RT_FAILURE(rc)) 812 { 813 /* Notifying device failed, continue but log it */ 814 LogRel(("HostSerial#%d: Notifying device failed with error %Rrc; continuing.\n", pDrvIns->iInstance, rc)); 815 } 816 } 817 else 818 { 819 /* Getting new state failed, continue but log it */ 820 LogRel(("HostSerial#%d: Getting status lines state failed with error %Rrc; continuing.\n", pDrvIns->iInstance, RTErrConvertFromWin32(GetLastError()))); 821 } 822 } 823 #endif 824 825 Log(("Read %d bytes.\n", cbRemaining)); 826 pbBuffer = abBuffer; 827 } 828 else 829 { 830 /* Send data to the guest. */ 831 size_t cbProcessed = cbRemaining; 832 rc = pThis->pDrvCharPort->pfnNotifyRead(pThis->pDrvCharPort, pbBuffer, &cbProcessed); 833 if (RT_SUCCESS(rc)) 834 { 835 Assert(cbProcessed); Assert(cbProcessed <= cbRemaining); 836 pbBuffer += cbProcessed; 837 cbRemaining -= cbProcessed; 838 STAM_COUNTER_ADD(&pThis->StatBytesRead, cbProcessed); 839 } 840 else if (rc == VERR_TIMEOUT) 841 { 842 /* Normal case, just means that the guest didn't accept a new 843 * character before the timeout elapsed. Just retry. */ 844 rc = VINF_SUCCESS; 845 } 846 else 847 { 848 LogRel(("HostSerial#%d: NotifyRead failed with %Rrc, terminating the worker thread.\n", pDrvIns->iInstance, rc)); 849 rcThread = rc; 850 break; 851 } 852 } 853 } 854 855 return rcThread; 856 } 857 858 /** 859 * Unblock the receive thread so it can respond to a state change. 860 * 861 * @returns a VBox status code. 862 * @param pDrvIns The driver instance. 863 * @param pThread The receive thread. 864 */ 865 static DECLCALLBACK(int) drvHostSerialWakeupRecvThread(PPDMDRVINS pDrvIns, PPDMTHREAD pThread) 866 { 867 RT_NOREF(pThread); 868 PDRVHOSTSERIAL pThis = PDMINS_2_DATA(pDrvIns, PDRVHOSTSERIAL); 869 #if defined(RT_OS_LINUX) || defined(RT_OS_DARWIN) || defined(RT_OS_SOLARIS) || defined(RT_OS_FREEBSD) 870 size_t cbIgnored; 871 return RTPipeWrite(pThis->hWakeupPipeW, "", 1, &cbIgnored); 872 873 #elif defined(RT_OS_WINDOWS) 874 if (!SetEvent(pThis->hHaltEventSem)) 875 return RTErrConvertFromWin32(GetLastError()); 876 return VINF_SUCCESS; 877 #else 878 # error adapt me! 879 #endif 880 } 881 882 #if defined(RT_OS_LINUX) || defined(RT_OS_DARWIN) || defined(RT_OS_SOLARIS) || defined(RT_OS_FREEBSD) 883 /* -=-=-=-=- Monitor thread -=-=-=-=- */ 884 885 /** 886 * Monitor thread loop. 887 * 888 * This thread monitors the status lines and notifies the device 889 * if they change. 890 * 891 * @returns VINF_SUCCESS. 892 * @param pDrvIns PDM driver instance data. 893 * @param pThread The PDM thread data. 894 */ 895 static DECLCALLBACK(int) drvHostSerialMonitorThread(PPDMDRVINS pDrvIns, PPDMTHREAD pThread) 896 { 897 PDRVHOSTSERIAL pThis = PDMINS_2_DATA(pDrvIns, PDRVHOSTSERIAL); 898 unsigned long const uStatusLinesToCheck = TIOCM_CAR | TIOCM_RNG | TIOCM_DSR | TIOCM_CTS; 899 #ifdef RT_OS_LINUX 900 bool fPoll = false; 901 #endif 902 903 if (pThread->enmState == PDMTHREADSTATE_INITIALIZING) 904 return VINF_SUCCESS; 905 906 do 907 { 908 unsigned int statusLines; 909 910 /* 911 * Get the status line state. 912 */ 913 int rcPsx = ioctl(RTFileToNative(pThis->hDeviceFile), TIOCMGET, &statusLines); 914 if (rcPsx < 0) 915 { 916 PDMDrvHlpVMSetRuntimeError(pDrvIns, 0 /*fFlags*/, "DrvHostSerialFail", 917 N_("Ioctl failed for serial host device '%s' (%Rrc). The device will not work properly"), 918 pThis->pszDevicePath, RTErrConvertFromErrno(errno)); 919 break; 920 } 921 922 uint32_t newStatusLine = 0; 923 924 if (statusLines & TIOCM_CAR) 925 newStatusLine |= PDMICHARPORT_STATUS_LINES_DCD; 926 if (statusLines & TIOCM_RNG) 927 newStatusLine |= PDMICHARPORT_STATUS_LINES_RI; 928 if (statusLines & TIOCM_DSR) 929 newStatusLine |= PDMICHARPORT_STATUS_LINES_DSR; 930 if (statusLines & TIOCM_CTS) 931 newStatusLine |= PDMICHARPORT_STATUS_LINES_CTS; 932 pThis->pDrvCharPort->pfnNotifyStatusLinesChanged(pThis->pDrvCharPort, newStatusLine); 933 934 if (PDMTHREADSTATE_RUNNING != pThread->enmState) 935 break; 936 937 # ifdef RT_OS_LINUX 938 /* 939 * Wait for status line change. 940 * 941 * XXX In Linux, if a thread calls tcsetattr while the monitor thread is 942 * waiting in ioctl for a modem status change then 8250.c wrongly disables 943 * modem irqs and so the monitor thread never gets released. The workaround 944 * is to send a signal after each tcsetattr. 945 * 946 * TIOCMIWAIT doesn't work for the DSR line with TIOCM_DSR set 947 * (see http://lxr.linux.no/#linux+v4.7/drivers/usb/class/cdc-acm.c#L949) 948 * However as it is possible to query the line state we will not just clear 949 * the TIOCM_DSR bit from the lines to check but resort to the polling 950 * approach just like on other hosts. 951 */ 952 if (!fPoll) 953 { 954 rcPsx = ioctl(RTFileToNative(pThis->hDeviceFile), TIOCMIWAIT, uStatusLinesToCheck); 955 if (rcPsx < 0 && errno != EINTR) 956 { 957 LogRel(("Serial#%u: Failed to wait for status line change with rcPsx=%d errno=%d, switch to polling\n", 958 pDrvIns->iInstance, rcPsx, errno)); 959 fPoll = true; 960 pThis->fStatusLines = statusLines; 961 } 962 } 963 else 964 { 965 /* Poll for status line change. */ 966 if (!((statusLines ^ pThis->fStatusLines) & uStatusLinesToCheck)) 967 PDMR3ThreadSleep(pThread, 500); /* 0.5 sec */ 968 pThis->fStatusLines = statusLines; 969 } 970 # else 971 /* Poll for status line change. */ 972 if (!((statusLines ^ pThis->fStatusLines) & uStatusLinesToCheck)) 973 PDMR3ThreadSleep(pThread, 500); /* 0.5 sec */ 974 pThis->fStatusLines = statusLines; 975 # endif 976 } while (PDMTHREADSTATE_RUNNING == pThread->enmState); 977 978 return VINF_SUCCESS; 979 } 980 981 /** 982 * Unblock the monitor thread so it can respond to a state change. 983 * We need to execute this code exactly once during initialization. 984 * But we don't want to block --- therefore this dedicated thread. 985 * 986 * @returns a VBox status code. 987 * @param pDrvIns The driver instance. 988 * @param pThread The send thread. 989 */ 990 static DECLCALLBACK(int) drvHostSerialWakeupMonitorThread(PPDMDRVINS pDrvIns, PPDMTHREAD pThread) 991 { 992 # ifdef RT_OS_LINUX 993 PDRVHOSTSERIAL pThis = PDMINS_2_DATA(pDrvIns, PDRVHOSTSERIAL); 994 int rc = VINF_SUCCESS; 995 996 rc = RTThreadPoke(pThread->Thread); 997 if (RT_FAILURE(rc)) 998 PDMDrvHlpVMSetRuntimeError(pDrvIns, 0 /*fFlags*/, "DrvHostSerialFail", 999 N_("Suspending serial monitor thread failed for serial device '%s' (%Rrc). The shutdown may take longer than expected"), 1000 pThis->pszDevicePath, RTErrConvertFromErrno(rc)); 1001 1002 # else /* !RT_OS_LINUX*/ 1003 1004 /* In polling mode there is nobody to wake up (PDMThread will cancel the sleep). */ 1005 NOREF(pDrvIns); 1006 NOREF(pThread); 1007 1008 # endif /* RT_OS_LINUX */ 1009 1010 return VINF_SUCCESS; 1011 } 1012 #endif /* RT_OS_LINUX || RT_OS_DARWIN || RT_OS_SOLARIS */ 319 320 return RTSerialPortEvtPollInterrupt(pThis->hSerialPort);; 321 } 322 1013 323 1014 324 /** … … 1017 327 * @returns VBox status code 1018 328 * @param pInterface Pointer to the interface structure. 1019 * @param RequestToSend Set to true if this control line should be made active. 1020 * @param DataTerminalReady Set to true if this control line should be made active. 1021 */ 1022 static DECLCALLBACK(int) drvHostSerialSetModemLines(PPDMICHARCONNECTOR pInterface, bool RequestToSend, bool DataTerminalReady) 1023 { 1024 PDRVHOSTSERIAL pThis = PDMICHAR_2_DRVHOSTSERIAL(pInterface); 1025 1026 #if defined(RT_OS_LINUX) || defined(RT_OS_DARWIN) || defined(RT_OS_SOLARIS) || defined(RT_OS_FREEBSD) 1027 int modemStateSet = 0; 1028 int modemStateClear = 0; 1029 1030 if (RequestToSend) 1031 modemStateSet |= TIOCM_RTS; 329 * @param fRts Set to true if this control line should be made active. 330 * @param fDtr Set to true if this control line should be made active. 331 */ 332 static DECLCALLBACK(int) drvHostSerialSetModemLines(PPDMICHARCONNECTOR pInterface, bool fRts, bool fDtr) 333 { 334 PDRVHOSTSERIAL pThis = RT_FROM_MEMBER(pInterface, DRVHOSTSERIAL, ICharConnector); 335 336 uint32_t fClear = 0; 337 uint32_t fSet = 0; 338 339 if (fRts) 340 fSet |= RTSERIALPORT_CHG_STS_LINES_F_RTS; 1032 341 else 1033 modemStateClear |= TIOCM_RTS;1034 1035 if ( DataTerminalReady)1036 modemStateSet |= TIOCM_DTR;342 fClear |= RTSERIALPORT_CHG_STS_LINES_F_RTS; 343 344 if (fDtr) 345 fSet |= RTSERIALPORT_CHG_STS_LINES_F_DTR; 1037 346 else 1038 modemStateClear |= TIOCM_DTR; 1039 1040 if (modemStateSet) 1041 ioctl(RTFileToNative(pThis->hDeviceFile), TIOCMBIS, &modemStateSet); 1042 1043 if (modemStateClear) 1044 ioctl(RTFileToNative(pThis->hDeviceFile), TIOCMBIC, &modemStateClear); 1045 1046 #elif defined(RT_OS_WINDOWS) 1047 if (RequestToSend) 1048 EscapeCommFunction(pThis->hDeviceFile, SETRTS); 1049 else 1050 EscapeCommFunction(pThis->hDeviceFile, CLRRTS); 1051 1052 if (DataTerminalReady) 1053 EscapeCommFunction(pThis->hDeviceFile, SETDTR); 1054 else 1055 EscapeCommFunction(pThis->hDeviceFile, CLRDTR); 1056 1057 #endif 1058 1059 return VINF_SUCCESS; 1060 } 347 fClear |= RTSERIALPORT_CHG_STS_LINES_F_DTR; 348 349 return RTSerialPortChgStatusLines(pThis->hSerialPort, fClear, fSet); 350 } 351 1061 352 1062 353 /** … … 1070 361 static DECLCALLBACK(int) drvHostSerialSetBreak(PPDMICHARCONNECTOR pInterface, bool fBreak) 1071 362 { 1072 PDRVHOSTSERIAL pThis = PDMICHAR_2_DRVHOSTSERIAL(pInterface); 1073 1074 #if defined(RT_OS_LINUX) || defined(RT_OS_DARWIN) || defined(RT_OS_SOLARIS) || defined(RT_OS_FREEBSD) 1075 if (fBreak) 1076 ioctl(RTFileToNative(pThis->hDeviceFile), TIOCSBRK); 1077 else 1078 ioctl(RTFileToNative(pThis->hDeviceFile), TIOCCBRK); 1079 1080 #elif defined(RT_OS_WINDOWS) 1081 if (fBreak) 1082 SetCommBreak(pThis->hDeviceFile); 1083 else 1084 ClearCommBreak(pThis->hDeviceFile); 1085 #endif 1086 1087 return VINF_SUCCESS; 1088 } 363 PDRVHOSTSERIAL pThis = RT_FROM_MEMBER(pInterface, DRVHOSTSERIAL, ICharConnector); 364 365 return RTSerialPortChgBreakCondition(pThis->hSerialPort, fBreak); 366 } 367 1089 368 1090 369 /* -=-=-=-=- driver interface -=-=-=-=- */ … … 1104 383 PDMDRV_CHECK_VERSIONS_RETURN_VOID(pDrvIns); 1105 384 1106 /* Empty the send queue */ 1107 if (pThis->SendSem != NIL_RTSEMEVENT) 1108 { 1109 RTSemEventDestroy(pThis->SendSem); 1110 pThis->SendSem = NIL_RTSEMEVENT; 1111 } 1112 1113 #if defined(RT_OS_LINUX) || defined(RT_OS_DARWIN) || defined(RT_OS_SOLARIS) || defined(RT_OS_FREEBSD) 1114 1115 int rc = RTPipeClose(pThis->hWakeupPipeW); AssertRC(rc); 1116 pThis->hWakeupPipeW = NIL_RTPIPE; 1117 rc = RTPipeClose(pThis->hWakeupPipeR); AssertRC(rc); 1118 pThis->hWakeupPipeR = NIL_RTPIPE; 1119 1120 # if defined(RT_OS_DARWIN) 1121 if (pThis->hDeviceFileR != NIL_RTFILE) 1122 { 1123 if (pThis->hDeviceFileR != pThis->hDeviceFile) 1124 { 1125 rc = RTFileClose(pThis->hDeviceFileR); 1126 AssertRC(rc); 1127 } 1128 pThis->hDeviceFileR = NIL_RTFILE; 1129 } 1130 # endif 1131 if (pThis->hDeviceFile != NIL_RTFILE) 1132 { 1133 rc = RTFileClose(pThis->hDeviceFile); AssertRC(rc); 1134 pThis->hDeviceFile = NIL_RTFILE; 1135 } 1136 1137 #elif defined(RT_OS_WINDOWS) 1138 CloseHandle(pThis->hEventRecv); 1139 CloseHandle(pThis->hEventSend); 1140 CancelIo(pThis->hDeviceFile); 1141 CloseHandle(pThis->hDeviceFile); 1142 1143 #endif 385 if (pThis->hSerialPort != NIL_RTSERIALPORT) 386 { 387 RTSerialPortClose(pThis->hSerialPort); 388 pThis->hSerialPort = NIL_RTSERIALPORT; 389 } 1144 390 1145 391 if (pThis->pszDevicePath) … … 1149 395 } 1150 396 } 397 1151 398 1152 399 /** … … 1165 412 * Init basic data members and interfaces. 1166 413 */ 1167 #if defined(RT_OS_LINUX) || defined(RT_OS_DARWIN) || defined(RT_OS_SOLARIS) || defined(RT_OS_FREEBSD) 1168 pThis->hDeviceFile = NIL_RTFILE; 1169 # ifdef RT_OS_DARWIN 1170 pThis->hDeviceFileR = NIL_RTFILE; 1171 # endif 1172 pThis->hWakeupPipeR = NIL_RTPIPE; 1173 pThis->hWakeupPipeW = NIL_RTPIPE; 1174 #elif defined(RT_OS_WINDOWS) 1175 pThis->hEventRecv = INVALID_HANDLE_VALUE; 1176 pThis->hEventSend = INVALID_HANDLE_VALUE; 1177 pThis->hDeviceFile = INVALID_HANDLE_VALUE; 1178 #endif 1179 pThis->SendSem = NIL_RTSEMEVENT; 414 pThis->hSerialPort = NIL_RTSERIALPORT; 415 pThis->offReadBuf = 0; 416 pThis->cbReadBufUsed = 0; 1180 417 /* IBase. */ 1181 418 pDrvIns->IBase.pfnQueryInterface = drvHostSerialQueryInterface; … … 1200 437 * Open the device 1201 438 */ 1202 #ifdef RT_OS_WINDOWS 1203 1204 pThis->hHaltEventSem = CreateEvent(NULL, FALSE, FALSE, NULL); 1205 AssertReturn(pThis->hHaltEventSem != NULL, VERR_NO_MEMORY); 1206 1207 pThis->hEventRecv = CreateEvent(NULL, FALSE, FALSE, NULL); 1208 AssertReturn(pThis->hEventRecv != NULL, VERR_NO_MEMORY); 1209 1210 pThis->hEventSend = CreateEvent(NULL, FALSE, FALSE, NULL); 1211 AssertReturn(pThis->hEventSend != NULL, VERR_NO_MEMORY); 1212 1213 HANDLE hFile = CreateFile(pThis->pszDevicePath, 1214 GENERIC_READ | GENERIC_WRITE, 1215 0, // must be opened with exclusive access 1216 NULL, // no SECURITY_ATTRIBUTES structure 1217 OPEN_EXISTING, // must use OPEN_EXISTING 1218 FILE_FLAG_OVERLAPPED, // overlapped I/O 1219 NULL); // no template file 1220 if (hFile == INVALID_HANDLE_VALUE) 1221 rc = RTErrConvertFromWin32(GetLastError()); 1222 else 1223 { 1224 pThis->hDeviceFile = hFile; 1225 /* for overlapped read */ 1226 if (!SetCommMask(hFile, EV_RXCHAR | EV_CTS | EV_DSR | EV_RING | EV_RLSD)) 1227 { 1228 LogRel(("HostSerial#%d: SetCommMask failed with error %d.\n", pDrvIns->iInstance, GetLastError())); 1229 return VERR_FILE_IO_ERROR; 1230 } 1231 rc = VINF_SUCCESS; 1232 } 1233 1234 #else /* !RT_OS_WINDOWS */ 1235 1236 uint32_t fOpen = RTFILE_O_READWRITE | RTFILE_O_OPEN | RTFILE_O_DENY_NONE; 1237 # ifdef RT_OS_LINUX 1238 /* This seems to be necessary on some Linux hosts, otherwise we hang here forever. */ 1239 fOpen |= RTFILE_O_NON_BLOCK; 1240 # endif 1241 rc = RTFileOpen(&pThis->hDeviceFile, pThis->pszDevicePath, fOpen); 1242 # ifdef RT_OS_LINUX 1243 /* RTFILE_O_NON_BLOCK not supported? */ 1244 if (rc == VERR_INVALID_PARAMETER) 1245 rc = RTFileOpen(&pThis->hDeviceFile, pThis->pszDevicePath, fOpen & ~RTFILE_O_NON_BLOCK); 1246 # endif 1247 # ifdef RT_OS_DARWIN 1248 if (RT_SUCCESS(rc)) 1249 rc = RTFileOpen(&pThis->hDeviceFileR, pThis->pszDevicePath, RTFILE_O_READ | RTFILE_O_OPEN | RTFILE_O_DENY_NONE); 1250 # endif 1251 1252 1253 #endif /* !RT_OS_WINDOWS */ 1254 439 uint32_t fOpenFlags = RTSERIALPORT_OPEN_F_READ 440 | RTSERIALPORT_OPEN_F_WRITE 441 | RTSERIALPORT_OPEN_F_SUPPORT_STATUS_LINE_MONITORING 442 | RTSERIALPORT_OPEN_F_DETECT_BREAK_CONDITION; 443 rc = RTSerialPortOpen(&pThis->hSerialPort, pThis->pszDevicePath, fOpenFlags); 1255 444 if (RT_FAILURE(rc)) 1256 445 { … … 1277 466 } 1278 467 1279 /* Set to non blocking I/O */1280 #if defined(RT_OS_LINUX) || defined(RT_OS_DARWIN) || defined(RT_OS_SOLARIS) || defined(RT_OS_FREEBSD)1281 1282 fcntl(RTFileToNative(pThis->hDeviceFile), F_SETFL, O_NONBLOCK);1283 # ifdef RT_OS_DARWIN1284 fcntl(RTFileToNative(pThis->hDeviceFileR), F_SETFL, O_NONBLOCK);1285 # endif1286 rc = RTPipeCreate(&pThis->hWakeupPipeR, &pThis->hWakeupPipeW, 0 /*fFlags*/);1287 AssertRCReturn(rc, rc);1288 1289 #elif defined(RT_OS_WINDOWS)1290 1291 /* Set the COMMTIMEOUTS to get non blocking I/O */1292 COMMTIMEOUTS comTimeout;1293 1294 comTimeout.ReadIntervalTimeout = MAXDWORD;1295 comTimeout.ReadTotalTimeoutMultiplier = 0;1296 comTimeout.ReadTotalTimeoutConstant = 0;1297 comTimeout.WriteTotalTimeoutMultiplier = 0;1298 comTimeout.WriteTotalTimeoutConstant = 0;1299 1300 SetCommTimeouts(pThis->hDeviceFile, &comTimeout);1301 1302 #endif1303 1304 468 /* 1305 469 * Get the ICharPort interface of the above driver/device. … … 1310 474 1311 475 /* 1312 * Create the receive, send and monitor threads plus the related send semaphore.476 * Create the I/O thread. 1313 477 */ 1314 rc = PDMDrvHlpThreadCreate(pDrvIns, &pThis->p RecvThread, pThis, drvHostSerialRecvThread, drvHostSerialWakeupRecvThread, 0, RTTHREADTYPE_IO, "SerRecv");478 rc = PDMDrvHlpThreadCreate(pDrvIns, &pThis->pIoThrd, pThis, drvHostSerialIoThread, drvHostSerialWakeupIoThread, 0, RTTHREADTYPE_IO, "SerIo"); 1315 479 if (RT_FAILURE(rc)) 1316 return PDMDrvHlpVMSetError(pDrvIns, rc, RT_SRC_POS, N_("HostSerial#%d cannot create receive thread"), pDrvIns->iInstance); 1317 1318 rc = RTSemEventCreate(&pThis->SendSem); 1319 AssertRC(rc); 1320 1321 rc = PDMDrvHlpThreadCreate(pDrvIns, &pThis->pSendThread, pThis, drvHostSerialSendThread, drvHostSerialWakeupSendThread, 0, RTTHREADTYPE_IO, "SerSend"); 1322 if (RT_FAILURE(rc)) 1323 return PDMDrvHlpVMSetError(pDrvIns, rc, RT_SRC_POS, N_("HostSerial#%d cannot create send thread"), pDrvIns->iInstance); 1324 1325 #if defined(RT_OS_LINUX) || defined(RT_OS_DARWIN) || defined(RT_OS_SOLARIS) || defined(RT_OS_FREEBSD) 1326 /* Linux & darwin needs a separate thread which monitors the status lines. */ 1327 int rcPsx = ioctl(RTFileToNative(pThis->hDeviceFile), TIOCMGET, &pThis->fStatusLines); 1328 if (!rcPsx) 1329 { 1330 rc = PDMDrvHlpThreadCreate(pDrvIns, &pThis->pMonitorThread, pThis, drvHostSerialMonitorThread, drvHostSerialWakeupMonitorThread, 0, RTTHREADTYPE_IO, "SerMon"); 1331 if (RT_FAILURE(rc)) 1332 return PDMDrvHlpVMSetError(pDrvIns, rc, RT_SRC_POS, N_("HostSerial#%d cannot create monitor thread"), pDrvIns->iInstance); 1333 } 1334 else 1335 { 1336 /* TIOCMGET is not supported for pseudo terminals so just silently skip it. */ 1337 if (errno != ENOTTY) 1338 PDMDrvHlpVMSetRuntimeError(pDrvIns, 0 /*fFlags*/, "DrvHostSerialFail", 1339 N_("Trying to get the status lines state failed for serial host device '%s' (%Rrc). The device will not work properly"), 1340 pThis->pszDevicePath, RTErrConvertFromErrno(errno)); 1341 } 1342 #endif 480 return PDMDrvHlpVMSetError(pDrvIns, rc, RT_SRC_POS, N_("HostSerial#%d cannot create I/O thread"), pDrvIns->iInstance); 1343 481 1344 482 /* … … 1347 485 PDMDrvHlpSTAMRegisterF(pDrvIns, &pThis->StatBytesWritten, STAMTYPE_COUNTER, STAMVISIBILITY_USED, STAMUNIT_BYTES, "Nr of bytes written", "/Devices/HostSerial%d/Written", pDrvIns->iInstance); 1348 486 PDMDrvHlpSTAMRegisterF(pDrvIns, &pThis->StatBytesRead, STAMTYPE_COUNTER, STAMVISIBILITY_USED, STAMUNIT_BYTES, "Nr of bytes read", "/Devices/HostSerial%d/Read", pDrvIns->iInstance); 1349 #ifdef RT_OS_DARWIN /* new Write code, not darwin specific. */1350 PDMDrvHlpSTAMRegisterF(pDrvIns, &pThis->StatSendOverflows, STAMTYPE_COUNTER, STAMVISIBILITY_USED, STAMUNIT_BYTES, "Nr of bytes overflowed", "/Devices/HostSerial%d/SendOverflow", pDrvIns->iInstance);1351 #endif1352 487 1353 488 return VINF_SUCCESS; … … 1367 502 /* szR0Mod */ 1368 503 "", 1369 /* pszDescription */504 /* pszDescription */ 1370 505 "Host serial driver.", 1371 506 /* fFlags */
Note:
See TracChangeset
for help on using the changeset viewer.