]> err.no Git - linux-2.6/blob - drivers/usb/serial/mct_u232.c
USB: RTS/CTS handshaking support, DTR fixes for MCT U232 serial adapter
[linux-2.6] / drivers / usb / serial / mct_u232.c
1 /*
2  * MCT (Magic Control Technology Corp.) USB RS232 Converter Driver
3  *
4  *   Copyright (C) 2000 Wolfgang Grandegger (wolfgang@ces.ch)
5  *
6  *   This program is free software; you can redistribute it and/or modify
7  *   it under the terms of the GNU General Public License as published by
8  *   the Free Software Foundation; either version 2 of the License, or
9  *   (at your option) any later version.
10  *
11  * This program is largely derived from the Belkin USB Serial Adapter Driver
12  * (see belkin_sa.[ch]). All of the information about the device was acquired
13  * by using SniffUSB on Windows98. For technical details see mct_u232.h.
14  *
15  * William G. Greathouse and Greg Kroah-Hartman provided great help on how to
16  * do the reverse engineering and how to write a USB serial device driver.
17  *
18  * TO BE DONE, TO BE CHECKED:
19  *   DTR/RTS signal handling may be incomplete or incorrect. I have mainly
20  *   implemented what I have seen with SniffUSB or found in belkin_sa.c.
21  *   For further TODOs check also belkin_sa.c.
22  *
23  * TEST STATUS:
24  *   Basic tests have been performed with minicom/zmodem transfers and
25  *   modem dialing under Linux 2.4.0-test10 (for me it works fine).
26  *
27  * 04-Nov-2003 Bill Marr <marr at flex dot com>
28  *   - Mimic Windows driver by sending 2 USB 'device request' messages
29  *     following normal 'baud rate change' message.  This allows data to be
30  *     transmitted to RS-232 devices which don't assert the 'CTS' signal.
31  *
32  * 10-Nov-2001 Wolfgang Grandegger
33  *   - Fixed an endianess problem with the baudrate selection for PowerPC.
34  *
35  * 06-Dec-2001 Martin Hamilton <martinh@gnu.org>
36  *      Added support for the Belkin F5U109 DB9 adaptor
37  *
38  * 30-May-2001 Greg Kroah-Hartman
39  *      switched from using spinlock to a semaphore, which fixes lots of problems.
40  *
41  * 04-May-2001 Stelian Pop
42  *   - Set the maximum bulk output size for Sitecom U232-P25 model to 16 bytes
43  *     instead of the device reported 32 (using 32 bytes causes many data
44  *     loss, Windows driver uses 16 too).
45  *
46  * 02-May-2001 Stelian Pop
47  *   - Fixed the baud calculation for Sitecom U232-P25 model
48  *
49  * 08-Apr-2001 gb
50  *   - Identify version on module load.
51  *
52  * 06-Jan-2001 Cornel Ciocirlan 
53  *   - Added support for Sitecom U232-P25 model (Product Id 0x0230)
54  *   - Added support for D-Link DU-H3SP USB BAY (Product Id 0x0200)
55  *
56  * 29-Nov-2000 Greg Kroah-Hartman
57  *   - Added device id table to fit with 2.4.0-test11 structure.
58  *   - took out DEAL_WITH_TWO_INT_IN_ENDPOINTS #define as it's not needed
59  *     (lots of things will change if/when the usb-serial core changes to
60  *     handle these issues.
61  *
62  * 27-Nov-2000 Wolfgang Grandegger
63  *   A version for kernel 2.4.0-test10 released to the Linux community 
64  *   (via linux-usb-devel).
65  */
66
67 #include <linux/kernel.h>
68 #include <linux/errno.h>
69 #include <linux/init.h>
70 #include <linux/slab.h>
71 #include <linux/tty.h>
72 #include <linux/tty_driver.h>
73 #include <linux/tty_flip.h>
74 #include <linux/module.h>
75 #include <linux/spinlock.h>
76 #include <asm/uaccess.h>
77 #include <linux/usb.h>
78 #include <linux/usb/serial.h>
79 #include "mct_u232.h"
80
81 /*
82  * Version Information
83  */
84 #define DRIVER_VERSION "z2.1"           /* Linux in-kernel version */
85 #define DRIVER_AUTHOR "Wolfgang Grandegger <wolfgang@ces.ch>"
86 #define DRIVER_DESC "Magic Control Technology USB-RS232 converter driver"
87
88 static int debug;
89
90 /*
91  * Function prototypes
92  */
93 static int  mct_u232_startup             (struct usb_serial *serial);
94 static void mct_u232_shutdown            (struct usb_serial *serial);
95 static int  mct_u232_open                (struct usb_serial_port *port,
96                                           struct file *filp);
97 static void mct_u232_close               (struct usb_serial_port *port,
98                                           struct file *filp);
99 static void mct_u232_read_int_callback   (struct urb *urb);
100 static void mct_u232_set_termios         (struct usb_serial_port *port,
101                                           struct ktermios * old);
102 static int  mct_u232_ioctl               (struct usb_serial_port *port,
103                                           struct file * file,
104                                           unsigned int cmd,
105                                           unsigned long arg);
106 static void mct_u232_break_ctl           (struct usb_serial_port *port,
107                                           int break_state );
108 static int  mct_u232_tiocmget            (struct usb_serial_port *port,
109                                           struct file *file);
110 static int  mct_u232_tiocmset            (struct usb_serial_port *port,
111                                           struct file *file, unsigned int set,
112                                           unsigned int clear);
113 static void mct_u232_throttle            (struct usb_serial_port *port);
114 static void mct_u232_unthrottle          (struct usb_serial_port *port);
115
116
117 /*
118  * All of the device info needed for the MCT USB-RS232 converter.
119  */
120 static struct usb_device_id id_table_combined [] = {
121         { USB_DEVICE(MCT_U232_VID, MCT_U232_PID) },
122         { USB_DEVICE(MCT_U232_VID, MCT_U232_SITECOM_PID) },
123         { USB_DEVICE(MCT_U232_VID, MCT_U232_DU_H3SP_PID) },
124         { USB_DEVICE(MCT_U232_BELKIN_F5U109_VID, MCT_U232_BELKIN_F5U109_PID) },
125         { }             /* Terminating entry */
126 };
127
128 MODULE_DEVICE_TABLE (usb, id_table_combined);
129
130 static struct usb_driver mct_u232_driver = {
131         .name =         "mct_u232",
132         .probe =        usb_serial_probe,
133         .disconnect =   usb_serial_disconnect,
134         .id_table =     id_table_combined,
135         .no_dynamic_id =        1,
136 };
137
138 static struct usb_serial_driver mct_u232_device = {
139         .driver = {
140                 .owner =        THIS_MODULE,
141                 .name =         "mct_u232",
142         },
143         .description =       "MCT U232",
144         .usb_driver =        &mct_u232_driver,
145         .id_table =          id_table_combined,
146         .num_interrupt_in =  2,
147         .num_bulk_in =       0,
148         .num_bulk_out =      1,
149         .num_ports =         1,
150         .open =              mct_u232_open,
151         .close =             mct_u232_close,
152         .throttle =          mct_u232_throttle,
153         .unthrottle =        mct_u232_unthrottle,
154         .read_int_callback = mct_u232_read_int_callback,
155         .ioctl =             mct_u232_ioctl,
156         .set_termios =       mct_u232_set_termios,
157         .break_ctl =         mct_u232_break_ctl,
158         .tiocmget =          mct_u232_tiocmget,
159         .tiocmset =          mct_u232_tiocmset,
160         .attach =            mct_u232_startup,
161         .shutdown =          mct_u232_shutdown,
162 };
163
164
165 struct mct_u232_private {
166         spinlock_t lock;
167         unsigned int         control_state; /* Modem Line Setting (TIOCM) */
168         unsigned char        last_lcr;      /* Line Control Register */
169         unsigned char        last_lsr;      /* Line Status Register */
170         unsigned char        last_msr;      /* Modem Status Register */
171         unsigned int         rx_flags;      /* Throttling flags */
172 };
173
174 #define THROTTLED               0x01
175
176 /*
177  * Handle vendor specific USB requests
178  */
179
180 #define WDR_TIMEOUT 5000 /* default urb timeout */
181
182 /*
183  * Later day 2.6.0-test kernels have new baud rates like B230400 which
184  * we do not know how to support. We ignore them for the moment.
185  * XXX Rate-limit the error message, it's user triggerable.
186  */
187 static int mct_u232_calculate_baud_rate(struct usb_serial *serial, int value)
188 {
189         if (le16_to_cpu(serial->dev->descriptor.idProduct) == MCT_U232_SITECOM_PID
190           || le16_to_cpu(serial->dev->descriptor.idProduct) == MCT_U232_BELKIN_F5U109_PID) {
191                 switch (value) {
192                 case    B300: return 0x01;
193                 case    B600: return 0x02; /* this one not tested */
194                 case   B1200: return 0x03;
195                 case   B2400: return 0x04;
196                 case   B4800: return 0x06;
197                 case   B9600: return 0x08;
198                 case  B19200: return 0x09;
199                 case  B38400: return 0x0a;
200                 case  B57600: return 0x0b;
201                 case B115200: return 0x0c;
202                 default:
203                         err("MCT USB-RS232: unsupported baudrate request 0x%x,"
204                             " using default of B9600", value);
205                         return 0x08;
206                 }
207         } else {
208                 switch (value) {
209                 case    B300: value =     300; break;
210                 case    B600: value =     600; break;
211                 case   B1200: value =    1200; break;
212                 case   B2400: value =    2400; break;
213                 case   B4800: value =    4800; break;
214                 case   B9600: value =    9600; break;
215                 case  B19200: value =   19200; break;
216                 case  B38400: value =   38400; break;
217                 case  B57600: value =   57600; break;
218                 case B115200: value =  115200; break;
219                 default:
220                         err("MCT USB-RS232: unsupported baudrate request 0x%x,"
221                             " using default of B9600", value);
222                         value = 9600;
223                 }
224                 return 115200/value;
225         }
226 }
227
228 static int mct_u232_set_baud_rate(struct usb_serial *serial, struct usb_serial_port *port,
229                                   int value)
230 {
231         __le32 divisor;
232         int rc;
233         unsigned char zero_byte = 0;
234         unsigned char cts_enable_byte = 0;
235
236         divisor = cpu_to_le32(mct_u232_calculate_baud_rate(serial, value));
237
238         rc = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
239                              MCT_U232_SET_BAUD_RATE_REQUEST,
240                              MCT_U232_SET_REQUEST_TYPE,
241                              0, 0, &divisor, MCT_U232_SET_BAUD_RATE_SIZE,
242                              WDR_TIMEOUT);
243         if (rc < 0)
244                 err("Set BAUD RATE %d failed (error = %d)", value, rc);
245         dbg("set_baud_rate: value: 0x%x, divisor: 0x%x", value, divisor);
246
247         /* Mimic the MCT-supplied Windows driver (version 1.21P.0104), which
248            always sends two extra USB 'device request' messages after the
249            'baud rate change' message.  The actual functionality of the
250            request codes in these messages is not fully understood but these
251            particular codes are never seen in any operation besides a baud
252            rate change.  Both of these messages send a single byte of data.
253            In the first message, the value of this byte is always zero.
254
255            The second message has been determined experimentally to control
256            whether data will be transmitted to a device which is not asserting
257            the 'CTS' signal.  If the second message's data byte is zero, data
258            will be transmitted even if 'CTS' is not asserted (i.e. no hardware
259            flow control).  if the second message's data byte is nonzero (a value
260            of 1 is used by this driver), data will not be transmitted to a device
261            which is not asserting 'CTS'.
262         */
263
264         rc = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
265                              MCT_U232_SET_UNKNOWN1_REQUEST, 
266                              MCT_U232_SET_REQUEST_TYPE,
267                              0, 0, &zero_byte, MCT_U232_SET_UNKNOWN1_SIZE, 
268                              WDR_TIMEOUT);
269         if (rc < 0)
270                 err("Sending USB device request code %d failed (error = %d)", 
271                     MCT_U232_SET_UNKNOWN1_REQUEST, rc);
272
273         if (port && C_CRTSCTS(port->tty)) {
274            cts_enable_byte = 1;
275         }
276
277         dbg("set_baud_rate: send second control message, data = %02X", cts_enable_byte);
278         rc = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
279                              MCT_U232_SET_CTS_REQUEST,
280                              MCT_U232_SET_REQUEST_TYPE,
281                              0, 0, &cts_enable_byte, MCT_U232_SET_CTS_SIZE,
282                              WDR_TIMEOUT);
283         if (rc < 0)
284           err("Sending USB device request code %d failed (error = %d)",
285               MCT_U232_SET_CTS_REQUEST, rc);
286
287         return rc;
288 } /* mct_u232_set_baud_rate */
289
290 static int mct_u232_set_line_ctrl(struct usb_serial *serial, unsigned char lcr)
291 {
292         int rc;
293         rc = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
294                              MCT_U232_SET_LINE_CTRL_REQUEST,
295                              MCT_U232_SET_REQUEST_TYPE,
296                              0, 0, &lcr, MCT_U232_SET_LINE_CTRL_SIZE,
297                              WDR_TIMEOUT);
298         if (rc < 0)
299                 err("Set LINE CTRL 0x%x failed (error = %d)", lcr, rc);
300         dbg("set_line_ctrl: 0x%x", lcr);
301         return rc;
302 } /* mct_u232_set_line_ctrl */
303
304 static int mct_u232_set_modem_ctrl(struct usb_serial *serial,
305                                    unsigned int control_state)
306 {
307         int rc;
308         unsigned char mcr = MCT_U232_MCR_NONE;
309
310         if (control_state & TIOCM_DTR)
311                 mcr |= MCT_U232_MCR_DTR;
312         if (control_state & TIOCM_RTS)
313                 mcr |= MCT_U232_MCR_RTS;
314
315         rc = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
316                              MCT_U232_SET_MODEM_CTRL_REQUEST,
317                              MCT_U232_SET_REQUEST_TYPE,
318                              0, 0, &mcr, MCT_U232_SET_MODEM_CTRL_SIZE,
319                              WDR_TIMEOUT);
320         if (rc < 0)
321                 err("Set MODEM CTRL 0x%x failed (error = %d)", mcr, rc);
322         dbg("set_modem_ctrl: state=0x%x ==> mcr=0x%x", control_state, mcr);
323
324         return rc;
325 } /* mct_u232_set_modem_ctrl */
326
327 static int mct_u232_get_modem_stat(struct usb_serial *serial, unsigned char *msr)
328 {
329         int rc;
330         rc = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0),
331                              MCT_U232_GET_MODEM_STAT_REQUEST,
332                              MCT_U232_GET_REQUEST_TYPE,
333                              0, 0, msr, MCT_U232_GET_MODEM_STAT_SIZE,
334                              WDR_TIMEOUT);
335         if (rc < 0) {
336                 err("Get MODEM STATus failed (error = %d)", rc);
337                 *msr = 0;
338         }
339         dbg("get_modem_stat: 0x%x", *msr);
340         return rc;
341 } /* mct_u232_get_modem_stat */
342
343 static void mct_u232_msr_to_state(unsigned int *control_state, unsigned char msr)
344 {
345         /* Translate Control Line states */
346         if (msr & MCT_U232_MSR_DSR)
347                 *control_state |=  TIOCM_DSR;
348         else
349                 *control_state &= ~TIOCM_DSR;
350         if (msr & MCT_U232_MSR_CTS)
351                 *control_state |=  TIOCM_CTS;
352         else
353                 *control_state &= ~TIOCM_CTS;
354         if (msr & MCT_U232_MSR_RI)
355                 *control_state |=  TIOCM_RI;
356         else
357                 *control_state &= ~TIOCM_RI;
358         if (msr & MCT_U232_MSR_CD)
359                 *control_state |=  TIOCM_CD;
360         else
361                 *control_state &= ~TIOCM_CD;
362         dbg("msr_to_state: msr=0x%x ==> state=0x%x", msr, *control_state);
363 } /* mct_u232_msr_to_state */
364
365 /*
366  * Driver's tty interface functions
367  */
368
369 static int mct_u232_startup (struct usb_serial *serial)
370 {
371         struct mct_u232_private *priv;
372         struct usb_serial_port *port, *rport;
373
374         priv = kzalloc(sizeof(struct mct_u232_private), GFP_KERNEL);
375         if (!priv)
376                 return -ENOMEM;
377         spin_lock_init(&priv->lock);
378         usb_set_serial_port_data(serial->port[0], priv);
379
380         init_waitqueue_head(&serial->port[0]->write_wait);
381
382         /* Puh, that's dirty */
383         port = serial->port[0];
384         rport = serial->port[1];
385         /* No unlinking, it wasn't submitted yet. */
386         usb_free_urb(port->read_urb);
387         port->read_urb = rport->interrupt_in_urb;
388         rport->interrupt_in_urb = NULL;
389         port->read_urb->context = port;
390
391         return (0);
392 } /* mct_u232_startup */
393
394
395 static void mct_u232_shutdown (struct usb_serial *serial)
396 {
397         struct mct_u232_private *priv;
398         int i;
399         
400         dbg("%s", __FUNCTION__);
401
402         for (i=0; i < serial->num_ports; ++i) {
403                 /* My special items, the standard routines free my urbs */
404                 priv = usb_get_serial_port_data(serial->port[i]);
405                 if (priv) {
406                         usb_set_serial_port_data(serial->port[i], NULL);
407                         kfree(priv);
408                 }
409         }
410 } /* mct_u232_shutdown */
411
412 static int  mct_u232_open (struct usb_serial_port *port, struct file *filp)
413 {
414         struct usb_serial *serial = port->serial;
415         struct mct_u232_private *priv = usb_get_serial_port_data(port);
416         int retval = 0;
417         unsigned int control_state;
418         unsigned long flags;
419         unsigned char last_lcr;
420         unsigned char last_msr;
421
422         dbg("%s port %d", __FUNCTION__, port->number);
423
424         /* Compensate for a hardware bug: although the Sitecom U232-P25
425          * device reports a maximum output packet size of 32 bytes,
426          * it seems to be able to accept only 16 bytes (and that's what
427          * SniffUSB says too...)
428          */
429         if (le16_to_cpu(serial->dev->descriptor.idProduct) == MCT_U232_SITECOM_PID)
430                 port->bulk_out_size = 16;
431
432         /* Do a defined restart: the normal serial device seems to 
433          * always turn on DTR and RTS here, so do the same. I'm not
434          * sure if this is really necessary. But it should not harm
435          * either.
436          */
437         spin_lock_irqsave(&priv->lock, flags);
438         if (port->tty->termios->c_cflag & CBAUD)
439                 priv->control_state = TIOCM_DTR | TIOCM_RTS;
440         else
441                 priv->control_state = 0;
442         
443         priv->last_lcr = (MCT_U232_DATA_BITS_8 | 
444                           MCT_U232_PARITY_NONE |
445                           MCT_U232_STOP_BITS_1);
446         control_state = priv->control_state;
447         last_lcr = priv->last_lcr;
448         spin_unlock_irqrestore(&priv->lock, flags);
449         mct_u232_set_modem_ctrl(serial, control_state);
450         mct_u232_set_line_ctrl(serial, last_lcr);
451
452         /* Read modem status and update control state */
453         mct_u232_get_modem_stat(serial, &last_msr);
454         spin_lock_irqsave(&priv->lock, flags);
455         priv->last_msr = last_msr;
456         mct_u232_msr_to_state(&priv->control_state, priv->last_msr);
457         spin_unlock_irqrestore(&priv->lock, flags);
458
459         port->read_urb->dev = port->serial->dev;
460         retval = usb_submit_urb(port->read_urb, GFP_KERNEL);
461         if (retval) {
462                 err("usb_submit_urb(read bulk) failed pipe 0x%x err %d",
463                     port->read_urb->pipe, retval);
464                 goto error;
465         }
466
467         port->interrupt_in_urb->dev = port->serial->dev;
468         retval = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL);
469         if (retval) {
470                 usb_kill_urb(port->read_urb);
471                 err(" usb_submit_urb(read int) failed pipe 0x%x err %d",
472                     port->interrupt_in_urb->pipe, retval);
473                 goto error;
474         }
475         return 0;
476
477 error:
478         return retval;
479 } /* mct_u232_open */
480
481
482 static void mct_u232_close (struct usb_serial_port *port, struct file *filp)
483 {
484         unsigned int c_cflag;
485         unsigned long flags;
486         unsigned int control_state;
487         struct mct_u232_private *priv = usb_get_serial_port_data(port);
488         dbg("%s port %d", __FUNCTION__, port->number);
489
490         if (port->tty) {
491                 c_cflag = port->tty->termios->c_cflag;
492                 if (c_cflag & HUPCL) {
493                    /* drop DTR and RTS */
494                    spin_lock_irqsave(&priv->lock, flags);
495                    priv->control_state &= ~(TIOCM_DTR | TIOCM_RTS);
496                    control_state = priv->control_state;
497                    spin_unlock_irqrestore(&priv->lock, flags);
498                    mct_u232_set_modem_ctrl(port->serial, control_state);
499                 }
500         }
501
502
503         if (port->serial->dev) {
504                 /* shutdown our urbs */
505                 usb_kill_urb(port->write_urb);
506                 usb_kill_urb(port->read_urb);
507                 usb_kill_urb(port->interrupt_in_urb);
508         }
509 } /* mct_u232_close */
510
511
512 static void mct_u232_read_int_callback (struct urb *urb)
513 {
514         struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
515         struct mct_u232_private *priv = usb_get_serial_port_data(port);
516         struct usb_serial *serial = port->serial;
517         struct tty_struct *tty;
518         unsigned char *data = urb->transfer_buffer;
519         int status;
520         unsigned long flags;
521
522         switch (urb->status) {
523         case 0:
524                 /* success */
525                 break;
526         case -ECONNRESET:
527         case -ENOENT:
528         case -ESHUTDOWN:
529                 /* this urb is terminated, clean up */
530                 dbg("%s - urb shutting down with status: %d", __FUNCTION__, urb->status);
531                 return;
532         default:
533                 dbg("%s - nonzero urb status received: %d", __FUNCTION__, urb->status);
534                 goto exit;
535         }
536
537         if (!serial) {
538                 dbg("%s - bad serial pointer, exiting", __FUNCTION__);
539                 return;
540         }
541
542         dbg("%s - port %d", __FUNCTION__, port->number);
543         usb_serial_debug_data(debug, &port->dev, __FUNCTION__, urb->actual_length, data);
544
545         /*
546          * Work-a-round: handle the 'usual' bulk-in pipe here
547          */
548         if (urb->transfer_buffer_length > 2) {
549                 int i;
550                 tty = port->tty;
551                 if (urb->actual_length) {
552                         for (i = 0; i < urb->actual_length ; ++i) {
553                                 tty_insert_flip_char(tty, data[i], 0);
554                         }
555                         tty_flip_buffer_push(tty);
556                 }
557                 goto exit;
558         }
559         
560         /*
561          * The interrupt-in pipe signals exceptional conditions (modem line
562          * signal changes and errors). data[0] holds MSR, data[1] holds LSR.
563          */
564         spin_lock_irqsave(&priv->lock, flags);
565         priv->last_msr = data[MCT_U232_MSR_INDEX];
566         
567         /* Record Control Line states */
568         mct_u232_msr_to_state(&priv->control_state, priv->last_msr);
569
570 #if 0
571         /* Not yet handled. See belin_sa.c for further information */
572         /* Now to report any errors */
573         priv->last_lsr = data[MCT_U232_LSR_INDEX];
574         /*
575          * fill in the flip buffer here, but I do not know the relation
576          * to the current/next receive buffer or characters.  I need
577          * to look in to this before committing any code.
578          */
579         if (priv->last_lsr & MCT_U232_LSR_ERR) {
580                 tty = port->tty;
581                 /* Overrun Error */
582                 if (priv->last_lsr & MCT_U232_LSR_OE) {
583                 }
584                 /* Parity Error */
585                 if (priv->last_lsr & MCT_U232_LSR_PE) {
586                 }
587                 /* Framing Error */
588                 if (priv->last_lsr & MCT_U232_LSR_FE) {
589                 }
590                 /* Break Indicator */
591                 if (priv->last_lsr & MCT_U232_LSR_BI) {
592                 }
593         }
594 #endif
595         spin_unlock_irqrestore(&priv->lock, flags);
596 exit:
597         status = usb_submit_urb (urb, GFP_ATOMIC);
598         if (status)
599                 err ("%s - usb_submit_urb failed with result %d",
600                      __FUNCTION__, status);
601 } /* mct_u232_read_int_callback */
602
603 static void mct_u232_set_termios (struct usb_serial_port *port,
604                                   struct ktermios *old_termios)
605 {
606         struct usb_serial *serial = port->serial;
607         struct mct_u232_private *priv = usb_get_serial_port_data(port);
608         unsigned int cflag = port->tty->termios->c_cflag;
609         unsigned int old_cflag = old_termios->c_cflag;
610         unsigned long flags;
611         unsigned int control_state;
612         unsigned char last_lcr;
613
614         /* get a local copy of the current port settings */
615         spin_lock_irqsave(&priv->lock, flags);
616         control_state = priv->control_state;
617         spin_unlock_irqrestore(&priv->lock, flags);
618         last_lcr = 0;
619
620         /*
621          * Update baud rate.
622          * Do not attempt to cache old rates and skip settings,
623          * disconnects screw such tricks up completely.
624          * Premature optimization is the root of all evil.
625          */
626
627         /* reassert DTR and RTS on transition from B0 */
628         if ((old_cflag & CBAUD) == B0) {
629                 dbg("%s: baud was B0", __FUNCTION__);
630                 control_state |= TIOCM_DTR | TIOCM_RTS;
631                 mct_u232_set_modem_ctrl(serial, control_state);
632         }
633
634         mct_u232_set_baud_rate(serial, port, cflag & CBAUD);
635
636         if ((cflag & CBAUD) == B0 ) {
637                 dbg("%s: baud is B0", __FUNCTION__);
638                 /* Drop RTS and DTR */
639                 control_state &= ~(TIOCM_DTR | TIOCM_RTS);
640                 mct_u232_set_modem_ctrl(serial, control_state);
641         }
642
643         /*
644          * Update line control register (LCR)
645          */
646
647         /* set the parity */
648         if (cflag & PARENB)
649                 last_lcr |= (cflag & PARODD) ?
650                         MCT_U232_PARITY_ODD : MCT_U232_PARITY_EVEN;
651         else
652                 last_lcr |= MCT_U232_PARITY_NONE;
653
654         /* set the number of data bits */
655         switch (cflag & CSIZE) {
656         case CS5:
657                 last_lcr |= MCT_U232_DATA_BITS_5; break;
658         case CS6:
659                 last_lcr |= MCT_U232_DATA_BITS_6; break;
660         case CS7:
661                 last_lcr |= MCT_U232_DATA_BITS_7; break;
662         case CS8:
663                 last_lcr |= MCT_U232_DATA_BITS_8; break;
664         default:
665                 err("CSIZE was not CS5-CS8, using default of 8");
666                 last_lcr |= MCT_U232_DATA_BITS_8;
667                 break;
668         }
669
670         /* set the number of stop bits */
671         last_lcr |= (cflag & CSTOPB) ?
672                 MCT_U232_STOP_BITS_2 : MCT_U232_STOP_BITS_1;
673
674         mct_u232_set_line_ctrl(serial, last_lcr);
675
676         /* save off the modified port settings */
677         spin_lock_irqsave(&priv->lock, flags);
678         priv->control_state = control_state;
679         priv->last_lcr = last_lcr;
680         spin_unlock_irqrestore(&priv->lock, flags);
681 } /* mct_u232_set_termios */
682
683 static void mct_u232_break_ctl( struct usb_serial_port *port, int break_state )
684 {
685         struct usb_serial *serial = port->serial;
686         struct mct_u232_private *priv = usb_get_serial_port_data(port);
687         unsigned char lcr;
688         unsigned long flags;
689
690         dbg("%sstate=%d", __FUNCTION__, break_state);
691
692         spin_lock_irqsave(&priv->lock, flags);
693         lcr = priv->last_lcr;
694         spin_unlock_irqrestore(&priv->lock, flags);
695
696         if (break_state)
697                 lcr |= MCT_U232_SET_BREAK;
698
699         mct_u232_set_line_ctrl(serial, lcr);
700 } /* mct_u232_break_ctl */
701
702
703 static int mct_u232_tiocmget (struct usb_serial_port *port, struct file *file)
704 {
705         struct mct_u232_private *priv = usb_get_serial_port_data(port);
706         unsigned int control_state;
707         unsigned long flags;
708         
709         dbg("%s", __FUNCTION__);
710
711         spin_lock_irqsave(&priv->lock, flags);
712         control_state = priv->control_state;
713         spin_unlock_irqrestore(&priv->lock, flags);
714
715         return control_state;
716 }
717
718 static int mct_u232_tiocmset (struct usb_serial_port *port, struct file *file,
719                               unsigned int set, unsigned int clear)
720 {
721         struct usb_serial *serial = port->serial;
722         struct mct_u232_private *priv = usb_get_serial_port_data(port);
723         unsigned int control_state;
724         unsigned long flags;
725         
726         dbg("%s", __FUNCTION__);
727
728         spin_lock_irqsave(&priv->lock, flags);
729         control_state = priv->control_state;
730
731         if (set & TIOCM_RTS)
732                 control_state |= TIOCM_RTS;
733         if (set & TIOCM_DTR)
734                 control_state |= TIOCM_DTR;
735         if (clear & TIOCM_RTS)
736                 control_state &= ~TIOCM_RTS;
737         if (clear & TIOCM_DTR)
738                 control_state &= ~TIOCM_DTR;
739
740         priv->control_state = control_state;
741         spin_unlock_irqrestore(&priv->lock, flags);
742         return mct_u232_set_modem_ctrl(serial, control_state);
743 }
744
745 static int mct_u232_ioctl (struct usb_serial_port *port, struct file * file,
746                            unsigned int cmd, unsigned long arg)
747 {
748         dbg("%scmd=0x%x", __FUNCTION__, cmd);
749
750         /* Based on code from acm.c and others */
751         switch (cmd) {
752         case TIOCMIWAIT:
753                 /* wait for any of the 4 modem inputs (DCD,RI,DSR,CTS)*/
754                 /* TODO */
755                 return( 0 );
756
757         case TIOCGICOUNT:
758                 /* return count of modemline transitions */
759                 /* TODO */
760                 return 0;
761
762         default:
763                 dbg("%s: arg not supported - 0x%04x", __FUNCTION__,cmd);
764                 return(-ENOIOCTLCMD);
765                 break;
766         }
767         return 0;
768 } /* mct_u232_ioctl */
769
770 static void mct_u232_throttle (struct usb_serial_port *port)
771 {
772         struct mct_u232_private *priv = usb_get_serial_port_data(port);
773         unsigned long flags;
774         unsigned int control_state;
775         struct tty_struct *tty;
776
777         tty = port->tty;
778         dbg("%s - port %d", __FUNCTION__, port->number);
779
780         spin_lock_irqsave(&priv->lock, flags);
781         priv->rx_flags |= THROTTLED;
782         if (C_CRTSCTS(tty)) {
783           priv->control_state &= ~TIOCM_RTS;
784           control_state = priv->control_state;
785           spin_unlock_irqrestore(&priv->lock, flags);
786           (void) mct_u232_set_modem_ctrl(port->serial, control_state);
787         } else {
788           spin_unlock_irqrestore(&priv->lock, flags);
789         }
790 }
791
792
793 static void mct_u232_unthrottle (struct usb_serial_port *port)
794 {
795         struct mct_u232_private *priv = usb_get_serial_port_data(port);
796         unsigned long flags;
797         unsigned int control_state;
798         struct tty_struct *tty;
799
800         dbg("%s - port %d", __FUNCTION__, port->number);
801
802         tty = port->tty;
803         spin_lock_irqsave(&priv->lock, flags);
804         if ((priv->rx_flags & THROTTLED) && C_CRTSCTS(tty)) {
805           priv->rx_flags &= ~THROTTLED;
806           priv->control_state |= TIOCM_RTS;
807           control_state = priv->control_state;
808           spin_unlock_irqrestore(&priv->lock, flags);
809           (void) mct_u232_set_modem_ctrl(port->serial, control_state);
810         } else {
811           spin_unlock_irqrestore(&priv->lock, flags);
812         }
813 }
814
815 static int __init mct_u232_init (void)
816 {
817         int retval;
818         retval = usb_serial_register(&mct_u232_device);
819         if (retval)
820                 goto failed_usb_serial_register;
821         retval = usb_register(&mct_u232_driver);
822         if (retval)
823                 goto failed_usb_register;
824         info(DRIVER_DESC " " DRIVER_VERSION);
825         return 0;
826 failed_usb_register:
827         usb_serial_deregister(&mct_u232_device);
828 failed_usb_serial_register:
829         return retval;
830 }
831
832
833 static void __exit mct_u232_exit (void)
834 {
835         usb_deregister (&mct_u232_driver);
836         usb_serial_deregister (&mct_u232_device);
837 }
838
839
840 module_init (mct_u232_init);
841 module_exit(mct_u232_exit);
842
843 MODULE_AUTHOR( DRIVER_AUTHOR );
844 MODULE_DESCRIPTION( DRIVER_DESC );
845 MODULE_LICENSE("GPL");
846
847 module_param(debug, bool, S_IRUGO | S_IWUSR);
848 MODULE_PARM_DESC(debug, "Debug enabled or not");