[haiku-commits] r42089 - haiku/trunk/src/add-ons/kernel/drivers/ports/usb_serial

  • From: mmlr@xxxxxxxx
  • To: haiku-commits@xxxxxxxxxxxxx
  • Date: Fri, 10 Jun 2011 19:35:46 +0200 (CEST)

Author: mmlr
Date: 2011-06-10 19:35:46 +0200 (Fri, 10 Jun 2011)
New Revision: 42089
Changeset: https://dev.haiku-os.org/changeset/42089

Modified:
   haiku/trunk/src/add-ons/kernel/drivers/ports/usb_serial/ACM.cpp
   haiku/trunk/src/add-ons/kernel/drivers/ports/usb_serial/ACM.h
   haiku/trunk/src/add-ons/kernel/drivers/ports/usb_serial/SerialDevice.cpp
   haiku/trunk/src/add-ons/kernel/drivers/ports/usb_serial/SerialDevice.h
Log:
* Finish the port to the new tty module. Back when I left off last time it was
  only halfway finished. The way it is supposed to work is that there are two
  tty cookies, representing the system and the device side. Reads and writes
  coming from the system and going to the device are using the system cookie
  while reads and writes coming from the device use the device cookie.
* Move writing to the device into an output thread, similar to how reading from
  the device works. This isn't necessarily a good idea and might be moved back
  into the write hook again to ensure that writes can be made blocking. Right
  now if you just write and then close, the writes will most likely be canceled
  before every going out to the device.
* Removed the read and write lock mutex. They aren't necessary as the tty layer
  will serialize the reads and writes anyway.
* Made simply copying the data to the write buffer the default implementation of
  the OnWrite callback and removed the OnWrite in ACMDevice. The ProlificDevice
  didn't provide an OnWrite hook before, so it would've never written anything.
* Break out the baud index to speed mapping into an inline function. Since the
  defines might change in termios.h just adding an array is a bit fragile (it
  already missed one entry and would've been broken for certain speeds).

This should make usb_serial usable for some (most?) cases. I've tested this with
an Arduino board that uses an FTDI interface. As mentioned above, since writes
currently just write into the tty layer and don't wait for the data to be
flushed, and since close doesn't wait for the output buffers to be drained
either, a simple write and close (as in "echo a > /dev/ports/usb0") will in most
cases cancel the output before it is written to the device. I'm looking into
a few ways to fix that next.


Modified: haiku/trunk/src/add-ons/kernel/drivers/ports/usb_serial/ACM.cpp
===================================================================
--- haiku/trunk/src/add-ons/kernel/drivers/ports/usb_serial/ACM.cpp     
2011-06-10 17:20:27 UTC (rev 42088)
+++ haiku/trunk/src/add-ons/kernel/drivers/ports/usb_serial/ACM.cpp     
2011-06-10 17:35:46 UTC (rev 42089)
@@ -134,10 +134,3 @@
        TRACE_FUNCRET("< ACMDevice::SetControlLineState() returns: 0x%08x\n", 
status);
        return status;
 }
-
-
-void
-ACMDevice::OnWrite(const char *buffer, size_t *numBytes, size_t *packetBytes)
-{
-       memcpy(WriteBuffer(), buffer, *numBytes);
-}

Modified: haiku/trunk/src/add-ons/kernel/drivers/ports/usb_serial/ACM.h
===================================================================
--- haiku/trunk/src/add-ons/kernel/drivers/ports/usb_serial/ACM.h       
2011-06-10 17:20:27 UTC (rev 42088)
+++ haiku/trunk/src/add-ons/kernel/drivers/ports/usb_serial/ACM.h       
2011-06-10 17:35:46 UTC (rev 42089)
@@ -19,9 +19,6 @@
 
 virtual        status_t                                
SetLineCoding(usb_cdc_line_coding *coding);
 virtual        status_t                                
SetControlLineState(uint16 state);
-
-virtual        void                                    OnWrite(const char 
*buffer, size_t *numBytes,
-                                                                       size_t 
*packetBytes);
 };
 
 #endif //_USB_ACM_H_

