pc_serial: cache IER and temporarily mask IRQs until dpc done
No need to be flooded by IRQs while filling in the FIFO...
This commit is contained in:
@@ -29,6 +29,7 @@ SerialDevice::SerialDevice(const struct serial_support_descriptor *device,
|
|||||||
fIOBase(ioBase),
|
fIOBase(ioBase),
|
||||||
fIRQ(irq),
|
fIRQ(irq),
|
||||||
fMaster(master),
|
fMaster(master),
|
||||||
|
fCachedIER(0x0),
|
||||||
fCachedIIR(0x1),
|
fCachedIIR(0x1),
|
||||||
fPendingDPC(0),
|
fPendingDPC(0),
|
||||||
fReadBufferAvail(0),
|
fReadBufferAvail(0),
|
||||||
@@ -89,6 +90,10 @@ SerialDevice::Init()
|
|||||||
fReadBufferSem = create_sem(0, "pc_serial:done_read");
|
fReadBufferSem = create_sem(0, "pc_serial:done_read");
|
||||||
fWriteBufferSem = create_sem(0, "pc_serial:done_write");
|
fWriteBufferSem = create_sem(0, "pc_serial:done_write");
|
||||||
|
|
||||||
|
// disable IRQ
|
||||||
|
fCachedIER = 0;
|
||||||
|
WriteReg8(IER, fCachedIER);
|
||||||
|
|
||||||
// disable DLAB
|
// disable DLAB
|
||||||
WriteReg8(LCR, 0);
|
WriteReg8(LCR, 0);
|
||||||
|
|
||||||
@@ -264,7 +269,8 @@ SerialDevice::Service(struct tty *tty, uint32 op, void *buffer, size_t length)
|
|||||||
// remove the handler
|
// remove the handler
|
||||||
remove_io_interrupt_handler(IRQ(), pc_serial_interrupt, this);
|
remove_io_interrupt_handler(IRQ(), pc_serial_interrupt, this);
|
||||||
// disable IRQ
|
// disable IRQ
|
||||||
WriteReg8(IER, 0);
|
fCachedIER = 0;
|
||||||
|
WriteReg8(IER, fCachedIER);
|
||||||
WriteReg8(MCR, 0);
|
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*/);
|
WriteReg8(MCR, MCR_DTR | MCR_RTS | MCR_IRQ_EN /*| MCR_LOOP*//*XXXXXXX*/);
|
||||||
// enable irqs
|
// enable irqs
|
||||||
WriteReg8(IER, IER_RLS | IER_MS | IER_RDA);
|
fCachedIER = IER_RLS | IER_MS | IER_RDA;
|
||||||
|
WriteReg8(IER, fCachedIER);
|
||||||
//WriteReg8(IER, IER_RDA);
|
//WriteReg8(IER, IER_RDA);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -330,7 +337,8 @@ SerialDevice::Service(struct tty *tty, uint32 op, void *buffer, size_t length)
|
|||||||
case TTYOSTART:
|
case TTYOSTART:
|
||||||
TRACE("TTYOSTART\n");
|
TRACE("TTYOSTART\n");
|
||||||
// enable irqs
|
// enable irqs
|
||||||
WriteReg8(IER, IER_RLS | IER_MS | IER_RDA | IER_THRE);
|
fCachedIER |= IER_THRE;
|
||||||
|
WriteReg8(IER, fCachedIER);
|
||||||
return true;
|
return true;
|
||||||
case TTYOSYNC:
|
case TTYOSYNC:
|
||||||
TRACE("TTYOSYNC\n");
|
TRACE("TTYOSYNC\n");
|
||||||
@@ -366,8 +374,14 @@ SerialDevice::IsInterruptPending()
|
|||||||
|
|
||||||
bool pending = (fCachedIIR & IIR_PENDING) == 0;
|
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);
|
atomic_add(&fPendingDPC, 1);
|
||||||
|
}
|
||||||
|
|
||||||
return pending; // 0 means yes
|
return pending; // 0 means yes
|
||||||
}
|
}
|
||||||
@@ -487,6 +501,9 @@ SerialDevice::InterruptHandler()
|
|||||||
|
|
||||||
atomic_add(&fPendingDPC, -1);
|
atomic_add(&fPendingDPC, -1);
|
||||||
|
|
||||||
|
// unmask IRQ
|
||||||
|
WriteReg8(IER, fCachedIER);
|
||||||
|
|
||||||
TRACE_FUNCRET("< IRQ:%d\n", ret);
|
TRACE_FUNCRET("< IRQ:%d\n", ret);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -116,6 +116,7 @@ static void InterruptCallbackFunction(void *cookie,
|
|||||||
//usb_serial_line_coding fLineCoding;
|
//usb_serial_line_coding fLineCoding;
|
||||||
|
|
||||||
/* deferred interrupt */
|
/* deferred interrupt */
|
||||||
|
uint8 fCachedIER; // last value written to IER
|
||||||
uint8 fCachedIIR; // cached IRQ condition
|
uint8 fCachedIIR; // cached IRQ condition
|
||||||
int32 fPendingDPC; // some IRQ still
|
int32 fPendingDPC; // some IRQ still
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user