hrev47763 adds 5 changesets to branch 'master' old head: 9bc823ff5c02e0b7c7d39e6347e6f9d1d42b60c1 new head: a9ccc3a5ec748d2dc296cadb376f54baa7272c3b overview: http://cgit.haiku-os.org/haiku/log/?qt=range&q=a9ccc3a+%5E9bc823f ---------------------------------------------------------------------------- 9ab4970: pc_serial: apply lcr parameters even when unmasking latch reg No need to change line params even more if it was already the same before. e9bbba8: pc_serial: cache IER and temporarily mask IRQs until dpc done No need to be flooded by IRQs while filling in the FIFO... 6e7189d: pc_serial: toggle THRE in IER to make VirtualBox happy Not sure it's needed on real hardware yet. b6708d7: pc_serial: wait for writes to complete on a sem This avoids close being called too early and discarding output. a9ccc3a: pc_serial: mask THRE again when we're out of data [ François Revol <revol@xxxxxxx> ] ---------------------------------------------------------------------------- 2 files changed, 48 insertions(+), 9 deletions(-) .../drivers/ports/pc_serial/SerialDevice.cpp | 56 ++++++++++++++++---- .../drivers/ports/pc_serial/SerialDevice.h | 1 + ############################################################################ Commit: 9ab497059d919d817f65dbcb881a72f99bcb1f41 URL: http://cgit.haiku-os.org/haiku/commit/?id=9ab4970 Author: François Revol <revol@xxxxxxx> Date: Fri Aug 29 10:48:03 2014 UTC pc_serial: apply lcr parameters even when unmasking latch reg No need to change line params even more if it was already the same before. ---------------------------------------------------------------------------- diff --git a/src/add-ons/kernel/drivers/ports/pc_serial/SerialDevice.cpp b/src/add-ons/kernel/drivers/ports/pc_serial/SerialDevice.cpp index ad83803..37e558a 100644 --- a/src/add-ons/kernel/drivers/ports/pc_serial/SerialDevice.cpp +++ b/src/add-ons/kernel/drivers/ports/pc_serial/SerialDevice.cpp @@ -161,7 +161,7 @@ SerialDevice::SetModes(struct termios *tios) WriteReg8(FCR, fcr); // unmask the divisor latch regs - WriteReg8(LCR, LCR_DLAB); + WriteReg8(LCR, lcr | LCR_DLAB); // set divisor WriteReg8(DLLB, divisor & 0x00ff); WriteReg8(DLHB, divisor >> 8); ############################################################################ Commit: e9bbba8b847ca4ca5d13493a08dad81c33b9d443 URL: http://cgit.haiku-os.org/haiku/commit/?id=e9bbba8 Author: François Revol <revol@xxxxxxx> Date: Fri Aug 29 11:37:31 2014 UTC pc_serial: cache IER and temporarily mask IRQs until dpc done No need to be flooded by IRQs while filling in the FIFO... ---------------------------------------------------------------------------- diff --git a/src/add-ons/kernel/drivers/ports/pc_serial/SerialDevice.cpp b/src/add-ons/kernel/drivers/ports/pc_serial/SerialDevice.cpp index 37e558a..5082d1b 100644 --- a/src/add-ons/kernel/drivers/ports/pc_serial/SerialDevice.cpp +++ b/src/add-ons/kernel/drivers/ports/pc_serial/SerialDevice.cpp @@ -29,6 +29,7 @@ SerialDevice::SerialDevice(const struct serial_support_descriptor *device, fIOBase(ioBase), fIRQ(irq), fMaster(master), + fCachedIER(0x0), fCachedIIR(0x1), fPendingDPC(0), fReadBufferAvail(0), @@ -89,6 +90,10 @@ SerialDevice::Init() fReadBufferSem = create_sem(0, "pc_serial:done_read"); fWriteBufferSem = create_sem(0, "pc_serial:done_write"); + // disable IRQ + fCachedIER = 0; + WriteReg8(IER, fCachedIER); + // disable DLAB WriteReg8(LCR, 0); @@ -264,7 +269,8 @@ SerialDevice::Service(struct tty *tty, uint32 op, void *buffer, size_t length) // remove the handler remove_io_interrupt_handler(IRQ(), pc_serial_interrupt, this); // disable IRQ - WriteReg8(IER, 0); + fCachedIER = 0; + WriteReg8(IER, fCachedIER); WriteReg8(MCR, 0); } @@ -277,7 +283,8 @@ SerialDevice::Service(struct tty *tty, uint32 op, void *buffer, size_t length) // WriteReg8(MCR, MCR_DTR | MCR_RTS | MCR_IRQ_EN /*| MCR_LOOP*//*XXXXXXX*/); // enable irqs - WriteReg8(IER, IER_RLS | IER_MS | IER_RDA); + fCachedIER = IER_RLS | IER_MS | IER_RDA; + WriteReg8(IER, fCachedIER); //WriteReg8(IER, IER_RDA); } @@ -330,7 +337,8 @@ SerialDevice::Service(struct tty *tty, uint32 op, void *buffer, size_t length) case TTYOSTART: TRACE("TTYOSTART\n"); // enable irqs - WriteReg8(IER, IER_RLS | IER_MS | IER_RDA | IER_THRE); + fCachedIER |= IER_THRE; + WriteReg8(IER, fCachedIER); return true; case TTYOSYNC: TRACE("TTYOSYNC\n"); @@ -366,8 +374,14 @@ SerialDevice::IsInterruptPending() bool pending = (fCachedIIR & IIR_PENDING) == 0; - if (pending) + if (pending) { + // temporarily mask the IRQ + // else VirtualBox triggers one per every written byte it seems + // not sure it's required on real hardware + WriteReg8(IER, fCachedIER & ~(IER_RLS | IER_MS | IER_RDA | IER_THRE)); + atomic_add(&fPendingDPC, 1); + } return pending; // 0 means yes } @@ -487,6 +501,9 @@ SerialDevice::InterruptHandler() atomic_add(&fPendingDPC, -1); + // unmask IRQ + WriteReg8(IER, fCachedIER); + TRACE_FUNCRET("< IRQ:%d\n", ret); return ret; } diff --git a/src/add-ons/kernel/drivers/ports/pc_serial/SerialDevice.h b/src/add-ons/kernel/drivers/ports/pc_serial/SerialDevice.h index 38fca92..3f9daf8 100644 --- a/src/add-ons/kernel/drivers/ports/pc_serial/SerialDevice.h +++ b/src/add-ons/kernel/drivers/ports/pc_serial/SerialDevice.h @@ -116,6 +116,7 @@ static void InterruptCallbackFunction(void *cookie, //usb_serial_line_coding fLineCoding; /* deferred interrupt */ + uint8 fCachedIER; // last value written to IER uint8 fCachedIIR; // cached IRQ condition int32 fPendingDPC; // some IRQ still ############################################################################ Commit: 6e7189d9b2b41e673c79e0fe9056543ded7c3c82 URL: http://cgit.haiku-os.org/haiku/commit/?id=6e7189d Author: François Revol <revol@xxxxxxx> Date: Fri Aug 29 11:43:20 2014 UTC pc_serial: toggle THRE in IER to make VirtualBox happy Not sure it's needed on real hardware yet. ---------------------------------------------------------------------------- diff --git a/src/add-ons/kernel/drivers/ports/pc_serial/SerialDevice.cpp b/src/add-ons/kernel/drivers/ports/pc_serial/SerialDevice.cpp index 5082d1b..883a0bb 100644 --- a/src/add-ons/kernel/drivers/ports/pc_serial/SerialDevice.cpp +++ b/src/add-ons/kernel/drivers/ports/pc_serial/SerialDevice.cpp @@ -338,6 +338,8 @@ SerialDevice::Service(struct tty *tty, uint32 op, void *buffer, size_t length) TRACE("TTYOSTART\n"); // enable irqs fCachedIER |= IER_THRE; + // XXX: toggle the bit to make VirtualBox happy !? + WriteReg8(IER, fCachedIER & ~IER_THRE); WriteReg8(IER, fCachedIER); return true; case TTYOSYNC: ############################################################################ Commit: b6708d7c47109f3e03d80211cdba141c43b95b43 URL: http://cgit.haiku-os.org/haiku/commit/?id=b6708d7 Author: François Revol <revol@xxxxxxx> Date: Fri Aug 29 13:00:57 2014 UTC pc_serial: wait for writes to complete on a sem This avoids close being called too early and discarding output. ---------------------------------------------------------------------------- diff --git a/src/add-ons/kernel/drivers/ports/pc_serial/SerialDevice.cpp b/src/add-ons/kernel/drivers/ports/pc_serial/SerialDevice.cpp index 883a0bb..e02917f 100644 --- a/src/add-ons/kernel/drivers/ports/pc_serial/SerialDevice.cpp +++ b/src/add-ons/kernel/drivers/ports/pc_serial/SerialDevice.cpp @@ -62,6 +62,8 @@ SerialDevice::~SerialDevice() { Removed(); + if (fDoneWrite >= B_OK) + delete_sem(fDoneWrite); if (fReadBufferSem >= B_OK) delete_sem(fReadBufferSem); if (fWriteBufferSem >= B_OK) @@ -87,6 +89,7 @@ SerialDevice::Probe() status_t SerialDevice::Init() { + fDoneWrite = create_sem(0, "pc_serial:done_write"); fReadBufferSem = create_sem(0, "pc_serial:done_read"); fWriteBufferSem = create_sem(0, "pc_serial:done_write"); @@ -429,6 +432,11 @@ SerialDevice::InterruptHandler() sizeof(readable)); TRACE("%s: FIONREAD: %d\n", __FUNCTION__, readable); + if (readable == 0) { + release_sem_etc(fDoneWrite, 1, B_DO_NOT_RESCHEDULE); + break; + } + bytesLeft = MIN(fifoavail, sizeof(buffer)); bytesLeft = MIN(bytesLeft, readable); TRACE("%s: left %d\n", __FUNCTION__, bytesLeft); @@ -619,6 +627,7 @@ SerialDevice::Write(const char *buffer, size_t *numBytes) return B_DEV_NOT_READY; } + status_t status; size_t bytesLeft = *numBytes; *numBytes = 0; @@ -629,11 +638,11 @@ SerialDevice::Write(const char *buffer, size_t *numBytes) // that isn't a problem, we shouldn't just hardcode the value here. TRACE("%s: tty_write(,&%d)\n", __FUNCTION__, length); - status_t result = gTTYModule->tty_write(fSystemTTYCookie, buffer, + status = gTTYModule->tty_write(fSystemTTYCookie, buffer, &length); - if (result != B_OK) { - TRACE_ALWAYS("failed to write to tty: %s\n", strerror(result)); - return result; + if (status != B_OK) { + TRACE_ALWAYS("failed to write to tty: %s\n", strerror(status)); + return status; } buffer += length; @@ -645,6 +654,14 @@ SerialDevice::Write(const char *buffer, size_t *numBytes) Service(fMasterTTY, TTYOSTART, NULL, 0); } + status = acquire_sem_etc(fDoneWrite, 1, B_CAN_INTERRUPT, 0); + if (status != B_OK) { + TRACE_ALWAYS("write: failed to get write done sem " + "0x%08x\n", status); + return status; + } + + if (*numBytes > 0) return B_OK; ############################################################################ Revision: hrev47763 Commit: a9ccc3a5ec748d2dc296cadb376f54baa7272c3b URL: http://cgit.haiku-os.org/haiku/commit/?id=a9ccc3a Author: François Revol <revol@xxxxxxx> Date: Fri Aug 29 13:05:03 2014 UTC pc_serial: mask THRE again when we're out of data ---------------------------------------------------------------------------- diff --git a/src/add-ons/kernel/drivers/ports/pc_serial/SerialDevice.cpp b/src/add-ons/kernel/drivers/ports/pc_serial/SerialDevice.cpp index e02917f..7e482db 100644 --- a/src/add-ons/kernel/drivers/ports/pc_serial/SerialDevice.cpp +++ b/src/add-ons/kernel/drivers/ports/pc_serial/SerialDevice.cpp @@ -434,6 +434,8 @@ SerialDevice::InterruptHandler() if (readable == 0) { release_sem_etc(fDoneWrite, 1, B_DO_NOT_RESCHEDULE); + // mask it until there's data again + fCachedIER &= ~IER_THRE; break; }