[haiku-commits] haiku: hrev47761 - src/add-ons/kernel/drivers/ports/pc_serial

  • From: revol@xxxxxxx
  • To: haiku-commits@xxxxxxxxxxxxx
  • Date: Fri, 29 Aug 2014 12:32:47 +0200 (CEST)

hrev47761 adds 11 changesets to branch 'master'
old head: 4a02fc4f421b27765bd6859c2d8593aa1f47fc9c
new head: 02f6c664cc2ea904245a890fe4447168894502aa
overview: http://cgit.haiku-os.org/haiku/log/?qt=range&q=02f6c66+%5E4a02fc4

----------------------------------------------------------------------------

c6870d5: pc_serial: WIP: kinda supports writes through tty module
  
  It's still not fully working, and the tty module doesn't help
  since it's not callable from an irq handler.

7e613b4: 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...

1a6072a: pc_serial: manually probe the default ISA ports
  
  Since config_manager is basically a stub, and even VirtualBox
  doesn't publish the serial ports as PCI devices, we must probe for them.
  
  Ideally config_manager would find them in the device manager tree
  which would have been populated from the PnP BIOS or even ACPI tables...

a5d33e1: pc_serial: try to skip the port used for kernel debugging output
  
  Not that easy to handle all cases correctly,
  but should work for the default case.

7b97fd6: pc_serial: use the tty module directly from the deferred IRQ
  
  It still crashes on close sometimes but writing seems to work.

c5c041a: pc_serial: fix KDL on close
  
  It's working \o/
  Just need to figure out why it waits for \n to transmit.
  
  We now only destroy the cookies in the free hook.
  
  Mention pending DPC as soon as when inside the irq handler.
  
  Also limit the number of loops in the IRQ handler to avoid busy looping.
  It only happened when testing with normal priority but you never know...

ddee8aa: pc_serial: invoke scheduler when queuing DPC
  
  We really want this to be done ASAP...

f71a01a: pc_serial: add a termios member to store config across open cycles

aa05d85: pc_serial: break instead of continue in irq handler
  
  We don't want to busy loop, do we?

efbc894: pc_serial: skip waiting for pending DPC in free hook
  
  Since it's possible to fail queuing them, the count doesn't go down to 0,
  and the process just hangs forever on exit. It might not be necessary anyway.

02f6c66: pc_serial: try to enable 64 byte FIFO
  
  We should probably detect the UART type properly first,
  but the IRQ handler also checks for the available FIFO length anyway.

                                          [ François Revol <revol@xxxxxxx> ]

----------------------------------------------------------------------------

3 files changed, 337 insertions(+), 96 deletions(-)
.../kernel/drivers/ports/pc_serial/Driver.cpp    | 131 +++++++--
.../drivers/ports/pc_serial/SerialDevice.cpp     | 285 ++++++++++++++-----
.../drivers/ports/pc_serial/SerialDevice.h       |  17 +-

############################################################################

Commit:      c6870d53dc268bd27ba6488c62c461c8ac765c2b
URL:         http://cgit.haiku-os.org/haiku/commit/?id=c6870d5
Author:      François Revol <revol@xxxxxxx>
Date:        Thu Aug 28 14:53:48 2014 UTC

pc_serial: WIP: kinda supports writes through tty module

It's still not fully working, and the tty module doesn't help
since it's not callable from an irq handler.

----------------------------------------------------------------------------

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 1e3611a..c16123c 100644
--- a/src/add-ons/kernel/drivers/ports/pc_serial/SerialDevice.cpp
+++ b/src/add-ons/kernel/drivers/ports/pc_serial/SerialDevice.cpp
@@ -12,6 +12,8 @@
 #include "SerialDevice.h"
 #include "UART.h"
 