Modified: 
haiku/trunk/src/add-ons/kernel/drivers/ports/usb_serial/SerialDevice.cpp
===================================================================
--- haiku/trunk/src/add-ons/kernel/drivers/ports/usb_serial/SerialDevice.cpp    
2011-06-10 17:20:27 UTC (rev 42088)
+++ haiku/trunk/src/add-ons/kernel/drivers/ports/usb_serial/SerialDevice.cpp    
2011-06-10 17:35:46 UTC (rev 42089)
@@ -29,6 +29,8 @@
                fBufferArea(-1),
                fReadBuffer(NULL),
                fReadBufferSize(ROUNDUP(DEF_BUFFER_SIZE, 16)),
+               fOutputBuffer(NULL),
+               fOutputBufferSize(ROUNDUP(DEF_BUFFER_SIZE, 16)),
                fWriteBuffer(NULL),
                fWriteBufferSize(ROUNDUP(DEF_BUFFER_SIZE, 16)),
                fInterruptBuffer(NULL),
@@ -39,12 +41,12 @@
                fInputStopped(false),
                fMasterTTY(NULL),
                fSlaveTTY(NULL),
-               fTTYCookie(NULL),
-               fDeviceThread(-1),
-               fStopDeviceThread(false)
+               fSystemTTYCookie(NULL),
+               fDeviceTTYCookie(NULL),
+               fInputThread(-1),
+               fOutputThread(-1),
+               fStopThreads(false)
 {
-       mutex_init(&fReadLock, "usb_serial read lock");
-       mutex_init(&fWriteLock, "usb_serial write lock");
 }
 
 
@@ -59,9 +61,6 @@
 
        if (fBufferArea >= B_OK)
                delete_area(fBufferArea);
-
-       mutex_destroy(&fReadLock);
-       mutex_destroy(&fWriteLock);
 }
 
 
@@ -70,16 +69,15 @@
 {
        fDoneRead = create_sem(0, "usb_serial:done_read");
        fDoneWrite = create_sem(0, "usb_serial:done_write");
-       mutex_init(&fReadLock, "usb_serial:read_lock");
-       mutex_init(&fWriteLock, "usb_serial:write_lock");
 
-       size_t totalBuffers = fReadBufferSize + fWriteBufferSize
+       size_t totalBuffers = fReadBufferSize + fOutputBufferSize + 
fWriteBufferSize
                + fInterruptBufferSize;
        fBufferArea = create_area("usb_serial:buffers_area", (void 
**)&fReadBuffer,
                B_ANY_KERNEL_ADDRESS, ROUNDUP(totalBuffers, B_PAGE_SIZE), 
B_CONTIGUOUS,
                B_READ_AREA | B_WRITE_AREA);
 
-       fWriteBuffer = fReadBuffer + fReadBufferSize;
+       fOutputBuffer = fReadBuffer + fReadBufferSize;
+       fWriteBuffer = fOutputBuffer + fOutputBufferSize;
        fInterruptBuffer = fWriteBuffer + fWriteBufferSize;
        return B_OK;
 }
@@ -106,47 +104,53 @@
 }
 
 
