X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=drivers%2Fusb%2Fserial%2Fio_edgeport.c;h=14c1dd64cb3626004f40cb31218eba5918c5c32a;hb=6a77f38946aaee1cd85eeec6cf4229b204c15071;hp=1ef47613b9583e6ae7969ac0cba4819e318122a0;hpb=87fc8d1bb10cd459024a742c6a10961fefcef18f;p=linux-2.6.git diff --git a/drivers/usb/serial/io_edgeport.c b/drivers/usb/serial/io_edgeport.c index 1ef47613b..14c1dd64c 100644 --- a/drivers/usb/serial/io_edgeport.c +++ b/drivers/usb/serial/io_edgeport.c @@ -23,6 +23,10 @@ * Edgeport/4D8 * Edgeport/8i * + * For questions or problems with this driver, contact Inside Out + * Networks technical support, or Peter Berger , + * or Al Borchers . + * * 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 and David Iacovelli" #define DRIVER_DESC "Edgeport USB Serial Driver" @@ -297,8 +301,6 @@ #define OPEN_TIMEOUT (5*HZ) /* 5 seconds */ #define COMMAND_TIMEOUT (5*HZ) /* 5 seconds */ -static int debug; - /* receive port state */ enum RXSTATE { EXPECT_HDR1 = 0, /* Expect header byte 1 */ @@ -329,6 +331,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 +373,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 +425,11 @@ static struct divisor_table_entry divisor_table[] = { }; /* 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 */ /* local function prototypes */ @@ -434,7 +443,7 @@ static void edge_bulk_out_cmd_callback (struct urb *urb, struct pt_regs *regs); /* function prototypes for the usbserial callbacks */ static int edge_open (struct usb_serial_port *port, struct file *filp); static void edge_close (struct usb_serial_port *port, struct file *filp); -static int edge_write (struct usb_serial_port *port, int from_user, const unsigned char *buf, int count); +static int edge_write (struct usb_serial_port *port, const unsigned char *buf, int count); static int edge_write_room (struct usb_serial_port *port); static int edge_chars_in_buffer (struct usb_serial_port *port); static void edge_throttle (struct usb_serial_port *port); @@ -459,8 +468,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 +488,9 @@ static void get_manufacturing_desc (struct edgeport_serial *edge_serial); 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, __le16 *unicode, int unicode_size); - - - // ************************************************************************ // ************************************************************************ // ************************************************************************ @@ -653,7 +659,7 @@ static void get_product_info(struct edgeport_serial *edge_serial) memset (product_info, 0, sizeof(struct edgeport_product_info)); - product_info->ProductId = (__u16)(edge_serial->serial->dev->descriptor.idProduct & ~ION_DEVICE_ID_80251_NETCHIP); + product_info->ProductId = (__u16)(le16_to_cpu(edge_serial->serial->dev->descriptor.idProduct) & ~ION_DEVICE_ID_80251_NETCHIP); product_info->NumPorts = edge_serial->manuf_descriptor.NumPorts; product_info->ProdInfoVer = 0; @@ -669,7 +675,7 @@ static void get_product_info(struct edgeport_serial *edge_serial) memcpy(product_info->ManufactureDescDate, edge_serial->manuf_descriptor.DescDate, sizeof(edge_serial->manuf_descriptor.DescDate)); // check if this is 2nd generation hardware - if (edge_serial->serial->dev->descriptor.idProduct & ION_DEVICE_ID_80251_NETCHIP) { + if (le16_to_cpu(edge_serial->serial->dev->descriptor.idProduct) & ION_DEVICE_ID_80251_NETCHIP) { product_info->FirmwareMajorVersion = OperationalCodeImageVersion_GEN2.MajorVersion; product_info->FirmwareMinorVersion = OperationalCodeImageVersion_GEN2.MinorVersion; product_info->FirmwareBuildNumber = cpu_to_le16(OperationalCodeImageVersion_GEN2.BuildNumber); @@ -784,20 +790,24 @@ static void edge_interrupt_callback (struct urb *urb, struct pt_regs *regs) 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 +819,14 @@ static void edge_interrupt_callback (struct urb *urb, struct pt_regs *regs) 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 +861,43 @@ static void edge_bulk_in_callback (struct urb *urb, struct pt_regs *regs) 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 +967,7 @@ static void edge_bulk_out_cmd_callback (struct urb *urb, struct pt_regs *regs) /* 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 +998,8 @@ static int edge_open (struct usb_serial_port *port, struct file * filp) 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 +1037,7 @@ static int edge_open (struct usb_serial_port *port, struct file * filp) 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 +1100,7 @@ static int edge_open (struct usb_serial_port *port, struct file * filp) /* 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 +1258,7 @@ static void edge_close (struct usb_serial_port *port, struct file * filp) 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 +1267,11 @@ static void edge_close (struct usb_serial_port *port, struct file * filp) 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__); @@ -1262,14 +1284,15 @@ static void edge_close (struct usb_serial_port *port, struct file * filp) * If successful, we return the number of bytes written, otherwise we return * a negative error number. *****************************************************************************/ -static int edge_write (struct usb_serial_port *port, int from_user, const unsigned char *data, int count) +static int edge_write (struct usb_serial_port *port, 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); @@ -1279,6 +1302,8 @@ static int edge_write (struct usb_serial_port *port, int from_user, const unsign // 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 +1313,7 @@ static int edge_write (struct usb_serial_port *port, int from_user, const unsign /* 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 +1327,7 @@ static int edge_write (struct usb_serial_port *port, int from_user, const unsign 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 +1343,7 @@ static int edge_write (struct usb_serial_port *port, int from_user, const unsign 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 +1351,9 @@ static int edge_write (struct usb_serial_port *port, int from_user, const unsign // 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); + 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 +1385,17 @@ static void send_more_port_data(struct edgeport_serial *edge_serial, struct edge 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 +1407,7 @@ static void send_more_port_data(struct edgeport_serial *edge_serial, struct edge // 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 +1428,7 @@ static void send_more_port_data(struct edgeport_serial *edge_serial, struct edge 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 +1466,7 @@ static void send_more_port_data(struct edgeport_serial *edge_serial, struct edge 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 +1474,9 @@ static void send_more_port_data(struct edgeport_serial *edge_serial, struct edge 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 +1490,9 @@ static void send_more_port_data(struct edgeport_serial *edge_serial, struct edge *****************************************************************************/ 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 +1509,9 @@ static int edge_write_room (struct usb_serial_port *port) } // 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 +1529,9 @@ static int edge_write_room (struct usb_serial_port *port) *****************************************************************************/ 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 +1545,9 @@ static int edge_chars_in_buffer (struct usb_serial_port *port) 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 +1563,7 @@ static int edge_chars_in_buffer (struct usb_serial_port *port) *****************************************************************************/ 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; @@ -1556,7 +1586,7 @@ static void edge_throttle (struct usb_serial_port *port) /* if we are implementing XON/XOFF, send the stop character */ if (I_IXOFF(tty)) { unsigned char stop_char = STOP_CHAR(tty); - status = edge_write (port, 0, &stop_char, 1); + status = edge_write (port, &stop_char, 1); if (status <= 0) { return; } @@ -1582,7 +1612,7 @@ static void edge_throttle (struct usb_serial_port *port) *****************************************************************************/ 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; @@ -1605,7 +1635,7 @@ static void edge_unthrottle (struct usb_serial_port *port) /* if we are implementing XON/XOFF, send the start character */ if (I_IXOFF(tty)) { unsigned char start_char = START_CHAR(tty); - status = edge_write (port, 0, &start_char, 1); + status = edge_write (port, &start_char, 1); if (status <= 0) { return; } @@ -1630,7 +1660,7 @@ static void edge_unthrottle (struct usb_serial_port *port) *****************************************************************************/ 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 +1672,18 @@ static void edge_set_termios (struct usb_serial_port *port, struct termios *old_ 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 +1716,15 @@ static void edge_set_termios (struct usb_serial_port *port, struct termios *old_ 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 +1750,7 @@ static int get_number_bytes_avail(struct edgeport_port *edge_port, unsigned int 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 +1779,7 @@ static int edge_tiocmset (struct usb_serial_port *port, struct file *file, unsig 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; @@ -1786,8 +1817,13 @@ static int get_serial_info(struct edgeport_port *edge_port, struct serial_struct tmp.flags = ASYNC_SKIP_TEST | ASYNC_AUTO_IRQ; tmp.xmit_fifo_size = edge_port->maxTxCredits; tmp.baud_base = 9600; + #if HZ < 2185 tmp.close_delay = 5*HZ; tmp.closing_wait = 30*HZ; + #else + tmp.close_delay = 2*HZ; + tmp.closing_wait = 65534; + #endif // tmp.custom_divisor = state->custom_divisor; // tmp.hub6 = state->hub6; // tmp.io_type = state->io_type; @@ -1805,7 +1841,7 @@ static int get_serial_info(struct edgeport_port *edge_port, struct serial_struct *****************************************************************************/ 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 +1923,7 @@ static int edge_ioctl (struct usb_serial_port *port, struct file *file, unsigned *****************************************************************************/ 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 +1957,13 @@ static void edge_break (struct usb_serial_port *port, int break_state) * 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 +2018,6 @@ static int process_rcvd_data (struct edgeport_serial *edge_serial, unsigned char // 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 +2058,7 @@ static int process_rcvd_data (struct edgeport_serial *edge_serial, unsigned char 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 +2079,6 @@ static int process_rcvd_data (struct edgeport_serial *edge_serial, unsigned char } } - - return 0; } @@ -2070,7 +2094,7 @@ static void process_rcvd_status (struct edgeport_serial *edge_serial, __u8 byte2 /* 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; @@ -2159,6 +2183,37 @@ static void process_rcvd_status (struct edgeport_serial *edge_serial, __u8 byte2 } +/***************************************************************************** + * 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 +2273,8 @@ static void handle_new_lsr(struct edgeport_port *edge_port, __u8 lsrData, __u8 l } /* 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 +2495,10 @@ static int write_cmd_usb (struct edgeport_port *edge_port, unsigned char *buffer if (status) { /* something went wrong */ - dbg("%s - usb_submit_urb(write bulk) failed", __FUNCTION__); - usb_unlink_urb (urb); - usb_free_urb (urb); + dev_err(&edge_port->port->dev, "%s - usb_submit_urb(write command) failed, status = %d\n", __FUNCTION__, status); + usb_kill_urb(urb); + usb_free_urb(urb); + CmdUrbs--; return status; } @@ -2524,8 +2578,6 @@ static int calc_baud_rate_divisor (int baudrate, int *divisor) { int i; __u16 custom; - __u16 round1; - __u16 round; dbg("%s - %d", __FUNCTION__, baudrate); @@ -2540,16 +2592,10 @@ static int calc_baud_rate_divisor (int baudrate, int *divisor) // 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); @@ -2601,6 +2647,9 @@ static int send_cmd_write_uart_register (struct edgeport_port *edge_port, __u8 r * This routine is called to set the UART on the device to match the specified * new settings. *****************************************************************************/ +#ifndef CMSPAR +#define CMSPAR 0 +#endif static void change_port_settings (struct edgeport_port *edge_port, struct termios *old_termios) { struct tty_struct *tty; @@ -2641,7 +2690,15 @@ static void change_port_settings (struct edgeport_port *edge_port, struct termio 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 { @@ -2745,9 +2802,12 @@ static void change_port_settings (struct edgeport_port *edge_port, struct termio static void unicode_to_ascii (char *string, __le16 *unicode, int unicode_size) { int i; - for (i = 0; i < unicode_size; ++i) { + + if (unicode_size <= 0) + return; + + for (i = 0; i < unicode_size; ++i) string[i] = (char)(le16_to_cpu(unicode[i])); - } string[unicode_size] = 0x00; } @@ -2868,7 +2928,7 @@ static void load_application_firmware (struct edgeport_serial *edge_serial) record = (struct edge_firmware_image_record *)firmware; response = sram_write (edge_serial->serial, le16_to_cpu(record->ExtAddr), le16_to_cpu(record->Addr), le16_to_cpu(record->Len), &record->Data[0]); if (response < 0) { - dev_err(&edge_serial->serial->dev->dev, "sram_write failed (%x, %x, %d)\n", le16_to_cpu(record->ExtAddr), le16_to_cpu(record->Addr), record->Len); + dev_err(&edge_serial->serial->dev->dev, "sram_write failed (%x, %x, %d)\n", le16_to_cpu(record->ExtAddr), le16_to_cpu(record->Addr), le16_to_cpu(record->Len)); break; } firmware += sizeof (struct edge_firmware_image_record) + le16_to_cpu(record->Len); @@ -2887,8 +2947,6 @@ static void load_application_firmware (struct edgeport_serial *edge_serial) } - - /**************************************************************************** * edge_startup ****************************************************************************/ @@ -2904,10 +2962,11 @@ static int edge_startup (struct usb_serial *serial) /* 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 +3019,13 @@ static int edge_startup (struct usb_serial *serial) 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); } @@ -2974,7 +3034,6 @@ static int edge_startup (struct usb_serial *serial) } - /**************************************************************************** * edge_shutdown * This function is called whenever the device is removed from the usb bus. @@ -3002,6 +3061,7 @@ static void edge_shutdown (struct usb_serial *serial) static int __init edgeport_init(void) { int retval; + retval = usb_serial_register(&edgeport_2port_device); if (retval) goto failed_2port_device_register; @@ -3016,6 +3076,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: @@ -3027,7 +3088,6 @@ failed_2port_device_register: } - /**************************************************************************** * edgeport_exit * Called when the driver is about to be unloaded. @@ -3050,3 +3110,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");