+#include <sys/ioctl.h>
+
 SerialDevice::SerialDevice(const struct serial_support_descriptor *device,
        uint32 ioBase, uint32 irq, const SerialDevice *master)
        :       /*fSupportDescriptor(device->descriptor),
@@ -30,9 +32,11 @@ SerialDevice::SerialDevice(const struct 
serial_support_descriptor *device,
                fReadBufferAvail(0),
                fReadBufferIn(0),
                fReadBufferOut(0),
+               fReadBufferSem(-1),
                fWriteBufferAvail(0),
                fWriteBufferIn(0),
                fWriteBufferOut(0),
+               fWriteBufferSem(-1),
                fDoneRead(-1),
                fDoneWrite(-1),
                fControlOut(0),
@@ -44,6 +48,8 @@ SerialDevice::SerialDevice(const struct 
serial_support_descriptor *device,
                fDeviceThread(-1),
                fStopDeviceThread(false)
 {
+       memset(fReadBuffer, 'z', DEF_BUFFER_SIZE);
+       memset(fWriteBuffer, 'z', DEF_BUFFER_SIZE);
 }
 
 
@@ -51,18 +57,18 @@ SerialDevice::~SerialDevice()
 {
        Removed();
 
-       if (fDoneRead >= B_OK)
-               delete_sem(fDoneRead);
-       if (fDoneWrite >= B_OK)
-               delete_sem(fDoneWrite);
+       if (fReadBufferSem >= B_OK)
+               delete_sem(fReadBufferSem);
+       if (fWriteBufferSem >= B_OK)
+               delete_sem(fWriteBufferSem);
 }
 
 
 status_t
 SerialDevice::Init()
 {
-       fDoneRead = create_sem(0, "usb_serial:done_read");
-       fDoneWrite = create_sem(0, "usb_serial:done_write");
+       fReadBufferSem = create_sem(0, "pc_serial:done_read");
+       fWriteBufferSem = create_sem(0, "pc_serial:done_write");
 
        // disable DLAB
        WriteReg8(LCR, 0);
@@ -204,6 +210,7 @@ SerialDevice::Service(struct tty *tty, uint32 op, void 
*buffer, size_t length)
        uint8 msr;
        status_t err;
 
+       TRACE("%s(,0x%08lx,,%d)\n", __FUNCTION__, op, length);
        if (tty != fMasterTTY)
                return false;
 
@@ -320,9 +327,12 @@ SerialDevice::InterruptHandler()
        //XXX: what should we do here ? (certainly not use a mutex !)
 
        uint8 iir, lsr, msr;
+       TRACE(("InterruptHandler()\n"));
 
        while (((iir = ReadReg8(IIR)) & IIR_PENDING) == 0) { // 0 means yes
                int fifoavail = 1;
+               int avail;
+               int i;
                
                //DEBUG
 //             for (int count = 0; ReadReg8(LSR) & LSR_DR; count++)
@@ -337,24 +347,31 @@ SerialDevice::InterruptHandler()
                                fifoavail = 16;
                        if (iir & IIR_F64EN)
                                fifoavail = 64;
-                       for (int i = 0; i < fifoavail; i++) {
-                               int chr;
-                               chr = 'H';//XXX: what should we do here ? 
(certainly not call tty_read() !)
-                               if (chr < 0) {
-                                       //WriteReg8(THB, (uint8)chr);
-                                       break;
-                               }
+                       avail = atomic_get(&fWriteBufferAvail);
+                       for (i = 0; i < fifoavail && i < avail; i++) {
+                               uint8 chr = fWriteBuffer[fWriteBufferOut];
                                WriteReg8(THB, (uint8)chr);
+                               fWriteBufferOut++;
+                               fWriteBufferOut %= DEF_BUFFER_SIZE;
                        }
+                       atomic_add(&fWriteBufferAvail, -i);
+                       release_sem_etc(fWriteBufferSem, 1,
+                               B_DO_NOT_RESCHEDULE | 
B_RELEASE_IF_WAITING_ONLY);
+
                        break;
                case IIR_TO:
                case IIR_TO | IIR_RDA:
                        // timeout: FALLTHROUGH
                case IIR_RDA:
                        TRACE(("IIR_TO/RDA\n"));
-                       // while data is ready... get it
-                       while (ReadReg8(LSR) & LSR_DR)
-                               ReadReg8(RBR);//XXX: what should we do here ? 
(certainly not call tty_write() !)
+                       // while data is ready... and we have room for it, get 
it
+                       avail = DEF_BUFFER_SIZE - atomic_get(&fReadBufferAvail);
+                       for (i = 0; i < avail && (ReadReg8(LSR) & LSR_DR); i++) 
{
+                               fReadBuffer[fReadBufferIn] = ReadReg8(RBR);
+                               fReadBufferIn++;
+                               fReadBufferIn %= DEF_BUFFER_SIZE;
+                       }
+                       atomic_add(&fReadBufferAvail, i);
                        break;
                case IIR_RLS:
                        TRACE(("IIR_RLS\n"));
@@ -384,8 +401,6 @@ SerialDevice::InterruptHandler()
                TRACE(("IRQ:h\n"));
        }
 
-
-       //XXX: what should we do here ? (certainly not use a mutex !)
        TRACE_FUNCRET("< IRQ:%d\n", ret);
        return ret;
 }
@@ -436,13 +451,17 @@ SerialDevice::Open(uint32 flags)
 
        ResetDevice();
 
+       //XXX: we shouldn't have to do this!
+       bool en = true;
+       Service(fMasterTTY, TTYENABLE, &en, sizeof(en));
+
        if (status < B_OK) {
                TRACE_ALWAYS("open: failed to open tty\n");
                return status;
        }
 
 #if 0
-       fDeviceThread = spawn_kernel_thread(DeviceThread, "usb_serial device 
thread",
+       fDeviceThread = spawn_kernel_thread(_DeviceThread, "usb_serial device 
thread",
                B_NORMAL_PRIORITY, this);
 
        if (fDeviceThread < B_OK) {
@@ -485,64 +504,55 @@ SerialDevice::Read(char *buffer, size_t *numBytes)
 status_t
 SerialDevice::Write(const char *buffer, size_t *numBytes)
 {
-       //size_t bytesLeft = *numBytes;
-       //*numBytes = 0;
-
-       status_t status = EINVAL;
-
-       //XXX: WTF tty_write() is not for write() hook ?
-       //status = gTTYModule->tty_write(fSystemTTYCookie, buffer, numBytes);
-
-#if 0
-       status_t status = mutex_lock(&fWriteLock);
-       if (status != B_OK) {
-               TRACE_ALWAYS("write: failed to get write lock\n");
-               return status;
-       }
-
+       TRACE("%s(,&%d)\n", __FUNCTION__, *numBytes);
        if (fDeviceRemoved) {
-               mutex_unlock(&fWriteLock);
+               *numBytes = 0;
                return B_DEV_NOT_READY;
        }
 
-       while (bytesLeft > 0) {
-               size_t length = MIN(bytesLeft, fWriteBufferSize);
-               size_t packetLength = length;
-               OnWrite(buffer, &length, &packetLength);
+       size_t bytesLeft = *numBytes;
+       *numBytes = 0;
 
-               status = gUSBModule->queue_bulk(fWritePipe, fWriteBuffer,
-                       packetLength, WriteCallbackFunction, this);
-               if (status < B_OK) {
-                       TRACE_ALWAYS("write: queueing failed with status 
0x%08x\n", status);
-                       break;
+       while (bytesLeft > 0) {
+               size_t length = MIN(bytesLeft, 256);
+                       // TODO: This is an ugly hack; We use a small buffer 
size so that
+                       // we don't overrun the tty line buffer and cause it to 
block. While
+                       // 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,
+                       &length);
+               if (result != B_OK) {
+                       TRACE_ALWAYS("failed to write to tty: %s\n", 
strerror(result));
+                       return result;
                }
 
-               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);
-                       break;
-               }
+               buffer += length;
+               *numBytes += length;
+               bytesLeft -= length;
 
-               if (fStatusWrite != B_OK) {
-                       TRACE("write: device status error 0x%08x\n", 
fStatusWrite);
-                       status = gUSBModule->clear_feature(fWritePipe,
-                               USB_FEATURE_ENDPOINT_HALT);
-                       if (status < B_OK) {
-                               TRACE_ALWAYS("write: failed to clear device 
halt\n");
-                               status = B_ERROR;
+               while (true) {
+                       // Write to the device as long as there's anything in 
the tty buffer
+                       int readable = 0;
+                       gTTYModule->tty_control(fDeviceTTYCookie, FIONREAD, 
&readable,
+                               sizeof(readable));
+                       TRACE("%s: FIONREAD: %d\n", __FUNCTION__, readable);
+                       if (readable == 0)
                                break;
+
+                       result = _WriteToDevice();
+                       if (result != B_OK) {
+                               TRACE_ALWAYS("failed to write to device: %s\n",
+                                       strerror(result));
+                               return result;
                        }
-                       continue;
                }
-
-               buffer += length;
-               *numBytes += length;
-               bytesLeft -= length;
        }
 
-       mutex_unlock(&fWriteLock);
-#endif
-       return status;
+       if (*numBytes > 0)
+               return B_OK;
+
+       return B_ERROR;
 }
 
 
@@ -595,6 +605,10 @@ SerialDevice::Close()
 #endif
        }
 
+       //XXX: we shouldn't have to do this!
+       bool en = false;
+       Service(fMasterTTY, TTYENABLE, &en, sizeof(en));
+
        gTTYModule->tty_destroy_cookie(fSystemTTYCookie);
        gTTYModule->tty_destroy_cookie(fDeviceTTYCookie);
 
@@ -633,8 +647,8 @@ SerialDevice::Removed()
        gUSBModule->cancel_queued_transfers(fControlPipe);
 #endif
 
-       //int32 result = B_OK;
-       //wait_for_thread(fDeviceThread, &result);
+       int32 result = B_OK;
+       wait_for_thread(fDeviceThread, &result);
        fDeviceThread = -1;
 }
 
@@ -695,7 +709,7 @@ SerialDevice::OnClose()
 
 
 int32
-SerialDevice::DeviceThread(void *data)
+SerialDevice::_DeviceThread(void *data)
 {
 #if 0
        SerialDevice *device = (SerialDevice *)data;
@@ -753,6 +767,39 @@ SerialDevice::DeviceThread(void *data)
 }
 
 
+status_t
+SerialDevice::_WriteToDevice()
+{
+       char *buffer = &fWriteBuffer[fWriteBufferIn];
+       size_t bytesLeft = DEF_BUFFER_SIZE - atomic_get(&fWriteBufferAvail);
+       bytesLeft = MIN(bytesLeft, DEF_BUFFER_SIZE - fWriteBufferIn);
+       TRACE("%s: in %d left %d\n", __FUNCTION__, fWriteBufferIn, bytesLeft);
+       status_t status = gTTYModule->tty_read(fDeviceTTYCookie, buffer,
+               &bytesLeft);
+       TRACE("%s: tty_read: %d\n", __FUNCTION__, bytesLeft);
+       if (status != B_OK) {
+               TRACE_ALWAYS("write to device: failed to read from TTY: %s\n",
+                       strerror(status));
+               return status;
+       }
+       fWriteBufferIn += bytesLeft;
+       fWriteBufferIn %= DEF_BUFFER_SIZE;
+       atomic_add(&fWriteBufferAvail, bytesLeft);
+
+       // XXX: WTF: this ought to be done by the tty module calling 
service_func!
+       // enable irqs
+       Service(fMasterTTY, TTYOSTART, NULL, 0);
+
+       status = acquire_sem_etc(fWriteBufferSem, 1, B_CAN_INTERRUPT, 0);
+       if (status != B_OK) {
+               TRACE_ALWAYS("write to device: failed to acquire sem: %s\n",
+                       strerror(status));
+               return status;
+       }
+       return B_OK;
+}
+
+
 void
 SerialDevice::ReadCallbackFunction(void *cookie, int32 status, void *data,
        uint32 actualLength)
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 ce02faf..a01c0c0 100644
--- a/src/add-ons/kernel/drivers/ports/pc_serial/SerialDevice.h
+++ b/src/add-ons/kernel/drivers/ports/pc_serial/SerialDevice.h
@@ -79,7 +79,8 @@ virtual       void                                    
OnClose();
                uint32                                  IRQ() const { return 
fIRQ; };
 
 private:
-static int32                                   DeviceThread(void *data);
+static int32                                   _DeviceThread(void *data);
+               status_t                                _WriteToDevice();
 
 static void                                    ReadCallbackFunction(void 
*cookie,
                                                                        int32 
status, void *data,
@@ -113,13 +114,15 @@ static    void                                    
InterruptCallbackFunction(void *cookie,
 
                /* data buffers */
                char                                    
