Greg --
Here is a patch for io_edgeport in 2.6.9-rc3. It
fixes SMP locking problems, and has several other
improvements/fixes. The complete change log is below.
Please apply.
Thanks,
-- Al
- Updated to version 2.7.
- Added locking to protect the circular buffer, txCredits, rxBytesAvail,
and read_in_progress.
- Added a "bounce buffer" and a semaphore to protect it when copying
data from user space to the circular buffer.
- With these locking fixes tests running 8 ports at 115200 bps on
SMP now runs for hours without problems; before these changes this
test would cause out of memory errors or oopses within minutes.
- Removed the RELEVANT_IFLAG macro which mistakenly filtered out the
software flow control stty flags.
- Added support for mark and space parity.
- Added a private read_in_progress flag rather than using (urb->status
== -EINPROGRESS).
- Low latency is now a module parameter, it is on by default.
- Added edge_tty_recv to pass data to the tty flip buffers.
- Cleared the write_urb pointer after freeing it, to prevent oops on
failed open.
- Cleared the txfifo.fifo pointer after freeing it, to prevent double
free on failed open.
- Used usb_kill_urb instead of synchronous usb_unlink_urb.
- Simplified rounding the baud rate divisor.
- Added some error messages.
Signed-off-by: Al Borchers <[EMAIL PROTECTED]>
--- linux-2.6.9-rc3.orig/drivers/usb/serial/io_edgeport.c 2004-10-04
22:52:09.114749968 -0500
+++ linux-2.6.9-rc3.new/drivers/usb/serial/io_edgeport.c 2004-10-04
18:53:43.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
@@ -267,7 +271,7 @@
/*
* Version Information
*/
-#define DRIVER_VERSION "v2.3"
+#define DRIVER_VERSION "v2.7"
#define DRIVER_AUTHOR "Greg Kroah-Hartman <[EMAIL PROTECTED]> and David Iacovelli"
#define DRIVER_DESC "Edgeport USB Serial Driver"
@@ -297,7 +301,7 @@
#define OPEN_TIMEOUT (5*HZ) /* 5 seconds */
#define COMMAND_TIMEOUT (5*HZ) /* 5 seconds */
-static int debug;
+#define EDGE_TMP_BUF_SIZE 1024
/* receive port state */
enum RXSTATE {
@@ -329,6 +333,7 @@ struct edgeport_port {
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 */
+ spinlock_t ep_lock;
__u8 shadowLCR; /* last LCR value received */
__u8 shadowMCR; /* last MCR value received */
@@ -370,6 +375,8 @@ struct edgeport_serial {
__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;
+ spinlock_t es_lock;
__u8 bulk_out_endpoint; /* the bulk out
endpoint handle */
@@ -420,7 +427,14 @@ static struct divisor_table_entry diviso
};
/* local variables */
-static int CmdUrbs = 0; /*
Number of outstanding Command Write Urbs */
+static int debug;
+
+static int low_latency = 1; /* tty low latency flag, on by default */
+
+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 */
@@ -459,8 +473,9 @@ static struct usb_driver io_driver = {
};
/* function prototypes for all of our local functions */
-static int process_rcvd_data (struct edgeport_serial *edge_serial, unsigned
char *buffer, __u16 bufferLength);
+static void process_rcvd_data (struct edgeport_serial *edge_serial, unsigned
char *buffer, __u16 bufferLength);
static void process_rcvd_status (struct edgeport_serial *edge_serial,
__u8 byte2, __u8 byte3);
+static void edge_tty_recv (struct device *dev, struct tty_struct
*tty, unsigned char *data, int length);
static void handle_new_msr (struct edgeport_port *edge_port, __u8 newMsr);
static void handle_new_lsr (struct edgeport_port *edge_port, __u8
lsrData, __u8 lsr, __u8 data);
static int send_iosp_ext_cmd (struct edgeport_port *edge_port, __u8
command, __u8 param);
@@ -478,13 +493,9 @@ static void get_manufacturing_desc (stru
static void get_boot_desc (struct edgeport_serial *edge_serial);
static void load_application_firmware (struct edgeport_serial *edge_serial);
-
static void unicode_to_ascii (char *string, short *unicode, int
unicode_size);
-
-
-
// ************************************************************************
// ************************************************************************
// ************************************************************************
@@ -784,20 +795,24 @@ static void edge_interrupt_callback (str
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);
+ dbg("%s - bytes_avail=%d, rxBytesAvail=%d,
read_in_progress=%d", __FUNCTION__, bytes_avail, edge_serial->rxBytesAvail,
edge_serial->read_in_progress);
- if ((edge_serial->rxBytesAvail > 0) &&
- (edge_serial->read_urb->status != -EINPROGRESS)) {
- dbg(" --- Posting a read");
+ if (edge_serial->rxBytesAvail > 0 &&
+ !edge_serial->read_in_progress) {
+ dbg("%s - posting a read", __FUNCTION__);
+ edge_serial->read_in_progress = TRUE;
/* 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,
GFP_ATOMIC);
if (result) {
- dbg("%s - usb_submit_urb(read bulk)
failed with result = %d", __FUNCTION__, result);
+
dev_err(&edge_serial->serial->dev->dev, "%s - usb_submit_urb(read bulk) failed with
result = %d\n", __FUNCTION__, result);
+ edge_serial->read_in_progress = FALSE;
}
}
+ spin_unlock(&edge_serial->es_lock);
}
}
/* grab the txcredits for the ports if available */
@@ -809,12 +824,14 @@ static void edge_interrupt_callback (str
port = edge_serial->serial->port[portNumber];
edge_port = usb_get_serial_port_data(port);
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 */
if (edge_port->port->tty)
-
wake_up_interruptible(&edge_port->port->tty->write_wait);
+ tty_wakeup(edge_port->port->tty);
// Since we have more credit, check if more
data can be sent
send_more_port_data(edge_serial, edge_port);
@@ -849,34 +866,43 @@ static void edge_bulk_in_callback (struc
if (urb->status) {
dbg("%s - nonzero read bulk status received: %d", __FUNCTION__,
urb->status);
+ edge_serial->read_in_progress = FALSE;
return;
}
- if (urb->actual_length) {
- raw_data_length = urb->actual_length;
+ if (urb->actual_length == 0) {
+ dbg("%s - read bulk callback with no data", __FUNCTION__);
+ edge_serial->read_in_progress = FALSE;
+ return;
+ }
- usb_serial_debug_data(debug, &edge_serial->serial->dev->dev,
__FUNCTION__, raw_data_length, data);
+ raw_data_length = urb->actual_length;
- /* decrement our rxBytes available by the number that we just got */
- edge_serial->rxBytesAvail -= raw_data_length;
+ usb_serial_debug_data(debug, &edge_serial->serial->dev->dev, __FUNCTION__,
raw_data_length, data);
- dbg("%s - Received = %d, rxBytesAvail %d", __FUNCTION__,
raw_data_length, edge_serial->rxBytesAvail);
+ spin_lock(&edge_serial->es_lock);
- process_rcvd_data (edge_serial, data, urb->actual_length);
+ /* decrement our rxBytes available by the number that we just got */
+ edge_serial->rxBytesAvail -= raw_data_length;
- /* 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");
+ dbg("%s - Received = %d, rxBytesAvail %d", __FUNCTION__, raw_data_length,
edge_serial->rxBytesAvail);
- /* there is, so resubmit our urb */
- edge_serial->read_urb->dev = edge_serial->serial->dev;
- status = usb_submit_urb(edge_serial->read_urb, GFP_ATOMIC);
- if (status) {
- dev_err(&urb->dev->dev, "%s - usb_submit_urb(read
bulk) failed, status = %d\n", __FUNCTION__, status);
- }
+ process_rcvd_data (edge_serial, data, urb->actual_length);
+
+ /* check to see if there's any more data for us to read */
+ if (edge_serial->rxBytesAvail > 0) {
+ dbg("%s - posting a read", __FUNCTION__);
+ edge_serial->read_urb->dev = edge_serial->serial->dev;
+ status = usb_submit_urb(edge_serial->read_urb, GFP_ATOMIC);
+ if (status) {
+ dev_err(&urb->dev->dev, "%s - usb_submit_urb(read bulk)
failed, status = %d\n", __FUNCTION__, status);
+ edge_serial->read_in_progress = FALSE;
}
+ } else {
+ edge_serial->read_in_progress = FALSE;
}
+
+ spin_unlock(&edge_serial->es_lock);
}
@@ -946,7 +972,7 @@ static void edge_bulk_out_cmd_callback (
/* tell the tty driver that something has changed */
if (tty && edge_port->open)
- wake_up_interruptible(&tty->write_wait);
+ tty_wakeup(tty);
/* we have completed the command */
edge_port->commandPending = FALSE;
@@ -977,11 +1003,8 @@ static int edge_open (struct usb_serial_
if (edge_port == NULL)
return -ENODEV;
- /* force low_latency on so that our tty_push actually forces the data through,
- otherwise it is scheduled, and with high data rates (like with OHCI) data
- can get lost. */
if (port->tty)
- port->tty->low_latency = 1;
+ port->tty->low_latency = low_latency;
/* see if we've set up our endpoint info yet (can't set it up in edge_startup
as the structures were not set up at that time.) */
@@ -1019,6 +1042,7 @@ static int edge_open (struct usb_serial_
port0->bulk_in_buffer,
edge_serial->read_urb->transfer_buffer_length,
edge_bulk_in_callback, edge_serial);
+ edge_serial->read_in_progress = FALSE;
/* start interrupt read for this edgeport
* this interrupt will continue as long as the edgeport is connected */
@@ -1081,6 +1105,7 @@ static int edge_open (struct usb_serial_
/* Allocate a URB for the write */
edge_port->write_urb = usb_alloc_urb (0, GFP_KERNEL);
+ edge_port->write_in_progress = FALSE;
if (!edge_port->write_urb) {
dbg("%s - no memory", __FUNCTION__);
@@ -1238,7 +1263,7 @@ static void edge_close (struct usb_seria
edge_port->openPending = FALSE;
if (edge_port->write_urb) {
- usb_unlink_urb (edge_port->write_urb);
+ usb_kill_urb (edge_port->write_urb);
}
if (edge_port->write_urb) {
@@ -1247,9 +1272,11 @@ static void edge_close (struct usb_seria
kfree(edge_port->write_urb->transfer_buffer);
}
usb_free_urb (edge_port->write_urb);
+ edge_port->write_urb = NULL;
}
if (edge_port->txfifo.fifo) {
kfree(edge_port->txfifo.fifo);
+ edge_port->txfifo.fifo = NULL;
}
dbg("%s exited", __FUNCTION__);
@@ -1264,21 +1291,38 @@ static void edge_close (struct usb_seria
*****************************************************************************/
static int edge_write (struct usb_serial_port *port, int from_user, const unsigned
char *data, int count)
{
- struct edgeport_port *edge_port = usb_get_serial_port_data(port);
+ struct edgeport_port *edge_port = usb_get_serial_port_data(port);
struct TxFifo *fifo;
int copySize;
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, so don't get spinlock yet) */
+ if (from_user) {
+ if (count > EDGE_TMP_BUF_SIZE)
+ count = EDGE_TMP_BUF_SIZE;
+ if (down_interruptible(&edge_tmp_buf_sem))
+ return -ERESTARTSYS;
+ if (copy_from_user(edge_tmp_buf, data, count) != 0) {
+ up(&edge_tmp_buf_sem);
+ dev_err(&port->dev, "%s - cannot copy from user space\n",
__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));
@@ -1288,7 +1332,7 @@ static int edge_write (struct usb_serial
/* catch writes of 0 bytes which the tty driver likes to give us, and when
txCredits is empty */
if (copySize == 0) {
dbg("%s - copySize = Zero", __FUNCTION__);
- return 0;
+ goto finish_write;
}
// queue the data
@@ -1302,12 +1346,7 @@ static int edge_write (struct usb_serial
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);
usb_serial_debug_data(debug, &port->dev, __FUNCTION__, firsthalf,
&fifo->fifo[fifo->head]);
// update the index and size
@@ -1323,12 +1362,7 @@ static int edge_write (struct usb_serial
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);
usb_serial_debug_data(debug, &port->dev, __FUNCTION__, secondhalf,
&fifo->fifo[fifo->head]);
// update the index and size
fifo->count += secondhalf;
@@ -1336,6 +1370,12 @@ static int edge_write (struct usb_serial
// No need to check for wrap since we can not get to end of fifo in
this part
}
+finish_write:
+ spin_unlock_irqrestore(&edge_port->ep_lock, flags);
+
+ if (from_user)
+ up(&edge_tmp_buf_sem);
+
send_more_port_data((struct edgeport_serial
*)usb_get_serial_data(port->serial), edge_port);
dbg("%s wrote %d byte(s) TxCredits %d, Fifo %d", __FUNCTION__, copySize,
edge_port->txCredits, fifo->count);
@@ -1367,14 +1407,17 @@ static void send_more_port_data(struct e
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)) {
dbg("%s(%d) EXIT - fifo %d, PendingWrite = %d", __FUNCTION__,
edge_port->port->number, fifo->count, edge_port->write_in_progress);
- return;
+ goto exit_send;
}
// since the amount of data in the fifo will always fit into the
@@ -1386,7 +1429,7 @@ static void send_more_port_data(struct e
// write.
if (edge_port->txCredits <
EDGE_FW_GET_TX_CREDITS_SEND_THRESHOLD(edge_port->maxTxCredits,EDGE_FW_BULK_MAX_PACKET_SIZE))
{
dbg("%s(%d) Not enough credit - fifo %d TxCredit %d", __FUNCTION__,
edge_port->port->number, fifo->count, edge_port->txCredits );
- return;
+ goto exit_send;
}
// lock this write
@@ -1407,7 +1450,7 @@ static void send_more_port_data(struct e
if (buffer == NULL) {
dev_err(&edge_port->port->dev, "%s - no more kernel memory...\n",
__FUNCTION__);
edge_port->write_in_progress = FALSE;
- return;
+ goto exit_send;
}
buffer[0] = IOSP_BUILD_DATA_HDR1 (edge_port->port->number -
edge_port->port->serial->minor, count);
buffer[1] = IOSP_BUILD_DATA_HDR2 (edge_port->port->number -
edge_port->port->serial->minor, count);
@@ -1445,7 +1488,7 @@ static void send_more_port_data(struct e
status = usb_submit_urb(urb, GFP_ATOMIC);
if (status) {
/* something went wrong */
- dbg("%s - usb_submit_urb(write bulk) failed", __FUNCTION__);
+ dev_err(&edge_port->port->dev, "%s - usb_submit_urb(write bulk)
failed, status = %d, data lost\n", __FUNCTION__, status);
edge_port->write_in_progress = FALSE;
/* revert the credits as something bad happened. */
@@ -1453,6 +1496,9 @@ static void send_more_port_data(struct e
edge_port->icount.tx -= count;
}
dbg("%s wrote %d byte(s) TxCredit %d, Fifo %d", __FUNCTION__, count,
edge_port->txCredits, fifo->count);
+
+exit_send:
+ spin_unlock_irqrestore(&edge_port->ep_lock, flags);
}
@@ -1466,8 +1512,9 @@ static void send_more_port_data(struct e
*****************************************************************************/
static int edge_write_room (struct usb_serial_port *port)
{
- struct edgeport_port *edge_port = usb_get_serial_port_data(port);
+ struct edgeport_port *edge_port = usb_get_serial_port_data(port);
int room;
+ unsigned long flags;
dbg("%s", __FUNCTION__);
@@ -1484,7 +1531,9 @@ static int edge_write_room (struct usb_s
}
// 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;
@@ -1502,8 +1551,9 @@ static int edge_write_room (struct usb_s
*****************************************************************************/
static int edge_chars_in_buffer (struct usb_serial_port *port)
{
- struct edgeport_port *edge_port = usb_get_serial_port_data(port);
+ struct edgeport_port *edge_port = usb_get_serial_port_data(port);
int num_chars;
+ unsigned long flags;
dbg("%s", __FUNCTION__);
@@ -1517,7 +1567,9 @@ static int edge_chars_in_buffer (struct
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);
}
@@ -1533,7 +1585,7 @@ static int edge_chars_in_buffer (struct
*****************************************************************************/
static void edge_throttle (struct usb_serial_port *port)
{
- struct edgeport_port *edge_port = usb_get_serial_port_data(port);
+ struct edgeport_port *edge_port = usb_get_serial_port_data(port);
struct tty_struct *tty;
int status;
@@ -1582,7 +1634,7 @@ static void edge_throttle (struct usb_se
*****************************************************************************/
static void edge_unthrottle (struct usb_serial_port *port)
{
- struct edgeport_port *edge_port = usb_get_serial_port_data(port);
+ struct edgeport_port *edge_port = usb_get_serial_port_data(port);
struct tty_struct *tty;
int status;
@@ -1630,7 +1682,7 @@ static void edge_unthrottle (struct usb_
*****************************************************************************/
static void edge_set_termios (struct usb_serial_port *port, struct termios
*old_termios)
{
- struct edgeport_port *edge_port = usb_get_serial_port_data(port);
+ struct edgeport_port *edge_port = usb_get_serial_port_data(port);
struct tty_struct *tty = port->tty;
unsigned int cflag;
@@ -1642,20 +1694,18 @@ static void edge_set_termios (struct usb
cflag = tty->termios->c_cflag;
/* check that they really want us to change something */
if (old_termios) {
- if ((cflag == old_termios->c_cflag) &&
- (RELEVANT_IFLAG(tty->termios->c_iflag) ==
RELEVANT_IFLAG(old_termios->c_iflag))) {
+ if (cflag == old_termios->c_cflag &&
+ tty->termios->c_iflag == old_termios->c_iflag) {
dbg("%s - nothing to change", __FUNCTION__);
return;
}
}
dbg("%s - clfag %08x iflag %08x", __FUNCTION__,
- tty->termios->c_cflag,
- RELEVANT_IFLAG(tty->termios->c_iflag));
+ tty->termios->c_cflag, tty->termios->c_iflag);
if (old_termios) {
dbg("%s - old clfag %08x old iflag %08x", __FUNCTION__,
- old_termios->c_cflag,
- RELEVANT_IFLAG(old_termios->c_iflag));
+ old_termios->c_cflag, old_termios->c_iflag);
}
dbg("%s - port %d", __FUNCTION__, port->number);
@@ -1688,12 +1738,15 @@ static void edge_set_termios (struct usb
static int get_lsr_info(struct edgeport_port *edge_port, unsigned int __user *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;
@@ -1719,7 +1772,7 @@ static int get_number_bytes_avail(struct
static int edge_tiocmset (struct usb_serial_port *port, struct file *file, unsigned
int set, unsigned int clear)
{
- struct edgeport_port *edge_port = usb_get_serial_port_data(port);
+ struct edgeport_port *edge_port = usb_get_serial_port_data(port);
unsigned int mcr;
dbg("%s - port %d", __FUNCTION__, port->number);
@@ -1748,7 +1801,7 @@ static int edge_tiocmset (struct usb_ser
static int edge_tiocmget(struct usb_serial_port *port, struct file *file)
{
- struct edgeport_port *edge_port = usb_get_serial_port_data(port);
+ struct edgeport_port *edge_port = usb_get_serial_port_data(port);
unsigned int result = 0;
unsigned int msr;
unsigned int mcr;
@@ -1805,7 +1858,7 @@ static int get_serial_info(struct edgepo
*****************************************************************************/
static int edge_ioctl (struct usb_serial_port *port, struct file *file, unsigned int
cmd, unsigned long arg)
{
- struct edgeport_port *edge_port = usb_get_serial_port_data(port);
+ struct edgeport_port *edge_port = usb_get_serial_port_data(port);
struct async_icount cnow;
struct async_icount cprev;
struct serial_icounter_struct icount;
@@ -1887,7 +1940,7 @@ static int edge_ioctl (struct usb_serial
*****************************************************************************/
static void edge_break (struct usb_serial_port *port, int break_state)
{
- struct edgeport_port *edge_port = usb_get_serial_port_data(port);
+ struct edgeport_port *edge_port = usb_get_serial_port_data(port);
int status;
/* flush and chase */
@@ -1921,14 +1974,13 @@ static void edge_break (struct usb_seria
* process_rcvd_data
* this function handles the data received on the bulk in pipe.
*****************************************************************************/
-static int process_rcvd_data (struct edgeport_serial *edge_serial, unsigned char *
buffer, __u16 bufferLength)
+static void process_rcvd_data (struct edgeport_serial *edge_serial, unsigned char *
buffer, __u16 bufferLength)
{
struct usb_serial_port *port;
struct edgeport_port *edge_port;
struct tty_struct *tty;
__u16 lastBufferLength;
__u16 rxLen;
- int i;
dbg("%s", __FUNCTION__);
@@ -1983,7 +2035,6 @@ static int process_rcvd_data (struct edg
// We have all the header bytes, process the
status now
process_rcvd_status (edge_serial,
edge_serial->rxHeader2, 0);
-
edge_serial->rxState = EXPECT_HDR1;
break;
} else {
@@ -2024,15 +2075,7 @@ static int process_rcvd_data (struct edg
tty = edge_port->port->tty;
if (tty) {
dbg("%s - Sending %d bytes to
TTY for port %d", __FUNCTION__, rxLen, edge_serial->rxPort);
- for (i = 0; i < rxLen ; ++i) {
- /* if we insert more
than TTY_FLIPBUF_SIZE characters, we drop them. */
- if(tty->flip.count >=
TTY_FLIPBUF_SIZE) {
-
tty_flip_buffer_push(tty);
- }
- /* this doesn't
actually push the data through unless tty->low_latency is set */
-
tty_insert_flip_char(tty, buffer[i], 0);
- }
- tty_flip_buffer_push(tty);
+
edge_tty_recv(&edge_serial->serial->dev->dev, tty, buffer, rxLen);
}
edge_port->icount.rx += rxLen;
}
@@ -2053,8 +2096,6 @@ static int process_rcvd_data (struct edg
}
}
-
- return 0;
}
@@ -2070,7 +2111,7 @@ static void process_rcvd_status (struct
/* switch the port pointer to the one being currently talked about */
port = edge_serial->serial->port[edge_serial->rxPort];
- edge_port = usb_get_serial_port_data(port);
+ edge_port = usb_get_serial_port_data(port);
if (edge_port == NULL) {
dev_err(&edge_serial->serial->dev->dev, "%s - edge_port == NULL for
port %d\n", __FUNCTION__, edge_serial->rxPort);
return;
@@ -2160,6 +2201,37 @@ static void process_rcvd_status (struct
/*****************************************************************************
+ * edge_tty_recv
+ * this function passes data on to the tty flip buffer
+ *****************************************************************************/
+static void edge_tty_recv(struct device *dev, struct tty_struct *tty, unsigned char
*data, int length)
+{
+ int cnt;
+
+ do {
+ if (tty->flip.count >= TTY_FLIPBUF_SIZE) {
+ tty_flip_buffer_push(tty);
+ if (tty->flip.count >= TTY_FLIPBUF_SIZE) {
+ dev_err(dev, "%s - dropping data, %d bytes lost\n",
+ __FUNCTION__, length);
+ return;
+ }
+ }
+ cnt = min(length, TTY_FLIPBUF_SIZE - tty->flip.count);
+ memcpy(tty->flip.char_buf_ptr, data, cnt);
+ memset(tty->flip.flag_buf_ptr, 0, cnt);
+ tty->flip.char_buf_ptr += cnt;
+ tty->flip.flag_buf_ptr += cnt;
+ tty->flip.count += cnt;
+ data += cnt;
+ length -= cnt;
+ } while (length > 0);
+
+ tty_flip_buffer_push(tty);
+}
+
+
+/*****************************************************************************
* handle_new_msr
* this function handles any change to the msr register for a port.
*****************************************************************************/
@@ -2218,10 +2290,8 @@ static void handle_new_lsr(struct edgepo
}
/* Place LSR data byte into Rx buffer */
- if (lsrData && edge_port->port->tty) {
- tty_insert_flip_char(edge_port->port->tty, data, 0);
- tty_flip_buffer_push(edge_port->port->tty);
- }
+ if (lsrData && edge_port->port->tty)
+ edge_tty_recv(&edge_port->port->dev, edge_port->port->tty, &data, 1);
/* update input line counters */
icount = &edge_port->icount;
@@ -2442,9 +2512,9 @@ static int write_cmd_usb (struct edgepor
if (status) {
/* something went wrong */
- dbg("%s - usb_submit_urb(write bulk) failed", __FUNCTION__);
- usb_unlink_urb (urb);
+ dev_err(&edge_port->port->dev, "%s - usb_submit_urb(write command)
failed, status = %d\n", __FUNCTION__, status);
usb_free_urb (urb);
+ CmdUrbs--;
return status;
}
@@ -2524,8 +2594,6 @@ static int calc_baud_rate_divisor (int b
{
int i;
__u16 custom;
- __u16 round1;
- __u16 round;
dbg("%s - %d", __FUNCTION__, baudrate);
@@ -2540,16 +2608,10 @@ static int calc_baud_rate_divisor (int b
// We have tried all of the standard baud rates
// lets try to calculate the divisor for this baud rate
// Make sure the baud rate is reasonable
- if (baudrate < 230400) {
+ if (baudrate > 50 && baudrate < 230400) {
// get divisor
- custom = (__u16)(230400L / baudrate);
+ custom = (__u16)((230400L + baudrate/2) / baudrate);
- // Check for round off
- round1 = (__u16)(2304000L / baudrate);
- round = (__u16)(round1 - (custom * 10));
- if (round > 4) {
- custom++;
- }
*divisor = custom;
dbg("%s - Baud %d = %d\n", __FUNCTION__, baudrate, custom);
@@ -2641,7 +2703,15 @@ static void change_port_settings (struct
lParity = LCR_PAR_NONE;
if (cflag & PARENB) {
- if (cflag & PARODD) {
+ if (cflag & CMSPAR) {
+ if (cflag & PARODD) {
+ lParity = LCR_PAR_MARK;
+ dbg("%s - parity = mark", __FUNCTION__);
+ } else {
+ lParity = LCR_PAR_SPACE;
+ dbg("%s - parity = space", __FUNCTION__);
+ }
+ } else if (cflag & PARODD) {
lParity = LCR_PAR_ODD;
dbg("%s - parity = odd", __FUNCTION__);
} else {
@@ -2904,10 +2974,11 @@ static int edge_startup (struct usb_seri
/* create our private serial structure */
edge_serial = kmalloc (sizeof(struct edgeport_serial), GFP_KERNEL);
if (edge_serial == NULL) {
- dev_err(&serial->dev->dev, "%s - Out of memory", __FUNCTION__);
+ dev_err(&serial->dev->dev, "%s - Out of memory\n", __FUNCTION__);
return -ENOMEM;
}
memset (edge_serial, 0, sizeof(struct edgeport_serial));
+ spin_lock_init(&edge_serial->es_lock);
edge_serial->serial = serial;
usb_set_serial_data(serial, edge_serial);
@@ -2960,12 +3031,13 @@ static int edge_startup (struct usb_seri
for (i = 0; i < serial->num_ports; ++i) {
edge_port = kmalloc (sizeof(struct edgeport_port), GFP_KERNEL);
if (edge_port == NULL) {
- dev_err(&serial->dev->dev, "%s - Out of memory", __FUNCTION__);
+ dev_err(&serial->dev->dev, "%s - Out of memory\n",
__FUNCTION__);
usb_set_serial_data(serial, NULL);
kfree(edge_serial);
return -ENOMEM;
}
memset (edge_port, 0, sizeof(struct edgeport_port));
+ spin_lock_init(&edge_port->ep_lock);
edge_port->port = serial->port[i];
usb_set_serial_port_data(serial->port[i], edge_port);
}
@@ -3002,6 +3074,9 @@ static void edge_shutdown (struct usb_se
static int __init edgeport_init(void)
{
int retval;
+
+ sema_init(&edge_tmp_buf_sem, 1);
+
retval = usb_serial_register(&edgeport_2port_device);
if (retval)
goto failed_2port_device_register;
@@ -3016,6 +3091,7 @@ static int __init edgeport_init(void)
goto failed_usb_register;
info(DRIVER_DESC " " DRIVER_VERSION);
return 0;
+
failed_usb_register:
usb_serial_deregister(&edgeport_8port_device);
failed_8port_device_register:
@@ -3050,3 +3126,6 @@ MODULE_LICENSE("GPL");
module_param(debug, bool, S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(debug, "Debug enabled or not");
+
+module_param(low_latency, bool, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(debug, "Low latency enabled or not");
-------------------------------------------------------
This SF.net email is sponsored by: IT Product Guide on ITManagersJournal
Use IT products in your business? Tell us what you think of them. Give us
Your Opinions, Get Free ThinkGeek Gift Certificates! Click to find out more
http://productguide.itmanagersjournal.com/guidepromo.tmpl
_______________________________________________
[EMAIL PROTECTED]
To unsubscribe, use the last form field at:
https://lists.sourceforge.net/lists/listinfo/linux-usb-devel