+inline int32
+baud_index_to_speed(int index)
+{
+       switch (index) {
+               case B0: return 0;
+               case B50: return 50;
+               case B75: return 75;
+               case B110: return 110;
+               case B134: return 134;
+               case B150: return 150;
+               case B200: return 200;
+               case B300: return 300;
+               case B600: return 600;
+               case B1200: return 1200;
+               case B1800: return 1800;
+               case B2400: return 2400;
+               case B4800: return 4800;
+               case B9600: return 9600;
+               case B19200: return 19200;
+               case B31250: return 31250;
+               case B38400: return 38400;
+               case B57600: return 57600;
+               case B115200: return 115200;
+               case B230400: return 230400;
+       }
+
+       TRACE_ALWAYS("invalid baud index %d\n", index);
+       return -1;
+}
+
+
 void
 SerialDevice::SetModes(struct termios *tios)
 {
        uint16 newControl = fControlOut;
        TRACE_FUNCRES(trace_termios, tios);
 
-       static uint32 baudRates[] = {
-               0x00000000, //B0
-               0x00000032, //B50
-               0x0000004B, //B75
-               0x0000006E, //B110
-               0x00000086, //B134
-               0x00000096, //B150
-               0x000000C8, //B200
-               0x0000012C, //B300
-               0x00000258, //B600
-               0x000004B0, //B1200
-               0x00000708, //B1800
-               0x00000960, //B2400
-               0x000012C0, //B4800
-               0x00002580, //B9600
-               0x00004B00, //B19200
-               0x00009600, //B38400
-               0x0000E100, //B57600
-               0x0001C200, //B115200
-               0x00038400, //B230400
-               0x00070800, //460800
-               0x000E1000, //921600
-       };
+       int32 speed = baud_index_to_speed(tios->c_cflag & CBAUD);
+       if (speed < 0)
+               speed = baud_index_to_speed(tios->c_ispeed);
+       if (speed < 0)
+               speed = baud_index_to_speed(tios->c_ospeed);
+       if (speed < 0)
+               speed = 19200;
 
-       uint32 baudCount = sizeof(baudRates) / sizeof(baudRates[0]);
-       uint32 baudIndex = tios->c_cflag & CBAUD;
-       if (baudIndex == 0)
-               baudIndex = tios->c_ispeed;
-       if (baudIndex == 0)
-               baudIndex = tios->c_ospeed;
-       if (baudIndex > baudCount)
-               baudIndex = baudCount - 1;
-
        usb_cdc_line_coding lineCoding;
-       lineCoding.speed = baudRates[baudIndex];
+       lineCoding.speed = speed;
        lineCoding.stopbits = (tios->c_cflag & CSTOPB)
                ? USB_CDC_LINE_CODING_2_STOPBITS : 
USB_CDC_LINE_CODING_1_STOPBIT;
 
@@ -190,8 +194,8 @@
                        bool enable = *(bool *)buffer;
                        TRACE("TTYENABLE: %sable\n", enable ? "en" : "dis");
 
-                       gTTYModule->tty_hardware_signal(fTTYCookie, TTYHWDCD, 
enable);
-                       gTTYModule->tty_hardware_signal(fTTYCookie, TTYHWCTS, 
enable);
+                       gTTYModule->tty_hardware_signal(fSystemTTYCookie, 
TTYHWDCD, enable);
+                       gTTYModule->tty_hardware_signal(fSystemTTYCookie, 
TTYHWCTS, enable);
 
                        fControlOut = enable ? USB_CDC_CONTROL_SIGNAL_STATE_DTR
                                | USB_CDC_CONTROL_SIGNAL_STATE_RTS : 0;
@@ -202,19 +206,19 @@
                case TTYISTOP:
                        fInputStopped = *(bool *)buffer;
                        TRACE("TTYISTOP: %sstopped\n", fInputStopped ? "" : 
"not ");
-                       gTTYModule->tty_hardware_signal(fTTYCookie, TTYHWCTS,
+                       gTTYModule->tty_hardware_signal(fSystemTTYCookie, 
TTYHWCTS,
                                !fInputStopped);
                        return true;
 
                case TTYGETSIGNALS:
                        TRACE("TTYGETSIGNALS\n");
-                       gTTYModule->tty_hardware_signal(fTTYCookie, TTYHWDCD,
+                       gTTYModule->tty_hardware_signal(fSystemTTYCookie, 
TTYHWDCD,
                                (fControlOut & (USB_CDC_CONTROL_SIGNAL_STATE_DTR
                                        | USB_CDC_CONTROL_SIGNAL_STATE_RTS)) != 
0);
-                       gTTYModule->tty_hardware_signal(fTTYCookie, TTYHWCTS,
+                       gTTYModule->tty_hardware_signal(fSystemTTYCookie, 
TTYHWCTS,
                                !fInputStopped);
-                       gTTYModule->tty_hardware_signal(fTTYCookie, TTYHWDSR, 
false);
-                       gTTYModule->tty_hardware_signal(fTTYCookie, TTYHWRI, 
false);
+                       gTTYModule->tty_hardware_signal(fSystemTTYCookie, 
TTYHWDSR, false);
+                       gTTYModule->tty_hardware_signal(fSystemTTYCookie, 
TTYHWRI, false);
                        return true;
 
                case TTYSETMODES:
@@ -263,39 +267,60 @@
                return B_NO_MEMORY;
        }
 
-       fSlaveTTY = gTTYModule->tty_create(NULL, false);
+       fSlaveTTY = gTTYModule->tty_create(usb_serial_service, false);
        if (fSlaveTTY == NULL) {
                TRACE_ALWAYS("open: failed to init slave tty\n");
                gTTYModule->tty_destroy(fMasterTTY);
                return B_NO_MEMORY;
        }
 
-       fTTYCookie = gTTYModule->tty_create_cookie(fMasterTTY, fSlaveTTY, 
flags);
-       if (fTTYCookie == NULL) {
-               TRACE_ALWAYS("open: failed to init tty cookie\n");
+       fSystemTTYCookie = gTTYModule->tty_create_cookie(fMasterTTY, fSlaveTTY,
+               flags);
+       if (fSystemTTYCookie == NULL) {
+               TRACE_ALWAYS("open: failed to init system tty cookie\n");
                gTTYModule->tty_destroy(fMasterTTY);
                gTTYModule->tty_destroy(fSlaveTTY);
                return B_NO_MEMORY;
        }
 
+       fDeviceTTYCookie = gTTYModule->tty_create_cookie(fSlaveTTY, fMasterTTY,
+               flags);
+       if (fDeviceTTYCookie == NULL) {
+               TRACE_ALWAYS("open: failed to init device tty cookie\n");
+               gTTYModule->tty_destroy_cookie(fSystemTTYCookie);
+               gTTYModule->tty_destroy(fMasterTTY);
+               gTTYModule->tty_destroy(fSlaveTTY);
+               return B_NO_MEMORY;
+       }
+
        ResetDevice();
 
-       fDeviceThread = spawn_kernel_thread(DeviceThread,
-               "usb_serial device thread", B_NORMAL_PRIORITY, this);
+       fStopThreads = false;
 
-       if (fDeviceThread < B_OK) {
-               TRACE_ALWAYS("open: failed to spawn kernel thread\n");
-               return fDeviceThread;
+       fInputThread = spawn_kernel_thread(_InputThread,
+               "usb_serial input thread", B_NORMAL_PRIORITY, this);
+       if (fInputThread < 0) {
+               TRACE_ALWAYS("open: failed to spawn input thread\n");
+               return fInputThread;
        }
 
-       resume_thread(fDeviceThread);
+       resume_thread(fInputThread);
 
+       fOutputThread = spawn_kernel_thread(_OutputThread,
+               "usb_serial output thread", B_NORMAL_PRIORITY, this);
+       if (fOutputThread < 0) {
+               TRACE_ALWAYS("open: failed to spawn output thread\n");
+               return fOutputThread;
+       }
+
+       resume_thread(fOutputThread);
+
        fControlOut = USB_CDC_CONTROL_SIGNAL_STATE_DTR
                | USB_CDC_CONTROL_SIGNAL_STATE_RTS;
        SetControlLineState(fControlOut);
 
        status_t status = gUSBModule->queue_interrupt(fControlPipe,
-               fInterruptBuffer, fInterruptBufferSize, 
InterruptCallbackFunction,
+               fInterruptBuffer, fInterruptBufferSize, 
_InterruptCallbackFunction,
                this);
        if (status < B_OK)
                TRACE_ALWAYS("failed to queue initial interrupt\n");
@@ -313,75 +338,19 @@
                return B_DEV_NOT_READY;
        }
 
-       status_t status = mutex_lock(&fReadLock);
-       if (status != B_OK) {
-               TRACE_ALWAYS("read: failed to get read lock\n");
-               *numBytes = 0;
-               return status;
-       }
-
-       status = gTTYModule->tty_read(fTTYCookie, buffer, numBytes);
-
-       mutex_unlock(&fReadLock);
-       return status;
+       return gTTYModule->tty_read(fSystemTTYCookie, buffer, numBytes);
 }
 
 
 status_t
 SerialDevice::Write(const char *buffer, size_t *numBytes)
 {
-       size_t bytesLeft = *numBytes;
-       *numBytes = 0;
-
-       status_t status = mutex_lock(&fWriteLock);
-       if (status != B_OK) {
-               TRACE_ALWAYS("write: failed to get write lock\n");
-               return status;
-       }
-
        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);
-
-               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;
-               }
-
-               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;
-               }
-
-               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;
-                               break;
-                       }
-                       continue;
-               }
-
-               buffer += length;
-               *numBytes += length;
-               bytesLeft -= length;
-       }
-
-       mutex_unlock(&fWriteLock);
-       return status;
+       return gTTYModule->tty_write(fSystemTTYCookie, buffer, numBytes);
 }
 
 