fReadBuffer[DEF_BUFFER_SIZE];
-               uint32                                  fReadBufferAvail;
+               int32                                   fReadBufferAvail;
                uint32                                  fReadBufferIn;
                uint32                                  fReadBufferOut;
+               sem_id                                  fReadBufferSem;
                char                                    
fWriteBuffer[DEF_BUFFER_SIZE];
-               uint32                                  fWriteBufferAvail;
+               int32                                   fWriteBufferAvail;
                uint32                                  fWriteBufferIn;
                uint32                                  fWriteBufferOut;
+               sem_id                                  fWriteBufferSem;
 
                /* variables used in callback functionality */
                size_t                                  fActualLengthRead;

############################################################################

Commit:      7e613b4759303d69a721d012dac36a87d75001a3
URL:         http://cgit.haiku-os.org/haiku/commit/?id=7e613b4
Author:      François Revol <revol@xxxxxxx>
Date:        Thu Aug 28 16:39:21 2014 UTC

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...

----------------------------------------------------------------------------

diff --git a/src/add-ons/kernel/drivers/ports/pc_serial/Driver.cpp 
b/src/add-ons/kernel/drivers/ports/pc_serial/Driver.cpp
index e0a56a7..feae10c 100644
--- a/src/add-ons/kernel/drivers/ports/pc_serial/Driver.cpp
+++ b/src/add-ons/kernel/drivers/ports/pc_serial/Driver.cpp
@@ -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;
                }
        }
 
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 c16123c..af4fe7e 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),
+               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);
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 a01c0c0..52d92cc 100644
--- a/src/add-ons/kernel/drivers/ports/pc_serial/SerialDevice.h
+++ b/src/add-ons/kernel/drivers/ports/pc_serial/SerialDevice.h
@@ -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;

