Jaakko --

Here is a patch against 2.4.26 for io_edgeport.c that I am testing.
The driver still has problems, but you can try this out if you
want.

This includes the changes needed to fix the 2.4.26 OHCI problem
you found, along with some other changes: fix for oops on disconnect,
and spin locks to protect txfifo, txCredits, and rxBytesAvail.

It does sort of work on OHCI.  If you push the data rate too
high or transmit data on two many ports it will fail, unable
to open ports or receive data (a bulk in callback is lost).
You will also see occasional data corruption.  Same problems
exist on UHCI.

-- Al


diff --exclude-from=diff.exclude -ur linux-2.4.26/drivers/usb/serial/io_edgeport.c linux-2.4.26-ion/drivers/usb/serial/io_edgeport.c
--- linux-2.4.26/drivers/usb/serial/io_edgeport.c 2004-04-14 08:05:35.000000000 -0500
+++ linux-2.4.26-ion/drivers/usb/serial/io_edgeport.c 2004-06-20 01:45:15.000000000 -0500
@@ -23,6 +23,10 @@
* Edgeport/4D8
* Edgeport/8i
*
+ * For questions or problems with this driver, contact Inside Out
+ * Networks technical support, or Peter Berger <[EMAIL PROTECTED]>,
+ * or Al Borchers <[EMAIL PROTECTED]>.
+ *
* Version history:
*
* 2003_04_03 al borchers
@@ -274,7 +278,7 @@
/*
* Version Information
*/
-#define DRIVER_VERSION "v2.3"
+#define DRIVER_VERSION "v2.3a"
#define DRIVER_AUTHOR "Greg Kroah-Hartman <[EMAIL PROTECTED]> and David Iacovelli"
#define DRIVER_DESC "Edgeport USB Serial Driver"


@@ -311,6 +315,8 @@
 #endif
 #define PORT_MAGIC             0x7301

