Changeset 83521 in vbox for trunk/src/VBox/Devices/Serial
- Timestamp:
- Apr 3, 2020 8:36:26 AM (5 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Devices/Serial/DrvHostSerial.cpp
r82968 r83521 62 62 /** the device path */ 63 63 char *pszDevicePath; 64 /** The active config of the serial port. */ 65 RTSERIALPORTCFG Cfg; 64 66 65 67 /** Flag whether data is available from the device/driver above as notified by the driver. */ … … 81 83 volatile size_t cbReadBuf; 82 84 85 /* Flag whether the host device ran into a fatal error condition and I/O is suspended 86 * until the nuext VM suspend/resume cycle where we will try again. */ 87 volatile bool fIoFatalErr; 88 /** Event semaphore the I/O thread is waiting on */ 89 RTSEMEVENT hSemEvtIoFatalErr; 90 83 91 /** Read/write statistics */ 84 92 STAMCOUNTER StatBytesRead; … … 186 194 187 195 196 /** 197 * Wakes up the serial port I/O thread. 198 * 199 * @returns VBox status code. 200 * @param pThis The host serial driver instance. 201 */ 202 static int drvHostSerialWakeupIoThread(PDRVHOSTSERIAL pThis) 203 { 204 205 if (RT_UNLIKELY(pThis->fIoFatalErr)) 206 return RTSemEventSignal(pThis->hSemEvtIoFatalErr); 207 208 return RTSerialPortEvtPollInterrupt(pThis->hSerialPort); 209 } 210 211 188 212 /* -=-=-=-=- IBase -=-=-=-=- */ 189 213 … … 212 236 bool fAvailOld = ASMAtomicXchgBool(&pThis->fAvailWrExt, true); 213 237 if (!fAvailOld) 214 rc = RTSerialPortEvtPollInterrupt(pThis->hSerialPort);238 rc = drvHostSerialWakeupIoThread(pThis); 215 239 216 240 return rc; … … 248 272 /* Kick the I/O thread if there is nothing to read to recalculate the poll flags. */ 249 273 if (!drvHostSerialReadBufGetRead(pThis, NULL)) 250 rc = RTSerialPortEvtPollInterrupt(pThis->hSerialPort);274 rc = drvHostSerialWakeupIoThread(pThis); 251 275 252 276 STAM_COUNTER_ADD(&pThis->StatBytesRead, cbReadAll); … … 263 287 { 264 288 PDRVHOSTSERIAL pThis = RT_FROM_MEMBER(pInterface, DRVHOSTSERIAL, ISerialConnector); 265 RTSERIALPORTCFG Cfg; 266 267 Cfg.uBaudRate = uBps; 289 290 pThis->Cfg.uBaudRate = uBps; 268 291 269 292 switch (enmParity) 270 293 { 271 294 case PDMSERIALPARITY_EVEN: 272 Cfg.enmParity = RTSERIALPORTPARITY_EVEN;295 pThis->Cfg.enmParity = RTSERIALPORTPARITY_EVEN; 273 296 break; 274 297 case PDMSERIALPARITY_ODD: 275 Cfg.enmParity = RTSERIALPORTPARITY_ODD;298 pThis->Cfg.enmParity = RTSERIALPORTPARITY_ODD; 276 299 break; 277 300 case PDMSERIALPARITY_NONE: 278 Cfg.enmParity = RTSERIALPORTPARITY_NONE;301 pThis->Cfg.enmParity = RTSERIALPORTPARITY_NONE; 279 302 break; 280 303 case PDMSERIALPARITY_MARK: 281 Cfg.enmParity = RTSERIALPORTPARITY_MARK;304 pThis->Cfg.enmParity = RTSERIALPORTPARITY_MARK; 282 305 break; 283 306 case PDMSERIALPARITY_SPACE: 284 Cfg.enmParity = RTSERIALPORTPARITY_SPACE;307 pThis->Cfg.enmParity = RTSERIALPORTPARITY_SPACE; 285 308 break; 286 309 default: 287 310 AssertMsgFailed(("Unsupported parity setting %d\n", enmParity)); /* Should not happen. */ 288 Cfg.enmParity = RTSERIALPORTPARITY_NONE;311 pThis->Cfg.enmParity = RTSERIALPORTPARITY_NONE; 289 312 } 290 313 … … 292 315 { 293 316 case 5: 294 Cfg.enmDataBitCount = RTSERIALPORTDATABITS_5BITS;317 pThis->Cfg.enmDataBitCount = RTSERIALPORTDATABITS_5BITS; 295 318 break; 296 319 case 6: 297 Cfg.enmDataBitCount = RTSERIALPORTDATABITS_6BITS;320 pThis->Cfg.enmDataBitCount = RTSERIALPORTDATABITS_6BITS; 298 321 break; 299 322 case 7: 300 Cfg.enmDataBitCount = RTSERIALPORTDATABITS_7BITS;323 pThis->Cfg.enmDataBitCount = RTSERIALPORTDATABITS_7BITS; 301 324 break; 302 325 case 8: 303 Cfg.enmDataBitCount = RTSERIALPORTDATABITS_8BITS;326 pThis->Cfg.enmDataBitCount = RTSERIALPORTDATABITS_8BITS; 304 327 break; 305 328 default: 306 329 AssertMsgFailed(("Unsupported data bit count %u\n", cDataBits)); /* Should not happen. */ 307 Cfg.enmDataBitCount = RTSERIALPORTDATABITS_8BITS;330 pThis->Cfg.enmDataBitCount = RTSERIALPORTDATABITS_8BITS; 308 331 } 309 332 … … 311 334 { 312 335 case PDMSERIALSTOPBITS_ONE: 313 Cfg.enmStopBitCount = RTSERIALPORTSTOPBITS_ONE;336 pThis->Cfg.enmStopBitCount = RTSERIALPORTSTOPBITS_ONE; 314 337 break; 315 338 case PDMSERIALSTOPBITS_ONEPOINTFIVE: 316 Cfg.enmStopBitCount = RTSERIALPORTSTOPBITS_ONEPOINTFIVE;339 pThis->Cfg.enmStopBitCount = RTSERIALPORTSTOPBITS_ONEPOINTFIVE; 317 340 break; 318 341 case PDMSERIALSTOPBITS_TWO: 319 Cfg.enmStopBitCount = RTSERIALPORTSTOPBITS_TWO;342 pThis->Cfg.enmStopBitCount = RTSERIALPORTSTOPBITS_TWO; 320 343 break; 321 344 default: 322 345 AssertMsgFailed(("Unsupported stop bit count %d\n", enmStopBits)); /* Should not happen. */ 323 Cfg.enmStopBitCount = RTSERIALPORTSTOPBITS_ONE;324 } 325 326 return RTSerialPortCfgSet(pThis->hSerialPort, & Cfg, NULL);346 pThis->Cfg.enmStopBitCount = RTSERIALPORTSTOPBITS_ONE; 347 } 348 349 return RTSerialPortCfgSet(pThis->hSerialPort, &pThis->Cfg, NULL); 327 350 } 328 351 … … 388 411 size_t cbOld = drvHostSerialReadBufReset(pThis); 389 412 if (cbOld) /* Kick the I/O thread to fetch new data. */ 390 rc = RTSerialPortEvtPollInterrupt(pThis->hSerialPort);413 rc = drvHostSerialWakeupIoThread(pThis); 391 414 } 392 415 … … 399 422 400 423 /** 401 * I/O thread loop. 402 * 403 * @returns VINF_SUCCESS. 404 * @param pDrvIns PDM driver instance data. 405 * @param pThread The PDM thread data. 406 */ 407 static DECLCALLBACK(int) drvHostSerialIoThread(PPDMDRVINS pDrvIns, PPDMTHREAD pThread) 408 { 409 PDRVHOSTSERIAL pThis = PDMINS_2_DATA(pDrvIns, PDRVHOSTSERIAL); 410 411 if (pThread->enmState == PDMTHREADSTATE_INITIALIZING) 412 return VINF_SUCCESS; 413 414 while (pThread->enmState == PDMTHREADSTATE_RUNNING) 424 * The normal I/O loop. 425 * 426 * @returns VBox status code. 427 * @param pDrvIns Pointer to the driver instance data. 428 * @param pThis Host serial driver instance data. 429 * @param pThread Thread instance data. 430 */ 431 static int drvHostSerialIoLoopNormal(PPDMDRVINS pDrvIns, PDRVHOSTSERIAL pThis, PPDMTHREAD pThread) 432 { 433 int rc = VINF_SUCCESS; 434 while ( pThread->enmState == PDMTHREADSTATE_RUNNING 435 && RT_SUCCESS(rc)) 415 436 { 416 437 uint32_t fEvtFlags = RTSERIALPORT_EVT_F_STATUS_LINE_CHANGED | RTSERIALPORT_EVT_F_BREAK_DETECTED; … … 429 450 430 451 uint32_t fEvtsRecv = 0; 431 intrc = RTSerialPortEvtPoll(pThis->hSerialPort, fEvtFlags, &fEvtsRecv, RT_INDEFINITE_WAIT);452 rc = RTSerialPortEvtPoll(pThis->hSerialPort, fEvtFlags, &fEvtsRecv, RT_INDEFINITE_WAIT); 432 453 if (RT_SUCCESS(rc)) 433 454 { … … 464 485 { 465 486 /* Move the data in the TX buffer to the front to fill the end again. */ 466 memmove(&pThis->abTxBuf[0], &pThis->abTxBuf[cbProcessed], pThis->cbTxUsed); } 487 memmove(&pThis->abTxBuf[0], &pThis->abTxBuf[cbProcessed], pThis->cbTxUsed); 488 } 467 489 else 468 490 pThis->pDrvSerialPort->pfnDataSentNotify(pThis->pDrvSerialPort); … … 531 553 LogRelMax(10, ("HostSerial#%d: Notifying device about changed status lines failed with error %Rrc; continuing.\n", 532 554 pDrvIns->iInstance, rc)); 555 rc = VINF_SUCCESS; 533 556 } 534 557 } 535 558 else 559 { 536 560 LogRelMax(10, ("HostSerial#%d: Getting status lines state failed with error %Rrc; continuing.\n", pDrvIns->iInstance, rc)); 561 rc = VINF_SUCCESS; 562 } 537 563 } 538 564 … … 547 573 } 548 574 575 LogRel(("HostSerial#%d: The underlying host device run into a fatal error condition %Rrc, any data transfer is disabled\n", 576 pDrvIns->iInstance, rc)); 577 578 return rc; 579 } 580 581 582 /** 583 * The error I/O loop. 584 * 585 * @returns VBox status code. 586 * @param pDrvIns Pointer to the driver instance data. 587 * @param pThis Host serial driver instance data. 588 * @param pThread Thread instance data. 589 */ 590 static void drvHostSerialIoLoopError(PDRVHOSTSERIAL pThis, PPDMTHREAD pThread) 591 { 592 ASMAtomicXchgBool(&pThis->fIoFatalErr, true); 593 594 PDMDrvHlpVMSetRuntimeError(pThis->pDrvIns, 0 /*fFlags*/, "SerialPortIoError", 595 N_("The host serial port \"%s\" encountered a fatal error and stopped functioning. " 596 "This can be caused by bad cabling or USB to serial converters being unplugged by accident. " 597 "To restart I/O transfers suspend and resume the VM after fixing the underlying issue."), 598 pThis->pszDevicePath); 599 600 while (pThread->enmState == PDMTHREADSTATE_RUNNING) 601 { 602 /* 603 * We have to discard any data which is going to be send (the error 604 * mode resembles the "someone just pulled the plug on the serial port" situation) 605 */ 606 RTSemEventWait(pThis->hSemEvtIoFatalErr, RT_INDEFINITE_WAIT); 607 608 if (ASMAtomicXchgBool(&pThis->fAvailWrExt, false)) 609 { 610 size_t cbFetched = 0; 611 612 do 613 { 614 /* Stuff as much data into the TX buffer as we can. */ 615 uint8_t abDiscard[64]; 616 int rc = pThis->pDrvSerialPort->pfnReadWr(pThis->pDrvSerialPort, &abDiscard, sizeof(abDiscard), 617 &cbFetched); 618 AssertRC(rc); 619 } while (cbFetched > 0); 620 621 /* Acknowledge the sent data. */ 622 pThis->pDrvSerialPort->pfnDataSentNotify(pThis->pDrvSerialPort); 623 624 /* 625 * Sleep a bit to avoid excessive I/O loop CPU usage, timing is not important in 626 * this mode. 627 */ 628 PDMR3ThreadSleep(pThread, 100); 629 } 630 } 631 } 632 633 634 /** 635 * I/O thread loop. 636 * 637 * @returns VINF_SUCCESS. 638 * @param pDrvIns PDM driver instance data. 639 * @param pThread The PDM thread data. 640 */ 641 static DECLCALLBACK(int) drvHostSerialIoThread(PPDMDRVINS pDrvIns, PPDMTHREAD pThread) 642 { 643 PDRVHOSTSERIAL pThis = PDMINS_2_DATA(pDrvIns, PDRVHOSTSERIAL); 644 645 if (pThread->enmState == PDMTHREADSTATE_INITIALIZING) 646 return VINF_SUCCESS; 647 648 int rc = VINF_SUCCESS; 649 if (!pThis->fIoFatalErr) 650 rc = drvHostSerialIoLoopNormal(pDrvIns, pThis, pThread); 651 652 if ( RT_FAILURE(rc) 653 || pThis->fIoFatalErr) 654 drvHostSerialIoLoopError(pThis, pThread); 655 549 656 return VINF_SUCCESS; 550 657 } … … 563 670 PDRVHOSTSERIAL pThis = PDMINS_2_DATA(pDrvIns, PDRVHOSTSERIAL); 564 671 565 return RTSerialPortEvtPollInterrupt(pThis->hSerialPort);672 return drvHostSerialWakeupIoThread(pThis); 566 673 } 567 674 568 675 569 676 /* -=-=-=-=- driver interface -=-=-=-=- */ 677 678 /** 679 * @callback_method_impl{FNPDMDRVRESUME} 680 */ 681 static DECLCALLBACK(void) drvHostSerialResume(PPDMDRVINS pDrvIns) 682 { 683 PDRVHOSTSERIAL pThis = PDMINS_2_DATA(pDrvIns, PDRVHOSTSERIAL); 684 685 if (RT_UNLIKELY(pThis->fIoFatalErr)) 686 { 687 /* Try to reopen the device and set the old config. */ 688 uint32_t fOpenFlags = RTSERIALPORT_OPEN_F_READ 689 | RTSERIALPORT_OPEN_F_WRITE 690 | RTSERIALPORT_OPEN_F_SUPPORT_STATUS_LINE_MONITORING 691 | RTSERIALPORT_OPEN_F_DETECT_BREAK_CONDITION; 692 int rc = RTSerialPortOpen(&pThis->hSerialPort, pThis->pszDevicePath, fOpenFlags); 693 if (rc == VERR_NOT_SUPPORTED) 694 { 695 /* 696 * For certain devices (or pseudo terminals) status line monitoring does not work 697 * so try again without it. 698 */ 699 fOpenFlags &= ~RTSERIALPORT_OPEN_F_SUPPORT_STATUS_LINE_MONITORING; 700 rc = RTSerialPortOpen(&pThis->hSerialPort, pThis->pszDevicePath, fOpenFlags); 701 } 702 703 if (RT_SUCCESS(rc)) 704 { 705 /* Set the config which is currently active. */ 706 rc = RTSerialPortCfgSet(pThis->hSerialPort, &pThis->Cfg, NULL); 707 if (RT_FAILURE(rc)) 708 LogRelMax(10, ("HostSerial#%d: Setting the active serial port config failed with error %Rrc during VM resume; continuing.\n", pDrvIns->iInstance, rc)); 709 /* Reset the I/O error flag on success to resume the normal I/O thread loop. */ 710 ASMAtomicXchgBool(&pThis->fIoFatalErr, false); 711 } 712 } 713 } 714 715 716 /** 717 * @callback_method_impl{FNPDMDRVSUSPEND} 718 */ 719 static DECLCALLBACK(void) drvHostSerialSuspend(PPDMDRVINS pDrvIns) 720 { 721 PDRVHOSTSERIAL pThis = PDMINS_2_DATA(pDrvIns, PDRVHOSTSERIAL); 722 723 if (RT_UNLIKELY(pThis->fIoFatalErr)) 724 { 725 /* Close the device and try reopening it on resume. */ 726 if (pThis->hSerialPort != NIL_RTSERIALPORT) 727 { 728 RTSerialPortClose(pThis->hSerialPort); 729 pThis->hSerialPort = NIL_RTSERIALPORT; 730 } 731 } 732 } 733 570 734 571 735 /** … … 587 751 RTSerialPortClose(pThis->hSerialPort); 588 752 pThis->hSerialPort = NIL_RTSERIALPORT; 753 } 754 755 if (pThis->hSemEvtIoFatalErr != NIL_RTSEMEVENT) 756 { 757 RTSemEventDestroy(pThis->hSemEvtIoFatalErr); 758 pThis->hSemEvtIoFatalErr = NIL_RTSEMEVENT; 589 759 } 590 760 … … 620 790 pThis->offRead = 0; 621 791 pThis->cbReadBuf = 0; 792 pThis->fIoFatalErr = false; 793 pThis->hSemEvtIoFatalErr = NIL_RTSEMEVENT; 622 794 /* IBase. */ 623 795 pDrvIns->IBase.pfnQueryInterface = drvHostSerialQueryInterface; … … 683 855 } 684 856 } 857 858 rc = RTSemEventCreate(&pThis->hSemEvtIoFatalErr); 859 if (RT_FAILURE(rc)) 860 return PDMDrvHlpVMSetError(pDrvIns, rc, RT_SRC_POS, N_("HostSerial#%d failed to create event semaphore"), pDrvIns->iInstance); 685 861 686 862 /* … … 745 921 NULL, 746 922 /* pfnSuspend */ 747 NULL,923 drvHostSerialSuspend, 748 924 /* pfnResume */ 749 NULL,925 drvHostSerialResume, 750 926 /* pfnAttach */ 751 927 NULL,
Note:
See TracChangeset
for help on using the changeset viewer.