############################################################################

Commit:      1a6072a0a1bf9c57347963a44fd415235c36c63a
URL:         http://cgit.haiku-os.org/haiku/commit/?id=1a6072a
Author:      François Revol <revol@xxxxxxx>
Date:        Thu Aug 28 17:13:23 2014 UTC

pc_serial: manually probe the default ISA ports

Since config_manager is basically a stub, and even VirtualBox
doesn't publish the serial ports as PCI devices, we must probe for them.

Ideally config_manager would find them in the device manager tree
which would have been populated from the PnP BIOS or even ACPI tables...

----------------------------------------------------------------------------

diff --git a/src/add-ons/kernel/drivers/ports/pc_serial/Driver.cpp 
b/src/add-ons/kernel/drivers/ports/pc_serial/Driver.cpp
index feae10c..46f3ef3 100644
--- a/src/add-ons/kernel/drivers/ports/pc_serial/Driver.cpp
+++ b/src/add-ons/kernel/drivers/ports/pc_serial/Driver.cpp
@@ -151,6 +151,17 @@ static const struct serial_support_descriptor 
sSupportedDevices[] = {
 };
 
 
+// hardcoded ISA ports
+static struct isa_ports {
+       uint32 ioBase;
+       uint32 irq;
+} sHardcodedPorts[] = {
+       { 0x3f8, 4 },
+       { 0x2f8, 3 },
+       { 0x3e8, 4 },
+       { 0x2e8, 3 },
+};
+
 #if 0
 status_t
 pc_serial_device_added(pc_device device, void **cookie)
@@ -492,6 +503,30 @@ next_split:
        return B_OK;
 }
 
+
+// until we support ISA device enumeration from PnP BIOS or ACPI,
+// we have to probe the 4 default COM ports...
+status_t
+scan_isa_hardcoded()
+{
+#ifdef HANDLE_ISA_COM
+       int i;
+
+       //TODO: check and filter out the kernel debug port
+       for (i = 0; i < 4; i++) {
+               SerialDevice *device;
+               device = new(std::nothrow) SerialDevice(&sSupportedDevices[0],
+                       sHardcodedPorts[i].ioBase, sHardcodedPorts[i].irq);
+               if (device && device->Probe())
+                       pc_serial_insert_device(device);
+               else
+                       delete device;
+       }
+#endif
+       return B_OK;
+}
+
+
 // this version doesn't use config_manager, but can't probe the IRQ yet
 status_t
 scan_pci_alt()
@@ -695,14 +730,15 @@ init_driver()
 
        status = ENOENT;
 
-       scan_bus(B_ISA_BUS);
+       (void)scan_bus;
+       //scan_bus(B_ISA_BUS);
        //scan_bus(B_PCI_BUS);
+       scan_isa_hardcoded();
        scan_pci_alt();
 
        // XXX: ISA cards
        // XXX: pcmcia
-       
-       
+
        TRACE_FUNCRET("< init_driver() returns\n");
        return B_OK;
 
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 af4fe7e..9b16729 100644
--- a/src/add-ons/kernel/drivers/ports/pc_serial/SerialDevice.cpp
+++ b/src/add-ons/kernel/drivers/ports/pc_serial/SerialDevice.cpp
@@ -65,6 +65,21 @@ SerialDevice::~SerialDevice()
 }
 
 
+bool
+SerialDevice::Probe()
+{
+       uint8 msr;
+       msr = ReadReg8(MSR);
+       // just in case read twice to make sure the "delta" bits are 0
+       msr = ReadReg8(MSR);
+       // this should be enough to probe for the device for now
+       // we might want to check the scratch reg, and try identifying
+       // the model as in:
+       // 
http://en.wikibooks.org/wiki/Serial_Programming/8250_UART_Programming#Software_Identification_of_the_UART
+       return (msr != 0xff);
+}
+
+
 status_t
 SerialDevice::Init()
 {
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 52d92cc..af2f3ae 100644
--- a/src/add-ons/kernel/drivers/ports/pc_serial/SerialDevice.h
+++ b/src/add-ons/kernel/drivers/ports/pc_serial/SerialDevice.h
@@ -22,6 +22,8 @@ public:
                                                                        
*device, uint32 ioBase, uint32 irq, const SerialDevice *master=NULL);
 virtual                                                        ~SerialDevice();
 
+               bool                                    Probe();
+
 static SerialDevice *                  MakeDevice(struct 
serial_config_descriptor 
                                                                        
*device);
 

############################################################################

Commit:      a5d33e1ab1b342bcf87ba7138ea72f94b496f2ac
URL:         http://cgit.haiku-os.org/haiku/commit/?id=a5d33e1
Author:      François Revol <revol@xxxxxxx>
Date:        Thu Aug 28 18:46:31 2014 UTC

pc_serial: try to skip the port used for kernel debugging output

Not that easy to handle all cases correctly,
but should work for the default case.

----------------------------------------------------------------------------

diff --git a/src/add-ons/kernel/drivers/ports/pc_serial/Driver.cpp 
b/src/add-ons/kernel/drivers/ports/pc_serial/Driver.cpp
index 46f3ef3..6b106f8 100644
--- a/src/add-ons/kernel/drivers/ports/pc_serial/Driver.cpp
+++ b/src/add-ons/kernel/drivers/ports/pc_serial/Driver.cpp
@@ -12,6 +12,7 @@
 #include <KernelExport.h>
 #include <dpc.h>
 #include <Drivers.h>
