Changeset 69980 in vbox for trunk/src/VBox/Runtime/r3/win
- Timestamp:
- Dec 7, 2017 2:17:47 PM (7 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Runtime/r3/win/serialport-win.cpp
r69966 r69980 66 66 /** The event handle to wait on for waking up waiting threads externally. */ 67 67 HANDLE hEvtIntr; 68 /** Events pending which were not queried yet. */ 69 volatile uint32_t fEvtsPending; 68 /** Events currently waited for. */ 69 uint32_t fEvtMask; 70 /** Flag whether a write is currently pending. */ 71 bool fWritePending; 72 /** Bounce buffer for writes. */ 73 uint8_t *pbBounceBuf; 74 /** Amount of used buffer space. */ 75 size_t cbBounceBufUsed; 76 /** Amount of allocated buffer space. */ 77 size_t cbBounceBufAlloc; 70 78 /** The current active port config. */ 71 79 DCB PortCfg; … … 79 87 * Defined Constants And Macros * 80 88 *********************************************************************************************************************************/ 89 /** The pipe buffer size we prefer. */ 90 #define RTSERIALPORT_NT_SIZE _32K 81 91 82 92 … … 91 101 * Internal Functions * 92 102 *********************************************************************************************************************************/ 103 104 /** 105 * Updatest the current event mask to wait for. 106 * 107 * @returns IPRT status code. 108 * @param pThis The internal serial port instance data. 109 * @param fEvtMask The new event mask to change to. 110 */ 111 static int rtSerialPortWinUpdateEvtMask(PRTSERIALPORTINTERNAL pThis, uint32_t fEvtMask) 112 { 113 DWORD dwEvtMask = 0; 114 115 if (fEvtMask & RTSERIALPORT_EVT_F_DATA_RX) 116 dwEvtMask |= EV_RXCHAR; 117 if (fEvtMask & RTSERIALPORT_EVT_F_DATA_TX) 118 dwEvtMask |= EV_TXEMPTY; 119 if (fEvtMask & RTSERIALPORT_EVT_F_BREAK_DETECTED) 120 dwEvtMask |= EV_BREAK; 121 if (fEvtMask & RTSERIALPORT_EVT_F_STATUS_LINE_CHANGED) 122 dwEvtMask |= EV_CTS | EV_DSR | EV_RING | EV_RLSD; 123 124 int rc = VINF_SUCCESS; 125 if (!SetCommMask(pThis->hDev, dwEvtMask)) 126 rc = RTErrConvertFromWin32(GetLastError()); 127 else 128 pThis->fEvtMask = fEvtMask; 129 130 return rc; 131 } 93 132 94 133 … … 123 162 124 163 164 /** 165 * Common worker for handling I/O completion. 166 * 167 * This is used by RTSerialPortClose, RTSerialPortWrite and RTPipeSerialPortNB. 168 * 169 * @returns IPRT status code. 170 * @param pThis The pipe instance handle. 171 */ 172 static int rtSerialPortWriteCheckCompletion(PRTSERIALPORTINTERNAL pThis) 173 { 174 int rc = VINF_SUCCESS; 175 DWORD dwRc = WaitForSingleObject(pThis->Overlapped.hEvent, 0); 176 if (dwRc == WAIT_OBJECT_0) 177 { 178 DWORD cbWritten = 0; 179 if (GetOverlappedResult(pThis->hDev, &pThis->Overlapped, &cbWritten, TRUE)) 180 { 181 for (;;) 182 { 183 if (cbWritten >= pThis->cbBounceBufUsed) 184 { 185 pThis->fWritePending = false; 186 rc = VINF_SUCCESS; 187 break; 188 } 189 190 /* resubmit the remainder of the buffer - can this actually happen? */ 191 memmove(&pThis->pbBounceBuf[0], &pThis->pbBounceBuf[cbWritten], pThis->cbBounceBufUsed - cbWritten); 192 rc = ResetEvent(pThis->Overlapped.hEvent); Assert(rc == TRUE); 193 if (!WriteFile(pThis->hDev, pThis->pbBounceBuf, (DWORD)pThis->cbBounceBufUsed, 194 &cbWritten, &pThis->Overlapped)) 195 { 196 if (GetLastError() == ERROR_IO_PENDING) 197 rc = VINF_TRY_AGAIN; 198 else 199 { 200 pThis->fWritePending = false; 201 rc = RTErrConvertFromWin32(GetLastError()); 202 } 203 break; 204 } 205 Assert(cbWritten > 0); 206 } 207 } 208 else 209 { 210 pThis->fWritePending = false; 211 rc = RTErrConvertFromWin32(GetLastError()); 212 } 213 } 214 else if (dwRc == WAIT_TIMEOUT) 215 rc = VINF_TRY_AGAIN; 216 else 217 { 218 pThis->fWritePending = false; 219 if (dwRc == WAIT_ABANDONED) 220 rc = VERR_INVALID_HANDLE; 221 else 222 rc = RTErrConvertFromWin32(GetLastError()); 223 } 224 return rc; 225 } 226 227 125 228 RTDECL(int) RTSerialPortOpen(PRTSERIALPORT phSerialPort, const char *pszPortAddress, uint32_t fFlags) 126 229 { … … 135 238 if (pThis) 136 239 { 137 pThis->fOpenFlags = fFlags; 138 pThis->fEvtsPending = 0; 139 pThis->hEvtDev = CreateEvent(NULL, FALSE, FALSE, NULL); 240 pThis->fOpenFlags = fFlags; 241 pThis->fEvtMask = 0; 242 pThis->fWritePending = false; 243 pThis->pbBounceBuf = NULL; 244 pThis->cbBounceBufUsed = 0; 245 pThis->cbBounceBufAlloc = 0; 246 pThis->hEvtDev = CreateEvent(NULL, FALSE, FALSE, NULL); 140 247 if (pThis->hEvtDev) 141 248 { 249 pThis->Overlapped.hEvent = pThis->hEvtDev, 142 250 pThis->hEvtIntr = CreateEvent(NULL, FALSE, FALSE, NULL); 143 251 if (pThis->hEvtIntr) … … 194 302 AssertReturn(ASMAtomicCmpXchgU32(&pThis->u32Magic, RTSERIALPORT_MAGIC_DEAD, RTSERIALPORT_MAGIC), VERR_INVALID_HANDLE); 195 303 304 if (pThis->fWritePending) 305 rtSerialPortWriteCheckCompletion(pThis); 306 196 307 CloseHandle(pThis->hDev); 197 308 CloseHandle(pThis->hEvtDev); … … 217 328 RTDECL(int) RTSerialPortRead(RTSERIALPORT hSerialPort, void *pvBuf, size_t cbToRead, size_t *pcbRead) 218 329 { 219 RT_NOREF(hSerialPort, pvBuf, cbToRead, pcbRead); 220 return VERR_NOT_IMPLEMENTED; 330 PRTSERIALPORTINTERNAL pThis = hSerialPort; 331 AssertPtrReturn(pThis, VERR_INVALID_PARAMETER); 332 AssertReturn(pThis->u32Magic == RTSERIALPORT_MAGIC, VERR_INVALID_HANDLE); 333 AssertPtrReturn(pvBuf, VERR_INVALID_POINTER); 334 AssertReturn(cbToRead > 0, VERR_INVALID_PARAMETER); 335 336 RT_NOREF(pcbRead); 337 int rc = VERR_NOT_IMPLEMENTED; 338 return rc; 221 339 } 222 340 … … 233 351 *pcbRead = 0; 234 352 235 return VERR_NOT_IMPLEMENTED; 353 /* 354 * Kick of an overlapped read. It should return immediately if 355 * there is bytes in the buffer. If not, we'll cancel it and see 356 * what we get back. 357 */ 358 int rc = VINF_SUCCESS; 359 BOOL fSucc = ResetEvent(pThis->Overlapped.hEvent); Assert(fSucc == TRUE); 360 DWORD cbRead = 0; 361 if ( cbToRead == 0 362 || ReadFile(pThis->hDev, pvBuf, 363 cbToRead <= ~(DWORD)0 ? (DWORD)cbToRead : ~(DWORD)0, 364 &cbRead, &pThis->Overlapped)) 365 { 366 *pcbRead = cbRead; 367 rc = VINF_SUCCESS; 368 } 369 else if (GetLastError() == ERROR_IO_PENDING) 370 { 371 if (!CancelIo(pThis->hDev)) 372 WaitForSingleObject(pThis->Overlapped.hEvent, INFINITE); 373 if (GetOverlappedResult(pThis->hDev, &pThis->Overlapped, &cbRead, TRUE /*fWait*/)) 374 { 375 *pcbRead = cbRead; 376 rc = VINF_SUCCESS; 377 } 378 else if (GetLastError() == ERROR_OPERATION_ABORTED) 379 { 380 *pcbRead = 0; 381 rc = VINF_TRY_AGAIN; 382 } 383 else 384 rc = RTErrConvertFromWin32(GetLastError()); 385 } 386 else 387 rc = RTErrConvertFromWin32(GetLastError()); 388 389 return rc; 236 390 } 237 391 … … 253 407 AssertPtrReturn(pcbWritten, VERR_INVALID_POINTER); 254 408 255 return VERR_NOT_IMPLEMENTED; 409 /* If I/O is pending, check if it has completed. */ 410 int rc = VINF_SUCCESS; 411 if (pThis->fWritePending) 412 rc = rtSerialPortWriteCheckCompletion(pThis); 413 if (rc == VINF_SUCCESS) 414 { 415 Assert(!pThis->fWritePending); 416 417 /* Do the bounce buffering. */ 418 if ( pThis->cbBounceBufAlloc < cbToWrite 419 && pThis->cbBounceBufAlloc < RTSERIALPORT_NT_SIZE) 420 { 421 if (cbToWrite > RTSERIALPORT_NT_SIZE) 422 cbToWrite = RTSERIALPORT_NT_SIZE; 423 void *pv = RTMemRealloc(pThis->pbBounceBuf, RT_ALIGN_Z(cbToWrite, _1K)); 424 if (pv) 425 { 426 pThis->pbBounceBuf = (uint8_t *)pv; 427 pThis->cbBounceBufAlloc = RT_ALIGN_Z(cbToWrite, _1K); 428 } 429 else 430 rc = VERR_NO_MEMORY; 431 } 432 else if (cbToWrite > RTSERIALPORT_NT_SIZE) 433 cbToWrite = RTSERIALPORT_NT_SIZE; 434 if (RT_SUCCESS(rc) && cbToWrite) 435 { 436 memcpy(pThis->pbBounceBuf, pvBuf, cbToWrite); 437 pThis->cbBounceBufUsed = (uint32_t)cbToWrite; 438 439 /* Submit the write. */ 440 rc = ResetEvent(pThis->Overlapped.hEvent); Assert(rc == TRUE); 441 DWORD cbWritten = 0; 442 if (WriteFile(pThis->hDev, pThis->pbBounceBuf, (DWORD)pThis->cbBounceBufUsed, 443 &cbWritten, &pThis->Overlapped)) 444 { 445 *pcbWritten = RT_MIN(cbWritten, cbToWrite); /* paranoia^3 */ 446 rc = VINF_SUCCESS; 447 } 448 else if (GetLastError() == ERROR_IO_PENDING) 449 { 450 *pcbWritten = cbToWrite; 451 pThis->fWritePending = true; 452 rc = VINF_SUCCESS; 453 } 454 else 455 rc = RTErrConvertFromWin32(GetLastError()); 456 } 457 else if (RT_SUCCESS(rc)) 458 *pcbWritten = 0; 459 } 460 else if (RT_SUCCESS(rc)) 461 *pcbWritten = 0; 462 463 return rc; 256 464 } 257 465 … … 263 471 AssertReturn(pThis->u32Magic == RTSERIALPORT_MAGIC, VERR_INVALID_HANDLE); 264 472 265 RT_NOREF(pCfg); 266 267 return VERR_NOT_IMPLEMENTED; 473 pCfg->uBaudRate = pThis->PortCfg.BaudRate; 474 switch (pThis->PortCfg.Parity) 475 { 476 case NOPARITY: 477 pCfg->enmParity = RTSERIALPORTPARITY_NONE; 478 break; 479 case EVENPARITY: 480 pCfg->enmParity = RTSERIALPORTPARITY_EVEN; 481 break; 482 case ODDPARITY: 483 pCfg->enmParity = RTSERIALPORTPARITY_ODD; 484 break; 485 case MARKPARITY: 486 pCfg->enmParity = RTSERIALPORTPARITY_MARK; 487 break; 488 case SPACEPARITY: 489 pCfg->enmParity = RTSERIALPORTPARITY_SPACE; 490 break; 491 default: 492 AssertFailed(); 493 return VERR_INTERNAL_ERROR; 494 } 495 496 switch (pThis->PortCfg.ByteSize) 497 { 498 case 5: 499 pCfg->enmDataBitCount = RTSERIALPORTDATABITS_5BITS; 500 break; 501 case 6: 502 pCfg->enmDataBitCount = RTSERIALPORTDATABITS_6BITS; 503 break; 504 case 7: 505 pCfg->enmDataBitCount = RTSERIALPORTDATABITS_7BITS; 506 break; 507 case 8: 508 pCfg->enmDataBitCount = RTSERIALPORTDATABITS_8BITS; 509 break; 510 default: 511 AssertFailed(); 512 return VERR_INTERNAL_ERROR; 513 } 514 515 switch (pThis->PortCfg.StopBits) 516 { 517 case ONESTOPBIT: 518 pCfg->enmStopBitCount = RTSERIALPORTSTOPBITS_ONE; 519 break; 520 case ONE5STOPBITS: 521 pCfg->enmStopBitCount = RTSERIALPORTSTOPBITS_ONEPOINTFIVE; 522 break; 523 case TWOSTOPBITS: 524 pCfg->enmStopBitCount = RTSERIALPORTSTOPBITS_TWO; 525 break; 526 default: 527 AssertFailed(); 528 return VERR_INTERNAL_ERROR; 529 } 530 531 return VINF_SUCCESS; 268 532 } 269 533 … … 275 539 AssertReturn(pThis->u32Magic == RTSERIALPORT_MAGIC, VERR_INVALID_HANDLE); 276 540 277 RT_NOREF(pCfg, pErrInfo); 278 279 return VERR_NOT_IMPLEMENTED; 541 RT_NOREF(pErrInfo); 542 543 DCB DcbNew; 544 memcpy(&DcbNew, &pThis->PortCfg, sizeof(DcbNew)); 545 DcbNew.BaudRate = pCfg->uBaudRate; 546 547 switch (pCfg->enmParity) 548 { 549 case RTSERIALPORTPARITY_NONE: 550 DcbNew.Parity = NOPARITY; 551 break; 552 case RTSERIALPORTPARITY_EVEN: 553 DcbNew.Parity = EVENPARITY; 554 break; 555 case RTSERIALPORTPARITY_ODD: 556 DcbNew.Parity = ODDPARITY; 557 break; 558 case RTSERIALPORTPARITY_MARK: 559 DcbNew.Parity = MARKPARITY; 560 break; 561 case RTSERIALPORTPARITY_SPACE: 562 DcbNew.Parity = SPACEPARITY; 563 break; 564 default: 565 AssertFailedReturn(VERR_INVALID_PARAMETER); 566 } 567 568 switch (pCfg->enmDataBitCount) 569 { 570 case RTSERIALPORTDATABITS_5BITS: 571 DcbNew.ByteSize = 5; 572 break; 573 case RTSERIALPORTDATABITS_6BITS: 574 DcbNew.ByteSize = 6; 575 break; 576 case RTSERIALPORTDATABITS_7BITS: 577 DcbNew.ByteSize = 7; 578 break; 579 case RTSERIALPORTDATABITS_8BITS: 580 DcbNew.ByteSize = 8; 581 break; 582 default: 583 AssertFailedReturn(VERR_INVALID_PARAMETER); 584 } 585 586 switch (pCfg->enmStopBitCount) 587 { 588 case RTSERIALPORTSTOPBITS_ONE: 589 DcbNew.StopBits = ONESTOPBIT; 590 break; 591 case RTSERIALPORTSTOPBITS_ONEPOINTFIVE: 592 AssertReturn(pCfg->enmDataBitCount == RTSERIALPORTDATABITS_5BITS, VERR_INVALID_PARAMETER); 593 DcbNew.StopBits = ONE5STOPBITS; 594 break; 595 case RTSERIALPORTSTOPBITS_TWO: 596 AssertReturn(pCfg->enmDataBitCount != RTSERIALPORTDATABITS_5BITS, VERR_INVALID_PARAMETER); 597 DcbNew.StopBits = TWOSTOPBITS; 598 break; 599 default: 600 AssertFailedReturn(VERR_INVALID_PARAMETER); 601 } 602 603 int rc = VINF_SUCCESS; 604 if (!SetCommState(pThis->hDev, &DcbNew)) 605 rc = RTErrConvertFromWin32(GetLastError()); 606 else 607 memcpy(&pThis->PortCfg, &DcbNew, sizeof(DcbNew)); 608 609 return rc; 280 610 } 281 611 … … 290 620 AssertPtrReturn(pfEvtsRecv, VERR_INVALID_POINTER); 291 621 292 RT_NOREF(msTimeout); 293 294 return VERR_NOT_IMPLEMENTED; 622 *pfEvtsRecv = 0; 623 624 int rc = VINF_SUCCESS; 625 if (fEvtMask != pThis->fEvtMask) 626 rc = rtSerialPortWinUpdateEvtMask(pThis, fEvtMask); 627 628 if (RT_SUCCESS(rc)) 629 { 630 DWORD dwEventMask = 0; 631 HANDLE ahWait[2]; 632 ahWait[0] = pThis->hEvtDev; 633 ahWait[1] = pThis->hEvtIntr; 634 635 RT_ZERO(pThis->Overlapped); 636 pThis->Overlapped.hEvent = pThis->hEvtDev; 637 638 if (!WaitCommEvent(pThis->hDev, &dwEventMask, &pThis->Overlapped)) 639 { 640 DWORD dwRet = GetLastError(); 641 if (dwRet == ERROR_IO_PENDING) 642 { 643 dwRet = WaitForMultipleObjects(2, ahWait, FALSE, msTimeout == RT_INDEFINITE_WAIT ? INFINITE : msTimeout); 644 if (dwRet == WAIT_TIMEOUT) 645 rc = VERR_TIMEOUT; 646 else if (dwRet == WAIT_FAILED) 647 rc = RTErrConvertFromWin32(GetLastError()); 648 else if (dwRet != WAIT_OBJECT_0) 649 rc = VERR_INTERRUPTED; 650 } 651 else 652 rc = RTErrConvertFromWin32(dwRet); 653 } 654 655 if (RT_SUCCESS(rc)) 656 { 657 /* Check the event */ 658 if (dwEventMask & EV_RXCHAR) 659 *pfEvtsRecv |= RTSERIALPORT_EVT_F_DATA_RX; 660 if (dwEventMask & EV_TXEMPTY) 661 { 662 if (pThis->fWritePending) 663 { 664 rc = rtSerialPortWriteCheckCompletion(pThis); 665 if (rc == VINF_SUCCESS) 666 *pfEvtsRecv |= RTSERIALPORT_EVT_F_DATA_TX; 667 else 668 rc = VINF_SUCCESS; 669 } 670 else 671 *pfEvtsRecv |= RTSERIALPORT_EVT_F_DATA_TX; 672 } 673 if (dwEventMask & EV_BREAK) 674 *pfEvtsRecv |= RTSERIALPORT_EVT_F_BREAK_DETECTED; 675 if (dwEventMask & (EV_CTS | EV_DSR | EV_RING | EV_RLSD)) 676 *pfEvtsRecv |= RTSERIALPORT_EVT_F_STATUS_LINE_CHANGED; 677 } 678 } 679 680 return rc; 295 681 } 296 682
Note:
See TracChangeset
for help on using the changeset viewer.