@@ -391,7 +360,9 @@
        if (fDeviceRemoved)
                return B_DEV_NOT_READY;
 
-       return gTTYModule->tty_control(fTTYCookie, op, arg, length);
+       gTTYModule->tty_control(fSystemTTYCookie, op, arg, length);
+       gTTYModule->tty_control(fDeviceTTYCookie, op, arg, length);
+       return B_OK;
 }
 
 
@@ -401,7 +372,7 @@
        if (fDeviceRemoved)
                return B_DEV_NOT_READY;
 
-       return gTTYModule->tty_select(fTTYCookie, event, ref, sync);
+       return gTTYModule->tty_select(fSystemTTYCookie, event, ref, sync);
 }
 
 
@@ -411,7 +382,7 @@
        if (fDeviceRemoved)
                return B_DEV_NOT_READY;
 
-       return gTTYModule->tty_deselect(fTTYCookie, event, sync);
+       return gTTYModule->tty_deselect(fSystemTTYCookie, event, sync);
 }
 
 
@@ -420,14 +391,30 @@
 {
        OnClose();
 
+       // TODO: wait for the output buffer to be flushed?
+
+       fStopThreads = true;
+       fInputStopped = false;
+
        if (!fDeviceRemoved) {
                gUSBModule->cancel_queued_transfers(fReadPipe);
                gUSBModule->cancel_queued_transfers(fWritePipe);
                gUSBModule->cancel_queued_transfers(fControlPipe);
        }
 
-       gTTYModule->tty_destroy_cookie(fTTYCookie);
+       int32 result = B_OK;
+       wait_for_thread(fInputThread, &result);
+       fInputThread = -1;
 
+       wait_for_thread(fOutputThread, &result);
+       fOutputThread = -1;
+
+       gTTYModule->tty_destroy_cookie(fSystemTTYCookie);
+       gTTYModule->tty_destroy_cookie(fDeviceTTYCookie);
+
+       gTTYModule->tty_destroy(fMasterTTY);
+       gTTYModule->tty_destroy(fSlaveTTY);
+
        fDeviceOpen = false;
        return B_OK;
 }