+#include <driver_settings.h>
 #include <image.h>
 #include <malloc.h>
 #include <stdio.h>
@@ -32,6 +33,7 @@ dpc_module_info *gDPCModule = NULL;
 void* gDPCHandle = NULL;
 sem_id gDriverLock = -1;
 bool gHandleISA = false;
+uint32 gKernelDebugPort = 0x3f8;
 
 // 24 MHz clock
 static const uint32 sDefaultRates[] = {
@@ -512,8 +514,11 @@ scan_isa_hardcoded()
 #ifdef HANDLE_ISA_COM
        int i;
 
-       //TODO: check and filter out the kernel debug port
        for (i = 0; i < 4; i++) {
+               // skip the port used for kernel debugging...
+               if (sHardcodedPorts[i].ioBase == gKernelDebugPort)
+                       continue;
+
                SerialDevice *device;
                device = new(std::nothrow) SerialDevice(&sSupportedDevices[0],
                        sHardcodedPorts[i].ioBase, sHardcodedPorts[i].irq);
@@ -669,6 +674,34 @@ next_split_alt:
 }
 
 
+static void
+check_kernel_debug_port()
+{
+       void *handle;
+       long int value;
+
+       handle = load_driver_settings("kernel");
+       const char *str = get_driver_parameter(handle, "serial_debug_port",
+               NULL, NULL);
+       if (str != NULL) {
+               value = strtol(str, NULL, 0);
+               if (value >= 4) // XXX: actually should be MAX_SERIAL_PORTS...
+                       gKernelDebugPort = (uint32)value;
+               else if (value >= 0) // XXX: we should use the kernel_arg's 
table...
+                       gKernelDebugPort = sHardcodedPorts[value].ioBase;
+       }
+
+       /* TODO: actually handle this in the kernel debugger too!
+       bool enabled = get_driver_boolean_parameter(handle, 
"serial_debug_output",
+               false, true);
+       if (!enabled)
+               gKernelDebugPort = 0;
+       */
+
+       unload_driver_settings(handle);
+}
+
+
 //#pragma mark -
 
 
@@ -730,6 +763,8 @@ init_driver()
 
        status = ENOENT;
 
+       check_kernel_debug_port();
+
        (void)scan_bus;
        //scan_bus(B_ISA_BUS);
        //scan_bus(B_PCI_BUS);

############################################################################

Commit:      7b97fd6dd88917454bca5e300a60e91054c7f19b
URL:         http://cgit.haiku-os.org/haiku/commit/?id=7b97fd6
Author:      François Revol <revol@xxxxxxx>
Date:        Thu Aug 28 21:30:50 2014 UTC

pc_serial: use the tty module directly from the deferred IRQ

It still crashes on close sometimes but writing seems to work.

----------------------------------------------------------------------------

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 9b16729..7c2fbdc 100644
--- a/src/add-ons/kernel/drivers/ports/pc_serial/SerialDevice.cpp
+++ b/src/add-ons/kernel/drivers/ports/pc_serial/SerialDevice.cpp
@@ -30,6 +30,7 @@ SerialDevice::SerialDevice(const struct 
serial_support_descriptor *device,
                fIRQ(irq),
                fMaster(master),
                fCachedIIR(0x1),
+               fPendingDPC(0),
                fReadBufferAvail(0),
                fReadBufferIn(0),
                fReadBufferOut(0),
@@ -356,14 +357,19 @@ SerialDevice::InterruptHandler()
        //XXX: what should we do here ? (certainly not use a mutex !)
 
        uint8 iir, lsr, msr;
+       uint8 buffer[64];
        TRACE(("InterruptHandler()\n"));
 
+       atomic_add(&fPendingDPC, 1);
+
        // start with the first (cached) irq condition
        iir = fCachedIIR;
        while ((iir & IIR_PENDING) == 0) { // 0 means yes
-               int fifoavail = 1;
-               int avail;
-               int i;
+               status_t status;
+               size_t bytesLeft;
+               size_t readable = 0;
+               size_t fifoavail = 1;
+               size_t i;
                
                //DEBUG
 //             for (int count = 0; ReadReg8(LSR) & LSR_DR; count++)
@@ -378,16 +384,26 @@ SerialDevice::InterruptHandler()
                                fifoavail = 16;
                        if (iir & IIR_F64EN)
                                fifoavail = 64;
-                       avail = atomic_get(&fWriteBufferAvail);
-                       for (i = 0; i < fifoavail && i < avail; i++) {
-                               uint8 chr = fWriteBuffer[fWriteBufferOut];
-                               WriteReg8(THB, (uint8)chr);
-                               fWriteBufferOut++;
-                               fWriteBufferOut %= DEF_BUFFER_SIZE;
+                       // we're not open... just discard the data
+                       if (!IsOpen())
+                               continue;
+                       gTTYModule->tty_control(fDeviceTTYCookie, FIONREAD, 
&readable,
+                               sizeof(readable));
+                       TRACE("%s: FIONREAD: %d\n", __FUNCTION__, readable);
+
+                       bytesLeft = MIN(fifoavail, sizeof(buffer));
+                       bytesLeft = MIN(bytesLeft, readable);
+                       TRACE("%s: left %d\n", __FUNCTION__, bytesLeft);
+                       status = gTTYModule->tty_read(fDeviceTTYCookie, buffer, 
&bytesLeft);
+                       TRACE("%s: tty_read: %d\n", __FUNCTION__, bytesLeft);
+                       if (status != B_OK) {
+                               dprintf(DRIVER_NAME ": irq: tty_read: %s\n", 
strerror(status));
+                               continue;
+                       }
+
+                       for (i = 0; i < bytesLeft; i++) {
+                               WriteReg8(THB, buffer[i]);
                        }
-                       atomic_add(&fWriteBufferAvail, -i);
-                       release_sem_etc(fWriteBufferSem, 1,
-                               B_DO_NOT_RESCHEDULE | 
B_RELEASE_IF_WAITING_ONLY);
 
                        break;
                case IIR_TO:
@@ -396,13 +412,19 @@ SerialDevice::InterruptHandler()
                case IIR_RDA:
                        TRACE(("IIR_TO/RDA\n"));
                        // while data is ready... and we have room for it, get 
it
-                       avail = DEF_BUFFER_SIZE - atomic_get(&fReadBufferAvail);
-                       for (i = 0; i < avail && (ReadReg8(LSR) & LSR_DR); i++) 
{
-                               fReadBuffer[fReadBufferIn] = ReadReg8(RBR);
-                               fReadBufferIn++;
-                               fReadBufferIn %= DEF_BUFFER_SIZE;
+                       bytesLeft = sizeof(buffer);
+                       for (i = 0; i < bytesLeft && (ReadReg8(LSR) & LSR_DR); 
i++) {
+                               buffer[i] = ReadReg8(RBR);
+                       }
+                       // we're not open... just discard the data
+                       if (!IsOpen())
+                               continue;
+                       // we shouldn't block here but it's < 256 bytes anyway
+                       status = gTTYModule->tty_write(fDeviceTTYCookie, 
buffer, &i);
+                       if (status != B_OK) {
+                               dprintf(DRIVER_NAME ": irq: tty_write: %s\n", 
strerror(status));
+                               continue;
                        }
-                       atomic_add(&fReadBufferAvail, i);
                        break;
                case IIR_RLS:
                        TRACE(("IIR_RLS\n"));
@@ -414,6 +436,8 @@ SerialDevice::InterruptHandler()
                        TRACE(("IIR_MS\n"));
                        // modem signals changed
                        msr = ReadReg8(MSR);
+                       if (!IsOpen())
+                               continue;
                        if (msr & MSR_DDCD)
                                SignalControlLineState(TTYHWDCD, msr & MSR_DCD);
                        if (msr & MSR_DCTS)
@@ -435,6 +459,8 @@ SerialDevice::InterruptHandler()
                iir = ReadReg8(IIR);
        }
 
+       atomic_add(&fPendingDPC, -1);
+
        TRACE_FUNCRET("< IRQ:%d\n", ret);
        return ret;
 }
@@ -565,22 +591,9 @@ SerialDevice::Write(const char *buffer, size_t *numBytes)
                *numBytes += length;
                bytesLeft -= length;
 
-               while (true) {
-                       // Write to the device as long as there's anything in 
the tty buffer
-                       int readable = 0;
-                       gTTYModule->tty_control(fDeviceTTYCookie, FIONREAD, 
&readable,
-                               sizeof(readable));
-                       TRACE("%s: FIONREAD: %d\n", __FUNCTION__, readable);
-                       if (readable == 0)
-                               break;
-
-                       result = _WriteToDevice();
-                       if (result != B_OK) {
-                               TRACE_ALWAYS("failed to write to device: %s\n",
-                                       strerror(result));
-                               return result;
-                       }
-               }
+               // XXX: WTF: this ought to be done by the tty module calling 
service_func!
+               // enable irqs
+               Service(fMasterTTY, TTYOSTART, NULL, 0);
        }
 
        if (*numBytes > 0)
@@ -639,14 +652,22 @@ SerialDevice::Close()
 #endif
        }
 
+       fDeviceOpen = false;
+
        //XXX: we shouldn't have to do this!
        bool en = false;
        Service(fMasterTTY, TTYENABLE, &en, sizeof(en));
+       // XXX: shouldn't we tty_close_cookie() as well ??
+
+       // wait until currently executing DPC is done. In case another one
+       // is run beyond this point it will just bail out on !IsOpen().
+       while (atomic_get(&fPendingDPC))
+               snooze(1000);
 
        gTTYModule->tty_destroy_cookie(fSystemTTYCookie);
        gTTYModule->tty_destroy_cookie(fDeviceTTYCookie);
+       fSystemTTYCookie = fDeviceTTYCookie = NULL;
 
-       fDeviceOpen = false;
        return status;
 }
 
