patch-2.4.21 linux-2.4.21/drivers/usb/serial/ftdi_sio.c
Next file: linux-2.4.21/drivers/usb/serial/ftdi_sio.h
Previous file: linux-2.4.21/drivers/usb/serial/Makefile
Back to the patch index
Back to the overall index
- Lines: 1310
- Date:
2003-06-13 07:51:36.000000000 -0700
- Orig file:
linux-2.4.20/drivers/usb/serial/ftdi_sio.c
- Orig date:
2002-11-28 15:53:14.000000000 -0800
diff -urN linux-2.4.20/drivers/usb/serial/ftdi_sio.c linux-2.4.21/drivers/usb/serial/ftdi_sio.c
@@ -17,6 +17,50 @@
* See http://ftdi-usb-sio.sourceforge.net for upto date testing info
* and extra documentation
*
+ * (23/Feb/2003) Bill Ryder
+ * Added matrix orb device vid/pids from Wayne Wylupski
+ *
+ * (19/Feb/2003) Ian Abbott
+ * For TIOCSSERIAL, set alt_speed to 0 when ASYNC_SPD_MASK value has
+ * changed to something other than ASYNC_SPD_HI, ASYNC_SPD_VHI,
+ * ASYNC_SPD_SHI or ASYNC_SPD_WARP. Also, unless ASYNC_SPD_CUST is in
+ * force, don't bother changing baud rate when custom_divisor has changed.
+ *
+ * (18/Feb/2003) Ian Abbott
+ * Fixed TIOCMGET handling to include state of DTR and RTS, the state
+ * of which are now saved by set_dtr() and set_rts().
+ * Fixed improper storage class for buf in set_dtr() and set_rts().
+ * Added FT232BM chip type and support for its extra baud rates (compared
+ * to FT8U232AM).
+ * Took account of special case divisor values for highest baud rates of
+ * FT8U232AM and FT232BM.
+ * For TIOCSSERIAL, forced alt_speed to 0 when ASYNC_SPD_CUST kludge used,
+ * as previous alt_speed setting is now stale.
+ * Moved startup code common between the startup routines for the
+ * different chip types into a common subroutine.
+ *
+ * (17/Feb/2003) Bill Ryder
+ * Added write urb buffer pool on a per device basis
+ * Added more checking for open file on callbacks (fixed OOPS)
+ * Added CrystalFontz 632 and 634 PIDs
+ * (thanx to CrystalFontz for the sample devices - they flushed out
+ * some driver bugs)
+ * Minor debugging message changes
+ * Added throttle, unthrottle and chars_in_buffer functions
+ * Fixed FTDI_SIO (the original device) bug
+ * Fixed some shutdown handling
+ *
+ *
+ *
+ *
+ * (07/Jun/2002) Kuba Ober
+ * Changed FTDI_SIO_BASE_BAUD_TO_DIVISOR macro into ftdi_baud_to_divisor
+ * function. It was getting too complex.
+ * Fix the divisor calculation logic which was setting divisor of 0.125
+ * instead of 0.5 for fractional parts of divisor equal to 5/8, 6/8, 7/8.
+ * Also make it bump up the divisor to next integer in case of 7/8 - it's
+ * a better approximation.
+ *
* (25/Jul/2002) Bill Ryder inserted Dmitri's TIOCMIWAIT patch
* Not tested by me but it doesn't break anything I use.
*
@@ -131,7 +175,7 @@
/*
* Version Information
*/
-#define DRIVER_VERSION "v1.2.1"
+#define DRIVER_VERSION "v1.3.2"
#define DRIVER_AUTHOR "Greg Kroah-Hartman <greg@kroah.com>, Bill Ryder <bryder@sgi.com>, Kuba Ober <kuba@mareimbrium.org>"
#define DRIVER_DESC "USB FTDI Serial Converters Driver"
@@ -148,12 +192,44 @@
* so .. 8U232AM's baudrate setting codes are different
* - it has a two byte status code.
* - it returns characters every 16ms (the FTDI does it every 40ms)
+ *
+ * the bcdDevice value is used to differentiate FT232BM and FT245BM from
+ * the earlier FT8U232AM and FT8U232BM. For now, include all known VID/PID
+ * combinations in both tables.
+ * FIXME: perhaps bcdDevice can also identify 12MHz devices, but I don't know
+ * if those ever went into mass production. [Ian Abbott]
*/
static struct usb_device_id id_table_8U232AM [] = {
- { USB_DEVICE(FTDI_VID, FTDI_8U232AM_PID) },
- { USB_DEVICE(FTDI_NF_RIC_VID, FTDI_NF_RIC_PID) },
+ { USB_DEVICE_VER(FTDI_VID, FTDI_8U232AM_PID, 0, 0x3ff) },
+ { USB_DEVICE_VER(FTDI_NF_RIC_VID, FTDI_NF_RIC_PID, 0, 0x3ff) },
+ { USB_DEVICE_VER(FTDI_VID, FTDI_XF_634_PID, 0, 0x3ff) },
+ { USB_DEVICE_VER(FTDI_VID, FTDI_XF_632_PID, 0, 0x3ff) },
+ { USB_DEVICE_VER(FTDI_MTXORB_VID, FTDI_MTXORB_0_PID, 0, 0x3ff) },
+ { USB_DEVICE_VER(FTDI_MTXORB_VID, FTDI_MTXORB_1_PID, 0, 0x3ff) },
+ { USB_DEVICE_VER(FTDI_MTXORB_VID, FTDI_MTXORB_2_PID, 0, 0x3ff) },
+ { USB_DEVICE_VER(FTDI_MTXORB_VID, FTDI_MTXORB_3_PID, 0, 0x3ff) },
+ { USB_DEVICE_VER(FTDI_MTXORB_VID, FTDI_MTXORB_4_PID, 0, 0x3ff) },
+ { USB_DEVICE_VER(FTDI_MTXORB_VID, FTDI_MTXORB_5_PID, 0, 0x3ff) },
+ { USB_DEVICE_VER(FTDI_MTXORB_VID, FTDI_MTXORB_6_PID, 0, 0x3ff) },
+ { } /* Terminating entry */
+};
+
+
+static struct usb_device_id id_table_FT232BM [] = {
+ { USB_DEVICE_VER(FTDI_VID, FTDI_8U232AM_PID, 0x400, 0xffff) },
+ { USB_DEVICE_VER(FTDI_NF_RIC_VID, FTDI_NF_RIC_PID, 0x400, 0xffff) },
+ { USB_DEVICE_VER(FTDI_VID, FTDI_XF_634_PID, 0x400, 0xffff) },
+ { USB_DEVICE_VER(FTDI_VID, FTDI_XF_632_PID, 0x400, 0xffff) },
+ { USB_DEVICE_VER(FTDI_MTXORB_VID, FTDI_MTXORB_0_PID, 0x400, 0xffff) },
+ { USB_DEVICE_VER(FTDI_MTXORB_VID, FTDI_MTXORB_1_PID, 0x400, 0xffff) },
+ { USB_DEVICE_VER(FTDI_MTXORB_VID, FTDI_MTXORB_2_PID, 0x400, 0xffff) },
+ { USB_DEVICE_VER(FTDI_MTXORB_VID, FTDI_MTXORB_3_PID, 0x400, 0xffff) },
+ { USB_DEVICE_VER(FTDI_MTXORB_VID, FTDI_MTXORB_4_PID, 0x400, 0xffff) },
+ { USB_DEVICE_VER(FTDI_MTXORB_VID, FTDI_MTXORB_5_PID, 0x400, 0xffff) },
+ { USB_DEVICE_VER(FTDI_MTXORB_VID, FTDI_MTXORB_6_PID, 0x400, 0xffff) },
+
{ } /* Terminating entry */
};
@@ -161,12 +237,27 @@
static __devinitdata struct usb_device_id id_table_combined [] = {
{ USB_DEVICE(FTDI_VID, FTDI_SIO_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_8U232AM_PID) },
+ { USB_DEVICE(FTDI_VID, FTDI_XF_634_PID) },
+ { USB_DEVICE(FTDI_VID, FTDI_XF_632_PID) },
{ USB_DEVICE(FTDI_NF_RIC_VID, FTDI_NF_RIC_PID) },
- { } /* Terminating entry */
+ { USB_DEVICE(FTDI_MTXORB_VID, FTDI_MTXORB_0_PID) },
+ { USB_DEVICE(FTDI_MTXORB_VID, FTDI_MTXORB_1_PID) },
+ { USB_DEVICE(FTDI_MTXORB_VID, FTDI_MTXORB_2_PID) },
+ { USB_DEVICE(FTDI_MTXORB_VID, FTDI_MTXORB_3_PID) },
+ { USB_DEVICE(FTDI_MTXORB_VID, FTDI_MTXORB_4_PID) },
+ { USB_DEVICE(FTDI_MTXORB_VID, FTDI_MTXORB_5_PID) },
+ { USB_DEVICE(FTDI_MTXORB_VID, FTDI_MTXORB_6_PID) }, { } /* Terminating entry */
};
MODULE_DEVICE_TABLE (usb, id_table_combined);
+
+/* constants which set the number of write urb buffers */
+#define NUM_URBS 32
+/* Don't be tempted to increase this buffer to > 64 ! I tried it and it doesn't work */
+#define URB_TRANSFER_BUFFER_SIZE 64 /* the device's max packet size */
+
+
struct ftdi_private {
ftdi_chip_type_t chip_type;
/* type of the device, either SIO or FT8U232AM */
@@ -178,8 +269,13 @@
* it is different between devices
*/
int flags; /* some ASYNC_xxxx flags are supported */
+ unsigned long last_dtr_rts; /* saved modem control outputs */
wait_queue_head_t delta_msr_wait; /* Used for TIOCMIWAIT */
char prev_status, diff_status; /* Used for TIOCMIWAIT */
+
+ struct urb *write_urb_pool[NUM_URBS];
+ spinlock_t write_urb_pool_lock;
+
};
/* Used for TIOCMIWAIT */
@@ -193,16 +289,25 @@
/* function prototypes for a FTDI serial converter */
static int ftdi_SIO_startup (struct usb_serial *serial);
static int ftdi_8U232AM_startup (struct usb_serial *serial);
+static int ftdi_FT232BM_startup (struct usb_serial *serial);
static void ftdi_shutdown (struct usb_serial *serial);
static int ftdi_open (struct usb_serial_port *port, struct file *filp);
static void ftdi_close (struct usb_serial_port *port, struct file *filp);
static int ftdi_write (struct usb_serial_port *port, int from_user, const unsigned char *buf, int count);
static int ftdi_write_room (struct usb_serial_port *port);
+static int ftdi_chars_in_buffer (struct usb_serial_port *port);
static void ftdi_write_bulk_callback (struct urb *urb);
static void ftdi_read_bulk_callback (struct urb *urb);
static void ftdi_set_termios (struct usb_serial_port *port, struct termios * old);
static int ftdi_ioctl (struct usb_serial_port *port, struct file * file, unsigned int cmd, unsigned long arg);
static void ftdi_break_ctl (struct usb_serial_port *port, int break_state );
+static void ftdi_throttle (struct usb_serial_port *port);
+static void ftdi_unthrottle (struct usb_serial_port *port);
+
+static unsigned short int ftdi_232am_baud_base_to_divisor (int baud, int base);
+static unsigned short int ftdi_232am_baud_to_divisor (int baud);
+static __u32 ftdi_232bm_baud_base_to_divisor (int baud, int base);
+static __u32 ftdi_232bm_baud_to_divisor (int baud);
static struct usb_serial_device_type ftdi_SIO_device = {
.owner = THIS_MODULE,
@@ -214,8 +319,11 @@
.num_ports = 1,
.open = ftdi_open,
.close = ftdi_close,
+ .throttle = ftdi_throttle,
+ .unthrottle = ftdi_unthrottle,
.write = ftdi_write,
.write_room = ftdi_write_room,
+ .chars_in_buffer = ftdi_chars_in_buffer,
.read_bulk_callback = ftdi_read_bulk_callback,
.write_bulk_callback = ftdi_write_bulk_callback,
.ioctl = ftdi_ioctl,
@@ -227,7 +335,7 @@
static struct usb_serial_device_type ftdi_8U232AM_device = {
.owner = THIS_MODULE,
- .name = "FTDI 8U232AM",
+ .name = "FTDI 8U232AM Compatible",
.id_table = id_table_8U232AM,
.num_interrupt_in = 0,
.num_bulk_in = 1,
@@ -235,8 +343,11 @@
.num_ports = 1,
.open = ftdi_open,
.close = ftdi_close,
+ .throttle = ftdi_throttle,
+ .unthrottle = ftdi_unthrottle,
.write = ftdi_write,
.write_room = ftdi_write_room,
+ .chars_in_buffer = ftdi_chars_in_buffer,
.read_bulk_callback = ftdi_read_bulk_callback,
.write_bulk_callback = ftdi_write_bulk_callback,
.ioctl = ftdi_ioctl,
@@ -246,8 +357,35 @@
.shutdown = ftdi_shutdown,
};
+static struct usb_serial_device_type ftdi_FT232BM_device = {
+ .owner = THIS_MODULE,
+ .name = "FTDI FT232BM Compatible",
+ .id_table = id_table_FT232BM,
+ .num_interrupt_in = 0,
+ .num_bulk_in = 1,
+ .num_bulk_out = 1,
+ .num_ports = 1,
+ .open = ftdi_open,
+ .close = ftdi_close,
+ .throttle = ftdi_throttle,
+ .unthrottle = ftdi_unthrottle,
+ .write = ftdi_write,
+ .write_room = ftdi_write_room,
+ .chars_in_buffer = ftdi_chars_in_buffer,
+ .read_bulk_callback = ftdi_read_bulk_callback,
+ .write_bulk_callback = ftdi_write_bulk_callback,
+ .ioctl = ftdi_ioctl,
+ .set_termios = ftdi_set_termios,
+ .break_ctl = ftdi_break_ctl,
+ .startup = ftdi_FT232BM_startup,
+ .shutdown = ftdi_shutdown,
+};
+
+
+
#define WDR_TIMEOUT (HZ * 5 ) /* default urb timeout */
+/* High and low are for DTR, RTS etc etc */
#define HIGH 1
#define LOW 0
@@ -257,15 +395,57 @@
* ***************************************************************************
*/
+static unsigned short int ftdi_232am_baud_base_to_divisor(int baud, int base)
+{
+ unsigned short int divisor;
+ int divisor3 = base / 2 / baud; // divisor shifted 3 bits to the left
+ if ((divisor3 & 0x7) == 7) divisor3 ++; // round x.7/8 up to x+1
+ divisor = divisor3 >> 3;
+ divisor3 &= 0x7;
+ if (divisor3 == 1) divisor |= 0xc000; else // 0.125
+ if (divisor3 >= 4) divisor |= 0x4000; else // 0.5
+ if (divisor3 != 0) divisor |= 0x8000; // 0.25
+ if (divisor == 1) divisor = 0; /* special case for maximum baud rate */
+ return divisor;
+}
+
+static unsigned short int ftdi_232am_baud_to_divisor(int baud)
+{
+ return(ftdi_232am_baud_base_to_divisor(baud, 48000000));
+}
-static int set_rts(struct usb_device *dev,
- unsigned int pipe,
- int high_or_low)
+static __u32 ftdi_232bm_baud_base_to_divisor(int baud, int base)
{
- static char buf[1];
- unsigned ftdi_high_or_low = (high_or_low? FTDI_SIO_SET_RTS_HIGH :
- FTDI_SIO_SET_RTS_LOW);
- return(usb_control_msg(dev, pipe,
+ static const unsigned char divfrac[8] = { 0, 3, 2, 4, 1, 5, 6, 7 };
+ __u32 divisor;
+ int divisor3 = base / 2 / baud; // divisor shifted 3 bits to the left
+ divisor = divisor3 >> 3;
+ divisor |= (__u32)divfrac[divisor3 & 0x7] << 14;
+ /* Deal with special cases for highest baud rates. */
+ if (divisor == 1) divisor = 0; else // 1.0
+ if (divisor == 0x4001) divisor = 1; // 1.5
+ return divisor;
+}
+
+static __u32 ftdi_232bm_baud_to_divisor(int baud)
+{
+ return(ftdi_232bm_baud_base_to_divisor(baud, 48000000));
+}
+
+static int set_rts(struct usb_serial_port *port, int high_or_low)
+{
+ struct ftdi_private * priv = (struct ftdi_private *)port->private;
+ char buf[1];
+ unsigned ftdi_high_or_low;
+ if (high_or_low) {
+ ftdi_high_or_low = FTDI_SIO_SET_RTS_HIGH;
+ priv->last_dtr_rts |= TIOCM_RTS;
+ } else {
+ ftdi_high_or_low = FTDI_SIO_SET_RTS_LOW;
+ priv->last_dtr_rts &= ~TIOCM_RTS;
+ }
+ return(usb_control_msg(port->serial->dev,
+ usb_sndctrlpipe(port->serial->dev, 0),
FTDI_SIO_SET_MODEM_CTRL_REQUEST,
FTDI_SIO_SET_MODEM_CTRL_REQUEST_TYPE,
ftdi_high_or_low, 0,
@@ -273,14 +453,20 @@
}
-static int set_dtr(struct usb_device *dev,
- unsigned int pipe,
- int high_or_low)
+static int set_dtr(struct usb_serial_port *port, int high_or_low)
{
- static char buf[1];
- unsigned ftdi_high_or_low = (high_or_low? FTDI_SIO_SET_DTR_HIGH :
- FTDI_SIO_SET_DTR_LOW);
- return(usb_control_msg(dev, pipe,
+ struct ftdi_private * priv = (struct ftdi_private *)port->private;
+ char buf[1];
+ unsigned ftdi_high_or_low;
+ if (high_or_low) {
+ ftdi_high_or_low = FTDI_SIO_SET_DTR_HIGH;
+ priv->last_dtr_rts |= TIOCM_DTR;
+ } else {
+ ftdi_high_or_low = FTDI_SIO_SET_DTR_LOW;
+ priv->last_dtr_rts &= ~TIOCM_DTR;
+ }
+ return(usb_control_msg(port->serial->dev,
+ usb_sndctrlpipe(port->serial->dev, 0),
FTDI_SIO_SET_MODEM_CTRL_REQUEST,
FTDI_SIO_SET_MODEM_CTRL_REQUEST_TYPE,
ftdi_high_or_low, 0,
@@ -288,30 +474,36 @@
}
-static __u16 get_ftdi_divisor(struct usb_serial_port * port);
+static __u32 get_ftdi_divisor(struct usb_serial_port * port);
static int change_speed(struct usb_serial_port *port)
{
char buf[1];
__u16 urb_value;
+ __u16 urb_index;
+ __u32 urb_index_value;
- urb_value = get_ftdi_divisor(port);
+ urb_index_value = get_ftdi_divisor(port);
+ urb_value = (__u16)urb_index_value;
+ urb_index = (__u16)(urb_index_value >> 16);
return (usb_control_msg(port->serial->dev,
usb_sndctrlpipe(port->serial->dev, 0),
FTDI_SIO_SET_BAUDRATE_REQUEST,
FTDI_SIO_SET_BAUDRATE_REQUEST_TYPE,
- urb_value, 0,
+ urb_value, urb_index,
buf, 0, 100) < 0);
}
-static __u16 get_ftdi_divisor(struct usb_serial_port * port)
+static __u32 get_ftdi_divisor(struct usb_serial_port * port)
{ /* get_ftdi_divisor */
struct ftdi_private * priv = (struct ftdi_private *)port->private;
- __u16 urb_value = 0;
+ __u32 div_value = 0;
+ int div_okay = 1;
+ char *chip_name = "";
int baud;
/*
@@ -356,37 +548,53 @@
if (!baud) baud = 9600;
switch(priv->chip_type) {
case SIO: /* SIO chip */
+ chip_name = "SIO";
switch(baud) {
- case 300: urb_value = ftdi_sio_b300; break;
- case 600: urb_value = ftdi_sio_b600; break;
- case 1200: urb_value = ftdi_sio_b1200; break;
- case 2400: urb_value = ftdi_sio_b2400; break;
- case 4800: urb_value = ftdi_sio_b4800; break;
- case 9600: urb_value = ftdi_sio_b9600; break;
- case 19200: urb_value = ftdi_sio_b19200; break;
- case 38400: urb_value = ftdi_sio_b38400; break;
- case 57600: urb_value = ftdi_sio_b57600; break;
- case 115200: urb_value = ftdi_sio_b115200; break;
+ case 300: div_value = ftdi_sio_b300; break;
+ case 600: div_value = ftdi_sio_b600; break;
+ case 1200: div_value = ftdi_sio_b1200; break;
+ case 2400: div_value = ftdi_sio_b2400; break;
+ case 4800: div_value = ftdi_sio_b4800; break;
+ case 9600: div_value = ftdi_sio_b9600; break;
+ case 19200: div_value = ftdi_sio_b19200; break;
+ case 38400: div_value = ftdi_sio_b38400; break;
+ case 57600: div_value = ftdi_sio_b57600; break;
+ case 115200: div_value = ftdi_sio_b115200; break;
} /* baud */
- if (urb_value == 0)
- dbg("%s - Baudrate (%d) requested is not supported", __FUNCTION__, baud);
+ if (div_value == 0) {
+ dbg("%s - Baudrate (%d) requested is not supported", __FUNCTION__, baud);
+ div_value = ftdi_sio_b9600;
+ div_okay = 0;
+ }
break;
case FT8U232AM: /* 8U232AM chip */
+ chip_name = "FT8U232AM";
+ if (baud <= 3000000) {
+ div_value = ftdi_232am_baud_to_divisor(baud);
+ } else {
+ dbg("%s - Baud rate too high!", __FUNCTION__);
+ div_value = ftdi_232am_baud_to_divisor(9600);
+ div_okay = 0;
+ }
+ break;
+ case FT232BM: /* FT232BM chip */
+ chip_name = "FT232BM";
if (baud <= 3000000) {
- urb_value = FTDI_SIO_BAUD_TO_DIVISOR(baud);
+ div_value = ftdi_232bm_baud_to_divisor(baud);
} else {
dbg("%s - Baud rate too high!", __FUNCTION__);
+ div_value = ftdi_232bm_baud_to_divisor(9600);
+ div_okay = 0;
}
break;
} /* priv->chip_type */
- if (urb_value == 0) {
- urb_value = ftdi_sio_b9600;
- } else {
- dbg("%s - Baud rate set to %d (divisor %d) on chip %s", __FUNCTION__, baud, urb_value, (priv->chip_type == SIO) ? "SIO" : "FT8U232AM" );
+ if (div_okay) {
+ dbg("%s - Baud rate set to %d (divisor 0x%lX) on chip %s",
+ __FUNCTION__, baud, (unsigned long)div_value, chip_name);
}
- return(urb_value);
+ return(div_value);
}
@@ -442,17 +650,23 @@
port->tty->low_latency = (priv->flags & ASYNC_LOW_LATENCY) ? 1 : 0;
check_and_exit:
- if (((old_priv.flags & ASYNC_SPD_MASK) !=
- (priv->flags & ASYNC_SPD_MASK)) ||
- (old_priv.custom_divisor != priv->custom_divisor)) {
+ if ((old_priv.flags & ASYNC_SPD_MASK) !=
+ (priv->flags & ASYNC_SPD_MASK)) {
if ((priv->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI)
port->tty->alt_speed = 57600;
- if ((priv->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI)
+ else if ((priv->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI)
port->tty->alt_speed = 115200;
- if ((priv->flags & ASYNC_SPD_MASK) == ASYNC_SPD_SHI)
+ else if ((priv->flags & ASYNC_SPD_MASK) == ASYNC_SPD_SHI)
port->tty->alt_speed = 230400;
- if ((priv->flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP)
+ else if ((priv->flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP)
port->tty->alt_speed = 460800;
+ else
+ port->tty->alt_speed = 0;
+ }
+ if (((old_priv.flags & ASYNC_SPD_MASK) !=
+ (priv->flags & ASYNC_SPD_MASK)) ||
+ (((priv->flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST) &&
+ (old_priv.custom_divisor != priv->custom_divisor))) {
change_speed(port);
}
@@ -466,66 +680,166 @@
* ***************************************************************************
*/
-/* Startup for the SIO chip */
-static int ftdi_SIO_startup (struct usb_serial *serial)
+/* Common startup subroutine */
+/* Called from ftdi_SIO_startup, etc. */
+static int ftdi_common_startup (struct usb_serial *serial)
{
struct ftdi_private *priv;
+ int i ;
+ struct urb *urb;
+
+ dbg("%s",__FUNCTION__);
priv = serial->port->private = kmalloc(sizeof(struct ftdi_private), GFP_KERNEL);
if (!priv){
err("%s- kmalloc(%Zd) failed.", __FUNCTION__, sizeof(struct ftdi_private));
return -ENOMEM;
}
+ memset(priv, 0, sizeof(*priv));
- priv->chip_type = SIO;
- priv->baud_base = 12000000 / 16;
- priv->custom_divisor = 0;
- priv->write_offset = 1;
- priv->prev_status = priv->diff_status = 0;
+ init_waitqueue_head(&priv->delta_msr_wait);
/* This will push the characters through immediately rather
than queue a task to deliver them */
priv->flags = ASYNC_LOW_LATENCY;
+
+ /* create our write urb pool and transfer buffers - shared across all ftdi devices */
+ spin_lock_init (&priv->write_urb_pool_lock);
+ for (i = 0; i < NUM_URBS; ++i) {
+ urb = usb_alloc_urb(0);
+ priv->write_urb_pool[i] = urb;
+ if (urb == NULL) {
+ err("Unable to create new urb in urb pool");
+ continue;
+ }
+
+ urb->transfer_buffer = NULL;
+ urb->transfer_buffer = kmalloc (URB_TRANSFER_BUFFER_SIZE, GFP_KERNEL);
+ if (!urb->transfer_buffer) {
+ err("%s - out of memory for urb buffers.",
+ __FUNCTION__);
+ continue;
+ }
+ }
+
+
+ return (0);
+}
+
+
+/* Startup for the SIO chip */
+/* Called from usbserial:serial_probe */
+static int ftdi_SIO_startup (struct usb_serial *serial)
+{
+ struct ftdi_private *priv;
+ int err;
+
+ dbg("%s",__FUNCTION__);
+
+ err = ftdi_common_startup(serial);
+ if (err){
+ return (err);
+ }
+
+ priv = serial->port->private;
+ priv->chip_type = SIO;
+ priv->baud_base = 12000000 / 16;
+ priv->write_offset = 1;
return (0);
}
/* Startup for the 8U232AM chip */
+/* Called from usbserial:serial_probe */
static int ftdi_8U232AM_startup (struct usb_serial *serial)
-{
+{ /* ftdi_8U232AM_startup */
struct ftdi_private *priv;
+ int err;
- priv = serial->port->private = kmalloc(sizeof(struct ftdi_private), GFP_KERNEL);
- if (!priv){
- err("%s- kmalloc(%Zd) failed.", __FUNCTION__, sizeof(struct ftdi_private));
- return -ENOMEM;
+ dbg("%s",__FUNCTION__);
+ err = ftdi_common_startup(serial);
+ if (err){
+ return (err);
}
+ priv = serial->port->private;
priv->chip_type = FT8U232AM;
priv->baud_base = 48000000 / 2; /* Would be / 16, but FTDI supports 0.125, 0.25 and 0.5 divisor fractions! */
- priv->custom_divisor = 0;
- priv->write_offset = 0;
- init_waitqueue_head(&priv->delta_msr_wait);
- /* This will push the characters through immediately rather
- than queue a task to deliver them */
- priv->flags = ASYNC_LOW_LATENCY;
return (0);
-}
+} /* ftdi_8U232AM_startup */
+
+/* Startup for the FT232BM chip */
+/* Called from usbserial:serial_probe */
+static int ftdi_FT232BM_startup (struct usb_serial *serial)
+{ /* ftdi_FT232BM_startup */
+ struct ftdi_private *priv;
+ int err;
+
+ dbg("%s",__FUNCTION__);
+ err = ftdi_common_startup(serial);
+ if (err){
+ return (err);
+ }
+
+ priv = serial->port->private;
+ priv->chip_type = FT232BM;
+ priv->baud_base = 48000000 / 2; /* Would be / 16, but FT232BM supports multiple of 0.125 divisor fractions! */
+
+ return (0);
+} /* ftdi_FT232BM_startup */
+
+/* ftdi_shutdown is called from usbserial:usb_serial_disconnect
+ * it is called when the usb device is disconnected
+ *
+ * usbserial:usb_serial_disconnect
+ * calls __serial_close for each open of the port
+ * shutdown is called then (ie ftdi_shutdown)
+ */
static void ftdi_shutdown (struct usb_serial *serial)
-{
+{ /* ftdi_shutdown */
+
+ struct usb_serial_port *port = &serial->port[0];
+ struct ftdi_private *priv = serial->port->private;
+ int i;
+ unsigned long flags;
+
dbg("%s", __FUNCTION__);
- /* stop reads and writes on all ports */
- while (serial->port[0].open_count > 0) {
- ftdi_close (&serial->port[0], NULL);
- }
- if (serial->port[0].private){
- kfree(serial->port[0].private);
- serial->port[0].private = NULL;
+ /* all open ports are closed at this point
+ * (by usbserial.c:__serial_close, which calls ftdi_close)
+ */
+
+
+ /* Only execute this if this is the final open port for this device */
+ if (port->open_count == 0){
+ spin_lock_irqsave (&priv->write_urb_pool_lock, flags);
+
+ for (i = 0; i < NUM_URBS; ++i) {
+ if (priv->write_urb_pool[i]) {
+ /* FIXME - uncomment the following usb_unlink_urb call when
+ * the host controllers get fixed to set urb->dev = NULL after
+ * the urb is finished. Otherwise this call oopses. */
+ /* usb_unlink_urb(priv->write_urb_pool[i]); */
+ if (priv->write_urb_pool[i]->transfer_buffer) {
+ kfree(priv->write_urb_pool[i]->transfer_buffer);
+ priv->write_urb_pool[i]->transfer_buffer = NULL;
+ }
+ usb_free_urb (priv->write_urb_pool[i]);
+ priv->write_urb_pool[i] = NULL;
+ }
+ }
+
+ spin_unlock_irqrestore (&priv->write_urb_pool_lock, flags);
+ /* usb_disconnect shuts down the port->read_urb so don't do it here */
+ /* as was done previously */
+ }
+ if (serial->port->private){
+ kfree(serial->port->private);
+ serial->port->private = NULL;
}
-}
+} /* ftdi_shutdown */
static int ftdi_open (struct usb_serial_port *port, struct file *filp)
@@ -559,13 +873,17 @@
/* FIXME: Flow control might be enabled, so it should be checked -
we have no control of defaults! */
/* Turn on RTS and DTR since we are not flow controlling by default */
- if (set_dtr(serial->dev, usb_sndctrlpipe(serial->dev, 0),HIGH) < 0) {
+ if (set_dtr(port, HIGH) < 0) {
err("%s Error from DTR HIGH urb", __FUNCTION__);
}
- if (set_rts(serial->dev, usb_sndctrlpipe(serial->dev, 0),HIGH) < 0){
+ if (set_rts(port, HIGH) < 0){
err("%s Error from RTS HIGH urb", __FUNCTION__);
}
+ /* Make sure write_urb is initialised since a write_pool is used now */
+ port->write_urb = NULL; /* prevents usbserial.c from trying something silly */
+
+
/* Start reading from the device */
FILL_BULK_URB(port->read_urb, serial->dev,
usb_rcvbulkpipe(serial->dev, port->bulk_in_endpointAddress),
@@ -575,18 +893,32 @@
if (result)
err("%s - failed submitting read urb, error %d", __FUNCTION__, result);
+
return result;
} /* ftdi_open */
+
+/*
+ * usbserial:__serial_close only calls ftdi_close if the point is open
+ *
+ * This only gets called when it is the last close
+ *
+ *
+ */
+
static void ftdi_close (struct usb_serial_port *port, struct file *filp)
{ /* ftdi_close */
- struct usb_serial *serial = port->serial; /* Checked in usbserial.c */
+ struct usb_serial *serial;
unsigned int c_cflag = port->tty->termios->c_cflag;
char buf[1];
dbg("%s", __FUNCTION__);
+ serial = get_usb_serial ( port, __FUNCTION__);
+ if (!serial)
+ return;
+
if (serial->dev) {
if (c_cflag & HUPCL){
/* Disable flow control */
@@ -599,115 +931,188 @@
}
/* drop DTR */
- if (set_dtr(serial->dev, usb_sndctrlpipe(serial->dev, 0), LOW) < 0){
+ if (set_dtr(port, LOW) < 0){
err("Error from DTR LOW urb");
}
/* drop RTS */
- if (set_rts(serial->dev, usb_sndctrlpipe(serial->dev, 0),LOW) < 0) {
+ if (set_rts(port, LOW) < 0) {
err("Error from RTS LOW urb");
}
+ /* shutdown our bulk read */
+ if (port->read_urb) {
+ usb_unlink_urb (port->read_urb);
+ }
+ /* unlink the running write urbs */
+
+
} /* Note change no line is hupcl is off */
+ } /* if (serial->dev) */
+
- /* shutdown our bulk reads and writes */
- /* ***CHECK*** behaviour when there is nothing queued */
- usb_unlink_urb (port->write_urb);
- usb_unlink_urb (port->read_urb);
- }
} /* ftdi_close */
-/* The ftdi_sio requires the first byte to have:
+/* The SIO requires the first byte to have:
* B0 1
* B1 0
* B2..7 length of message excluding byte 0
+ *
+ * The new devices do not require this byte
*/
static int ftdi_write (struct usb_serial_port *port, int from_user,
const unsigned char *buf, int count)
{ /* ftdi_write */
- struct usb_serial *serial = port->serial;
+ struct usb_serial *serial = get_usb_serial ( port, __FUNCTION__);
struct ftdi_private *priv = (struct ftdi_private *)port->private;
- unsigned char *first_byte = port->write_urb->transfer_buffer;
- int data_offset ;
+ unsigned char *first_byte;
+ int data_offset ; /* will be 1 for the SIO and 0 otherwise */
int result;
+ int user_bytes_sent = 0 ; /* amount of user data sent */
+
+ /* Variables for urb pool management */
+ unsigned char *current_position = (unsigned char *)buf;
+ int i;
+ struct urb *urb; /* pointer to urb from urb pool */
+ unsigned long flags;
+ /* end of urb pool management */
+
dbg("%s port %d, %d bytes", __FUNCTION__, port->number, count);
if (count == 0) {
err("write request of 0 bytes");
- return 0;
+ goto exit;
}
data_offset = priv->write_offset;
dbg("data_offset set to %d",data_offset);
- if (port->write_urb->status == -EINPROGRESS) {
- dbg("%s - already writing", __FUNCTION__);
- return (0);
- }
-
- count += data_offset;
- count = (count > port->bulk_out_size) ? port->bulk_out_size : count;
-
- /* Copy in the data to send */
- if (from_user) {
- if (copy_from_user(port->write_urb->transfer_buffer + data_offset,
- buf, count - data_offset )){
- return -EFAULT;
+ while (count > 0) {
+ /* urb_byte_count = user_byte_count + data_offset */
+ int urb_byte_count; /* Number of bytes of URB data */
+ int user_byte_count; /* Number of bytes of user data */
+
+ /* Find a free urb in the list */
+ urb = NULL;
+
+ spin_lock_irqsave (&(priv->write_urb_pool_lock), flags) ;
+
+ for (i = 0 ; i < NUM_URBS; i++) {
+ if (priv->write_urb_pool[i] -> status != -EINPROGRESS) {
+ urb = priv->write_urb_pool[i];
+ /* Must make sure another device doesn't grab this */
+ /* BUT unfortunately the uhci stack errors if it sees this */
+ /* so have to increase the size of the spin_lock */
+ /* urb->status = -EINPROGRESS; */
+ break;
+ }
}
- } else {
- memcpy(port->write_urb->transfer_buffer + data_offset,
- buf, count - data_offset );
- }
-
- first_byte = port->write_urb->transfer_buffer;
- if (data_offset > 0){
- /* Write the control byte at the front of the packet*/
- *first_byte = 1 | ((count-data_offset) << 2) ;
- }
- dbg("%s Bytes: %d, First Byte: 0x%02x", __FUNCTION__,count, first_byte[0]);
- usb_serial_debug_data (__FILE__, __FUNCTION__, count, first_byte);
+
+ if (urb == NULL) {
+ spin_unlock_irqrestore (&priv->write_urb_pool_lock, flags);
+ dbg("%s - no more free urbs", __FUNCTION__);
+ goto exit;
+ }
+
+ /* Allocate memory for the urb if necessary */
+ if (urb->transfer_buffer == NULL) {
+ urb->transfer_buffer = kmalloc (URB_TRANSFER_BUFFER_SIZE, GFP_KERNEL);
+ if (urb->transfer_buffer == NULL) {
+ spin_unlock_irqrestore (&priv->write_urb_pool_lock, flags);
+ err("%s ran out of kernel memory for urb ...", __FUNCTION__);
+ goto exit;
+ }
+ }
+
+ /* The original sio needs the first byte to contain the bytecount
+ * so the urb may be one byte bigger than the user data
+ */
+ urb_byte_count = min (count + data_offset, URB_TRANSFER_BUFFER_SIZE);
+ user_byte_count = urb_byte_count - data_offset;
+
+ /* Copy in the data to send */
+ if (from_user) {
+ if (copy_from_user(urb->transfer_buffer + data_offset,
+ current_position, user_byte_count )){
+ spin_unlock_irqrestore (&priv->write_urb_pool_lock, flags);
+ return -EFAULT;
+ }
+ } else {
+ memcpy(urb->transfer_buffer + data_offset,
+ current_position, user_byte_count );
+ }
+
+ first_byte = urb->transfer_buffer;
+ if (data_offset > 0){
+ /* Write the control byte at the front of the packet*/
+ *first_byte = 1 | ((user_byte_count) << 2) ;
+ dbg("%s Bytes: %d, First Byte: 0x%02x", __FUNCTION__,count, first_byte[0]);
+ }
- /* send the data out the bulk port */
- FILL_BULK_URB(port->write_urb, serial->dev,
- usb_sndbulkpipe(serial->dev, port->bulk_out_endpointAddress),
- port->write_urb->transfer_buffer, count,
- ftdi_write_bulk_callback, port);
+ usb_serial_debug_data (__FILE__, __FUNCTION__, urb_byte_count, first_byte);
- result = usb_submit_urb(port->write_urb);
- if (result) {
- err("%s - failed submitting write urb, error %d", __FUNCTION__, result);
- return 0;
- }
+ /* fill the buffer and send it */
+ FILL_BULK_URB(urb, serial->dev,
+ usb_sndbulkpipe(serial->dev, port->bulk_out_endpointAddress),
+ urb->transfer_buffer, urb_byte_count,
+ ftdi_write_bulk_callback, port);
+ urb->transfer_flags |= USB_QUEUE_BULK;
+
+ result = usb_submit_urb(urb);
+ if (result) {
+ spin_unlock_irqrestore (&priv->write_urb_pool_lock, flags);
+ err("%s - failed submitting write urb, error %d", __FUNCTION__, result);
+ user_bytes_sent = result;
+ goto exit;
+ }
+ spin_unlock_irqrestore (&priv->write_urb_pool_lock, flags);
+
+ /* house keeping */
+ current_position += user_byte_count;
+ user_bytes_sent += user_byte_count;
+ count -= user_byte_count;
+
+ } /* while count > 0 */
+
+ exit:
+
+ dbg("%s write returning: %d", __FUNCTION__, user_bytes_sent);
+ return user_bytes_sent;
- dbg("%s write returning: %d", __FUNCTION__, count - data_offset);
- return (count - data_offset);
} /* ftdi_write */
+/* This function may get called when the device is closed */
+
static void ftdi_write_bulk_callback (struct urb *urb)
{
struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
- struct usb_serial *serial;
+ struct usb_serial *serial = get_usb_serial (port, __FUNCTION__);
dbg("%s", __FUNCTION__);
- if (port_paranoia_check (port, "ftdi_write_bulk_callback")) {
+ if (port_paranoia_check (port, __FUNCTION__))
return;
- }
-
- serial = port->serial;
- if (serial_paranoia_check (serial, "ftdi_write_bulk_callback")) {
- return;
- }
if (urb->status) {
dbg("nonzero write bulk status received: %d", urb->status);
return;
}
- queue_task(&port->tqueue, &tq_immediate);
- mark_bh(IMMEDIATE_BH);
+
+ if (!serial) {
+ dbg("%s - bad serial pointer, exiting", __FUNCTION__);
+ return;
+ }
+
+ /* Have to check for validity of queueing up the tasks */
+ dbg("%s - port->open_count = %d", __FUNCTION__, port->open_count);
+
+ if (port->open_count > 0){
+ queue_task(&port->tqueue, &tq_immediate);
+ mark_bh(IMMEDIATE_BH);
+ }
return;
} /* ftdi_write_bulk_callback */
@@ -716,22 +1121,59 @@
static int ftdi_write_room( struct usb_serial_port *port )
{
struct ftdi_private *priv = (struct ftdi_private *)port->private;
- int room;
+ int room = 0;
+ int i;
+ unsigned long flags;
- if ( port->write_urb->status == -EINPROGRESS) {
- /* There is a race here with the _write routines but it won't hurt */
- room = 0;
- } else {
- room = port->bulk_out_size - priv->write_offset;
+
+ spin_lock_irqsave (&priv->write_urb_pool_lock, flags);
+
+ for (i = 0; i < NUM_URBS; i++) {
+ if (priv->write_urb_pool[i]->status != -EINPROGRESS) {
+ room += URB_TRANSFER_BUFFER_SIZE - priv->write_offset;
+ }
}
+
+ spin_unlock_irqrestore (&priv->write_urb_pool_lock, flags);
+
+ dbg("%s - returns %d", __FUNCTION__, room);
return(room);
} /* ftdi_write_room */
+static int ftdi_chars_in_buffer (struct usb_serial_port *port)
+{ /* ftdi_chars_in_buffer */
+ unsigned long flags;
+ int i;
+ int chars = 0;
+ struct ftdi_private *priv = (struct ftdi_private *)port->private;
+ int data_offset = priv->write_offset;
+
+ dbg("%s - port %d", __FUNCTION__, port->number);
+
+ spin_lock_irqsave (&priv->write_urb_pool_lock, flags);
+
+ /* tally up the number of bytes waiting */
+ for (i = 0; i < NUM_URBS; ++i) {
+ if (priv->write_urb_pool[i]->status == -EINPROGRESS) {
+ chars += URB_TRANSFER_BUFFER_SIZE - data_offset;
+ }
+ }
+
+ spin_unlock_irqrestore (&priv->write_urb_pool_lock, flags);
+
+ dbg("%s - returns %d", __FUNCTION__, chars);
+
+ return (chars);
+
+} /* ftdi_chars_in_buffer */
+
+
+
static void ftdi_read_bulk_callback (struct urb *urb)
{ /* ftdi_read_bulk_callback */
struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
- struct usb_serial *serial;
+ struct usb_serial *serial = get_usb_serial(port,__FUNCTION__);
struct tty_struct *tty = port->tty ;
struct ftdi_private *priv = (struct ftdi_private *) port->private;
char error_flag;
@@ -741,27 +1183,36 @@
int i;
int result;
- dbg("%s - port %d", __FUNCTION__, port->number);
+ dbg("%s", __FUNCTION__);
- if (port_paranoia_check (port, "ftdi_sio_read_bulk_callback")) {
+ if (port_paranoia_check (port, __FUNCTION__)) {
return;
}
+ if (port->open_count <= 0)
+ return;
- serial = port->serial;
- if (serial_paranoia_check (serial, "ftdi_sio_read_bulk_callback")) {
+ if (!serial){
+ dbg("%s - bad serial pointer - exiting",__FUNCTION__);
+ return;
+ }
+
+ if (!tty) {
+ dbg("%s - bad tty pointer - exiting",__FUNCTION__);
return;
}
+
if (urb->status) {
/* This will happen at close every time so it is a dbg not an err */
- dbg("nonzero read bulk status received: %d", urb->status);
+ dbg("(this is ok on close) nonzero read bulk status received: %d", urb->status);
return;
}
+ /* The first two bytes of every read packet are status */
if (urb->actual_length > 2) {
usb_serial_debug_data (__FILE__, __FUNCTION__, urb->actual_length, data);
} else {
- dbg("Just status 0o%03o0o%03o",data[0],data[1]);
+ dbg("Status only: %03oo %03oo",data[0],data[1]);
}
@@ -816,8 +1267,6 @@
tty_insert_flip_char(tty, data[i], error_flag);
}
tty_flip_buffer_push(tty);
-
-
}
#ifdef NOT_CORRECT_BUT_KEEPING_IT_FOR_NOW
@@ -842,15 +1291,18 @@
}
#endif
- /* Continue trying to always read */
- FILL_BULK_URB(port->read_urb, serial->dev,
- usb_rcvbulkpipe(serial->dev, port->bulk_in_endpointAddress),
- port->read_urb->transfer_buffer, port->read_urb->transfer_buffer_length,
- ftdi_read_bulk_callback, port);
-
- result = usb_submit_urb(port->read_urb);
- if (result)
- err("%s - failed resubmitting read urb, error %d", __FUNCTION__, result);
+ /* if the port is closed stop trying to read */
+ if (port->open_count > 0){
+ /* Continue trying to always read */
+ FILL_BULK_URB(port->read_urb, serial->dev,
+ usb_rcvbulkpipe(serial->dev, port->bulk_in_endpointAddress),
+ port->read_urb->transfer_buffer, port->read_urb->transfer_buffer_length,
+ ftdi_read_bulk_callback, port);
+
+ result = usb_submit_urb(port->read_urb);
+ if (result)
+ err("%s - failed resubmitting read urb, error %d", __FUNCTION__, result);
+ }
return;
} /* ftdi_read_bulk_callback */
@@ -954,10 +1406,10 @@
err("%s error from disable flowcontrol urb", __FUNCTION__);
}
/* Drop RTS and DTR */
- if (set_dtr(serial->dev, usb_sndctrlpipe(serial->dev, 0),LOW) < 0){
+ if (set_dtr(port, LOW) < 0){
err("%s Error from DTR LOW urb", __FUNCTION__);
}
- if (set_rts(serial->dev, usb_sndctrlpipe(serial->dev, 0),LOW) < 0){
+ if (set_rts(port, LOW) < 0){
err("%s Error from RTS LOW urb", __FUNCTION__);
}
@@ -1029,6 +1481,7 @@
}
break;
case FT8U232AM:
+ case FT232BM:
/* the 8U232AM returns a two byte value (the sio is a 1 byte value) - in the same
format as the data returned from the in point */
if ((ret = usb_control_msg(serial->dev,
@@ -1050,7 +1503,8 @@
return put_user((buf[0] & FTDI_SIO_DSR_MASK ? TIOCM_DSR : 0) |
(buf[0] & FTDI_SIO_CTS_MASK ? TIOCM_CTS : 0) |
(buf[0] & FTDI_SIO_RI_MASK ? TIOCM_RI : 0) |
- (buf[0] & FTDI_SIO_RLSD_MASK ? TIOCM_CD : 0),
+ (buf[0] & FTDI_SIO_RLSD_MASK ? TIOCM_CD : 0) |
+ priv->last_dtr_rts,
(unsigned long *) arg);
break;
@@ -1059,13 +1513,16 @@
if (get_user(mask, (unsigned long *) arg))
return -EFAULT;
urb_value = ((mask & TIOCM_DTR) ? HIGH : LOW);
- if (set_dtr(serial->dev, usb_sndctrlpipe(serial->dev, 0),urb_value) < 0){
+ if ((ret = set_dtr(port, urb_value)) < 0){
err("Error from DTR set urb (TIOCMSET)");
+ return(ret);
}
urb_value = ((mask & TIOCM_RTS) ? HIGH : LOW);
- if (set_rts(serial->dev, usb_sndctrlpipe(serial->dev, 0),urb_value) < 0){
+ if ((ret = set_rts(port, urb_value)) < 0){
err("Error from RTS set urb (TIOCMSET)");
- }
+ return(ret);
+ }
+ return(0);
break;
case TIOCMBIS: /* turns on (Sets) the lines as specified by the mask */
@@ -1073,43 +1530,37 @@
if (get_user(mask, (unsigned long *) arg))
return -EFAULT;
if (mask & TIOCM_DTR){
- if ((ret = set_dtr(serial->dev,
- usb_sndctrlpipe(serial->dev, 0),
- HIGH)) < 0) {
+ if ((ret = set_dtr(port, HIGH)) < 0) {
err("Urb to set DTR failed");
return(ret);
}
}
if (mask & TIOCM_RTS) {
- if ((ret = set_rts(serial->dev,
- usb_sndctrlpipe(serial->dev, 0),
- HIGH)) < 0){
+ if ((ret = set_rts(port, HIGH)) < 0){
err("Urb to set RTS failed");
return(ret);
}
}
- break;
+ return(0);
+ break;
case TIOCMBIC: /* turns off (Clears) the lines as specified by the mask */
dbg("%s TIOCMBIC", __FUNCTION__);
if (get_user(mask, (unsigned long *) arg))
return -EFAULT;
if (mask & TIOCM_DTR){
- if ((ret = set_dtr(serial->dev,
- usb_sndctrlpipe(serial->dev, 0),
- LOW)) < 0){
+ if ((ret = set_dtr(port, LOW)) < 0){
err("Urb to unset DTR failed");
return(ret);
}
}
if (mask & TIOCM_RTS) {
- if ((ret = set_rts(serial->dev,
- usb_sndctrlpipe(serial->dev, 0),
- LOW)) < 0){
+ if ((ret = set_rts(port, LOW)) < 0){
err("Urb to unset RTS failed");
return(ret);
}
}
+ return(0);
break;
/*
@@ -1164,25 +1615,58 @@
*/
}
}
- /* NOTREACHED */
-
+ return(0);
+ break;
default:
- /* This is not an error - turns out the higher layers will do
- * some ioctls itself (see comment above)
- */
- dbg("%s arg not supported - it was 0x%04x", __FUNCTION__,cmd);
- return(-ENOIOCTLCMD);
break;
+
}
- return 0;
+
+
+ /* This is not necessarily an error - turns out the higher layers will do
+ * some ioctls itself (see comment above)
+ */
+ dbg("%s arg not supported - it was 0x%04x - check /usr/include/asm/ioctls.h", __FUNCTION__, cmd);
+
+ return(-ENOIOCTLCMD);
} /* ftdi_ioctl */
+static void ftdi_throttle (struct usb_serial_port *port)
+{
+ dbg("%s - port %d", __FUNCTION__, port->number);
+ usb_unlink_urb (port->read_urb);
+}
+
+
+static void ftdi_unthrottle (struct usb_serial_port *port)
+{
+ int result;
+ struct usb_serial *serial = port->serial;
+
+ dbg("%s - port %d", __FUNCTION__, port->number);
+
+ port->read_urb->dev = serial->dev;
+
+ FILL_BULK_URB(port->read_urb, serial->dev,
+ usb_rcvbulkpipe(serial->dev, port->bulk_in_endpointAddress),
+ port->read_urb->transfer_buffer, port->read_urb->transfer_buffer_length,
+ ftdi_read_bulk_callback, port);
+
+ result = usb_submit_urb(port->read_urb);
+ if (result)
+ err("%s - failed submitting read urb, error %d", __FUNCTION__, result);
+}
+
static int __init ftdi_init (void)
{
+
dbg("%s", __FUNCTION__);
usb_serial_register (&ftdi_SIO_device);
usb_serial_register (&ftdi_8U232AM_device);
+ usb_serial_register (&ftdi_FT232BM_device);
+
+
info(DRIVER_VERSION ":" DRIVER_DESC);
return 0;
}
@@ -1190,9 +1674,13 @@
static void __exit ftdi_exit (void)
{
+
dbg("%s", __FUNCTION__);
- usb_serial_deregister (&ftdi_SIO_device);
+
+ usb_serial_deregister (&ftdi_FT232BM_device);
usb_serial_deregister (&ftdi_8U232AM_device);
+ usb_serial_deregister (&ftdi_SIO_device);
+
}
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)