@@ -436,8 +423,6 @@
 status_t
 SerialDevice::Free()
 {
-       gTTYModule->tty_destroy(fMasterTTY);
-       gTTYModule->tty_destroy(fSlaveTTY);
        return B_OK;
 }
 
@@ -452,18 +437,18 @@
        fDeviceRemoved = true;
 
        // we need to ensure that we do not use the device anymore
-       fStopDeviceThread = true;
+       fStopThreads = true;
        fInputStopped = false;
        gUSBModule->cancel_queued_transfers(fReadPipe);
        gUSBModule->cancel_queued_transfers(fWritePipe);
        gUSBModule->cancel_queued_transfers(fControlPipe);
 
        int32 result = B_OK;
-       wait_for_thread(fDeviceThread, &result);
-       fDeviceThread = -1;
+       wait_for_thread(fInputThread, &result);
+       fInputThread = -1;
 
-       mutex_lock(&fWriteLock);
-       mutex_unlock(&fWriteLock);
+       wait_for_thread(fOutputThread, &result);
+       fOutputThread = -1;
 }
 
 
@@ -509,7 +494,7 @@
 void
 SerialDevice::OnWrite(const char *buffer, size_t *numBytes, size_t 
*packetBytes)
 {
-       // default implementation - does nothing
+       memcpy(fWriteBuffer, buffer, *numBytes);
 }
 
 
@@ -521,35 +506,37 @@
 
 
 int32