@@ -658,6 +679,7 @@ SerialDevice::Free()
 
        gTTYModule->tty_destroy(fMasterTTY);
        gTTYModule->tty_destroy(fSlaveTTY);
+       fMasterTTY = fSlaveTTY = NULL;
 
        return status;
 }
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 af2f3ae..35e208c 100644
--- a/src/add-ons/kernel/drivers/ports/pc_serial/SerialDevice.h
+++ b/src/add-ons/kernel/drivers/ports/pc_serial/SerialDevice.h
@@ -117,6 +117,7 @@ static      void                                    
InterruptCallbackFunction(void *cookie,
 
                /* deferred interrupt */
                uint8                                   fCachedIIR;     // 
cached IRQ condition
+               int32                                   fPendingDPC; // some 
IRQ still
 
                /* data buffers */
                char                                    
fReadBuffer[DEF_BUFFER_SIZE];

############################################################################

Commit:      c5c041a5ba9b5d05013436b29e741b6fc0b26b65
URL:         http://cgit.haiku-os.org/haiku/commit/?id=c5c041a
Author:      François Revol <revol@xxxxxxx>
Date:        Thu Aug 28 22:34:25 2014 UTC

pc_serial: fix KDL on close

It's working \o/
Just need to figure out why it waits for \n to transmit.

We now only destroy the cookies in the free hook.

Mention pending DPC as soon as when inside the irq handler.

Also limit the number of loops in the IRQ handler to avoid busy looping.
It only happened when testing with normal priority but you never know...

----------------------------------------------------------------------------

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 7c2fbdc..7774e20 100644
--- a/src/add-ons/kernel/drivers/ports/pc_serial/SerialDevice.cpp
+++ b/src/add-ons/kernel/drivers/ports/pc_serial/SerialDevice.cpp
@@ -346,7 +346,13 @@ SerialDevice::IsInterruptPending()
        // 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
+
+       bool pending = (fCachedIIR & IIR_PENDING) == 0;
+
+       if (pending)
+               atomic_add(&fPendingDPC, 1);
+
+       return pending; // 0 means yes
 }
 
 
