Greg -- Here is a patch for io_ti in 2.6.9-rc3. This adds support for all the new Edgeport devices and improves/fixes the driver in several ways. The changelog is below.
This patch applies to 2.6.9-rc3, but it was mostly tested in 2.6.9-rc2. It does not change set_termios to avoid sleeping, since that will be changing again before the final 2.6.9, I assume. I have a patch for a non-sleeping set_termios if needed. Please apply. Thanks, -- Al Change Log - Updated to version 0.7. - Added support for Edgeport 4s, 221c, 22c, 21c, 1, 1i, Watchports, Plus Power Port HP4CD, and Plus Power Port PCI. - Added ION_SETMODE ioctl to set 232 or 485 mode for Edgeport 4s. - Added a circular write buffer and locking to protect it. This fixes OPOST processing problems. - Added a "bounce buffer" and a semaphore to protect it when copying data from user space to the circular buffer. - Rewrote TIChase to wait for the circular buffer to drain, to wait up to the closing wait time, and to wait for the last character out. - Fixed hardware flow control by having it stop and restart reads and set and clear tty->hw_stopped. - Removed the RELEVANT_IFLAG macro which mistakenly filtered out the software flow control stty flags. - Added a semaphore to to protect num_ports_open to fix a race during simultaneous opens--two opens could both try to submit the interrupt urb, an error. - Added a separate write_urb_in_use flag rather than relying on (urb->status == -EINPROGRESS). - Added edge_tty_recv to pass data to the tty flip buffers. - Freed memory on failed startup. - Used usb_kill_urb instead of synchronous usb_unlink_urb. - Added low latency as a module parameter, it is on by default. - Added closing wait as a module parameter, it is 40 seconds by default. - Simplified rounding the baud rate divisor. - Added some error messages. Signed-off-by: Al Borchers <[EMAIL PROTECTED]> diff -urp -X dontdiff linux-2.6.9-rc3.orig/drivers/usb/serial/io_ti.c linux-2.6.9-rc3.new/drivers/usb/serial/io_ti.c --- linux-2.6.9-rc3.orig/drivers/usb/serial/io_ti.c 2004-10-04 22:52:09.162742672 -0500 +++ linux-2.6.9-rc3.new/drivers/usb/serial/io_ti.c 2004-10-04 22:23:42.000000000 -0500 @@ -10,7 +10,11 @@ * (at your option) any later version. * * Supports the following devices: - * EP/1 EP/2 EP/4 + * EP/1 EP/2 EP/4 EP/21 EP/22 EP/221 EP/42 EP/421 WATCHPORT + * + * 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: * @@ -34,18 +38,18 @@ #include <linux/serial.h> #include <linux/ioctl.h> #include <asm/uaccess.h> +#include <asm/semaphore.h> #include <linux/usb.h> + #include "usb-serial.h" #include "io_16654.h" #include "io_usbvend.h" #include "io_ti.h" -static int debug; - /* * Version Information */ -#define DRIVER_VERSION "v0.2" +#define DRIVER_VERSION "v0.7" #define DRIVER_AUTHOR "Greg Kroah-Hartman <[EMAIL PROTECTED]> and David Iacovelli" #define DRIVER_DESC "Edgeport USB Serial Driver" @@ -73,6 +77,17 @@ struct edgeport_uart_buf_desc { #define TI_MODE_DOWNLOAD 2 // Made it to download mode #define TI_MODE_TRANSITIONING 3 // Currently in boot mode but transitioning to download mode +/* read urb state */ +#define EDGE_READ_URB_RUNNING 0 +#define EDGE_READ_URB_STOPPING 1 +#define EDGE_READ_URB_STOPPED 2 + +#define EDGE_LOW_LATENCY 1 +#define EDGE_CLOSING_WAIT 4000 /* in .01 sec */ + +#define EDGE_OUT_BUF_SIZE 1024 +#define EDGE_TMP_BUF_SIZE 1024 + /* Product information read from the Edgeport */ struct product_info @@ -81,6 +96,13 @@ struct product_info __u8 hardware_type; // Type of hardware } __attribute__((packed)); +/* circular buffer */ +struct edge_buf { + unsigned int buf_size; + char *buf_buf; + char *buf_get; + char *buf_put; +}; struct edgeport_port { __u16 uart_base; @@ -102,12 +124,18 @@ struct edgeport_port { happen */ struct edgeport_serial *edge_serial; struct usb_serial_port *port; + __u8 bUartMode; /* Port type, 0: RS232, etc. */ + spinlock_t ep_lock; + int ep_read_urb_state; + int ep_write_urb_in_use; + struct edge_buf *ep_out_buf; }; struct edgeport_serial { struct product_info product_info; u8 TI_I2C_Type; // Type of I2C in UMP u8 TiReadI2C; // Set to TRUE if we have read the I2c in Boot Mode + struct semaphore es_sem; int num_ports_open; struct usb_serial *serial; }; @@ -116,6 +144,21 @@ struct edgeport_serial { /* Devices that this driver supports */ static struct usb_device_id edgeport_1port_id_table [] = { { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_1) }, + { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_TI3410_EDGEPORT_1) }, + { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_TI3410_EDGEPORT_1I) }, + { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_WP_PROXIMITY) }, + { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_WP_MOTION) }, + { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_WP_MOISTURE) }, + { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_WP_TEMPERATURE) }, + { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_WP_HUMIDITY) }, + { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_WP_POWER) }, + { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_WP_LIGHT) }, + { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_WP_RADIATION) }, + { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_WP_DISTANCE) }, + { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_WP_ACCELERATION) }, + { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_WP_PROX_DIST) }, + { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_PLUS_PWR_HP4CD) }, + { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_PLUS_PWR_PCI) }, { } }; @@ -129,12 +172,32 @@ static struct usb_device_id edgeport_2po { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_4) }, { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_4I) }, { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_22I) }, + { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_221C) }, + { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_22C) }, + { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_21C) }, +// The 4-port shows up as two 2-port devices + { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_4S) }, { } }; /* Devices that this driver supports */ static struct usb_device_id id_table_combined [] = { { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_1) }, + { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_TI3410_EDGEPORT_1) }, + { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_TI3410_EDGEPORT_1I) }, + { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_WP_PROXIMITY) }, + { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_WP_MOTION) }, + { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_WP_MOISTURE) }, + { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_WP_TEMPERATURE) }, + { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_WP_HUMIDITY) }, + { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_WP_POWER) }, + { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_WP_LIGHT) }, + { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_WP_RADIATION) }, + { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_WP_DISTANCE) }, + { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_WP_ACCELERATION) }, + { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_WP_PROX_DIST) }, + { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_PLUS_PWR_HP4CD) }, + { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_PLUS_PWR_PCI) }, { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_2) }, { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_2C) }, { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_2I) }, @@ -144,6 +207,10 @@ static struct usb_device_id id_table_com { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_4) }, { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_4I) }, { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_22I) }, + { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_221C) }, + { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_22C) }, + { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_21C) }, + { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_4S) }, { } }; @@ -160,12 +227,36 @@ static struct usb_driver io_driver = { static struct EDGE_FIRMWARE_VERSION_INFO OperationalCodeImageVersion; +static int debug; + static int TIStayInBootMode = 0; +static int low_latency = EDGE_LOW_LATENCY; +static int closing_wait = EDGE_CLOSING_WAIT; static int ignore_cpu_rev = 0; +static char edge_tmp_buf[EDGE_TMP_BUF_SIZE]; +static struct semaphore edge_tmp_buf_sem; +static void edge_tty_recv(struct device *dev, struct tty_struct *tty, unsigned char *data, int length); + +static void stop_read(struct edgeport_port *edge_port); +static int restart_read(struct edgeport_port *edge_port); + static void edge_set_termios (struct usb_serial_port *port, struct termios *old_termios); +static void edge_send(struct usb_serial_port *port); + +/* circular buffer */ +static struct edge_buf *edge_buf_alloc(unsigned int size); +static void edge_buf_free(struct edge_buf *eb); +static void edge_buf_clear(struct edge_buf *eb); +static unsigned int edge_buf_data_avail(struct edge_buf *eb); +static unsigned int edge_buf_space_avail(struct edge_buf *eb); +static unsigned int edge_buf_put(struct edge_buf *eb, const char *buf, + unsigned int count); +static unsigned int edge_buf_get(struct edge_buf *eb, char *buf, + unsigned int count); + static int TIReadVendorRequestSync (struct usb_device *dev, __u8 request, @@ -241,7 +332,6 @@ static int TIWriteCommandSync (struct us } - /* clear tx/rx buffers and fifo in TI UMP */ static int TIPurgeDataSync (struct usb_serial_port *port, __u16 mask) { @@ -436,7 +526,7 @@ static int TIWriteDownloadI2C (struct ed buffer, // TransferBuffer write_length); // TransferBufferLength if (status) { - dbg ("%s - ERROR %d", __FUNCTION__, status); + dev_err (&serial->serial->dev->dev, "%s - ERROR %d\n", __FUNCTION__, status); return status; } @@ -510,74 +600,54 @@ exit_is_tx_active: return bytes_left; } -static void TIChasePort(struct edgeport_port *port) +static void TIChasePort(struct edgeport_port *port, unsigned long timeout, int flush) { - int loops; - int last_count; - int write_size; - -restart_tx_loop: - // Base the LoopTime on the baud rate - if (port->baud_rate == 0) - port->baud_rate = 1200; - - write_size = port->tx.count; - loops = max(100, (100*write_size)/(port->baud_rate/10)); - dbg ("%s - write_size %d, baud %d loop = %d", __FUNCTION__, - write_size, port->baud_rate, loops); - - while (1) { - // Save Last count - last_count = port->tx.count; - - dbg ("%s - Tx Buffer Size = %d loops = %d", __FUNCTION__, - last_count, loops); - - /* Is the Edgeport Buffer empty? */ - if (port->tx.count == 0) + int baud_rate; + struct tty_struct *tty = port->port->tty; + wait_queue_t wait; + unsigned long flags; + + if (!timeout) + timeout = (HZ*EDGE_CLOSING_WAIT)/100; + + /* wait for data to drain from the buffer */ + spin_lock_irqsave(&port->ep_lock, flags); + init_waitqueue_entry(&wait, current); + add_wait_queue(&tty->write_wait, &wait); + for (;;) { + set_current_state(TASK_INTERRUPTIBLE); + if (edge_buf_data_avail(port->ep_out_buf) == 0 + || timeout == 0 || signal_pending(current) + || !usb_get_intfdata(port->port->serial->interface)) /* disconnect */ + break; + spin_unlock_irqrestore(&port->ep_lock, flags); + timeout = schedule_timeout(timeout); + spin_lock_irqsave(&port->ep_lock, flags); + } + set_current_state(TASK_RUNNING); + remove_wait_queue(&tty->write_wait, &wait); + if (flush) + edge_buf_clear(port->ep_out_buf); + spin_unlock_irqrestore(&port->ep_lock, flags); + + /* wait for data to drain from the device */ + timeout += jiffies; + while ((long)(jiffies - timeout) < 0 && !signal_pending(current) + && usb_get_intfdata(port->port->serial->interface)) { /* not disconnected */ + if (!TIIsTxActive(port)) break; - - /* Block the thread for 10ms */ msleep(10); - - if (last_count == port->tx.count) { - /* No activity.. count down. */ - --loops; - if (loops == 0) { - dbg ("%s - Wait for TxEmpty - TIMEOUT", - __FUNCTION__); - return; - } - } else { - /* Reset timeout value back to a minimum of 1 second */ - dbg ("%s - Wait for TxEmpty Reset Count", __FUNCTION__); - goto restart_tx_loop; - } } - dbg ("%s - Local Tx Buffer Empty -- Waiting for TI UMP to EMPTY X/Y and FIFO", - __FUNCTION__); - - write_size = TIIsTxActive (port); - loops = max(50, (100*write_size)/(port->baud_rate/10)); - dbg ("%s - write_size %d, baud %d loop = %d", __FUNCTION__, - write_size, port->baud_rate, loops); - - while (1) { - /* This function takes 4 ms; */ - if (!TIIsTxActive (port)) { - /* Delay a few char times */ - msleep(50); - dbg ("%s - Empty", __FUNCTION__); - return; - } + /* disconnected */ + if (!usb_get_intfdata(port->port->serial->interface)) + return; - --loops; - if (loops == 0) { - dbg ("%s - TIMEOUT", __FUNCTION__); - return; - } - } + /* wait one more character time, based on baud rate */ + /* (TIIsTxActive doesn't seem to wait for the last byte) */ + if ((baud_rate=port->baud_rate) == 0) + baud_rate = 50; + msleep(max(1,(10000+baud_rate-1)/baud_rate)); } static int TIChooseConfiguration (struct usb_device *dev) @@ -688,6 +758,7 @@ static int TiValidateI2cImage (struct ed struct ti_i2c_desc *rom_desc; int start_address = 2; __u8 *buffer; + __u16 ttype; rom_desc = kmalloc (sizeof (*rom_desc), GFP_KERNEL); if (!rom_desc) { @@ -701,12 +772,12 @@ static int TiValidateI2cImage (struct ed return -ENOMEM; } - // Read the first byte (Signature0) must be 0x52 + // Read the first byte (Signature0) must be 0x52 or 0x10 status = TIReadRom (serial, 0, 1, buffer); if (status) goto ExitTiValidateI2cImage; - if (*buffer != 0x52) { + if (*buffer != UMP5152 && *buffer != UMP3410) { dev_err (dev, "%s - invalid buffer signature\n", __FUNCTION__); status = -ENODEV; goto ExitTiValidateI2cImage; @@ -730,7 +801,9 @@ static int TiValidateI2cImage (struct ed dbg ("%s Type = 0x%x", __FUNCTION__, rom_desc->Type); // Skip type 2 record - if ((rom_desc->Type & 0x0f) != I2C_DESC_TYPE_FIRMWARE_BASIC) { + ttype = rom_desc->Type & 0x0f; + if ( ttype != I2C_DESC_TYPE_FIRMWARE_BASIC + && ttype != I2C_DESC_TYPE_FIRMWARE_AUTO ) { // Read the descriptor data status = TIReadRom(serial, start_address+sizeof(struct ti_i2c_desc), @@ -840,7 +913,7 @@ static int BuildI2CFirmwareHeader (__u8 memcpy (buffer + sizeof(struct ti_i2c_firmware_rec), &PagableOperationalCodeImage[sizeof(struct ti_i2c_image_header)], - img_header->Length); + le16_to_cpu(img_header->Length)); for (i=0; i < buffer_size; i++) { cs = (__u8)(cs + buffer[i]); @@ -878,7 +951,7 @@ static int TIGetI2cTypeInBootMode (struc dbg ("%s - read 2 status error = %d", __FUNCTION__, status); else dbg ("%s - read 2 data = 0x%x", __FUNCTION__, data); - if ((!status) && data == 0x52) { + if ((!status) && (data == UMP5152 || data == UMP3410)) { dbg ("%s - ROM_TYPE_II", __FUNCTION__); serial->TI_I2C_Type = DTK_ADDR_SPACE_I2C_TYPE_II; return 0; @@ -895,7 +968,7 @@ static int TIGetI2cTypeInBootMode (struc dbg ("%s - read 3 status error = %d", __FUNCTION__, status); else dbg ("%s - read 2 data = 0x%x", __FUNCTION__, data); - if ((!status) && data == 0x52) { + if ((!status) && (data == UMP5152 || data == UMP3410)) { dbg ("%s - ROM_TYPE_III", __FUNCTION__); serial->TI_I2C_Type = DTK_ADDR_SPACE_I2C_TYPE_III; return 0; @@ -983,7 +1056,7 @@ static int TIDownloadFirmware (struct ed interface = &serial->serial->interface->cur_altsetting->desc; if (!interface) { - dev_err (&serial->serial->dev->dev, "%s - no interface set, error!", __FUNCTION__); + dev_err (dev, "%s - no interface set, error!\n", __FUNCTION__); return -ENODEV; } @@ -1249,7 +1322,7 @@ static int TIDownloadFirmware (struct ed dbg ("%s - Update complete 0x%x", __FUNCTION__, status); if (status) { - dbg ("%s - UMPC_COPY_DNLD_TO_I2C failed", __FUNCTION__); + dev_err (dev, "%s - UMPC_COPY_DNLD_TO_I2C failed\n", __FUNCTION__); kfree (rom_desc); kfree (ti_manuf_desc); return status; @@ -1356,7 +1429,7 @@ static int TIDownloadFirmware (struct ed header = (struct ti_i2c_image_header *)buffer; // update length and checksum after padding - header->Length = (__u16)(buffer_size - sizeof(struct ti_i2c_image_header)); + header->Length = cpu_to_le16((__u16)(buffer_size - sizeof(struct ti_i2c_image_header))); header->CheckSum = cs; // Download the operational code @@ -1560,6 +1633,7 @@ static __u8 MapLineStatus (__u8 ti_lsr) static void handle_new_msr (struct edgeport_port *edge_port, __u8 msr) { struct async_icount *icount; + struct tty_struct *tty; dbg ("%s - %02x", __FUNCTION__, msr); @@ -1581,6 +1655,17 @@ static void handle_new_msr (struct edgep /* Save the new modem status */ edge_port->shadow_msr = msr & 0xf0; + tty = edge_port->port->tty; + /* handle CTS flow control */ + if (tty && C_CRTSCTS(tty)) { + if (msr & EDGEPORT_MSR_CTS) { + tty->hw_stopped = 0; + tty_wakeup(tty); + } else { + tty->hw_stopped = 1; + } + } + return; } @@ -1602,10 +1687,8 @@ static void handle_new_lsr (struct edgep } /* Place LSR data byte into Rx buffer */ - if (lsr_data && edge_port->port->tty) { - tty_insert_flip_char(edge_port->port->tty, data, 0); - tty_flip_buffer_push(edge_port->port->tty); - } + if (lsr_data && 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; @@ -1646,7 +1729,7 @@ static void edge_interrupt_callback (str dbg("%s - urb shutting down with status: %d", __FUNCTION__, urb->status); return; default: - dbg("%s - nonzero urb status received: %d", __FUNCTION__, urb->status); + dev_err(&urb->dev->dev, "%s - nonzero urb status received: %d\n", __FUNCTION__, urb->status); goto exit; } @@ -1715,21 +1798,31 @@ static void edge_bulk_in_callback (struc struct edgeport_port *edge_port = (struct edgeport_port *)urb->context; unsigned char *data = urb->transfer_buffer; struct tty_struct *tty; - int status; - int i; + int status = 0; int port_number; dbg("%s", __FUNCTION__); - if (urb->status) { - dbg ("%s - nonzero read bulk status received: %d", - __FUNCTION__, urb->status); + switch (urb->status) { + case 0: + /* success */ + break; + case -ECONNRESET: + case -ENOENT: + case -ESHUTDOWN: + /* this urb is terminated, clean up */ + dbg("%s - urb shutting down with status: %d", __FUNCTION__, urb->status); + return; + default: + dev_err (&urb->dev->dev,"%s - nonzero read bulk status received: %d\n", + __FUNCTION__, urb->status ); + } - if (urb->status == -EPIPE) { - /* clear any problem that might have happened on this pipe */ - usb_clear_halt (edge_port->port->serial->dev, urb->pipe); - goto exit; - } + if (urb->status == -EPIPE) + goto exit; + + if (urb->status) { + dev_err(&urb->dev->dev,"%s - stopping read!\n", __FUNCTION__); return; } @@ -1752,52 +1845,78 @@ static void edge_bulk_in_callback (struc if (edge_port->close_pending) { dbg ("%s - close is pending, dropping data on the floor.", __FUNCTION__); } else { - for (i = 0; i < urb->actual_length ; ++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, data[i], 0); - } - tty_flip_buffer_push(tty); + edge_tty_recv(&edge_port->port->dev, tty, data, urb->actual_length); } edge_port->icount.rx += urb->actual_length; } exit: - /* continue always trying to read */ - status = usb_submit_urb (urb, GFP_ATOMIC); + /* continue read unless stopped */ + spin_lock(&edge_port->ep_lock); + if (edge_port->ep_read_urb_state == EDGE_READ_URB_RUNNING) { + urb->dev = edge_port->port->serial->dev; + status = usb_submit_urb(urb, GFP_ATOMIC); + } else if (edge_port->ep_read_urb_state == EDGE_READ_URB_STOPPING) { + edge_port->ep_read_urb_state = EDGE_READ_URB_STOPPED; + } + spin_unlock(&edge_port->ep_lock); if (status) dev_err (&urb->dev->dev, "%s - usb_submit_urb failed with result %d\n", __FUNCTION__, status); } +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); +} + static void edge_bulk_out_callback (struct urb *urb, struct pt_regs *regs) { struct usb_serial_port *port = (struct usb_serial_port *)urb->context; - struct tty_struct *tty; + struct edgeport_port *edge_port = usb_get_serial_port_data(port); dbg ("%s - port %d", __FUNCTION__, port->number); - if (urb->status) { - dbg ("%s - nonzero write bulk status received: %d", - __FUNCTION__, urb->status); + edge_port->ep_write_urb_in_use = 0; - if (urb->status == -EPIPE) { - /* clear any problem that might have happened on this pipe */ - usb_clear_halt (port->serial->dev, urb->pipe); - } + switch (urb->status) { + case 0: + /* success */ + break; + case -ECONNRESET: + case -ENOENT: + case -ESHUTDOWN: + /* this urb is terminated, clean up */ + dbg("%s - urb shutting down with status: %d", __FUNCTION__, urb->status); return; + default: + dev_err (&urb->dev->dev,"%s - nonzero write bulk status received: %d\n", + __FUNCTION__, urb->status); } - tty = port->tty; - if (tty) { - /* let the tty driver wakeup if it has a special write_wakeup function */ - tty_wakeup(tty); - } + /* send any buffered data */ + edge_send(port); } static int edge_open (struct usb_serial_port *port, struct file * filp) @@ -1816,11 +1935,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; port_number = port->number - port->serial->minor; switch (port_number) { @@ -1847,8 +1963,11 @@ static int edge_open (struct usb_serial_ /* turn off loopback */ status = TIClearLoopBack (edge_port); - if (status) + if (status) { + dev_err(&port->dev,"%s - cannot send clear loopback command, %d\n", + __FUNCTION__, status); return status; + } /* set up the port settings */ edge_set_termios (port, NULL); @@ -1874,8 +1993,10 @@ static int edge_open (struct usb_serial_ open_settings, NULL, 0); - if (status) + if (status) { + dev_err(&port->dev,"%s - cannot send open command, %d\n", __FUNCTION__, status); return status; + } /* Start the DMA? */ status = TIWriteCommandSync (dev, @@ -1884,13 +2005,17 @@ static int edge_open (struct usb_serial_ 0, NULL, 0); - if (status) + if (status) { + dev_err(&port->dev,"%s - cannot send start DMA command, %d\n", __FUNCTION__, status); return status; + } /* Clear TX and RX buffers in UMP */ status = TIPurgeDataSync (port, UMP_PORT_DIR_OUT | UMP_PORT_DIR_IN); - if (status) + if (status) { + dev_err(&port->dev,"%s - cannot send clear buffers command, %d\n", __FUNCTION__, status); return status; + } /* Read Initial MSR */ status = TIReadVendorRequestSync (dev, @@ -1899,18 +2024,27 @@ static int edge_open (struct usb_serial_ (__u16)(UMPM_UART1_PORT + port_number), // wIndex (Address) &edge_port->shadow_msr, // TransferBuffer 1); // TransferBufferLength - if (status) + if (status) { + dev_err(&port->dev,"%s - cannot send read MSR command, %d\n", __FUNCTION__, status); return status; + } dbg ("ShadowMSR 0x%X", edge_port->shadow_msr); + /* Set Initial MCR */ + edge_port->shadow_mcr = MCR_RTS | MCR_DTR; + dbg ("ShadowMCR 0x%X", edge_port->shadow_mcr); + edge_serial = edge_port->edge_serial; + if (down_interruptible(&edge_serial->es_sem)) + return -ERESTARTSYS; if (edge_serial->num_ports_open == 0) { /* we are the first port to be opened, let's post the interrupt urb */ urb = edge_serial->serial->port[0]->interrupt_in_urb; if (!urb) { dev_err (&port->dev, "%s - no interrupt urb present, exiting\n", __FUNCTION__); - return -EINVAL; + status = -EINVAL; + goto up_es_sem; } urb->complete = edge_interrupt_callback; urb->context = edge_serial; @@ -1918,7 +2052,7 @@ static int edge_open (struct usb_serial_ status = usb_submit_urb (urb, GFP_KERNEL); if (status) { dev_err (&port->dev, "%s - usb_submit_urb failed with value %d\n", __FUNCTION__, status); - return status; + goto up_es_sem; } } @@ -1933,25 +2067,34 @@ static int edge_open (struct usb_serial_ urb = port->read_urb; if (!urb) { dev_err (&port->dev, "%s - no read urb present, exiting\n", __FUNCTION__); - return -EINVAL; + status = -EINVAL; + goto unlink_int_urb; } + edge_port->ep_read_urb_state = EDGE_READ_URB_RUNNING; urb->complete = edge_bulk_in_callback; urb->context = edge_port; urb->dev = dev; status = usb_submit_urb (urb, GFP_KERNEL); if (status) { dev_err (&port->dev, "%s - read bulk usb_submit_urb failed with value %d\n", __FUNCTION__, status); - return status; + goto unlink_int_urb; } ++edge_serial->num_ports_open; dbg("%s - exited", __FUNCTION__); - return 0; + goto up_es_sem; + +unlink_int_urb: + if (edge_port->edge_serial->num_ports_open == 0) + usb_kill_urb (port->serial->port[0]->interrupt_in_urb); +up_es_sem: + up(&edge_serial->es_sem); + return status; } -static void edge_close (struct usb_serial_port *port, struct file * filp) +static void edge_close (struct usb_serial_port *port, struct file *filp) { struct edgeport_serial *edge_serial; struct edgeport_port *edge_port; @@ -1969,10 +2112,12 @@ static void edge_close (struct usb_seria * this flag and dump add read data */ edge_port->close_pending = 1; - /* chase the port close */ - TIChasePort (edge_port); + /* chase the port close and flush */ + TIChasePort (edge_port, (HZ*closing_wait)/100, 1); - usb_unlink_urb (port->read_urb); + usb_kill_urb(port->read_urb); + usb_kill_urb(port->write_urb); + edge_port->ep_write_urb_in_use = 0; /* assuming we can still talk to the device, * send a close port command to it */ @@ -1984,12 +2129,14 @@ static void edge_close (struct usb_seria 0, NULL, 0); + down(&edge_serial->es_sem); --edge_port->edge_serial->num_ports_open; if (edge_port->edge_serial->num_ports_open <= 0) { /* last port is now closed, let's shut down our interrupt urb */ - usb_unlink_urb (port->serial->port[0]->interrupt_in_urb); + usb_kill_urb (port->serial->port[0]->interrupt_in_urb); edge_port->edge_serial->num_ports_open = 0; } + up(&edge_serial->es_sem); edge_port->close_pending = 0; dbg("%s - exited", __FUNCTION__); @@ -1998,7 +2145,7 @@ 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); - int result; + unsigned long flags; dbg("%s - port %d", __FUNCTION__, port->number); @@ -2011,21 +2158,62 @@ static int edge_write (struct usb_serial return -ENODEV; if (edge_port->close_pending == 1) return -ENODEV; - - if (port->write_urb->status == -EINPROGRESS) { - dbg ("%s - already writing", __FUNCTION__); - return 0; - } - - count = min (count, port->bulk_out_size); + /* copy user data (which can sleep) */ if (from_user) { - if (copy_from_user(port->write_urb->transfer_buffer, data, count)) + 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); + dev_err(&port->dev,"%s - cannot copy from user space\n", __FUNCTION__); return -EFAULT; - } else { - memcpy (port->write_urb->transfer_buffer, data, count); + } + data = edge_tmp_buf; } + spin_lock_irqsave(&edge_port->ep_lock, flags); + count = edge_buf_put(edge_port->ep_out_buf, data, count); + spin_unlock_irqrestore(&edge_port->ep_lock, flags); + + if (from_user) + up(&edge_tmp_buf_sem); + + edge_send(port); + + return count; +} + +static void edge_send(struct usb_serial_port *port) +{ + int count, result; + struct edgeport_port *edge_port = usb_get_serial_port_data(port); + struct tty_struct *tty = port->tty; + unsigned long flags; + + + dbg("%s - port %d", __FUNCTION__, port->number); + + spin_lock_irqsave(&edge_port->ep_lock, flags); + + if (edge_port->ep_write_urb_in_use) { + spin_unlock_irqrestore(&edge_port->ep_lock, flags); + return; + } + + count = edge_buf_get(edge_port->ep_out_buf, + port->write_urb->transfer_buffer, + port->bulk_out_size); + + if (count == 0) { + spin_unlock_irqrestore(&edge_port->ep_lock, flags); + return; + } + + edge_port->ep_write_urb_in_use = 1; + + spin_unlock_irqrestore(&edge_port->ep_lock, flags); + usb_serial_debug_data(debug, &port->dev, __FUNCTION__, count, port->write_urb->transfer_buffer); /* set up our urb */ @@ -2038,33 +2226,38 @@ static int edge_write (struct usb_serial /* send the data out the bulk port */ result = usb_submit_urb(port->write_urb, GFP_ATOMIC); - if (result) + if (result) { dev_err(&port->dev, "%s - failed submitting write urb, error %d\n", __FUNCTION__, result); - else - result = count; - - if (result > 0) + edge_port->ep_write_urb_in_use = 0; + // TODO: reschedule edge_send + } else { edge_port->icount.tx += count; + } - return result; + /* wakeup any process waiting for writes to complete */ + /* there is now more room in the buffer for new writes */ + if (tty) { + /* let the tty driver wakeup if it has a special write_wakeup function */ + tty_wakeup(tty); + } } static int edge_write_room (struct usb_serial_port *port) { struct edgeport_port *edge_port = usb_get_serial_port_data(port); int room = 0; + unsigned long flags; - dbg("%s", __FUNCTION__); + dbg("%s - port %d", __FUNCTION__, port->number); if (edge_port == NULL) return -ENODEV; if (edge_port->close_pending == 1) return -ENODEV; - - dbg("%s - port %d", __FUNCTION__, port->number); - if (port->write_urb->status != -EINPROGRESS) - room = port->bulk_out_size; + spin_lock_irqsave(&edge_port->ep_lock, flags); + room = edge_buf_space_avail(edge_port->ep_out_buf); + spin_unlock_irqrestore(&edge_port->ep_lock, flags); dbg("%s - returns %d", __FUNCTION__, room); return room; @@ -2074,18 +2267,18 @@ static int edge_chars_in_buffer (struct { struct edgeport_port *edge_port = usb_get_serial_port_data(port); int chars = 0; + unsigned long flags; - dbg("%s", __FUNCTION__); + dbg("%s - port %d", __FUNCTION__, port->number); if (edge_port == NULL) return -ENODEV; if (edge_port->close_pending == 1) return -ENODEV; - dbg("%s - port %d", __FUNCTION__, port->number); - - if (port->write_urb->status == -EINPROGRESS) - chars = port->write_urb->transfer_buffer_length; + spin_lock_irqsave(&edge_port->ep_lock, flags); + chars = edge_buf_data_avail(edge_port->ep_out_buf); + spin_unlock_irqrestore(&edge_port->ep_lock, flags); dbg ("%s - returns %d", __FUNCTION__, chars); return chars; @@ -2107,21 +2300,21 @@ static void edge_throttle (struct usb_se dbg ("%s - no tty available", __FUNCTION__); return; } + /* 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); if (status <= 0) { - return; + dev_err(&port->dev, "%s - failed to write stop character, %d\n", __FUNCTION__, status); } } - /* if we are implementing RTS/CTS, toggle that line */ - if (tty->termios->c_cflag & CRTSCTS) { - status = TIClearRts (edge_port); - } + /* if we are implementing RTS/CTS, stop reads */ + /* and the Edgeport will clear the RTS line */ + if (C_CRTSCTS(tty)) + stop_read(edge_port); - usb_unlink_urb (port->read_urb); } static void edge_unthrottle (struct usb_serial_port *port) @@ -2146,29 +2339,61 @@ static void edge_unthrottle (struct usb_ unsigned char start_char = START_CHAR(tty); status = edge_write (port, 0, &start_char, 1); if (status <= 0) { - return; + dev_err(&port->dev, "%s - failed to write start character, %d\n", __FUNCTION__, status); } } - /* if we are implementing RTS/CTS, toggle that line */ - if (tty->termios->c_cflag & CRTSCTS) { - status = TISetRts (edge_port); + /* if we are implementing RTS/CTS, restart reads */ + /* are the Edgeport will assert the RTS line */ + if (C_CRTSCTS(tty)) { + status = restart_read(edge_port); + if (status) + dev_err(&port->dev, "%s - read bulk usb_submit_urb failed with value %d\n", __FUNCTION__, status); } - port->read_urb->dev = port->serial->dev; - status = usb_submit_urb (port->read_urb, GFP_ATOMIC); - if (status) { - dev_err (&port->dev, "%s - usb_submit_urb failed with value %d\n", __FUNCTION__, status); - } } +static void stop_read(struct edgeport_port *edge_port) +{ + unsigned long flags; + + spin_lock_irqsave(&edge_port->ep_lock, flags); + + if (edge_port->ep_read_urb_state == EDGE_READ_URB_RUNNING) + edge_port->ep_read_urb_state = EDGE_READ_URB_STOPPING; + edge_port->shadow_mcr &= ~MCR_RTS; + + spin_unlock_irqrestore(&edge_port->ep_lock, flags); +} + +static int restart_read(struct edgeport_port *edge_port) +{ + struct urb *urb; + int status = 0; + unsigned long flags; + + spin_lock_irqsave(&edge_port->ep_lock, flags); + + if (edge_port->ep_read_urb_state == EDGE_READ_URB_STOPPED) { + urb = edge_port->port->read_urb; + urb->complete = edge_bulk_in_callback; + urb->context = edge_port; + urb->dev = edge_port->port->serial->dev; + status = usb_submit_urb(urb, GFP_KERNEL); + } + edge_port->ep_read_urb_state = EDGE_READ_URB_RUNNING; + edge_port->shadow_mcr |= MCR_RTS; + + spin_unlock_irqrestore(&edge_port->ep_lock, flags); + + return status; +} static void change_port_settings (struct edgeport_port *edge_port, struct termios *old_termios) { struct ump_uart_config *config; struct tty_struct *tty; int baud; - int round; unsigned cflag; int status; int port_number = edge_port->port->number - edge_port->port->serial->minor; @@ -2195,7 +2420,7 @@ static void change_port_settings (struct /* These flags must be set */ config->wFlags |= UMP_MASK_UART_FLAGS_RECEIVE_MS_INT; config->wFlags |= UMP_MASK_UART_FLAGS_AUTO_START_ON_ERR; - config->bUartMode = 0; + config->bUartMode = (__u8)(edge_port->bUartMode); switch (cflag & CSIZE) { case CS5: @@ -2247,6 +2472,8 @@ static void change_port_settings (struct dbg("%s - RTS/CTS is enabled", __FUNCTION__); } else { dbg("%s - RTS/CTS is disabled", __FUNCTION__); + tty->hw_stopped = 0; + restart_read(edge_port); } /* if we are implementing XON/XOFF, set the start and stop character in the device */ @@ -2279,10 +2506,8 @@ static void change_port_settings (struct /* pick a default, any default... */ baud = 9600; } - config->wBaudRate = (__u16)(461550L / baud); - round = 4615500L / baud; - if ((round - (config->wBaudRate * 10)) >= 5) - config->wBaudRate++; + edge_port->baud_rate = baud; + config->wBaudRate = (__u16)((461550L + baud/2) / baud); dbg ("%s - baud rate = %d, wBaudRate = %d", __FUNCTION__, baud, config->wBaudRate); @@ -2329,20 +2554,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); @@ -2358,7 +2581,7 @@ static void edge_set_termios (struct usb 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); @@ -2387,7 +2610,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; @@ -2426,7 +2649,7 @@ static int get_serial_info (struct edgep tmp.xmit_fifo_size = edge_port->port->bulk_out_size; tmp.baud_base = 9600; tmp.close_delay = 5*HZ; - tmp.closing_wait = 30*HZ; + tmp.closing_wait = closing_wait; // tmp.custom_divisor = state->custom_divisor; // tmp.hub6 = state->hub6; // tmp.io_type = state->io_type; @@ -2442,10 +2665,24 @@ static int edge_ioctl (struct usb_serial struct edgeport_port *edge_port = usb_get_serial_port_data(port); struct async_icount cnow; struct async_icount cprev; + unsigned int tmp; dbg("%s - port %d, cmd = 0x%x", __FUNCTION__, port->number, cmd); switch (cmd) { + case ION_SETMODE : + if (port->serial->vendor == USB_VENDOR_ID_ION && + port->serial->product == ION_DEVICE_ID_TI_EDGEPORT_4S) { + edge_port->bUartMode = (__u8)arg; + return 0; + } else + return -ENOTTY; + case ION_GETMODE : + tmp = (unsigned int)edge_port->bUartMode; + if (copy_to_user((void *)arg, &tmp, sizeof(tmp) )) + return -EFAULT; + return 0; + case TIOCINQ: dbg("%s - (%d) TIOCINQ", __FUNCTION__, port->number); // return get_number_bytes_avail(edge_port, (unsigned int *) arg); @@ -2507,7 +2744,7 @@ static void edge_break (struct usb_seria dbg ("%s - state = %d", __FUNCTION__, break_state); /* chase the port close */ - TIChasePort (edge_port); + TIChasePort (edge_port, 0, 0); if (break_state == -1) { status = TISetBreak (edge_port); @@ -2537,6 +2774,7 @@ static int edge_startup (struct usb_seri return -ENOMEM; } memset (edge_serial, 0, sizeof(struct edgeport_serial)); + sema_init(&edge_serial->es_sem, 1); edge_serial->serial = serial; usb_set_serial_data(serial, edge_serial); @@ -2551,25 +2789,47 @@ static int edge_startup (struct usb_seri edge_port = kmalloc (sizeof(struct edgeport_port), GFP_KERNEL); if (edge_port == NULL) { dev_err(&serial->dev->dev, "%s - Out of memory\n", __FUNCTION__); - return -ENOMEM; + goto cleanup; } memset (edge_port, 0, sizeof(struct edgeport_port)); + spin_lock_init(&edge_port->ep_lock); + edge_port->ep_out_buf = edge_buf_alloc(EDGE_OUT_BUF_SIZE); + if (edge_port->ep_out_buf == NULL) { + dev_err(&serial->dev->dev, "%s - Out of memory\n", __FUNCTION__); + kfree(edge_port); + goto cleanup; + } edge_port->port = serial->port[i]; edge_port->edge_serial = edge_serial; usb_set_serial_port_data(serial->port[i], edge_port); + edge_port->bUartMode = 0; /* Default is RS232 */ } return 0; + +cleanup: + for (--i; i>=0; --i) { + edge_port = usb_get_serial_port_data(serial->port[i]); + edge_buf_free(edge_port->ep_out_buf); + kfree(edge_port); + usb_set_serial_port_data(serial->port[i], NULL); + } + return -ENOMEM; } static void edge_shutdown (struct usb_serial *serial) { int i; + struct edgeport_port *edge_port; dbg ("%s", __FUNCTION__); for (i=0; i < serial->num_ports; ++i) { - kfree (usb_get_serial_port_data(serial->port[i])); + edge_port = usb_get_serial_port_data(serial->port[i]); + if (edge_port) { + edge_buf_free(edge_port->ep_out_buf); + kfree(edge_port); + } usb_set_serial_port_data(serial->port[i], NULL); } kfree (usb_get_serial_data(serial)); @@ -2577,6 +2837,185 @@ static void edge_shutdown (struct usb_se } +/* Circular Buffer */ + +/* + * edge_buf_alloc + * + * Allocate a circular buffer and all associated memory. + */ + +static struct edge_buf *edge_buf_alloc(unsigned int size) +{ + struct edge_buf *eb; + + + if (size == 0) + return NULL; + + eb = (struct edge_buf *)kmalloc(sizeof(struct edge_buf), GFP_KERNEL); + if (eb == NULL) + return NULL; + + eb->buf_buf = kmalloc(size, GFP_KERNEL); + if (eb->buf_buf == NULL) { + kfree(eb); + return NULL; + } + + eb->buf_size = size; + eb->buf_get = eb->buf_put = eb->buf_buf; + + return eb; +} + + +/* + * edge_buf_free + * + * Free the buffer and all associated memory. + */ + +void edge_buf_free(struct edge_buf *eb) +{ + if (eb != NULL) { + if (eb->buf_buf != NULL) + kfree(eb->buf_buf); + kfree(eb); + } +} + + +/* + * edge_buf_clear + * + * Clear out all data in the circular buffer. + */ + +static void edge_buf_clear(struct edge_buf *eb) +{ + if (eb != NULL) + eb->buf_get = eb->buf_put; + /* equivalent to a get of all data available */ +} + + +/* + * edge_buf_data_avail + * + * Return the number of bytes of data available in the circular + * buffer. + */ + +static unsigned int edge_buf_data_avail(struct edge_buf *eb) +{ + if (eb != NULL) + return ((eb->buf_size + eb->buf_put - eb->buf_get) % eb->buf_size); + else + return 0; +} + + +/* + * edge_buf_space_avail + * + * Return the number of bytes of space available in the circular + * buffer. + */ + +static unsigned int edge_buf_space_avail(struct edge_buf *eb) +{ + if (eb != NULL) + return ((eb->buf_size + eb->buf_get - eb->buf_put - 1) % eb->buf_size); + else + return 0; +} + + +/* + * edge_buf_put + * + * Copy data data from a user buffer and put it into the circular buffer. + * Restrict to the amount of space available. + * + * Return the number of bytes copied. + */ + +static unsigned int edge_buf_put(struct edge_buf *eb, const char *buf, + unsigned int count) +{ + unsigned int len; + + + if (eb == NULL) + return 0; + + len = edge_buf_space_avail(eb); + if (count > len) + count = len; + + if (count == 0) + return 0; + + len = eb->buf_buf + eb->buf_size - eb->buf_put; + if (count > len) { + memcpy(eb->buf_put, buf, len); + memcpy(eb->buf_buf, buf+len, count - len); + eb->buf_put = eb->buf_buf + count - len; + } else { + memcpy(eb->buf_put, buf, count); + if (count < len) + eb->buf_put += count; + else /* count == len */ + eb->buf_put = eb->buf_buf; + } + + return count; +} + + +/* + * edge_buf_get + * + * Get data from the circular buffer and copy to the given buffer. + * Restrict to the amount of data available. + * + * Return the number of bytes copied. + */ + +static unsigned int edge_buf_get(struct edge_buf *eb, char *buf, + unsigned int count) +{ + unsigned int len; + + + if (eb == NULL) + return 0; + + len = edge_buf_data_avail(eb); + if (count > len) + count = len; + + if (count == 0) + return 0; + + len = eb->buf_buf + eb->buf_size - eb->buf_get; + if (count > len) { + memcpy(buf, eb->buf_get, len); + memcpy(buf+len, eb->buf_buf, count - len); + eb->buf_get = eb->buf_buf + count - len; + } else { + memcpy(buf, eb->buf_get, count); + if (count < len) + eb->buf_get += count; + else /* count == len */ + eb->buf_get = eb->buf_buf; + } + + return count; +} + + static struct usb_serial_device_type edgeport_1port_device = { .owner = THIS_MODULE, .name = "Edgeport TI 1 port adapter", @@ -2641,6 +3080,7 @@ static int __init edgeport_init(void) if (retval) goto failed_usb_register; info(DRIVER_DESC " " DRIVER_VERSION); + sema_init(&edge_tmp_buf_sem, 1); return 0; failed_usb_register: usb_serial_deregister(&edgeport_2port_device); @@ -2668,6 +3108,12 @@ 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(low_latency, "Low latency enabled or not"); + +module_param(closing_wait, int, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(closing_wait, "Maximum wait for data to drain, in .01 secs"); + module_param(ignore_cpu_rev, bool, S_IRUGO | S_IWUSR); MODULE_PARM_DESC(ignore_cpu_rev, "Ignore the cpu revision when connecting to a device"); diff -urp -X dontdiff linux-2.6.9-rc3.orig/drivers/usb/serial/io_ti.h linux-2.6.9-rc3.new/drivers/usb/serial/io_ti.h --- linux-2.6.9-rc3.orig/drivers/usb/serial/io_ti.h 2004-08-14 05:55:10.000000000 -0500 +++ linux-2.6.9-rc3.new/drivers/usb/serial/io_ti.h 2004-10-04 18:51:05.000000000 -0500 @@ -177,4 +177,11 @@ struct ump_interrupt /* Interrupt pack #define TIUMP_INTERRUPT_CODE_LSR 0x03 #define TIUMP_INTERRUPT_CODE_MSR 0x04 +/* + * IOCTL DEFINITIONS + */ +#define ION_IOC_MAGIC 'E' /* "Edgeport" */ +#define ION_SETMODE _IOW(ION_IOC_MAGIC,0x01, unsigned int) /* Set Edgeport 4S mode, e.g: RS232, RS422... */ +#define ION_GETMODE _IOR(ION_IOC_MAGIC,0x02, unsigned int) /* Get Edgeport 4S mode, e.g: RS232, RS422... */ + #endif ------------------------------------------------------- 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