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);