@@ -358,10 +364,9 @@ SerialDevice::InterruptHandler()
 
        uint8 iir, lsr, msr;
        uint8 buffer[64];
+       int tries = 8; // avoid busy looping
        TRACE(("InterruptHandler()\n"));
 
-       atomic_add(&fPendingDPC, 1);
-
        // start with the first (cached) irq condition
        iir = fCachedIIR;
        while ((iir & IIR_PENDING) == 0) { // 0 means yes
@@ -455,6 +460,10 @@ SerialDevice::InterruptHandler()
                ret = B_HANDLED_INTERRUPT;
                TRACE(("IRQ:h\n"));
 
+               // enough for now
+               if (tries-- == 0)
+                       break;
+
                // check the next IRQ condition
                iir = ReadReg8(IIR);
        }
@@ -654,19 +663,12 @@ SerialDevice::Close()
 
        fDeviceOpen = false;
 
+       gTTYModule->tty_close_cookie(fSystemTTYCookie);
+       gTTYModule->tty_close_cookie(fDeviceTTYCookie);
+
        //XXX: we shouldn't have to do this!
        bool en = false;
        Service(fMasterTTY, TTYENABLE, &en, sizeof(en));
-       // XXX: shouldn't we tty_close_cookie() as well ??
-
-       // wait until currently executing DPC is done. In case another one
-       // is run beyond this point it will just bail out on !IsOpen().
-       while (atomic_get(&fPendingDPC))
-               snooze(1000);
-
-       gTTYModule->tty_destroy_cookie(fSystemTTYCookie);
-       gTTYModule->tty_destroy_cookie(fDeviceTTYCookie);
-       fSystemTTYCookie = fDeviceTTYCookie = NULL;
 
        return status;
 }
@@ -677,6 +679,15 @@ SerialDevice::Free()
 {
        status_t status = B_OK;
 
+       // wait until currently executing DPC is done. In case another one
+       // is run beyond this point it will just bail out on !IsOpen().
+       while (atomic_get(&fPendingDPC))
+               snooze(1000);
+
+       gTTYModule->tty_destroy_cookie(fSystemTTYCookie);
+       gTTYModule->tty_destroy_cookie(fDeviceTTYCookie);
+       fSystemTTYCookie = fDeviceTTYCookie = NULL;
+
        gTTYModule->tty_destroy(fMasterTTY);
        gTTYModule->tty_destroy(fSlaveTTY);
        fMasterTTY = fSlaveTTY = NULL;

############################################################################

Commit:      ddee8aa960719275fd3919b43d01a20e5da1db9d
URL:         http://cgit.haiku-os.org/haiku/commit/?id=ddee8aa
Author:      François Revol <revol@xxxxxxx>
Date:        Thu Aug 28 22:45:49 2014 UTC

pc_serial: invoke scheduler when queuing DPC

We really want this to be done ASAP...

----------------------------------------------------------------------------

diff --git a/src/add-ons/kernel/drivers/ports/pc_serial/Driver.cpp 
b/src/add-ons/kernel/drivers/ports/pc_serial/Driver.cpp
index 6b106f8..7d0f1e7 100644
--- a/src/add-ons/kernel/drivers/ports/pc_serial/Driver.cpp
+++ b/src/add-ons/kernel/drivers/ports/pc_serial/Driver.cpp
@@ -879,8 +879,8 @@ pc_serial_interrupt(void *arg)
                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;
+                       TRACE_FUNCRET("< pc_serial_interrupt() returns: 
resched\n");
+                       return B_INVOKE_SCHEDULER;
                }
        }
 

############################################################################

Commit:      f71a01ad56085476b025b1b3d213b6436a76c745
URL:         http://cgit.haiku-os.org/haiku/commit/?id=f71a01a
Author:      François Revol <revol@xxxxxxx>
Date:        Thu Aug 28 22:56:13 2014 UTC

pc_serial: add a termios member to store config across open cycles

----------------------------------------------------------------------------

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 7774e20..44cbfcd 100644
--- a/src/add-ons/kernel/drivers/ports/pc_serial/SerialDevice.cpp
+++ b/src/add-ons/kernel/drivers/ports/pc_serial/SerialDevice.cpp
@@ -50,6 +50,8 @@ SerialDevice::SerialDevice(const struct 
serial_support_descriptor *device,
                fDeviceThread(-1),
                fStopDeviceThread(false)
 {
+       memset(&fTTYConfig, 0, sizeof(termios));
+       fTTYConfig.c_cflag = B9600 | CS8 | CREAD;
        memset(fReadBuffer, 'z', DEF_BUFFER_SIZE);
        memset(fWriteBuffer, 'z', DEF_BUFFER_SIZE);
 }
@@ -103,6 +105,21 @@ SerialDevice::SetModes(struct termios *tios)
        if (baudIndex > BLAST)
                baudIndex = BLAST;
 
+       // update our master config in full
+       memcpy(&fTTYConfig, tios, sizeof(termios));
+       fTTYConfig.c_cflag &= ~CBAUD;
+       fTTYConfig.c_cflag |= baudIndex;
+
+       // only apply the relevant parts to the device side
+       termios config;
+       memset(&config, 0, sizeof(termios));
+       config.c_cflag = tios->c_cflag;
+       config.c_cflag &= ~CBAUD;
+       config.c_cflag |= baudIndex;
+
+       // update the termios of the device side
+       gTTYModule->tty_control(fDeviceTTYCookie, TCSETA, &config, 
sizeof(termios));
+
        uint8 lcr = 0;
        uint16 divisor = SupportDescriptor()->bauds[baudIndex];
 
@@ -529,6 +546,10 @@ SerialDevice::Open(uint32 flags)
                return status;
        }
 