-SerialDevice::DeviceThread(void *data)
+SerialDevice::_InputThread(void *data)
 {
        SerialDevice *device = (SerialDevice *)data;
 
-       while (!device->fStopDeviceThread) {
+       while (!device->fStopThreads) {
                status_t status = gUSBModule->queue_bulk(device->fReadPipe,
                        device->fReadBuffer, device->fReadBufferSize,
-                       device->ReadCallbackFunction, data);
+                       device->_ReadCallbackFunction, data);
                if (status < B_OK) {
-                       TRACE_ALWAYS("device thread: queueing failed with 
error: 0x%08x\n",
+                       TRACE_ALWAYS("input thread: queueing failed with error: 
0x%08x\n",
                                status);
-                       break;
+                       return status;
                }
 
                status = acquire_sem_etc(device->fDoneRead, 1, B_CAN_INTERRUPT, 
0);
                if (status < B_OK) {
-                       TRACE_ALWAYS("device thread: failed to get read done 
sem 0x%08x\n",
+                       TRACE_ALWAYS("input thread: failed to get read done sem 
0x%08x\n",
                                status);
-                       break;
+                       return status;
                }
 
                if (device->fStatusRead != B_OK) {
-                       TRACE("device thread: device status error 0x%08x\n",
+                       TRACE("input thread: device status error 0x%08x\n",
                                device->fStatusRead);
                        if (gUSBModule->clear_feature(device->fReadPipe,
                                USB_FEATURE_ENDPOINT_HALT) != B_OK) {
-                               TRACE_ALWAYS("device thread: failed to clear 
halt feature\n");
-                               break;
+                               TRACE_ALWAYS("input thread: failed to clear 
halt feature\n");
+                               return B_ERROR;
                        }
+
+                       continue;
                }
 
                char *buffer = device->fReadBuffer;
@@ -561,15 +548,79 @@
                while (device->fInputStopped)
                        snooze(100);
 
-               gTTYModule->tty_write(device->fTTYCookie, buffer, &readLength);
+               status = gTTYModule->tty_write(device->fDeviceTTYCookie, buffer,
+                       &readLength);
+               if (status != B_OK) {
+                       TRACE_ALWAYS("input thread: failed to write into 
TTY\n");
+                       return status;
+               }
        }
 
        return B_OK;
 }
 
 
+int32
+SerialDevice::_OutputThread(void *data)
+{
+       SerialDevice *device = (SerialDevice *)data;
+
+       while (!device->fStopThreads) {
+               char *buffer = device->fOutputBuffer;
+               size_t bytesLeft = device->fOutputBufferSize;
+               status_t status = 
gTTYModule->tty_read(device->fDeviceTTYCookie, buffer,
+                       &bytesLeft);
+               if (status != B_OK) {
+                       TRACE_ALWAYS("output thread: failed to read from 
TTY\n");
+                       return status;
+               }
+
+               while (bytesLeft > 0) {
+                       size_t length = MIN(bytesLeft, 
device->fWriteBufferSize);
+                       size_t packetLength = length;
+                       device->OnWrite(buffer, &length, &packetLength);
+
+                       status = gUSBModule->queue_bulk(device->fWritePipe,
+                               device->fWriteBuffer, packetLength, 
_WriteCallbackFunction,
+                               device);
+                       if (status < B_OK) {
+                               TRACE_ALWAYS("output thread: queueing failed 
with status "
+                                       "0x%08x\n", status);
+                               return status;
+                       }
+
+                       status = acquire_sem_etc(device->fDoneWrite, 1, 
B_CAN_INTERRUPT, 0);
+                       if (status != B_OK) {
+                               TRACE_ALWAYS("output thread: failed to get 
write done sem "
+                                       "0x%08x\n", status);
+                               return status;
+                       }
+
+                       if (device->fStatusWrite != B_OK) {
+                               TRACE("output thread: device status error 
0x%08x\n",
+                                       device->fStatusWrite);
+                               status = 
gUSBModule->clear_feature(device->fWritePipe,
+                                       USB_FEATURE_ENDPOINT_HALT);
+                               if (status < B_OK) {
+                                       TRACE_ALWAYS("output thread: failed to 
clear device "
+                                               "halt\n");
+                                       return B_ERROR;
+                               }
+
+                               continue;
+                       }
+
+                       buffer += length;
+                       bytesLeft -= length;
+               }
+       }
+
+       return B_OK;
+}
+
+
 void
-SerialDevice::ReadCallbackFunction(void *cookie, int32 status, void *data,
+SerialDevice::_ReadCallbackFunction(void *cookie, int32 status, void *data,
        uint32 actualLength)
 {
        TRACE_FUNCALLS("read callback: cookie: 0x%08x status: 0x%08x data: 
0x%08x "
@@ -583,7 +634,7 @@
 
 
 void
-SerialDevice::WriteCallbackFunction(void *cookie, int32 status, void *data,
+SerialDevice::_WriteCallbackFunction(void *cookie, int32 status, void *data,
        uint32 actualLength)
 {
        TRACE_FUNCALLS("write callback: cookie: 0x%08x status: 0x%08x data: 
0x%08x "
@@ -597,7 +648,7 @@
 
 
 void
-SerialDevice::InterruptCallbackFunction(void *cookie, int32 status,
+SerialDevice::_InterruptCallbackFunction(void *cookie, int32 status,
        void *data, uint32 actualLength)
 {
        TRACE_FUNCALLS("interrupt callback: cookie: 0x%08x status: 0x%08x data: 
"
@@ -612,7 +663,7 @@
        if (status == B_OK && !device->fDeviceRemoved) {
                status = gUSBModule->queue_interrupt(device->fControlPipe,
                        device->fInterruptBuffer, device->fInterruptBufferSize,
-                       device->InterruptCallbackFunction, device);
+                       device->_InterruptCallbackFunction, device);
        }
 }
 

Modified: haiku/trunk/src/add-ons/kernel/drivers/ports/usb_serial/SerialDevice.h
===================================================================
--- haiku/trunk/src/add-ons/kernel/drivers/ports/usb_serial/SerialDevice.h      
2011-06-10 17:20:27 UTC (rev 42088)
+++ haiku/trunk/src/add-ons/kernel/drivers/ports/usb_serial/SerialDevice.h      
2011-06-10 17:35:46 UTC (rev 42089)
@@ -76,16 +76,18 @@
                void                                    
SetReadBufferSize(size_t size) { fReadBufferSize = size; };
                void                                    
SetWriteBufferSize(size_t size) { fWriteBufferSize = size; };
                void                                    
SetInterruptBufferSize(size_t size) { fInterruptBufferSize = size; };
+
 private:
-static int32                                   DeviceThread(void *data);
+static int32                                   _InputThread(void *data);
+static int32                                   _OutputThread(void *data);
 
-static void                                    ReadCallbackFunction(void 
*cookie,
+static void                                    _ReadCallbackFunction(void 
*cookie,
                                                                        int32 
status, void *data,
                                                                        uint32 
actualLength);
-static void                                    WriteCallbackFunction(void 
*cookie,
+static void                                    _WriteCallbackFunction(void 
*cookie,
                                                                        int32 
status, void *data,
                                                                        uint32 
actualLength);
-static void                                    InterruptCallbackFunction(void 
*cookie,
+static void                                    _InterruptCallbackFunction(void 
*cookie,
                                                                        int32 
status, void *data,
                                                                        uint32 
actualLength);
 
@@ -108,6 +110,8 @@
                area_id                                 fBufferArea;
                char *                                  fReadBuffer;
                size_t                                  fReadBufferSize;
+               char *                                  fOutputBuffer;
+               size_t                                  fOutputBufferSize;
                char *                                  fWriteBuffer;
                size_t                                  fWriteBufferSize;
                char *                                  fInterruptBuffer;
@@ -129,15 +133,13 @@
                bool                                    fInputStopped;
                struct tty *                    fMasterTTY;
                struct tty *                    fSlaveTTY;
-               struct tty_cookie *             fTTYCookie;
+               struct tty_cookie *             fSystemTTYCookie;
+               struct tty_cookie *             fDeviceTTYCookie;
 
-               /* device thread management */
-               thread_id                               fDeviceThread;
-               bool                                    fStopDeviceThread;
-
-               /* device locks to ensure no concurent reads/writes */
-               mutex                                   fReadLock;
-               mutex                                   fWriteLock;
+               /* input/output thread management */
+               thread_id                               fInputThread;
+               thread_id                               fOutputThread;
+               bool                                    fStopThreads;
 };
 
 #endif // _USB_DEVICE_H_


Other related posts: