summaryrefslogtreecommitdiffstats
path: root/drivers/usb/usb-serial.c
diff options
context:
space:
mode:
authorRalf Baechle <ralf@linux-mips.org>2000-03-02 02:36:47 +0000
committerRalf Baechle <ralf@linux-mips.org>2000-03-02 02:36:47 +0000
commit8624512aa908741ba2795200133eae0d7f4557ea (patch)
treed5d3036fccf2604f4c98dedc11e8adb929d6b52e /drivers/usb/usb-serial.c
parent7b8f5d6f1d45d9f9de1d26e7d3c32aa5af11b488 (diff)
Merge with 2.3.48.
Diffstat (limited to 'drivers/usb/usb-serial.c')
-rw-r--r--drivers/usb/usb-serial.c590
1 files changed, 554 insertions, 36 deletions
diff --git a/drivers/usb/usb-serial.c b/drivers/usb/usb-serial.c
index f87600e83..6b9615e72 100644
--- a/drivers/usb/usb-serial.c
+++ b/drivers/usb/usb-serial.c
@@ -14,6 +14,17 @@
*
* See Documentation/usb/usb-serial.txt for more information on using this driver
*
+ * (02/21/2000) gkh
+ * Made it so that any serial devices only have to specify which functions
+ * they want to overload from the generic function calls (great,
+ * inheritance in C, in a driver, just what I wanted...)
+ * Added support for set_termios and ioctl function calls. No drivers take
+ * advantage of this yet.
+ * Removed the #ifdef MODULE, now there is no module specific code.
+ * Cleaned up a few comments in usb-serial.h that were wrong (thanks again
+ * to Miles Lott).
+ * Small fix to get_free_serial.
+ *
* (02/14/2000) gkh
* Removed the Belkin and Peracom functionality from the driver due to
* the lack of support from the vendor, and me not wanting people to
@@ -169,6 +180,19 @@
#include "usb-serial.h"
+/* parity check flag */
+#define RELEVANT_IFLAG(iflag) (iflag & (IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK))
+
+/* local function prototypes */
+static int serial_open (struct tty_struct *tty, struct file * filp);
+static void serial_close (struct tty_struct *tty, struct file * filp);
+static int serial_write (struct tty_struct * tty, int from_user, const unsigned char *buf, int count);
+static int serial_write_room (struct tty_struct *tty);
+static int serial_chars_in_buffer (struct tty_struct *tty);
+static void serial_throttle (struct tty_struct * tty);
+static void serial_unthrottle (struct tty_struct * tty);
+static int serial_ioctl (struct tty_struct *tty, struct file * file, unsigned int cmd, unsigned long arg);
+static void serial_set_termios (struct tty_struct *tty, struct termios * old);
static void * usb_serial_probe(struct usb_device *dev, unsigned int ifnum);
static void usb_serial_disconnect(struct usb_device *dev, void *ptr);
@@ -224,7 +248,7 @@ static struct usb_serial *get_free_serial (int num_ports, int *minor)
continue;
good_spot = 1;
- for (j = 0; j < num_ports-1; ++j)
+ for (j = 1; j <= num_ports-1; ++j)
if (serial_table[i+j])
good_spot = 0;
if (good_spot == 0)
@@ -328,12 +352,12 @@ static int serial_open (struct tty_struct *tty, struct file * filp)
tty->driver_data = serial;
serial->tty = tty;
- /* pass on to the driver specific version of this function */
+ /* pass on to the driver specific version of this function if it is available */
if (serial->type->open) {
return (serial->type->open(tty, filp));
+ } else {
+ return (generic_serial_open(tty, filp));
}
-
- return (0);
}
@@ -363,9 +387,11 @@ static void serial_close(struct tty_struct *tty, struct file * filp)
return;
}
- /* pass on to the driver specific version of this function */
+ /* pass on to the driver specific version of this function if it is available */
if (serial->type->close) {
serial->type->close(tty, filp);
+ } else {
+ generic_serial_close(tty, filp);
}
}
@@ -391,13 +417,12 @@ static int serial_write (struct tty_struct * tty, int from_user, const unsigned
return (-EINVAL);
}
- /* pass on to the driver specific version of this function */
+ /* pass on to the driver specific version of this function if it is available */
if (serial->type->write) {
return (serial->type->write(tty, from_user, buf, count));
+ } else {
+ return (generic_serial_write(tty, from_user, buf, count));
}
-
- /* no specific driver, so return that we didn't write anything */
- return (0);
}
@@ -422,12 +447,12 @@ static int serial_write_room (struct tty_struct *tty)
return (-EINVAL);
}
- /* pass on to the driver specific version of this function */
+ /* pass on to the driver specific version of this function if it is available */
if (serial->type->write_room) {
return (serial->type->write_room(tty));
+ } else {
+ return (generic_write_room(tty));
}
-
- return (0);
}
@@ -452,12 +477,12 @@ static int serial_chars_in_buffer (struct tty_struct *tty)
return (-EINVAL);
}
- /* pass on to the driver specific version of this function */
+ /* pass on to the driver specific version of this function if it is available */
if (serial->type->chars_in_buffer) {
return (serial->type->chars_in_buffer(tty));
+ } else {
+ return (generic_chars_in_buffer(tty));
}
-
- return (0);
}
@@ -485,6 +510,8 @@ static void serial_throttle (struct tty_struct * tty)
/* pass on to the driver specific version of this function */
if (serial->type->throttle) {
serial->type->throttle(tty);
+ } else {
+ generic_throttle(tty);
}
return;
@@ -515,12 +542,86 @@ static void serial_unthrottle (struct tty_struct * tty)
/* pass on to the driver specific version of this function */
if (serial->type->unthrottle) {
serial->type->unthrottle(tty);
+ } else {
+ generic_unthrottle(tty);
}
return;
}
+static int serial_ioctl (struct tty_struct *tty, struct file * file, unsigned int cmd, unsigned long arg)
+{
+ struct usb_serial *serial = (struct usb_serial *) tty->driver_data;
+ int port;
+
+ dbg("serial_ioctl");
+
+ if (!serial) {
+ dbg("serial == NULL!");
+ return -ENODEV;
+ }
+
+ port = MINOR(tty->device) - serial->minor;
+
+ dbg("serial_ioctl port %d", port);
+
+ /* do some sanity checking that we really have a device present */
+ if (!serial->type) {
+ dbg("serial->type == NULL!");
+ return -ENODEV;
+ }
+ if (!serial->active[port]) {
+ dbg ("device not open");
+ return -ENODEV;
+ }
+
+ /* pass on to the driver specific version of this function if it is available */
+ if (serial->type->ioctl) {
+ return (serial->type->ioctl(tty, file, cmd, arg));
+ } else {
+ return (generic_ioctl (tty, file, cmd, arg));
+ }
+}
+
+
+static void serial_set_termios (struct tty_struct *tty, struct termios * old)
+{
+ struct usb_serial *serial = (struct usb_serial *) tty->driver_data;
+ int port;
+
+ dbg("serial_set_termios");
+
+ if (!serial) {
+ dbg("serial == NULL!");
+ return;
+ }
+
+ port = MINOR(tty->device) - serial->minor;
+
+ dbg("serial_set_termios port %d", port);
+
+ /* do some sanity checking that we really have a device present */
+ if (!serial->type) {
+ dbg("serial->type == NULL!");
+ return;
+ }
+ if (!serial->active[port]) {
+ dbg ("device not open");
+ return;
+ }
+
+ /* pass on to the driver specific version of this function if it is available */
+ if (serial->type->set_termios) {
+ serial->type->set_termios(tty, old);
+ } else {
+ generic_set_termios (tty, old);
+ }
+
+ return;
+}
+
+
#ifdef CONFIG_USB_SERIAL_WHITEHEAT
/*****************************************************************************
* Connect Tech's White Heat specific driver functions
@@ -566,6 +667,29 @@ static void whiteheat_serial_close(struct tty_struct *tty, struct file * filp)
}
+static void whiteheat_set_termios (struct tty_struct *tty, struct termios *old_termios)
+{
+ struct usb_serial *serial = (struct usb_serial *) tty->driver_data;
+ int port = MINOR(tty->device) - serial->minor;
+ unsigned int cflag = tty->termios->c_cflag;
+
+ dbg("whiteheat_set_termios port %d", port);
+
+ /* 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))) {
+ dbg("nothing to change...");
+ return;
+ }
+ }
+
+ /* do the parsing of the cflag to see what to set the line to */
+ /* FIXME!! */
+
+ return;
+}
+
static void whiteheat_throttle (struct tty_struct * tty)
{
struct usb_serial *serial = (struct usb_serial *) tty->driver_data;
@@ -813,25 +937,96 @@ static int visor_startup (struct usb_serial *serial)
/******************************************************************************
* FTDI SIO Serial Converter specific driver functions
******************************************************************************/
+
+/* Bill Ryder - bryder@sgi.com - wrote the FTDI_SIO implementation */
+/* Thanx to FTDI for so kindly providing details of the protocol required */
+/* to talk to the device */
+
+#include "ftdi_sio.h"
+
static int ftdi_sio_serial_open (struct tty_struct *tty, struct file *filp)
{
struct usb_serial *serial = (struct usb_serial *) tty->driver_data;
+ char buf[1]; /* Needed for the usb_control_msg I think */
int port = MINOR(tty->device) - serial->minor;
- dbg("ftdi_serial_open port %d", port);
+ dbg("ftdi_sio_serial_open port %d", port);
if (serial->active[port]) {
dbg ("device already open");
return -EINVAL;
}
serial->active[port] = 1;
-
+
+ usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
+ FTDI_SIO_RESET_REQUEST, FTDI_SIO_RESET_REQUEST_TYPE,
+ FTDI_SIO_RESET_SIO,
+ 0, buf, 0, HZ * 5);
+
+ /* FIXME - Should I really purge the buffers? */
+ usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
+ FTDI_SIO_RESET_REQUEST, FTDI_SIO_RESET_REQUEST_TYPE,
+ FTDI_SIO_RESET_PURGE_RX,
+ 0, buf, 0, HZ * 5);
+
+ usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
+ FTDI_SIO_RESET_REQUEST, FTDI_SIO_RESET_REQUEST_TYPE,
+ FTDI_SIO_RESET_PURGE_TX,
+ 0, buf, 0, HZ * 5);
+
+
+ /* As per usb_serial_init s/be CS8, B9600, 1 STOP BIT */
+ if ( usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
+ FTDI_SIO_SET_BAUDRATE_REQUEST,
+ FTDI_SIO_SET_BAUDRATE_REQUEST_TYPE,
+ ftdi_sio_b9600, 0,
+ buf, 0, HZ * 5) < 0){
+ dbg("Error from baudrate urb");
+ return(-EINVAL);
+ }
+
+ if ( usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
+ FTDI_SIO_SET_DATA_REQUEST,
+ FTDI_SIO_SET_DATA_REQUEST_TYPE,
+ 8 | FTDI_SIO_SET_DATA_PARITY_NONE |
+ FTDI_SIO_SET_DATA_STOP_BITS_1, 0,
+ buf, 0, HZ * 5) < 0){
+ dbg("Error from cs8/noparity/1 stopbit urb");
+ return(-EINVAL);
+ }
+
+ /* Disable flow control */
+ if (usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
+ FTDI_SIO_SET_FLOW_CTRL_REQUEST,
+ FTDI_SIO_SET_FLOW_CTRL_REQUEST_TYPE,
+ 0, 0,
+ buf, 0, HZ * 5) < 0) {
+ dbg("error from flowcontrol urb");
+ return(-EINVAL);
+ }
+
+ /* Turn on RTS and DTR since we are not flow controlling*/
+ /* FIXME - check for correct behaviour clocal vs non clocal */
+ /* FIXME - might be able to do both simultaneously */
+ if (usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
+ FTDI_SIO_SET_MODEM_CTRL_REQUEST,
+ FTDI_SIO_SET_MODEM_CTRL_REQUEST_TYPE,
+ (unsigned)FTDI_SIO_SET_DTR_HIGH, 0,
+ buf, 0, HZ * 5) < 0) {
+ dbg("Error from DTR HIGH urb");
+ }
+ if (usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
+ FTDI_SIO_SET_MODEM_CTRL_REQUEST,
+ FTDI_SIO_SET_MODEM_CTRL_REQUEST_TYPE,
+ (unsigned)FTDI_SIO_SET_RTS_HIGH, 0,
+ buf, 0, HZ * 5) < 0) {
+ dbg("Error from RTS HIGH urb");
+ }
+
/*Start reading from the device*/
if (usb_submit_urb(&serial->read_urb[port]))
dbg("usb_submit_urb(read bulk) failed");
- /* Need to do device specific setup here (control lines, baud rate, etc.) */
- /* FIXME!!! */
return (0);
}
@@ -840,13 +1035,29 @@ static int ftdi_sio_serial_open (struct tty_struct *tty, struct file *filp)
static void ftdi_sio_serial_close (struct tty_struct *tty, struct file *filp)
{
struct usb_serial *serial = (struct usb_serial *) tty->driver_data;
+ char buf[1];
int port = MINOR(tty->device) - serial->minor;
- dbg("ftdi_serial_close port %d", port);
-
- /* Need to change the control lines here */
- /* FIXME */
+ dbg("ftdi_sio_serial_close port %d", port);
+ /* FIXME - might be able to do both simultaneously */
+ if (usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
+ FTDI_SIO_SET_MODEM_CTRL_REQUEST,
+ FTDI_SIO_SET_MODEM_CTRL_REQUEST_TYPE,
+ (unsigned)FTDI_SIO_SET_DTR_LOW, 0,
+ buf, 0, HZ * 5) < 0) {
+ dbg("Error from DTR LOW urb");
+ }
+ if (usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
+ FTDI_SIO_SET_MODEM_CTRL_REQUEST,
+ FTDI_SIO_SET_MODEM_CTRL_REQUEST_TYPE,
+ (unsigned)FTDI_SIO_SET_RTS_LOW, 0,
+ buf, 0, HZ * 5) < 0) {
+ dbg("Error from RTS LOW urb");
+ }
+
+ /* FIXME Should I flush the device here? - not doing it for now */
+
/* shutdown our bulk reads and writes */
usb_unlink_urb (&serial->write_urb[port]);
usb_unlink_urb (&serial->read_urb[port]);
@@ -854,6 +1065,290 @@ static void ftdi_sio_serial_close (struct tty_struct *tty, struct file *filp)
}
+
+/* The ftdi_sio requires the first byte to have:
+ B0 1
+ B1 0
+ B2..7 length of message excluding byte 0
+*/
+static int ftdi_sio_serial_write (struct tty_struct * tty, int from_user,
+ const unsigned char *buf, int count)
+{
+ struct usb_serial *serial = (struct usb_serial *) tty->driver_data;
+ int port = MINOR(tty->device) - serial->minor;
+ const int data_offset = 1;
+
+ dbg("ftdi_sio_serial_write port %d, %d bytes", port, count);
+
+ if (count == 0) {
+ dbg("write request of 0 bytes");
+ return (0);
+ }
+
+ /* only do something if we have a bulk out endpoint */
+ if (serial->num_bulk_out) {
+ unsigned char *first_byte = serial->write_urb[port].transfer_buffer;
+
+ if (serial->write_urb[port].status == -EINPROGRESS) {
+ dbg ("already writing");
+ return (0);
+ }
+
+ count += data_offset;
+ count = (count > serial->bulk_out_size[port]) ?
+ serial->bulk_out_size[port] : count;
+
+
+ /* Copy in the data to send */
+ if (from_user) {
+ copy_from_user(serial->write_urb[port].transfer_buffer + data_offset ,
+ buf, count - data_offset );
+ }
+ else {
+ memcpy(serial->write_urb[port].transfer_buffer + data_offset,
+ buf, count - data_offset );
+ }
+
+ /* Write the control byte at the front of the packet*/
+ first_byte = serial->write_urb[port].transfer_buffer;
+ *first_byte = 1 | ((count-data_offset) << 2) ;
+
+#ifdef DEBUG
+ dbg("Bytes: %d, Control Byte: 0o%03o",count, first_byte[0]);
+
+ if (count) {
+ int i;
+ printk (KERN_DEBUG __FILE__ ": data written - length = %d, data = ", count);
+ for (i = 0; i < count; ++i) {
+ printk ("0x%02x ", first_byte[i]);
+ if (first_byte[i] > ' ' && first_byte[i] < '~') {
+ printk("%c ", first_byte[i]);
+ } else {
+ printk(" ");
+ }
+ }
+
+
+ printk ("\n");
+ }
+
+#endif
+
+
+ /* send the data out the bulk port */
+ serial->write_urb[port].transfer_buffer_length = count;
+
+ if (usb_submit_urb(&serial->write_urb[port]))
+ dbg("usb_submit_urb(write bulk) failed");
+
+ dbg("write returning: %d",count - data_offset);
+ return (count - data_offset);
+ }
+
+ /* no bulk out, so return 0 bytes written */
+ return (0);
+}
+
+
+static void ftdi_sio_read_bulk_callback (struct urb *urb)
+{ /* ftdi_sio_serial_buld_callback */
+ struct usb_serial *serial = (struct usb_serial *)urb->context;
+ struct tty_struct *tty = serial->tty;
+ unsigned char *data = urb->transfer_buffer;
+ const int data_offset = 2;
+ int i;
+
+ dbg("ftdi_sio_read_bulk_callback");
+
+ if (urb->status) {
+ dbg("nonzero read bulk status received: %d", urb->status);
+ return;
+ }
+
+#ifdef DEBUG
+ if (urb->actual_length > 2) {
+ printk (KERN_DEBUG __FILE__ ": data read - length = %d, data = ", urb->actual_length);
+ for (i = 0; i < urb->actual_length; ++i) {
+ printk ("0x%.2x ", data[i]);
+ if (data[i] > ' ' && data[i] < '~') {
+ printk("%c ", data[i]);
+ } else {
+ printk(" ");
+ }
+ }
+ printk ("\n");
+ }
+#endif
+
+
+ if (urb->actual_length > data_offset) {
+ for (i = data_offset ; i < urb->actual_length ; ++i) {
+ tty_insert_flip_char(tty, data[i], 0);
+ }
+ tty_flip_buffer_push(tty);
+ }
+
+ /* Continue trying to always read */
+ if (usb_submit_urb(urb))
+ dbg("failed resubmitting read urb");
+
+ return;
+} /* ftdi_sio_serial_read_bulk_callback */
+
+static void ftdi_sio_set_termios (struct tty_struct *tty, struct termios *old_termios)
+{
+ struct usb_serial *serial = (struct usb_serial *) tty->driver_data;
+ int port = MINOR(tty->device) - serial->minor;
+ unsigned int cflag = tty->termios->c_cflag;
+ __u16 urb_value; /* Will hold the new flags */
+ char buf[1]; /* Perhaps I should dynamically alloc this? */
+ dbg("ftdi_sio_set_termios port %d", port);
+
+ /* FIXME - we should keep the old termios really */
+ /* FIXME -For this cut I don't care if the line is really changing or
+ not - so just do the change regardless */
+
+ /* Set number of data bits, parity, stop bits */
+
+ urb_value = 0;
+ urb_value |= (cflag & CSTOPB ? FTDI_SIO_SET_DATA_STOP_BITS_2 :
+ FTDI_SIO_SET_DATA_STOP_BITS_1);
+ urb_value |= (cflag & PARENB ?
+ (cflag & PARODD ? FTDI_SIO_SET_DATA_PARITY_ODD :
+ FTDI_SIO_SET_DATA_PARITY_EVEN) :
+ FTDI_SIO_SET_DATA_PARITY_NONE);
+ if (cflag & CSIZE) {
+ switch (cflag & CSIZE) {
+ case CS5: urb_value |= 5; dbg("Setting CS5"); break;
+ case CS6: urb_value |= 6; dbg("Setting CS6"); break;
+ case CS7: urb_value |= 7; dbg("Setting CS7"); break;
+ case CS8: urb_value |= 8; dbg("Setting CS8"); break;
+ default:
+ dbg("CSIZE was set but not CS5-CS8");
+ }
+ }
+ if (usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
+ FTDI_SIO_SET_DATA_REQUEST,
+ FTDI_SIO_SET_DATA_REQUEST_TYPE,
+ urb_value , 0,
+ buf, 0, 100) < 0) {
+ dbg("FAILED to set databits/stopbits/parity");
+ }
+
+ /* Now do the baudrate */
+ /* FIXME - should drop lines on B0 */
+ /* FIXME Should also handle CLOCAL here */
+
+ switch(cflag & CBAUD){
+ case B300: urb_value = ftdi_sio_b300; dbg("Set to 300"); break;
+ case B600: urb_value = ftdi_sio_b600; dbg("Set to 600") ; break;
+ case B1200: urb_value = ftdi_sio_b1200; dbg("Set to 1200") ; break;
+ case B2400: urb_value = ftdi_sio_b2400; dbg("Set to 2400") ; break;
+ case B4800: urb_value = ftdi_sio_b4800; dbg("Set to 4800") ; break;
+ case B9600: urb_value = ftdi_sio_b9600; dbg("Set to 9600") ; break;
+ case B19200: urb_value = ftdi_sio_b19200; dbg("Set to 19200") ; break;
+ case B38400: urb_value = ftdi_sio_b38400; dbg("Set to 38400") ; break;
+ case B57600: urb_value = ftdi_sio_b57600; dbg("Set to 57600") ; break;
+ case B115200: urb_value = ftdi_sio_b115200; dbg("Set to 115200") ; break;
+ default: dbg("FTDI_SIO does not support the baudrate requested");
+ /* FIXME - how to return an error for this? */ break;
+ }
+ /* Send the URB */
+ if (usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
+ FTDI_SIO_SET_BAUDRATE_REQUEST,
+ FTDI_SIO_SET_BAUDRATE_REQUEST_TYPE,
+ urb_value, 0,
+ buf, 0, 100) < 0) {
+ dbg("urb failed to set baurdrate");
+ }
+ return;
+}
+
+/*FIXME - the beginnings of this implementation - not even hooked into the driver yet */
+static int ftdi_sio_ioctl (struct tty_struct *tty, struct file * file, unsigned int cmd, unsigned long arg)
+{
+ struct usb_serial *serial = (struct usb_serial *) tty->driver_data;
+ int port = MINOR(tty->device) - serial->minor;
+ __u16 urb_value=0; /* Will hold the new flags */
+ char buf[1];
+ int ret, mask;
+ dbg("ftdi_sio_ioctl port %d", port);
+
+ /* Based on code from acm.c */
+ switch (cmd) {
+
+ case TIOCMGET:
+ /* Request the status from the device */
+ if ((ret = usb_control_msg(serial->dev,
+ usb_sndctrlpipe(serial->dev, 0),
+ FTDI_SIO_GET_MODEM_STATUS_REQUEST,
+ FTDI_SIO_GET_MODEM_STATUS_REQUEST_TYPE,
+ 0, 0,
+ buf, 1, HZ * 5)) < 0 ) {
+ dbg("Get not get modem status of device");
+ return(ret);
+ }
+
+ 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),
+ (unsigned long *) arg);
+ break;
+
+ case TIOCMSET:
+ case TIOCMBIS:
+ case TIOCMBIC:
+ if ((ret = get_user(mask, (unsigned long *) arg))) return ret;
+
+ /* FIXME Need to remember if we have set DTR or RTS since we
+ can't ask the device */
+ /* FIXME - also need to find the meaning of TIOCMBIS/BIC/SET */
+ if (mask & TIOCM_DTR) {
+ switch(cmd) {
+ case TIOCMSET:
+ urb_value = FTDI_SIO_SET_DTR_HIGH | FTDI_SIO_SET_RTS_LOW;
+ break;
+
+ case TIOCMBIS:
+ /* Will leave RTS alone and set DTR */
+ urb_value = FTDI_SIO_SET_DTR_HIGH;
+ break;
+
+ case TIOCMBIC:
+ urb_value = FTDI_SIO_SET_DTR_LOW;
+ break;
+ }
+ }
+
+ if (mask & TIOCM_RTS) {
+ switch(cmd) {
+ case TIOCMSET:
+ urb_value = FTDI_SIO_SET_DTR_LOW | FTDI_SIO_SET_RTS_HIGH;
+ break;
+
+ case TIOCMBIS:
+ /* Will leave DTR and set RTS */
+ urb_value = FTDI_SIO_SET_RTS_HIGH;
+ break;
+
+ case TIOCMBIC:
+ /* Will unset RTS */
+ urb_value = FTDI_SIO_SET_RTS_LOW;
+ break;
+ }
+ }
+
+
+ return(usb_control_msg(serial->dev,
+ usb_sndctrlpipe(serial->dev, 0),
+ FTDI_SIO_SET_MODEM_CTRL_REQUEST,
+ FTDI_SIO_SET_MODEM_CTRL_REQUEST_TYPE,
+ urb_value , 0,
+ buf, 0, HZ * 5));
+ }
+}
+
#endif /* CONFIG_USB_SERIAL_FTDI_SIO */
@@ -1041,6 +1536,34 @@ static int generic_chars_in_buffer (struct tty_struct *tty)
}
+static void generic_throttle (struct tty_struct *tty)
+{
+ /* do nothing for the generic device */
+ return;
+}
+
+
+static void generic_unthrottle (struct tty_struct *tty)
+{
+ /* do nothing for the generic device */
+ return;
+}
+
+
+static int generic_ioctl (struct tty_struct *tty, struct file * file, unsigned int cmd, unsigned long arg)
+{
+ /* generic driver doesn't support any ioctls yet */
+ return -ENOIOCTLCMD;
+}
+
+
+static void generic_set_termios (struct tty_struct *tty, struct termios * old)
+{
+ /* generic driver doesn't really care about setting any line settings */
+ return;
+}
+
+
static void generic_read_bulk_callback (struct urb *urb)
{
struct usb_serial *serial = (struct usb_serial *)urb->context;
@@ -1059,7 +1582,7 @@ static void generic_read_bulk_callback (struct urb *urb)
if (urb->actual_length) {
printk (KERN_DEBUG __FILE__ ": data read - length = %d, data = ", urb->actual_length);
for (i = 0; i < urb->actual_length; ++i) {
- printk ("0x%.2x ", data[i]);
+ printk ("%.2x ", data[i]);
}
printk ("\n");
}
@@ -1352,8 +1875,8 @@ static struct tty_driver serial_tty_driver = {
put_char: NULL,
flush_chars: NULL,
write_room: serial_write_room,
- ioctl: NULL,
- set_termios: NULL,
+ ioctl: serial_ioctl,
+ set_termios: serial_set_termios,
set_ldisc: NULL,
throttle: serial_throttle,
unthrottle: serial_unthrottle,
@@ -1397,19 +1920,14 @@ int usb_serial_init(void)
}
-#ifdef MODULE
-int init_module(void)
-{
- return usb_serial_init();
-}
-
-void cleanup_module(void)
+void usb_serial_exit(void)
{
tty_unregister_driver(&serial_tty_driver);
usb_deregister(&usb_serial_driver);
}
-#else
-__initcall(usb_serial_init);
-#endif
+
+module_init(usb_serial_init);
+module_exit(usb_serial_exit);
+