+#define EDGE_TMP_BUF_SIZE      4096
+

 /* receive port state */
 enum RXSTATE {
@@ -342,6 +348,8 @@
        struct TxFifo           txfifo;                 /* transmit fifo -- size will 
be maxTxCredits */
        struct urb              *write_urb;             /* write URB for this port */
        char                    write_in_progress;      /* TRUE while a write URB is 
outstanding */
+       struct tasklet_struct   send_data_tasklet;
+       spinlock_t              ep_lock;

__u8 shadowLCR; /* last LCR value received */
__u8 shadowMCR; /* last MCR value received */
@@ -383,6 +391,9 @@
__u8 bulk_in_endpoint; /* the bulk in endpoint handle */
unsigned char * bulk_in_buffer; /* the buffer we use for the bulk in endpoint */
struct urb * read_urb; /* our bulk read urb */
+ int read_in_progress;
+ struct tasklet_struct submit_read_tasklet;
+ spinlock_t es_lock;


        __u8                    bulk_out_endpoint;              /* the bulk out 
endpoint handle */

@@ -435,6 +446,9 @@
/* local variables */
static int CmdUrbs = 0; /* Number of outstanding Command Write Urbs */


+static char edge_tmp_buf[EDGE_TMP_BUF_SIZE];
+static struct semaphore edge_tmp_buf_sem;
+

 /* local function prototypes */

@@ -762,16 +776,16 @@
        int position;
        int txCredits;
        int portNumber;
-       int result;
+       int do_read;

        dbg("%s", __FUNCTION__);

- if (serial_paranoia_check (edge_serial->serial, __FUNCTION__)) {
+ if (urb->status) {
+ dbg("%s - nonzero control read status received: %d", __FUNCTION__, urb->status);
return;
}


- if (urb->status) {
- dbg("%s - nonzero control read status received: %d", __FUNCTION__, urb->status);
+ if (serial_paranoia_check (edge_serial->serial, __FUNCTION__)) {
return;
}


@@ -782,19 +796,16 @@
if (length > 1) {
bytes_avail = data[0] | (data[1] << 8);
if (bytes_avail) {
+ spin_lock(&edge_serial->es_lock);
edge_serial->rxBytesAvail += bytes_avail;
- dbg("%s - bytes_avail = %d, rxBytesAvail %d", __FUNCTION__, bytes_avail, edge_serial->rxBytesAvail);
-
- if ((edge_serial->rxBytesAvail > 0) &&
- (edge_serial->read_urb->status != -EINPROGRESS)) {
- dbg(" --- Posting a read");
+ do_read = (edge_serial->rxBytesAvail > 0);
+ spin_unlock(&edge_serial->es_lock);
+ dbg("%s - bytes_avail = %d, rxBytesAvail %d, read_in_progress=%d", __FUNCTION__, bytes_avail, edge_serial->rxBytesAvail, edge_serial->read_in_progress);


+ if (do_read) {
+ dbg("%s - scheduling a read", __FUNCTION__);
/* we have pending bytes on the bulk in pipe, send a request */
- edge_serial->read_urb->dev = edge_serial->serial->dev;
- result = usb_submit_urb(edge_serial->read_urb);
- if (result) {
- dbg("%s - usb_submit_urb(read bulk) failed with result = %d", __FUNCTION__, result);
- }
+ tasklet_schedule(&edge_serial->submit_read_tasklet);
}
}
}
@@ -808,7 +819,9 @@
if (port_paranoia_check (port, __FUNCTION__) == 0) {
edge_port = (struct edgeport_port *)port->private;
if (edge_port->open) {
+ spin_lock(&edge_port->ep_lock);
edge_port->txCredits += txCredits;
+ spin_unlock(&edge_port->ep_lock);
dbg("%s - txcredits for port%d = %d", __FUNCTION__, portNumber, edge_port->txCredits);


                                                /* tell the tty driver that something 
has changed */
@@ -816,7 +829,7 @@
                                                        
wake_up_interruptible(&edge_port->port->tty->write_wait);

                                                // Since we have more credit, check if 
more data can be sent
-                                               send_more_port_data(edge_serial, 
edge_port);
+                                               
tasklet_schedule(&edge_port->send_data_tasklet);
                                        }
                                }
                        }
@@ -827,6 +840,39 @@
 }


+static void edge_submit_read(unsigned long arg)
+{
+ struct edgeport_serial *edge_serial = (struct edgeport_serial *)arg;
+ int result;
+
+ dbg("%s", __FUNCTION__);
+
+ spin_lock(&edge_serial->es_lock);
+
+ if (!edge_serial->read_in_progress) {
+ edge_serial->read_in_progress = TRUE;
+ edge_serial->read_urb->dev = edge_serial->serial->dev;
+ result = usb_submit_urb(edge_serial->read_urb);
+ if (result) {
+ dbg("%s - usb_submit_urb(read bulk) failed with result = %d", __FUNCTION__, result);
+ edge_serial->read_in_progress = FALSE;
+ }
+ }
+
+ spin_unlock(&edge_serial->es_lock);
+}
+
+
+static void edge_send_data(unsigned long arg)
+{
+ struct edgeport_port *edge_port = (struct edgeport_port *)arg;
+
+ dbg("%s", __FUNCTION__);
+
+ send_more_port_data((struct edgeport_serial *)(edge_port->port->serial->private), edge_port);
+}
+
+


/*****************************************************************************
* edge_bulk_in_callback
* this is the callback function for when we have received data on the
@@ -836,17 +882,19 @@
{
struct edgeport_serial *edge_serial = (struct edgeport_serial *)urb->context;
unsigned char *data = urb->transfer_buffer;
- int status;
__u16 raw_data_length;
+ int do_read;


        dbg("%s", __FUNCTION__);

- if (serial_paranoia_check (edge_serial->serial, __FUNCTION__)) {
+ if (urb->status) {
+ dbg("%s - nonzero read bulk status received: %d", __FUNCTION__, urb->status);
+ edge_serial->read_in_progress = FALSE;
return;
}


- if (urb->status) {
- dbg("%s - nonzero read bulk status received: %d", __FUNCTION__, urb->status);
+ if (serial_paranoia_check (edge_serial->serial, __FUNCTION__)) {
+ edge_serial->read_in_progress = FALSE;
return;
}


@@ -856,24 +904,24 @@
                usb_serial_debug_data (__FILE__, __FUNCTION__, raw_data_length, data);

                /* decrement our rxBytes available by the number that we just got */
+               spin_lock(&edge_serial->es_lock);
                edge_serial->rxBytesAvail -= raw_data_length;
+               do_read = (edge_serial->rxBytesAvail > 0);
+               spin_unlock(&edge_serial->es_lock);

dbg("%s - Received = %d, rxBytesAvail %d", __FUNCTION__, raw_data_length, edge_serial->rxBytesAvail);

                process_rcvd_data (edge_serial, data, urb->actual_length);

+ edge_serial->read_in_progress = FALSE;
+
/* check to see if there's any more data for us to read */
- if ((edge_serial->rxBytesAvail > 0) &&
- (edge_serial->read_urb->status != -EINPROGRESS)) {
- dbg(" --- Posting a read");
-
- /* there is, so resubmit our urb */
- edge_serial->read_urb->dev = edge_serial->serial->dev;
- status = usb_submit_urb(edge_serial->read_urb);
- if (status) {
- err("%s - usb_submit_urb(read bulk) failed, status = %d", __FUNCTION__, status);
- }
+ if (do_read) {
+ dbg("%s - posting a read", __FUNCTION__);
+ edge_submit_read((unsigned long)edge_serial);
}
+ } else {
+ edge_serial->read_in_progress = FALSE;
}
}


@@ -890,14 +938,14 @@

        dbg("%s", __FUNCTION__);

- if (port_paranoia_check (edge_port->port, __FUNCTION__)) {
- return;
- }
-
if (urb->status) {
dbg("%s - nonzero write bulk status received: %d", __FUNCTION__, urb->status);
}


+       if (port_paranoia_check (edge_port->port, __FUNCTION__)) {
+               return;
+       }
+
        tty = edge_port->port->tty;

        if (tty && edge_port->open) {
@@ -944,12 +992,12 @@
        usb_unlink_urb (urb);
        usb_free_urb   (urb);

-       if (port_paranoia_check (edge_port->port, __FUNCTION__)) {
+       if (status) {
+               dbg("%s - nonzero write bulk status received: %d", __FUNCTION__, 
status);
                return;
        }

-       if (status) {
-               dbg("%s - nonzero write bulk status received: %d", __FUNCTION__, 
status);
+       if (port_paranoia_check (edge_port->port, __FUNCTION__)) {
                return;
        }

@@ -1080,6 +1128,10 @@
                return -ENODEV;
        }

+ /* send the current line settings to the port so we are in sync with any further termios calls */
+ if (port->tty)
+ change_port_settings (edge_port, port->tty->termios);
+
/* create the txfifo */
edge_port->txfifo.head = 0;
edge_port->txfifo.tail = 0;
@@ -1095,6 +1147,7 @@


        /* Allocate a URB for the write */
        edge_port->write_urb = usb_alloc_urb (0);
+       edge_port->write_in_progress = FALSE;

        if (!edge_port->write_urb) {
                dbg("%s - no memory", __FUNCTION__);
@@ -1294,15 +1347,31 @@
        int bytesleft;
        int firsthalf;
        int secondhalf;
+       unsigned long flags;

        dbg("%s - port %d", __FUNCTION__, port->number);

        if (edge_port == NULL)
                return -ENODEV;

+       /* copy user data (which can sleep) */
+       if (from_user) {
+               if (count > EDGE_TMP_BUF_SIZE)
+                       count = EDGE_TMP_BUF_SIZE;
+               down(&edge_tmp_buf_sem);
+               if (copy_from_user(edge_tmp_buf, data, count) != 0) {
+                       up(&edge_tmp_buf_sem);
+                       err("%s - cannot copy from user space", __FUNCTION__);
+                       return -EFAULT;
+               }
+               data = edge_tmp_buf;
+       }
+
        // get a pointer to the Tx fifo
        fifo = &edge_port->txfifo;

+ spin_lock_irqsave(&edge_port->ep_lock, flags);
+
// calculate number of bytes to put in fifo
copySize = min ((unsigned int)count, (edge_port->txCredits - fifo->count));


@@ -1311,6 +1380,9 @@

/* catch writes of 0 bytes which the tty driver likes to give us, and when txCredits is empty */
if (copySize == 0) {
+ spin_unlock_irqrestore(&edge_port->ep_lock, flags);
+ if (from_user)
+ up(&edge_tmp_buf_sem);
dbg("%s - copySize = Zero", __FUNCTION__);
return 0;
}
@@ -1326,12 +1398,7 @@
dbg("%s - copy %d bytes of %d into fifo ", __FUNCTION__, firsthalf, bytesleft);


        /* now copy our data */
-       if (from_user) {
-               if (copy_from_user(&fifo->fifo[fifo->head], data, firsthalf))
-                       return -EFAULT;
-       } else {
-               memcpy(&fifo->fifo[fifo->head], data, firsthalf);
-       }
+       memcpy(&fifo->fifo[fifo->head], data, firsthalf);

        // update the index and size
        fifo->head  += firsthalf;
@@ -1346,22 +1413,22 @@

if (secondhalf) {
dbg("%s - copy rest of data %d", __FUNCTION__, secondhalf);
- if (from_user) {
- if (copy_from_user(&fifo->fifo[fifo->head], &data[firsthalf], secondhalf))
- return -EFAULT;
- } else {
- memcpy(&fifo->fifo[fifo->head], &data[firsthalf], secondhalf);
- }
+ memcpy(&fifo->fifo[fifo->head], &data[firsthalf], secondhalf);
// update the index and size
fifo->count += secondhalf;
fifo->head += secondhalf;
// No need to check for wrap since we can not get to end of fifo in this part
}


+       spin_unlock_irqrestore(&edge_port->ep_lock, flags);
+
        if (copySize) {
                usb_serial_debug_data (__FILE__, __FUNCTION__, copySize, data);
        }

+ if (from_user)
+ up(&edge_tmp_buf_sem);
+
send_more_port_data((struct edgeport_serial *)port->serial->private, edge_port);


dbg("%s wrote %d byte(s) TxCredits %d, Fifo %d", __FUNCTION__, copySize, edge_port->txCredits, fifo->count);
@@ -1393,12 +1460,16 @@
int bytesleft;
int firsthalf;
int secondhalf;
+ unsigned long flags;


        dbg("%s(%d)", __FUNCTION__, edge_port->port->number);

+ spin_lock_irqsave(&edge_port->ep_lock, flags);
+
if (edge_port->write_in_progress ||
!edge_port->open ||
(fifo->count == 0)) {
+ spin_unlock_irqrestore(&edge_port->ep_lock, flags);
dbg("%s(%d) EXIT - fifo %d, PendingWrite = %d", __FUNCTION__, edge_port->port->number, fifo->count, edge_port->write_in_progress);
return;
}
@@ -1411,6 +1482,7 @@
// it's better to wait for more credits so we can do a larger
// write.
if (edge_port->txCredits < EDGE_FW_GET_TX_CREDITS_SEND_THRESHOLD(edge_port->maxTxCredits)) {
+ spin_unlock_irqrestore(&edge_port->ep_lock, flags);
dbg("%s(%d) Not enough credit - fifo %d TxCredit %d", __FUNCTION__, edge_port->port->number, fifo->count, edge_port->txCredits );
return;
}
@@ -1431,8 +1503,9 @@
count = fifo->count;
buffer = kmalloc (count+2, GFP_ATOMIC);
if (buffer == NULL) {
- err("%s - no more kernel memory...", __FUNCTION__);
edge_port->write_in_progress = FALSE;
+ spin_unlock_irqrestore(&edge_port->ep_lock, flags);
+ err("%s - no more kernel memory...", __FUNCTION__);
return;
}
buffer[0] = IOSP_BUILD_DATA_HDR1 (edge_port->port->number - edge_port->port->serial->minor, count);
@@ -1482,6 +1555,9 @@
edge_port->txCredits += count;
edge_port->icount.tx -= count;
}
+
+ spin_unlock_irqrestore(&edge_port->ep_lock, flags);
+
dbg("%s wrote %d byte(s) TxCredit %d, Fifo %d", __FUNCTION__, count, edge_port->txCredits, fifo->count);
}


@@ -1498,6 +1574,7 @@
{
struct edgeport_port *edge_port = (struct edgeport_port *)(port->private);
int room;
+ unsigned long flags;


        dbg("%s", __FUNCTION__);

@@ -1514,7 +1591,9 @@
        }

        // total of both buffers is still txCredit
+       spin_lock_irqsave(&edge_port->ep_lock, flags);
        room = edge_port->txCredits - edge_port->txfifo.count;
+       spin_unlock_irqrestore(&edge_port->ep_lock, flags);

dbg("%s - returns %d", __FUNCTION__, room);
return room;
@@ -1534,6 +1613,7 @@
{
struct edgeport_port *edge_port = (struct edgeport_port *)(port->private);
int num_chars;
+ unsigned long flags;


        dbg("%s", __FUNCTION__);

@@ -1547,7 +1627,9 @@
                return -EINVAL;
        }

+ spin_lock_irqsave(&edge_port->ep_lock, flags);
num_chars = edge_port->maxTxCredits - edge_port->txCredits + edge_port->txfifo.count;
+ spin_unlock_irqrestore(&edge_port->ep_lock, flags);
if (num_chars) {
dbg("%s(port %d) - returns %d", __FUNCTION__, port->number, num_chars);
}
@@ -1718,12 +1800,15 @@
static int get_lsr_info(struct edgeport_port *edge_port, unsigned int *value)
{
unsigned int result = 0;
+ unsigned long flags;


+       spin_lock_irqsave(&edge_port->ep_lock, flags);
        if (edge_port->maxTxCredits == edge_port->txCredits &&
            edge_port->txfifo.count == 0) {
                dbg("%s -- Empty", __FUNCTION__);
                result = TIOCSER_TEMT;
        }
+       spin_unlock_irqrestore(&edge_port->ep_lock, flags);

if (copy_to_user(value, &result, sizeof(int)))
return -EFAULT;
@@ -2164,10 +2249,6 @@
dbg("%s - Port %u Open Response Inital MSR = %02x TxBufferSize = %d", __FUNCTION__, edge_serial->rxPort, byte2, edge_port->txCredits);
handle_new_msr (edge_port, byte2);


- /* send the current line settings to the port so we are in sync with any further termios calls */
- if (edge_port->port->tty)
- change_port_settings (edge_port, edge_port->port->tty->termios);
-
/* we have completed the open */
edge_port->openPending = FALSE;
edge_port->open = TRUE;
@@ -2507,6 +2588,7 @@
dbg("%s - usb_submit_urb(write bulk) failed", __FUNCTION__);
usb_unlink_urb (urb);
usb_free_urb (urb);
+ CmdUrbs--;
return status;
}


@@ -2970,6 +3052,8 @@
return -ENOMEM;
}
memset (edge_serial, 0, sizeof(struct edgeport_serial));
+ spin_lock_init(&edge_serial->es_lock);
+ tasklet_init(&edge_serial->submit_read_tasklet, edge_submit_read, (unsigned long)edge_serial);
edge_serial->serial = serial;
serial->private = edge_serial;


@@ -3026,6 +3110,8 @@
return -ENOMEM;
}
memset (edge_port, 0, sizeof(struct edgeport_port));
+ spin_lock_init(&edge_port->ep_lock);
+ tasklet_init(&edge_port->send_data_tasklet, edge_send_data, (unsigned long)edge_port);
edge_port->port = &serial->port[i];
serial->port[i].private = edge_port;
}
@@ -3042,11 +3128,15 @@
static void edge_shutdown (struct usb_serial *serial)
{
int i;
+ struct edgeport_serial *edge_serial = (struct edgeport_serial *)serial->private;


        dbg("%s", __FUNCTION__);

+ tasklet_kill(&edge_serial->submit_read_tasklet);
+
/* stop reads and writes on all ports */
for (i=0; i < serial->num_ports; ++i) {
+ tasklet_kill(&((struct edgeport_port *)serial->port[i].private)->send_data_tasklet);
kfree (serial->port[i].private);
serial->port[i].private = NULL;
}
@@ -3066,6 +3156,7 @@
usb_serial_register (&edgeport_4port_device);
usb_serial_register (&edgeport_8port_device);
info(DRIVER_DESC " " DRIVER_VERSION);
+ sema_init(&edge_tmp_buf_sem, 1);
return 0;
}







------------------------------------------------------- This SF.Net email is sponsored by The 2004 JavaOne(SM) Conference Learn from the experts at JavaOne(SM), Sun's Worldwide Java Developer Conference, June 28 - July 1 at the Moscone Center in San Francisco, CA REGISTER AND SAVE! http://java.sun.com/javaone/sf Priority Code NWMGYKND _______________________________________________ [EMAIL PROTECTED] To unsubscribe, use the last form field at: https://lists.sourceforge.net/lists/listinfo/linux-usb-devel

Reply via email to