pc_serial: convert irq handler to use DPC
Let's hope we won't loose data because it. We have to cache the value of IIR read from IsInterruptPending(), because some conditions are acknowledged only by reading it...
This commit is contained in:
parent
c6870d53dc
commit
7e613b4759
@ -10,6 +10,7 @@
|
||||
* Distributed under the terms of the MIT License.
|
||||
*/
|
||||
#include <KernelExport.h>
|
||||
#include <dpc.h>
|
||||
#include <Drivers.h>
|
||||
#include <image.h>
|
||||
#include <malloc.h>
|
||||
@ -27,6 +28,8 @@ config_manager_for_driver_module_info *gConfigManagerModule = NULL;
|
||||
isa_module_info *gISAModule = NULL;
|
||||
pci_module_info *gPCIModule = NULL;
|
||||
tty_module_info *gTTYModule = NULL;
|
||||
dpc_module_info *gDPCModule = NULL;
|
||||
void* gDPCHandle = NULL;
|
||||
sem_id gDriverLock = -1;
|
||||
bool gHandleISA = false;
|
||||
|
||||
@ -653,6 +656,10 @@ init_driver()
|
||||
|
||||
TRACE_FUNCALLS("> init_driver()\n");
|
||||
|
||||
status = get_module(B_DPC_MODULE_NAME, (module_info **)&gDPCModule);
|
||||
if (status < B_OK)
|
||||
goto err_dpc;
|
||||
|
||||
status = get_module(B_TTY_MODULE_NAME, (module_info **)&gTTYModule);
|
||||
if (status < B_OK)
|
||||
goto err_tty;
|
||||
@ -670,6 +677,11 @@ init_driver()
|
||||
if (status < B_OK)
|
||||
goto err_cm;
|
||||
|
||||
status = gDPCModule->new_dpc_queue(&gDPCHandle, "pc_serial irq",
|
||||
B_REAL_TIME_PRIORITY);
|
||||
if (status != B_OK)
|
||||
goto err_dpcq;
|
||||
|
||||
for (int32 i = 0; i < DEVICES_COUNT; i++)
|
||||
gSerialDevices[i] = NULL;
|
||||
|
||||
@ -697,6 +709,9 @@ init_driver()
|
||||
//err_none:
|
||||
delete_sem(gDriverLock);
|
||||
err_sem:
|
||||
gDPCModule->delete_dpc_queue(gDPCHandle);
|
||||
gDPCHandle = NULL;
|
||||
err_dpcq:
|
||||
put_module(B_CONFIG_MANAGER_FOR_DRIVER_MODULE_NAME);
|
||||
err_cm:
|
||||
put_module(B_ISA_MODULE_NAME);
|
||||
@ -705,6 +720,8 @@ err_isa:
|
||||
err_pci:
|
||||
put_module(B_TTY_MODULE_NAME);
|
||||
err_tty:
|
||||
put_module(B_DPC_MODULE_NAME);
|
||||
err_dpc:
|
||||
TRACE_FUNCRET("< init_driver() returns %s\n", strerror(status));
|
||||
return status;
|
||||
}
|
||||
@ -735,10 +752,13 @@ uninit_driver()
|
||||
free(gDeviceNames[i]);
|
||||
|
||||
delete_sem(gDriverLock);
|
||||
gDPCModule->delete_dpc_queue(gDPCHandle);
|
||||
gDPCHandle = NULL;
|
||||
put_module(B_CONFIG_MANAGER_FOR_DRIVER_MODULE_NAME);
|
||||
put_module(B_ISA_MODULE_NAME);
|
||||
put_module(B_PCI_MODULE_NAME);
|
||||
put_module(B_TTY_MODULE_NAME);
|
||||
put_module(B_DPC_MODULE_NAME);
|
||||
|
||||
TRACE_FUNCRET("< uninit_driver() returns\n");
|
||||
}
|
||||
@ -764,28 +784,32 @@ pc_serial_service(struct tty *tty, uint32 op, void *buffer, size_t length)
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
pc_serial_dpc(void *arg)
|
||||
{
|
||||
SerialDevice *master = (SerialDevice *)arg;
|
||||
TRACE_FUNCALLS("> pc_serial_dpc(%p)\n", arg);
|
||||
master->InterruptHandler();
|
||||
}
|
||||
|
||||
|
||||
int32
|
||||
pc_serial_interrupt(void *arg)
|
||||
{
|
||||
int32 ret;
|
||||
SerialDevice *master = (SerialDevice *)arg;
|
||||
SerialDevice *device = (SerialDevice *)arg;
|
||||
TRACE_FUNCALLS("> pc_serial_interrupt(%p)\n", arg);
|
||||
|
||||
if (!master)
|
||||
if (!device)
|
||||
return B_UNHANDLED_INTERRUPT;
|
||||
|
||||
ret = master->InterruptHandler();
|
||||
return ret;
|
||||
|
||||
|
||||
for (int32 i = 0; i < DEVICES_COUNT; i++) {
|
||||
if (gSerialDevices[i] && gSerialDevices[i]->Master() == master) {
|
||||
ret = gSerialDevices[i]->InterruptHandler();
|
||||
// XXX: handle more than 1 ?
|
||||
if (ret != B_UNHANDLED_INTERRUPT) {
|
||||
TRACE_FUNCRET("< pc_serial_interrupt() returns: true\n");
|
||||
return ret;
|
||||
}
|
||||
if (device->IsInterruptPending()) {
|
||||
status_t err;
|
||||
err = gDPCModule->queue_dpc(gDPCHandle, pc_serial_dpc, device);
|
||||
if (err != B_OK)
|
||||
dprintf(DRIVER_NAME ": error queing irq: %s\n", strerror(err));
|
||||
else {
|
||||
TRACE_FUNCRET("< pc_serial_interrupt() returns: handled\n");
|
||||
return B_HANDLED_INTERRUPT;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -29,6 +29,7 @@ SerialDevice::SerialDevice(const struct serial_support_descriptor *device,
|
||||
fIOBase(ioBase),
|
||||
fIRQ(irq),
|
||||
fMaster(master),
|
||||
fCachedIIR(0x1),
|
||||
fReadBufferAvail(0),
|
||||
fReadBufferIn(0),
|
||||
fReadBufferOut(0),
|
||||
@ -320,6 +321,19 @@ SerialDevice::Service(struct tty *tty, uint32 op, void *buffer, size_t length)
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
SerialDevice::IsInterruptPending()
|
||||
{
|
||||
TRACE(("IsInterruptPending()\n"));
|
||||
|
||||
// because reading the IIR acknowledges some IRQ conditions,
|
||||
// the next time we'll read we'll miss the IRQ condition
|
||||
// so we just cache the value for the real handler
|
||||
fCachedIIR = ReadReg8(IIR);
|
||||
return ((fCachedIIR & IIR_PENDING) == 0); // 0 means yes
|
||||
}
|
||||
|
||||
|
||||
int32
|
||||
SerialDevice::InterruptHandler()
|
||||
{
|
||||
@ -329,7 +343,9 @@ SerialDevice::InterruptHandler()
|
||||
uint8 iir, lsr, msr;
|
||||
TRACE(("InterruptHandler()\n"));
|
||||
|
||||
while (((iir = ReadReg8(IIR)) & IIR_PENDING) == 0) { // 0 means yes
|
||||
// start with the first (cached) irq condition
|
||||
iir = fCachedIIR;
|
||||
while ((iir & IIR_PENDING) == 0) { // 0 means yes
|
||||
int fifoavail = 1;
|
||||
int avail;
|
||||
int i;
|
||||
@ -399,6 +415,9 @@ SerialDevice::InterruptHandler()
|
||||
}
|
||||
ret = B_HANDLED_INTERRUPT;
|
||||
TRACE(("IRQ:h\n"));
|
||||
|
||||
// check the next IRQ condition
|
||||
iir = ReadReg8(IIR);
|
||||
}
|
||||
|
||||
TRACE_FUNCRET("< IRQ:%d\n", ret);
|
||||
|
@ -46,6 +46,7 @@ static SerialDevice * MakeDevice(struct serial_config_descriptor
|
||||
bool Service(struct tty *tty, uint32 op,
|
||||
void *buffer, size_t length);
|
||||
|
||||
bool IsInterruptPending();
|
||||
int32 InterruptHandler();
|
||||
|
||||
status_t Open(uint32 flags);
|
||||
@ -112,6 +113,9 @@ static void InterruptCallbackFunction(void *cookie,
|
||||
/* line coding */
|
||||
//usb_serial_line_coding fLineCoding;
|
||||
|
||||
/* deferred interrupt */
|
||||
uint8 fCachedIIR; // cached IRQ condition
|
||||
|
||||
/* data buffers */
|
||||
char fReadBuffer[DEF_BUFFER_SIZE];
|
||||
int32 fReadBufferAvail;
|
||||
|
Loading…
x
Reference in New Issue
Block a user