- Timestamp:
- May 27, 2010 4:25:28 PM (15 years ago)
- Location:
- trunk/src/VBox/Devices/Serial
- Files:
-
- 2 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Devices/Serial/DevSerial.cpp
r28800 r29846 1 1 /* $Id$ */ 2 2 /** @file 3 * DevSerial - 16450 UART emulation. 3 * DevSerial - 16550A UART emulation. 4 * (taken from hw/serial.c 2010/05/15 with modifications) 4 5 */ 5 6 6 7 /* 7 * Copyright (C) 2006-20 07Oracle Corporation8 * Copyright (C) 2006-2010 Oracle Corporation 8 9 * 9 10 * This file is part of VirtualBox Open Source Edition (OSE), as … … 19 20 * This code is based on: 20 21 * 21 * QEMU 16 450UART emulation22 * QEMU 16550A UART emulation 22 23 * 23 24 * Copyright (c) 2003-2004 Fabrice Bellard 25 * Copyright (c) 2008 Citrix Systems, Inc. 24 26 * 25 27 * Permission is hereby granted, free of charge, to any person obtaining a copy … … 40 42 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 41 43 * THE SOFTWARE. 42 *43 44 */ 44 45 … … 68 69 #define SERIAL_SAVED_STATE_VERSION 3 69 70 70 #define UART_LCR_DLAB 0x80 /* Divisor latch access bit */ 71 72 #define UART_IER_MSI 0x08 /* Enable Modem status interrupt */ 73 #define UART_IER_RLSI 0x04 /* Enable receiver line status interrupt */ 74 #define UART_IER_THRI 0x02 /* Enable Transmitter holding register int. */ 75 #define UART_IER_RDI 0x01 /* Enable receiver data interrupt */ 76 77 #define UART_IIR_NO_INT 0x01 /* No interrupts pending */ 78 #define UART_IIR_ID 0x06 /* Mask for the interrupt ID */ 79 80 #define UART_IIR_MSI 0x00 /* Modem status interrupt */ 81 #define UART_IIR_THRI 0x02 /* Transmitter holding register empty */ 82 #define UART_IIR_RDI 0x04 /* Receiver data interrupt */ 83 #define UART_IIR_RLSI 0x06 /* Receiver line status interrupt */ 71 #define UART_LCR_DLAB 0x80 /* Divisor latch access bit */ 72 73 #define UART_IER_MSI 0x08 /* Enable Modem status interrupt */ 74 #define UART_IER_RLSI 0x04 /* Enable receiver line status interrupt */ 75 #define UART_IER_THRI 0x02 /* Enable Transmitter holding register int. */ 76 #define UART_IER_RDI 0x01 /* Enable receiver data interrupt */ 77 78 #define UART_IIR_NO_INT 0x01 /* No interrupts pending */ 79 #define UART_IIR_ID 0x06 /* Mask for the interrupt ID */ 80 81 #define UART_IIR_MSI 0x00 /* Modem status interrupt */ 82 #define UART_IIR_THRI 0x02 /* Transmitter holding register empty */ 83 #define UART_IIR_RDI 0x04 /* Receiver data interrupt */ 84 #define UART_IIR_RLSI 0x06 /* Receiver line status interrupt */ 85 #define UART_IIR_CTI 0x0C /* Character Timeout Indication */ 86 87 #define UART_IIR_FENF 0x80 /* Fifo enabled, but not functionning */ 88 #define UART_IIR_FE 0xC0 /* Fifo enabled */ 84 89 85 90 /* 86 91 * These are the definitions for the Modem Control Register 87 92 */ 88 #define UART_MCR_LOOP 89 #define UART_MCR_OUT2 90 #define UART_MCR_OUT1 91 #define UART_MCR_RTS 92 #define UART_MCR_DTR 93 #define UART_MCR_LOOP 0x10 /* Enable loopback test mode */ 94 #define UART_MCR_OUT2 0x08 /* Out2 complement */ 95 #define UART_MCR_OUT1 0x04 /* Out1 complement */ 96 #define UART_MCR_RTS 0x02 /* RTS complement */ 97 #define UART_MCR_DTR 0x01 /* DTR complement */ 93 98 94 99 /* 95 100 * These are the definitions for the Modem Status Register 96 101 */ 97 #define UART_MSR_DCD 0x80 /* Data Carrier Detect */ 98 #define UART_MSR_RI 0x40 /* Ring Indicator */ 99 #define UART_MSR_DSR 0x20 /* Data Set Ready */ 100 #define UART_MSR_CTS 0x10 /* Clear to Send */ 101 #define UART_MSR_DDCD 0x08 /* Delta DCD */ 102 #define UART_MSR_TERI 0x04 /* Trailing edge ring indicator */ 103 #define UART_MSR_DDSR 0x02 /* Delta DSR */ 104 #define UART_MSR_DCTS 0x01 /* Delta CTS */ 105 #define UART_MSR_ANY_DELTA 0x0F /* Any of the delta bits! */ 106 107 #define UART_LSR_TEMT 0x40 /* Transmitter empty */ 108 #define UART_LSR_THRE 0x20 /* Transmit-hold-register empty */ 109 #define UART_LSR_BI 0x10 /* Break interrupt indicator */ 110 #define UART_LSR_FE 0x08 /* Frame error indicator */ 111 #define UART_LSR_PE 0x04 /* Parity error indicator */ 112 #define UART_LSR_OE 0x02 /* Overrun error indicator */ 113 #define UART_LSR_DR 0x01 /* Receiver data ready */ 114 102 #define UART_MSR_DCD 0x80 /* Data Carrier Detect */ 103 #define UART_MSR_RI 0x40 /* Ring Indicator */ 104 #define UART_MSR_DSR 0x20 /* Data Set Ready */ 105 #define UART_MSR_CTS 0x10 /* Clear to Send */ 106 #define UART_MSR_DDCD 0x08 /* Delta DCD */ 107 #define UART_MSR_TERI 0x04 /* Trailing edge ring indicator */ 108 #define UART_MSR_DDSR 0x02 /* Delta DSR */ 109 #define UART_MSR_DCTS 0x01 /* Delta CTS */ 110 #define UART_MSR_ANY_DELTA 0x0F /* Any of the delta bits! */ 111 112 #define UART_LSR_TEMT 0x40 /* Transmitter empty */ 113 #define UART_LSR_THRE 0x20 /* Transmit-hold-register empty */ 114 #define UART_LSR_BI 0x10 /* Break interrupt indicator */ 115 #define UART_LSR_FE 0x08 /* Frame error indicator */ 116 #define UART_LSR_PE 0x04 /* Parity error indicator */ 117 #define UART_LSR_OE 0x02 /* Overrun error indicator */ 118 #define UART_LSR_DR 0x01 /* Receiver data ready */ 119 #define UART_LSR_INT_ANY 0x1E /* Any of the lsr-interrupt-triggering status bits */ 120 121 /* 122 * Interrupt trigger levels. 123 * The byte-counts are for 16550A - in newer UARTs the byte-count for each ITL is higher. 124 */ 125 #define UART_FCR_ITL_1 0x00 /* 1 byte ITL */ 126 #define UART_FCR_ITL_2 0x40 /* 4 bytes ITL */ 127 #define UART_FCR_ITL_3 0x80 /* 8 bytes ITL */ 128 #define UART_FCR_ITL_4 0xC0 /* 14 bytes ITL */ 129 130 #define UART_FCR_DMS 0x08 /* DMA Mode Select */ 131 #define UART_FCR_XFR 0x04 /* XMIT Fifo Reset */ 132 #define UART_FCR_RFR 0x02 /* RCVR Fifo Reset */ 133 #define UART_FCR_FE 0x01 /* FIFO Enable */ 134 135 #define UART_FIFO_LENGTH 16 /* 16550A Fifo Length */ 136 137 #define XMIT_FIFO 0 138 #define RECV_FIFO 1 139 #define MAX_XMIT_RETRY 8 115 140 116 141 /******************************************************************************* 117 142 * Structures and Typedefs * 118 143 *******************************************************************************/ 144 145 struct SerialFifo 146 { 147 uint8_t data[UART_FIFO_LENGTH]; 148 uint8_t count; 149 uint8_t itl; 150 uint8_t tail; 151 uint8_t head; 152 }; 153 119 154 /** 120 155 * Serial device. … … 127 162 /** Access critical section. */ 128 163 PDMCRITSECT CritSect; 129 130 164 /** Pointer to the device instance - R3 Ptr. */ 131 165 PPDMDEVINSR3 pDevInsR3; … … 134 168 /** Pointer to the device instance - RC Ptr. */ 135 169 PPDMDEVINSRC pDevInsRC; 136 RTRCPTR Alignment0; /**< Alignment. */ 170 /** Alignment. */ 171 RTRCPTR Alignment0; 137 172 /** LUN\#0: The base interface. */ 138 173 PDMIBASE IBase; … … 142 177 R3PTRTYPE(PPDMIBASE) pDrvBase; 143 178 /** Pointer to the attached character driver. */ 144 R3PTRTYPE(PPDMICHARCONNECTOR) pDrvChar; 145 179 R3PTRTYPE(PPDMICHARCONNECTOR) pDrvChar; 180 181 RTSEMEVENT ReceiveSem; 182 PTMTIMERR3 fifo_timeout_timer; 183 PTMTIMERR3 transmit_timerR3; 184 PTMTIMERR0 transmit_timerR0; /* currently not used */ 185 PTMTIMERRC transmit_timerRC; /* currently not used */ 186 RTRCPTR Alignment1; 187 SerialFifo recv_fifo; 188 SerialFifo xmit_fifo; 189 190 uint32_t base; 146 191 uint16_t divider; 147 uint16_t auAlignment[3]; 148 uint8_t rbr; /* receive register */ 149 uint8_t ier; 150 uint8_t iir; /* read only */ 151 uint8_t lcr; 152 uint8_t mcr; 153 uint8_t lsr; /* read only */ 154 uint8_t msr; /* read only */ 155 uint8_t scr; 192 uint16_t Alignment2[1]; 193 uint8_t rbr; /**< receive register */ 194 uint8_t thr; /**< transmit holding register */ 195 uint8_t tsr; /**< transmit shift register */ 196 uint8_t ier; /**< interrupt enable register */ 197 uint8_t iir; /**< interrupt itentification register, R/O */ 198 uint8_t lcr; /**< line control register */ 199 uint8_t mcr; /**< modem control register */ 200 uint8_t lsr; /**< line status register, R/O */ 201 uint8_t msr; /**< modem status register, R/O */ 202 uint8_t scr; /**< scratch register */ 203 uint8_t fcr; /**< fifo control register */ 204 uint8_t fcr_vmstate; 156 205 /* NOTE: this hidden state is necessary for tx irq generation as 157 206 it can be reset while reading iir */ 158 207 int thr_ipending; 208 int timeout_ipending; 159 209 int irq; 210 int last_break_enable; 211 /** Counter for retrying xmit */ 212 int tsr_retry; 160 213 bool msr_changed; 161 162 214 bool fGCEnabled; 163 215 bool fR0Enabled; 164 216 bool fYieldOnLSRRead; 165 bool afAlignment[4]; 166 167 RTSEMEVENT ReceiveSem; 168 int last_break_enable; 169 uint32_t base; 217 bool volatile fRecvWaiting; 218 bool Alignment3[3]; 219 /** Time it takes to transmit a character */ 220 uint64_t char_transmit_time; 170 221 171 222 #ifdef VBOX_SERIAL_PCI … … 194 245 #ifdef IN_RING3 195 246 247 static int serial_can_receive(SerialState *s); 248 static void serial_receive(void *opaque, const uint8_t *buf, int size); 249 250 static void fifo_clear(SerialState *s, int fifo) 251 { 252 SerialFifo *f = (fifo) ? &s->recv_fifo : &s->xmit_fifo; 253 memset(f->data, 0, UART_FIFO_LENGTH); 254 f->count = 0; 255 f->head = 0; 256 f->tail = 0; 257 } 258 259 static int fifo_put(SerialState *s, int fifo, uint8_t chr) 260 { 261 SerialFifo *f = (fifo) ? &s->recv_fifo : &s->xmit_fifo; 262 263 /* Receive overruns do not overwrite FIFO contents. */ 264 if (fifo == XMIT_FIFO || f->count < UART_FIFO_LENGTH) 265 { 266 f->data[f->head++] = chr; 267 if (f->head == UART_FIFO_LENGTH) 268 f->head = 0; 269 } 270 271 if (f->count < UART_FIFO_LENGTH) 272 f->count++; 273 else if (fifo == RECV_FIFO) 274 s->lsr |= UART_LSR_OE; 275 276 return 1; 277 } 278 279 static uint8_t fifo_get(SerialState *s, int fifo) 280 { 281 SerialFifo *f = (fifo) ? &s->recv_fifo : &s->xmit_fifo; 282 uint8_t c; 283 284 if (f->count == 0) 285 return 0; 286 287 c = f->data[f->tail++]; 288 if (f->tail == UART_FIFO_LENGTH) 289 f->tail = 0; 290 f->count--; 291 292 return c; 293 } 294 196 295 static void serial_update_irq(SerialState *s) 197 296 { 198 if ((s->lsr & UART_LSR_DR) && (s->ier & UART_IER_RDI)) { 199 s->iir = UART_IIR_RDI; 200 } else if (s->thr_ipending && (s->ier & UART_IER_THRI)) { 201 s->iir = UART_IIR_THRI; 202 } else if (s->msr_changed && (s->ier & UART_IER_RLSI)) { 203 s->iir = UART_IIR_RLSI; 204 } else if (s->lsr & UART_LSR_BI) { 205 s->iir = 0; /* No special status bit */ 206 } else { 207 s->iir = UART_IIR_NO_INT; 208 } 209 if (s->iir != UART_IIR_NO_INT) { 297 uint8_t tmp_iir = UART_IIR_NO_INT; 298 299 if ( (s->ier & UART_IER_RLSI) 300 && (s->lsr & UART_LSR_INT_ANY)) { 301 tmp_iir = UART_IIR_RLSI; 302 } else if ((s->ier & UART_IER_RDI) && s->timeout_ipending) { 303 /* Note that(s->ier & UART_IER_RDI) can mask this interrupt, 304 * this is not in the specification but is observed on existing 305 * hardware. */ 306 tmp_iir = UART_IIR_CTI; 307 } else if ( (s->ier & UART_IER_RDI) 308 && (s->lsr & UART_LSR_DR) 309 && ( !(s->fcr & UART_FCR_FE) 310 || s->recv_fifo.count >= s->recv_fifo.itl)) { 311 tmp_iir = UART_IIR_RDI; 312 } else if ( (s->ier & UART_IER_THRI) 313 && s->thr_ipending) { 314 tmp_iir = UART_IIR_THRI; 315 } else if ( (s->ier & UART_IER_MSI) 316 && (s->msr & UART_MSR_ANY_DELTA)) { 317 tmp_iir = UART_IIR_MSI; 318 } 319 s->iir = tmp_iir | (s->iir & 0xF0); 320 321 /** XXX only call the SetIrq function if the state really changes! */ 322 if (tmp_iir != UART_IIR_NO_INT) { 210 323 Log(("serial_update_irq %d 1\n", s->irq)); 211 324 # ifdef VBOX_SERIAL_PCI … … 226 339 static void serial_update_parameters(SerialState *s) 227 340 { 228 int speed, parity, data_bits, stop_bits; 229 341 int speed, parity, data_bits, stop_bits, frame_size; 342 343 if (s->divider == 0) 344 return; 345 346 frame_size = 1; 230 347 if (s->lcr & 0x08) { 348 frame_size++; 231 349 if (s->lcr & 0x10) 232 350 parity = 'E'; … … 240 358 else 241 359 stop_bits = 1; 360 242 361 data_bits = (s->lcr & 0x03) + 5; 243 if (s->divider == 0) 244 return; 362 frame_size += data_bits + stop_bits; 245 363 speed = 115200 / s->divider; 364 s->char_transmit_time = (TMTimerGetFreq(CTX_SUFF(s->transmit_timer)) / speed) * frame_size; 246 365 Log(("speed=%d parity=%c data=%d stop=%d\n", speed, parity, data_bits, stop_bits)); 366 247 367 if (RT_LIKELY(s->pDrvChar)) 248 368 s->pDrvChar->pfnSetParameters(s->pDrvChar, speed, parity, data_bits, stop_bits); 249 369 } 250 370 371 static void serial_xmit(void *opaque) 372 { 373 SerialState *s = (SerialState*)opaque; 374 uint64_t new_xmit_ts = TMTimerGet(CTX_SUFF(s->transmit_timer)); 375 376 if (s->tsr_retry <= 0) { 377 if (s->fcr & UART_FCR_FE) { 378 s->tsr = fifo_get(s, XMIT_FIFO); 379 if (!s->xmit_fifo.count) 380 s->lsr |= UART_LSR_THRE; 381 } else { 382 s->tsr = s->thr; 383 s->lsr |= UART_LSR_THRE; 384 } 385 } 386 387 if (s->mcr & UART_MCR_LOOP) { 388 /* in loopback mode, say that we just received a char */ 389 serial_receive(s, &s->tsr, 1); 390 } else if ( RT_LIKELY(s->pDrvChar) 391 && RT_FAILURE(s->pDrvChar->pfnWrite(s->pDrvChar, &s->tsr, 1))) { 392 if ((s->tsr_retry >= 0) && (s->tsr_retry <= MAX_XMIT_RETRY)) { 393 s->tsr_retry++; 394 TMTimerSet(CTX_SUFF(s->transmit_timer), new_xmit_ts + s->char_transmit_time); 395 return; 396 } else { 397 /* drop this character. */ 398 s->tsr_retry = 0; 399 } 400 } 401 else { 402 s->tsr_retry = 0; 403 } 404 405 if (!(s->lsr & UART_LSR_THRE)) 406 TMTimerSet(CTX_SUFF(s->transmit_timer), 407 TMTimerGet(CTX_SUFF(s->transmit_timer)) + s->char_transmit_time); 408 409 if (s->lsr & UART_LSR_THRE) { 410 s->lsr |= UART_LSR_TEMT; 411 s->thr_ipending = 1; 412 serial_update_irq(s); 413 } 414 } 415 251 416 #endif /* IN_RING3 */ 252 417 253 static int serial_ioport_write(void *opaque, uint32_t addr, uint32_t val) 254 { 255 SerialState *s = (SerialState *)opaque; 256 unsigned char ch; 257 418 static int serial_ioport_write(SerialState *s, uint32_t addr, uint32_t val) 419 { 258 420 addr &= 7; 259 LogFlow(("serial: write addr=0x%02x val=0x%02x\n", addr, val));260 421 261 422 #ifndef IN_RING3 262 NOREF(ch);263 423 NOREF(s); 264 424 return VINF_IOM_HC_IOPORT_WRITE; … … 270 430 s->divider = (s->divider & 0xff00) | val; 271 431 serial_update_parameters(s); 272 #if 0 /* disabled because this causes regressions */ 273 } else if (s->lsr & UART_LSR_THRE) { 274 s->thr_ipending = 0; 275 ch = val; 276 if (RT_LIKELY(s->pDrvChar)) 277 { 278 Log(("serial_ioport_write: write 0x%X\n", ch)); 279 int rc = s->pDrvChar->pfnWrite(s->pDrvChar, &ch, 1); 280 AssertRC(rc); 432 } else { 433 s->thr = (uint8_t) val; 434 if (s->fcr & UART_FCR_FE) { 435 fifo_put(s, XMIT_FIFO, s->thr); 436 s->thr_ipending = 0; 437 s->lsr &= ~UART_LSR_TEMT; 438 s->lsr &= ~UART_LSR_THRE; 439 serial_update_irq(s); 440 } else { 441 s->thr_ipending = 0; 442 s->lsr &= ~UART_LSR_THRE; 443 serial_update_irq(s); 281 444 } 282 s->thr_ipending = 1; 283 serial_update_irq(s); 284 } else 285 Log(("serial: THR not EMPTY!\n")); 286 #else 287 } else { 288 s->thr_ipending = 0; 289 s->lsr &= ~UART_LSR_THRE; 290 serial_update_irq(s); 291 ch = val; 292 if (RT_LIKELY(s->pDrvChar)) 293 { 294 Log(("serial_ioport_write: write 0x%X\n", ch)); 295 int rc = s->pDrvChar->pfnWrite(s->pDrvChar, &ch, 1); 296 AssertRC(rc); 297 } 298 s->thr_ipending = 1; 299 s->lsr |= UART_LSR_THRE; 300 s->lsr |= UART_LSR_TEMT; 301 serial_update_irq(s); 302 } 303 #endif 445 serial_xmit(s); 446 } 304 447 break; 305 448 case 1: … … 311 454 if (s->lsr & UART_LSR_THRE) { 312 455 s->thr_ipending = 1; 456 serial_update_irq(s); 313 457 } 314 serial_update_irq(s);315 458 } 316 459 break; 317 460 case 2: 461 val = val & 0xFF; 462 463 if (s->fcr == val) 464 break; 465 466 /* Did the enable/disable flag change? If so, make sure FIFOs get flushed */ 467 if ((val ^ s->fcr) & UART_FCR_FE) 468 val |= UART_FCR_XFR | UART_FCR_RFR; 469 470 /* FIFO clear */ 471 if (val & UART_FCR_RFR) { 472 TMTimerStop(s->fifo_timeout_timer); 473 s->timeout_ipending = 0; 474 fifo_clear(s, RECV_FIFO); 475 } 476 if (val & UART_FCR_XFR) { 477 fifo_clear(s, XMIT_FIFO); 478 } 479 480 if (val & UART_FCR_FE) { 481 s->iir |= UART_IIR_FE; 482 /* Set RECV_FIFO trigger Level */ 483 switch (val & 0xC0) { 484 case UART_FCR_ITL_1: 485 s->recv_fifo.itl = 1; 486 break; 487 case UART_FCR_ITL_2: 488 s->recv_fifo.itl = 4; 489 break; 490 case UART_FCR_ITL_3: 491 s->recv_fifo.itl = 8; 492 break; 493 case UART_FCR_ITL_4: 494 s->recv_fifo.itl = 14; 495 break; 496 } 497 } else 498 s->iir &= ~UART_IIR_FE; 499 500 /* Set fcr - or at least the bits in it that are supposed to "stick" */ 501 s->fcr = val & 0xC9; 502 serial_update_irq(s); 318 503 break; 319 504 case 3: 320 505 { 321 506 int break_enable; 322 if (s->lcr != val) 323 { 324 s->lcr = val; 325 serial_update_parameters(s); 326 } 507 s->lcr = val; 508 serial_update_parameters(s); 327 509 break_enable = (val >> 6) & 1; 328 510 if (break_enable != s->last_break_enable) { … … 341 523 if (RT_LIKELY(s->pDrvChar)) 342 524 { 343 int rc = s->pDrvChar->pfnSetModemLines(s->pDrvChar, !!(s->mcr & UART_MCR_RTS), !!(s->mcr & UART_MCR_DTR)); 525 int rc = s->pDrvChar->pfnSetModemLines(s->pDrvChar, 526 !!(s->mcr & UART_MCR_RTS), 527 !!(s->mcr & UART_MCR_DTR)); 344 528 AssertRC(rc); 345 529 } … … 369 553 case 0: 370 554 if (s->lcr & UART_LCR_DLAB) { 555 /* DLAB == 1: divisor latch (LS) */ 371 556 ret = s->divider & 0xff; 372 557 } else { … … 374 559 *pRC = VINF_IOM_HC_IOPORT_READ; 375 560 #else 376 Log(("serial_io_port_read: read 0x%X\n", s->rbr)); 377 ret = s->rbr; 378 s->lsr &= ~(UART_LSR_DR | UART_LSR_BI); 561 if (s->fcr & UART_FCR_FE) { 562 ret = fifo_get(s, RECV_FIFO); 563 if (s->recv_fifo.count == 0) 564 s->lsr &= ~(UART_LSR_DR | UART_LSR_BI); 565 else 566 TMTimerSet(s->fifo_timeout_timer, 567 TMTimerGet(s->fifo_timeout_timer) + s->char_transmit_time * 4); 568 s->timeout_ipending = 0; 569 } else { 570 Log(("serial_io_port_read: read 0x%X\n", s->rbr)); 571 ret = s->rbr; 572 s->lsr &= ~(UART_LSR_DR | UART_LSR_BI); 573 } 379 574 serial_update_irq(s); 575 if (s->fRecvWaiting) 380 576 { 577 s->fRecvWaiting = false; 381 578 int rc = RTSemEventSignal(s->ReceiveSem); 382 579 AssertRC(rc); … … 387 584 case 1: 388 585 if (s->lcr & UART_LCR_DLAB) { 586 /* DLAB == 1: divisor latch (MS) */ 389 587 ret = (s->divider >> 8) & 0xff; 390 588 } else { … … 397 595 #else 398 596 ret = s->iir; 399 /* reset THR pending bit */ 400 if ((ret & 0x7) == UART_IIR_THRI) 597 if ((ret & UART_IIR_ID) == UART_IIR_THRI) { 401 598 s->thr_ipending = 0; 599 serial_update_irq(s); 600 } 402 601 /* reset msr changed bit */ 403 602 s->msr_changed = false; 404 serial_update_irq(s);405 603 #endif 406 604 break; … … 423 621 } 424 622 ret = s->lsr; 623 /* Clear break and overrun interrupts */ 624 if (s->lsr & (UART_LSR_BI|UART_LSR_OE)) { 625 #ifndef IN_RING3 626 *pRC = VINF_IOM_HC_IOPORT_READ; 627 #else 628 s->lsr &= ~(UART_LSR_BI|UART_LSR_OE); 629 serial_update_irq(s); 630 #endif 631 } 425 632 break; 426 633 case 6: … … 433 640 } else { 434 641 ret = s->msr; 435 /* Reset delta bits. */ 436 s->msr &= ~UART_MSR_ANY_DELTA; 642 /* Clear delta bits & msr int after read, if they were set */ 643 if (s->msr & UART_MSR_ANY_DELTA) { 644 #ifndef IN_RING3 645 *pRC = VINF_IOM_HC_IOPORT_READ; 646 #else 647 s->msr &= 0xF0; 648 serial_update_irq(s); 649 #endif 650 } 437 651 } 438 652 break; … … 441 655 break; 442 656 } 443 LogFlow(("serial: read addr=0x%02x val=0x%02x\n", addr, ret));444 657 return ret; 445 658 } … … 447 660 #ifdef IN_RING3 448 661 662 static int serial_can_receive(SerialState *s) 663 { 664 if (s->fcr & UART_FCR_FE) { 665 if (s->recv_fifo.count < UART_FIFO_LENGTH) 666 return (s->recv_fifo.count <= s->recv_fifo.itl) 667 ? s->recv_fifo.itl - s->recv_fifo.count : 1; 668 else 669 return 0; 670 } else { 671 return !(s->lsr & UART_LSR_DR); 672 } 673 } 674 675 static void serial_receive(void *opaque, const uint8_t *buf, int size) 676 { 677 SerialState *s = (SerialState*)opaque; 678 if (s->fcr & UART_FCR_FE) { 679 int i; 680 for (i = 0; i < size; i++) { 681 fifo_put(s, RECV_FIFO, buf[i]); 682 } 683 s->lsr |= UART_LSR_DR; 684 /* call the timeout receive callback in 4 char transmit time */ 685 TMTimerSet(s->fifo_timeout_timer, TMTimerGet(s->fifo_timeout_timer) + s->char_transmit_time * 4); 686 } else { 687 if (s->lsr & UART_LSR_DR) 688 s->lsr |= UART_LSR_OE; 689 s->rbr = buf[0]; 690 s->lsr |= UART_LSR_DR; 691 } 692 serial_update_irq(s); 693 } 694 695 /** @copydoc PDMICHARPORT::pfnNotifyRead */ 449 696 static DECLCALLBACK(int) serialNotifyRead(PPDMICHARPORT pInterface, const void *pvBuf, size_t *pcbRead) 450 697 { 451 698 SerialState *pThis = PDMICHARPORT_2_SERIALSTATE(pInterface); 452 int rc; 453 454 Assert(*pcbRead != 0); 699 const uint8_t *pu8Buf = (const uint8_t*)pvBuf; 700 size_t cbRead = *pcbRead; 455 701 456 702 PDMCritSectEnter(&pThis->CritSect, VERR_PERMISSION_DENIED); 457 if (pThis->lsr & UART_LSR_DR) 458 { 459 /* If a character is still in the read queue, then wait for it to be emptied. */ 460 PDMCritSectLeave(&pThis->CritSect); 461 rc = RTSemEventWait(pThis->ReceiveSem, 250); 462 if (RT_FAILURE(rc)) 463 return rc; 464 465 PDMCritSectEnter(&pThis->CritSect, VERR_PERMISSION_DENIED); 466 } 467 468 if (!(pThis->lsr & UART_LSR_DR)) 469 { 470 pThis->rbr = *(const char *)pvBuf; 471 pThis->lsr |= UART_LSR_DR; 472 serial_update_irq(pThis); 473 *pcbRead = 1; 474 rc = VINF_SUCCESS; 475 } 476 else 477 rc = VERR_TIMEOUT; 478 703 for (; cbRead > 0; cbRead--, pu8Buf++) 704 { 705 if (!serial_can_receive(pThis)) 706 { 707 /* If we cannot receive then wait for not more than 250ms. If we still 708 * cannot receive then the new character will either overwrite rbr 709 * or it will be dropped at fifo_put(). */ 710 pThis->fRecvWaiting = true; 711 PDMCritSectLeave(&pThis->CritSect); 712 int rc = RTSemEventWait(pThis->ReceiveSem, 250); 713 PDMCritSectEnter(&pThis->CritSect, VERR_PERMISSION_DENIED); 714 } 715 serial_receive(pThis, &pu8Buf[0], 1); 716 } 479 717 PDMCritSectLeave(&pThis->CritSect); 480 481 return rc; 482 } 483 718 return VINF_SUCCESS; 719 } 720 721 /** @copydoc PDMICHARPORT::pfnNotifyStatusLinesChanged */ 484 722 static DECLCALLBACK(int) serialNotifyStatusLinesChanged(PPDMICHARPORT pInterface, uint32_t newStatusLines) 485 723 { … … 520 758 } 521 759 760 /** @copydoc PDMICHARPORT::pfnNotifyBufferFull */ 522 761 static DECLCALLBACK(int) serialNotifyBufferFull(PPDMICHARPORT pInterface, bool fFull) 523 762 { 524 #if 0525 SerialState *pThis = PDMICHARPORT_2_SERIALSTATE(pInterface);526 PDMCritSectEnter(&pThis->CritSect, VERR_PERMISSION_DENIED);527 if (fFull)528 {529 pThis->lsr &= ~UART_LSR_THRE;530 }531 else532 {533 pThis->thr_ipending = 1;534 pThis->lsr |= UART_LSR_THRE;535 pThis->lsr |= UART_LSR_TEMT;536 }537 serial_update_irq(pThis);538 PDMCritSectLeave(&pThis->CritSect);539 #endif540 763 return VINF_SUCCESS; 541 764 } 542 765 766 /** @copydoc PDMICHARPORT::pfnNotifyBreak */ 543 767 static DECLCALLBACK(int) serialNotifyBreak(PPDMICHARPORT pInterface) 544 768 { … … 555 779 556 780 return VINF_SUCCESS; 781 } 782 783 /** 784 * Fifo timer functions. 785 */ 786 static DECLCALLBACK(void) serialFifoTimer(PPDMDEVINS pDevIns, PTMTIMER pTimer, void *pvUser) 787 { 788 SerialState *s = (SerialState*)pvUser; 789 if (s->recv_fifo.count) 790 { 791 s->timeout_ipending = 1; 792 serial_update_irq(s); 793 } 794 } 795 796 /** 797 * Transmit timer function. 798 * Just retry to transmit a character. 799 * 800 * @param pTimer The timer handle. 801 * @param pDevIns The device instance. 802 * @param pvUser The user pointer. 803 */ 804 static DECLCALLBACK(void) serialTransmitTimer(PPDMDEVINS pDevIns, PTMTIMER pTimer, void *pvUser) 805 { 806 SerialState *s = (SerialState*)pvUser; 807 serial_xmit(s); 808 } 809 810 /** 811 * Reset the serial device. 812 * 813 * @param pDevIns The device instance. 814 */ 815 static DECLCALLBACK(void) serialReset(PPDMDEVINS pDevIns) 816 { 817 SerialState *s = PDMINS_2_DATA(pDevIns, SerialState *); 818 819 s->rbr = 0; 820 s->ier = 0; 821 s->iir = UART_IIR_NO_INT; 822 s->lcr = 0; 823 s->lsr = UART_LSR_TEMT | UART_LSR_THRE; 824 s->msr = UART_MSR_DCD | UART_MSR_DSR | UART_MSR_CTS; 825 /* Default to 9600 baud, 1 start bit, 8 data bits, 1 stop bit, no parity. */ 826 s->divider = 0x0C; 827 s->mcr = UART_MCR_OUT2; 828 s->scr = 0; 829 s->tsr_retry = 0; 830 s->char_transmit_time = (TMTimerGetFreq(CTX_SUFF(s->transmit_timer)) / 9600) * 10; 831 832 fifo_clear(s, RECV_FIFO); 833 fifo_clear(s, XMIT_FIFO); 834 835 s->thr_ipending = 0; 836 s->last_break_enable = 0; 837 # ifdef VBOX_SERIAL_PCI 838 PDMDevHlpPCISetIrqNoWait(s->CTX_SUFF(pDevIns), 0, 0); 839 # else /* !VBOX_SERIAL_PCI */ 840 PDMDevHlpISASetIrqNoWait(s->CTX_SUFF(pDevIns), s->irq, 0); 841 # endif /* !VBOX_SERIAL_PCI */ 557 842 } 558 843 … … 701 986 if ( pThis->irq != iIrq 702 987 || pThis->base != IOBase) 703 return SSMR3SetCfgError(pSSM, RT_SRC_POS, N_("Config mismatch - saved irq=%#x iobase=%#x; configured irq=%#x iobase=%#x"), 988 return SSMR3SetCfgError(pSSM, RT_SRC_POS, 989 N_("Config mismatch - saved irq=%#x iobase=%#x; configured irq=%#x iobase=%#x"), 704 990 iIrq, IOBase, pThis->irq, pThis->base); 705 991 … … 735 1021 static DECLCALLBACK(void) serialRelocate(PPDMDEVINS pDevIns, RTGCINTPTR offDelta) 736 1022 { 737 SerialState *pThis = PDMINS_2_DATA(pDevIns, SerialState *); 738 pThis->pDevInsRC = PDMDEVINS_2_RCPTR(pDevIns); 1023 SerialState *pThis = PDMINS_2_DATA(pDevIns, SerialState *); 1024 pThis->pDevInsRC = PDMDEVINS_2_RCPTR(pDevIns); 1025 pThis->transmit_timerRC = TMTimerRCPtr(pThis->transmit_timerR3); 739 1026 } 740 1027 … … 766 1053 767 1054 /** 768 * @interface_method_impl{PDMIBASE, pfnQueryInterface}1055 * @interface_method_impl{PDMIBASE, pfnQueryInterface} 769 1056 */ 770 1057 static DECLCALLBACK(void *) serialQueryInterface(PPDMIBASE pInterface, const char *pszIID) … … 799 1086 800 1087 /** 801 * @interface_method_impl{PDMDEVREG,pfnConstruct} 802 */ 803 static DECLCALLBACK(int) serialConstruct(PPDMDEVINS pDevIns, 804 int iInstance, 805 PCFGMNODE pCfg) 1088 * @interface_method_impl{PDMDEVREG, pfnConstruct} 1089 */ 1090 static DECLCALLBACK(int) serialConstruct(PPDMDEVINS pDevIns, int iInstance, PCFGMNODE pCfg) 806 1091 { 807 1092 int rc; … … 820 1105 pThis->pDevInsR0 = PDMDEVINS_2_R0PTR(pDevIns); 821 1106 pThis->pDevInsRC = PDMDEVINS_2_RCPTR(pDevIns); 822 823 pThis->lsr = UART_LSR_TEMT | UART_LSR_THRE;824 pThis->iir = UART_IIR_NO_INT;825 pThis->msr = UART_MSR_DCD | UART_MSR_DSR | UART_MSR_CTS;826 1107 827 1108 /* IBase */ … … 921 1202 rc = RTSemEventCreate(&pThis->ReceiveSem); 922 1203 AssertRC(rc); 1204 1205 rc = PDMDevHlpTMTimerCreate(pDevIns, TMCLOCK_VIRTUAL, serialFifoTimer, pThis, 1206 TMTIMER_FLAGS_NO_CRIT_SECT, "Serial Fifo Timer", 1207 &pThis->fifo_timeout_timer); 1208 AssertRC(rc); 1209 1210 rc = PDMDevHlpTMTimerCreate(pDevIns, TMCLOCK_VIRTUAL, serialTransmitTimer, pThis, 1211 TMTIMER_FLAGS_NO_CRIT_SECT, "Serial Transmit Timer", 1212 &pThis->transmit_timerR3); 1213 AssertRC(rc); 1214 pThis->transmit_timerR0 = TMTimerR0Ptr(pThis->transmit_timerR3); 1215 pThis->transmit_timerRC = TMTimerRCPtr(pThis->transmit_timerR3); 1216 1217 serialReset(pDevIns); 923 1218 924 1219 #ifdef VBOX_SERIAL_PCI … … 1036 1331 NULL, 1037 1332 /* pfnReset */ 1038 NULL,1333 serialReset, 1039 1334 /* pfnSuspend */ 1040 1335 NULL, … … 1058 1353 #endif /* IN_RING3 */ 1059 1354 1060 1061 1355 #endif /* !VBOX_DEVICE_STRUCT_TESTCASE */ -
trunk/src/VBox/Devices/Serial/DrvChar.cpp
r28800 r29846 5 5 * Converts synchronous calls (PDMICHARCONNECTOR::pfnWrite, PDMISTREAM::pfnRead) 6 6 * into asynchronous ones. 7 * 8 * Note that we don't use a send buffer here to be able to handle 9 * dropping of bytes for xmit at device level. 7 10 */ 8 11 … … 37 40 * Defined Constants And Macros * 38 41 *******************************************************************************/ 39 /** Size of the send fifo queue (in bytes) */40 #define CHAR_MAX_SEND_QUEUE 0x8041 #define CHAR_MAX_SEND_QUEUE_MASK 0x7f42 43 42 /** Converts a pointer to DRVCHAR::ICharConnector to a PDRVCHAR. */ 44 43 #define PDMICHAR_2_DRVCHAR(pInterface) RT_FROM_MEMBER(pInterface, DRVCHAR, ICharConnector) … … 73 72 74 73 /** Internal send FIFO queue */ 75 uint8_t aSendQueue[CHAR_MAX_SEND_QUEUE]; 76 uint32_t volatile iSendQueueHead; 77 uint32_t iSendQueueTail; 78 uint32_t volatile cEntries; 74 uint8_t volatile u8SendByte; 75 bool volatile fSending; 76 uint8_t Alignment[2]; 79 77 80 78 /** Read/write statistics */ … … 115 113 for (uint32_t i = 0; i < cbWrite; i++) 116 114 { 117 uint32_t iOld = pThis->iSendQueueHead;118 uint32_t iNew = (iOld + 1) & CHAR_MAX_SEND_QUEUE_MASK;119 120 pThis-> aSendQueue[iOld]= pbBuffer[i];121 115 if (ASMAtomicXchgBool(&pThis->fSending, true)) 116 return VERR_BUFFER_OVERFLOW; 117 118 pThis->u8SendByte = pbBuffer[i]; 119 RTSemEventSignal(pThis->SendSem); 122 120 STAM_COUNTER_INC(&pThis->StatBytesWritten); 123 ASMAtomicXchgU32(&pThis->iSendQueueHead, iNew); 124 ASMAtomicIncU32(&pThis->cEntries); 125 if (pThis->cEntries > CHAR_MAX_SEND_QUEUE_MASK / 2) 126 pThis->pDrvCharPort->pfnNotifyBufferFull(pThis->pDrvCharPort, true /*fFull*/); 127 } 128 RTSemEventSignal(pThis->SendSem); 121 } 129 122 return VINF_SUCCESS; 130 123 } … … 153 146 PDRVCHAR pThis = (PDRVCHAR)pvUser; 154 147 148 int rc = VINF_SUCCESS; 155 149 while (!pThis->fShutdown) 156 150 { 157 int rc = RTSemEventWait(pThis->SendSem, RT_INDEFINITE_WAIT); 158 if (RT_FAILURE(rc)) 151 RTMSINTERVAL cMillies = (rc == VERR_TIMEOUT) ? 50 : RT_INDEFINITE_WAIT; 152 rc = RTSemEventWait(pThis->SendSem, cMillies); 153 if ( RT_FAILURE(rc) 154 && rc != VERR_TIMEOUT) 159 155 break; 160 156 … … 166 162 break; 167 163 168 while ( pThis->iSendQueueTail != pThis->iSendQueueHead 169 && !pThis->fShutdown) 164 size_t cbProcessed = 1; 165 uint8_t ch = pThis->u8SendByte; 166 rc = pThis->pDrvStream->pfnWrite(pThis->pDrvStream, &ch, &cbProcessed); 167 if (RT_SUCCESS(rc)) 170 168 { 171 size_t cbProcessed = 1; 172 173 rc = pThis->pDrvStream->pfnWrite(pThis->pDrvStream, &pThis->aSendQueue[pThis->iSendQueueTail], &cbProcessed); 174 pThis->pDrvCharPort->pfnNotifyBufferFull(pThis->pDrvCharPort, false /*fFull*/); 175 if (RT_SUCCESS(rc)) 176 { 177 Assert(cbProcessed); 178 pThis->iSendQueueTail++; 179 pThis->iSendQueueTail &= CHAR_MAX_SEND_QUEUE_MASK; 180 ASMAtomicDecU32(&pThis->cEntries); 181 } 182 else if (rc == VERR_TIMEOUT) 183 { 184 /* Normal case, just means that the stream didn't accept a new 185 * character before the timeout elapsed. Just retry. */ 186 rc = VINF_SUCCESS; 187 } 188 else 189 { 190 LogFlow(("Write failed with %Rrc; skipping\n", rc)); 191 break; 192 } 169 ASMAtomicXchgBool(&pThis->fSending, false); 170 Assert(cbProcessed == 1); 171 } 172 else if (rc == VERR_TIMEOUT) 173 { 174 /* Normal case, just means that the stream didn't accept a new 175 * character before the timeout elapsed. Just retry. */ 176 rc = VINF_SUCCESS; 177 } 178 else 179 { 180 LogRel(("Write failed with %Rrc; skipping\n", rc)); 181 break; 193 182 } 194 183 } … … 462 451 PDM_DRVREG_VERSION 463 452 }; 464
Note:
See TracChangeset
for help on using the changeset viewer.