+       // set our config (will propagate to the slave config as well in 
SetModes()
+       gTTYModule->tty_control(fSystemTTYCookie, TCSETA, &fTTYConfig,
+               sizeof(termios));
+
 #if 0
        fDeviceThread = spawn_kernel_thread(_DeviceThread, "usb_serial device 
thread",
                B_NORMAL_PRIORITY, this);
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 35e208c..38fca92 100644
--- a/src/add-ons/kernel/drivers/ports/pc_serial/SerialDevice.h
+++ b/src/add-ons/kernel/drivers/ports/pc_serial/SerialDevice.h
@@ -150,6 +150,7 @@ static      void                                    
InterruptCallbackFunction(void *cookie,
                struct tty *                    fSlaveTTY;
                struct tty_cookie *             fSystemTTYCookie;
                struct tty_cookie *             fDeviceTTYCookie;
+               struct termios                  fTTYConfig;
 
                /* device thread management */
                thread_id                               fDeviceThread;

############################################################################

Commit:      aa05d85ca61d21501714d483f1d8bff8ca909dcd
URL:         http://cgit.haiku-os.org/haiku/commit/?id=aa05d85
Author:      François Revol <revol@xxxxxxx>
Date:        Thu Aug 28 23:11:34 2014 UTC

pc_serial: break instead of continue in irq handler

We don't want to busy loop, do we?

----------------------------------------------------------------------------

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 44cbfcd..5b80fe4 100644
--- a/src/add-ons/kernel/drivers/ports/pc_serial/SerialDevice.cpp
+++ b/src/add-ons/kernel/drivers/ports/pc_serial/SerialDevice.cpp
@@ -408,7 +408,7 @@ SerialDevice::InterruptHandler()
                                fifoavail = 64;
                        // we're not open... just discard the data
                        if (!IsOpen())
-                               continue;
+                               break;
                        gTTYModule->tty_control(fDeviceTTYCookie, FIONREAD, 
&readable,
                                sizeof(readable));
                        TRACE("%s: FIONREAD: %d\n", __FUNCTION__, readable);
@@ -420,7 +420,7 @@ SerialDevice::InterruptHandler()
                        TRACE("%s: tty_read: %d\n", __FUNCTION__, bytesLeft);
                        if (status != B_OK) {
                                dprintf(DRIVER_NAME ": irq: tty_read: %s\n", 
strerror(status));
-                               continue;
+                               break;
                        }
 
                        for (i = 0; i < bytesLeft; i++) {
@@ -440,12 +440,12 @@ SerialDevice::InterruptHandler()
                        }
                        // we're not open... just discard the data
                        if (!IsOpen())
-                               continue;
+                               break;
                        // we shouldn't block here but it's < 256 bytes anyway
                        status = gTTYModule->tty_write(fDeviceTTYCookie, 
buffer, &i);
                        if (status != B_OK) {
                                dprintf(DRIVER_NAME ": irq: tty_write: %s\n", 
strerror(status));
-                               continue;
+                               break;
                        }
                        break;
                case IIR_RLS:
@@ -459,7 +459,7 @@ SerialDevice::InterruptHandler()
                        // modem signals changed
                        msr = ReadReg8(MSR);
                        if (!IsOpen())
-                               continue;
+                               break;
                        if (msr & MSR_DDCD)
                                SignalControlLineState(TTYHWDCD, msr & MSR_DCD);
                        if (msr & MSR_DCTS)

############################################################################

Commit:      efbc894614f3e5d3e31d1886a443928292a164d6
URL:         http://cgit.haiku-os.org/haiku/commit/?id=efbc894
Author:      François Revol <revol@xxxxxxx>
Date:        Thu Aug 28 23:29:35 2014 UTC

pc_serial: skip waiting for pending DPC in free hook

Since it's possible to fail queuing them, the count doesn't go down to 0,
and the process just hangs forever on exit. It might not be necessary anyway.

----------------------------------------------------------------------------

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 5b80fe4..d27a830 100644
--- a/src/add-ons/kernel/drivers/ports/pc_serial/SerialDevice.cpp
+++ b/src/add-ons/kernel/drivers/ports/pc_serial/SerialDevice.cpp
@@ -702,8 +702,8 @@ SerialDevice::Free()
 
        // wait until currently executing DPC is done. In case another one
        // is run beyond this point it will just bail out on !IsOpen().
-       while (atomic_get(&fPendingDPC))
-               snooze(1000);
+       //while (atomic_get(&fPendingDPC))
+       //      snooze(1000);
 
        gTTYModule->tty_destroy_cookie(fSystemTTYCookie);
        gTTYModule->tty_destroy_cookie(fDeviceTTYCookie);

############################################################################

Revision:    hrev47761
Commit:      02f6c664cc2ea904245a890fe4447168894502aa
URL:         http://cgit.haiku-os.org/haiku/commit/?id=02f6c66
Author:      François Revol <revol@xxxxxxx>
Date:        Fri Aug 29 09:41:18 2014 UTC

pc_serial: try to enable 64 byte FIFO

We should probably detect the UART type properly first,
but the IRQ handler also checks for the available FIFO length anyway.

----------------------------------------------------------------------------

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 d27a830..ad83803 100644
--- a/src/add-ons/kernel/drivers/ports/pc_serial/SerialDevice.cpp
+++ b/src/add-ons/kernel/drivers/ports/pc_serial/SerialDevice.cpp
@@ -155,7 +155,7 @@ SerialDevice::SetModes(struct termios *tios)
        } else {
                // set FCR now, 
                // 16650 and later chips have another reg at 2 when DLAB=1
-               uint8 fcr = FCR_ENABLE | FCR_RX_RST | FCR_TX_RST | FCR_F_8;
+               uint8 fcr = FCR_ENABLE | FCR_RX_RST | FCR_TX_RST | FCR_F_8 | 
FCR_F64EN;
                // enable fifo
                //fcr = 0;
                WriteReg8(FCR, fcr);


Other related posts: