Lines Matching +full:usb +full:- +full:to +full:- +full:serial
1 // SPDX-License-Identifier: GPL-2.0+
3 * MCT (Magic Control Technology Corp.) USB RS232 Converter Driver
7 * This program is largely derived from the Belkin USB Serial Adapter Driver
11 * William G. Greathouse and Greg Kroah-Hartman provided great help on how to
12 * do the reverse engineering and how to write a USB serial device driver.
14 * TO BE DONE, TO BE CHECKED:
30 #include <linux/usb.h>
31 #include <linux/usb/serial.h>
32 #include <linux/serial.h>
36 #define DRIVER_DESC "Magic Control Technology USB-RS232 converter driver"
59 * All of the device info needed for the MCT USB-RS232 converter.
68 MODULE_DEVICE_TABLE(usb, id_table);
110 * Handle vendor specific USB requests
116 * Later day 2.6.0-test kernels have new baud rates like B230400 which
117 * we do not know how to support. We ignore them for the moment.
119 static int mct_u232_calculate_baud_rate(struct usb_serial *serial, in mct_u232_calculate_baud_rate() argument
124 if (le16_to_cpu(serial->dev->descriptor.idProduct) == MCT_U232_SITECOM_PID in mct_u232_calculate_baud_rate()
125 || le16_to_cpu(serial->dev->descriptor.idProduct) == MCT_U232_BELKIN_F5U109_PID) { in mct_u232_calculate_baud_rate()
152 /* FIXME: Can we use any divider - should we do in mct_u232_calculate_baud_rate()
175 struct usb_serial *serial, struct usb_serial_port *port, speed_t value) in mct_u232_set_baud_rate() argument
185 return -ENOMEM; in mct_u232_set_baud_rate()
187 divisor = mct_u232_calculate_baud_rate(serial, value, &speed); in mct_u232_set_baud_rate()
189 rc = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), in mct_u232_set_baud_rate()
195 dev_err(&port->dev, "Set BAUD RATE %d failed (error = %d)\n", in mct_u232_set_baud_rate()
199 dev_dbg(&port->dev, "set_baud_rate: value: 0x%x, divisor: 0x%x\n", value, divisor); in mct_u232_set_baud_rate()
201 /* Mimic the MCT-supplied Windows driver (version 1.21P.0104), which in mct_u232_set_baud_rate()
202 always sends two extra USB 'device request' messages after the in mct_u232_set_baud_rate()
209 The second message has been determined experimentally to control in mct_u232_set_baud_rate()
210 whether data will be transmitted to a device which is not asserting in mct_u232_set_baud_rate()
214 value of 1 is used by this driver), data will not be transmitted to in mct_u232_set_baud_rate()
219 rc = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), in mct_u232_set_baud_rate()
225 dev_err(&port->dev, "Sending USB device request code %d " in mct_u232_set_baud_rate()
232 dev_dbg(&port->dev, "set_baud_rate: send second control message, data = %02X\n", in mct_u232_set_baud_rate()
235 rc = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), in mct_u232_set_baud_rate()
241 dev_err(&port->dev, "Sending USB device request code %d " in mct_u232_set_baud_rate()
256 return -ENOMEM; in mct_u232_set_line_ctrl()
259 rc = usb_control_msg(port->serial->dev, usb_sndctrlpipe(port->serial->dev, 0), in mct_u232_set_line_ctrl()
265 dev_err(&port->dev, "Set LINE CTRL 0x%x failed (error = %d)\n", lcr, rc); in mct_u232_set_line_ctrl()
266 dev_dbg(&port->dev, "set_line_ctrl: 0x%x\n", lcr); in mct_u232_set_line_ctrl()
280 return -ENOMEM; in mct_u232_set_modem_ctrl()
289 rc = usb_control_msg(port->serial->dev, usb_sndctrlpipe(port->serial->dev, 0), in mct_u232_set_modem_ctrl()
296 dev_dbg(&port->dev, "set_modem_ctrl: state=0x%x ==> mcr=0x%x\n", control_state, mcr); in mct_u232_set_modem_ctrl()
299 dev_err(&port->dev, "Set MODEM CTRL 0x%x failed (error = %d)\n", mcr, rc); in mct_u232_set_modem_ctrl()
314 return -ENOMEM; in mct_u232_get_modem_stat()
316 rc = usb_control_msg(port->serial->dev, usb_rcvctrlpipe(port->serial->dev, 0), in mct_u232_get_modem_stat()
322 dev_err(&port->dev, "Get MODEM STATus failed (error = %d)\n", rc); in mct_u232_get_modem_stat()
325 rc = -EIO; in mct_u232_get_modem_stat()
331 dev_dbg(&port->dev, "get_modem_stat: 0x%x\n", *msr); in mct_u232_get_modem_stat()
341 icount->dsr++; in mct_u232_msr_to_icount()
343 icount->cts++; in mct_u232_msr_to_icount()
345 icount->rng++; in mct_u232_msr_to_icount()
347 icount->dcd++; in mct_u232_msr_to_icount()
370 dev_dbg(&port->dev, "msr_to_state: msr=0x%x ==> state=0x%x\n", msr, *control_state); in mct_u232_msr_to_state()
379 struct usb_serial *serial = port->serial; in mct_u232_port_probe() local
382 /* check first to simplify error handling */ in mct_u232_port_probe()
383 if (!serial->port[1] || !serial->port[1]->interrupt_in_urb) { in mct_u232_port_probe()
384 dev_err(&port->dev, "expected endpoint missing\n"); in mct_u232_port_probe()
385 return -ENODEV; in mct_u232_port_probe()
390 return -ENOMEM; in mct_u232_port_probe()
392 /* Use second interrupt-in endpoint for reading. */ in mct_u232_port_probe()
393 priv->read_urb = serial->port[1]->interrupt_in_urb; in mct_u232_port_probe()
394 priv->read_urb->context = port; in mct_u232_port_probe()
396 spin_lock_init(&priv->lock); in mct_u232_port_probe()
413 struct usb_serial *serial = port->serial; in mct_u232_open() local
421 /* Compensate for a hardware bug: although the Sitecom U232-P25 in mct_u232_open()
423 * it seems to be able to accept only 16 bytes (and that's what in mct_u232_open()
426 if (le16_to_cpu(serial->dev->descriptor.idProduct) in mct_u232_open()
428 port->bulk_out_size = 16; in mct_u232_open()
430 /* Do a defined restart: the normal serial device seems to in mct_u232_open()
435 spin_lock_irqsave(&priv->lock, flags); in mct_u232_open()
437 priv->control_state = TIOCM_DTR | TIOCM_RTS; in mct_u232_open()
439 priv->control_state = 0; in mct_u232_open()
441 priv->last_lcr = (MCT_U232_DATA_BITS_8 | in mct_u232_open()
444 control_state = priv->control_state; in mct_u232_open()
445 last_lcr = priv->last_lcr; in mct_u232_open()
446 spin_unlock_irqrestore(&priv->lock, flags); in mct_u232_open()
452 spin_lock_irqsave(&priv->lock, flags); in mct_u232_open()
453 priv->last_msr = last_msr; in mct_u232_open()
454 mct_u232_msr_to_state(port, &priv->control_state, priv->last_msr); in mct_u232_open()
455 spin_unlock_irqrestore(&priv->lock, flags); in mct_u232_open()
457 retval = usb_submit_urb(priv->read_urb, GFP_KERNEL); in mct_u232_open()
459 dev_err(&port->dev, in mct_u232_open()
461 port->read_urb->pipe, retval); in mct_u232_open()
465 retval = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL); in mct_u232_open()
467 usb_kill_urb(priv->read_urb); in mct_u232_open()
468 dev_err(&port->dev, in mct_u232_open()
470 port->interrupt_in_urb->pipe, retval); in mct_u232_open()
484 spin_lock_irq(&priv->lock); in mct_u232_dtr_rts()
486 priv->control_state |= TIOCM_DTR | TIOCM_RTS; in mct_u232_dtr_rts()
488 priv->control_state &= ~(TIOCM_DTR | TIOCM_RTS); in mct_u232_dtr_rts()
489 control_state = priv->control_state; in mct_u232_dtr_rts()
490 spin_unlock_irq(&priv->lock); in mct_u232_dtr_rts()
499 usb_kill_urb(priv->read_urb); in mct_u232_close()
500 usb_kill_urb(port->interrupt_in_urb); in mct_u232_close()
508 struct usb_serial_port *port = urb->context; in mct_u232_read_int_callback()
510 unsigned char *data = urb->transfer_buffer; in mct_u232_read_int_callback()
512 int status = urb->status; in mct_u232_read_int_callback()
519 case -ECONNRESET: in mct_u232_read_int_callback()
520 case -ENOENT: in mct_u232_read_int_callback()
521 case -ESHUTDOWN: in mct_u232_read_int_callback()
523 dev_dbg(&port->dev, "%s - urb shutting down with status: %d\n", in mct_u232_read_int_callback()
527 dev_dbg(&port->dev, "%s - nonzero urb status received: %d\n", in mct_u232_read_int_callback()
532 usb_serial_debug_data(&port->dev, __func__, urb->actual_length, data); in mct_u232_read_int_callback()
535 * Work-a-round: handle the 'usual' bulk-in pipe here in mct_u232_read_int_callback()
537 if (urb->transfer_buffer_length > 2) { in mct_u232_read_int_callback()
538 if (urb->actual_length) { in mct_u232_read_int_callback()
539 tty_insert_flip_string(&port->port, data, in mct_u232_read_int_callback()
540 urb->actual_length); in mct_u232_read_int_callback()
541 tty_flip_buffer_push(&port->port); in mct_u232_read_int_callback()
547 * The interrupt-in pipe signals exceptional conditions (modem line in mct_u232_read_int_callback()
550 spin_lock_irqsave(&priv->lock, flags); in mct_u232_read_int_callback()
551 priv->last_msr = data[MCT_U232_MSR_INDEX]; in mct_u232_read_int_callback()
554 mct_u232_msr_to_state(port, &priv->control_state, priv->last_msr); in mct_u232_read_int_callback()
556 mct_u232_msr_to_icount(&port->icount, priv->last_msr); in mct_u232_read_int_callback()
560 /* Now to report any errors */ in mct_u232_read_int_callback()
561 priv->last_lsr = data[MCT_U232_LSR_INDEX]; in mct_u232_read_int_callback()
564 * to the current/next receive buffer or characters. I need in mct_u232_read_int_callback()
565 * to look in to this before committing any code. in mct_u232_read_int_callback()
567 if (priv->last_lsr & MCT_U232_LSR_ERR) { in mct_u232_read_int_callback()
568 tty = tty_port_tty_get(&port->port); in mct_u232_read_int_callback()
570 if (priv->last_lsr & MCT_U232_LSR_OE) { in mct_u232_read_int_callback()
573 if (priv->last_lsr & MCT_U232_LSR_PE) { in mct_u232_read_int_callback()
576 if (priv->last_lsr & MCT_U232_LSR_FE) { in mct_u232_read_int_callback()
579 if (priv->last_lsr & MCT_U232_LSR_BI) { in mct_u232_read_int_callback()
584 wake_up_interruptible(&port->port.delta_msr_wait); in mct_u232_read_int_callback()
585 spin_unlock_irqrestore(&priv->lock, flags); in mct_u232_read_int_callback()
589 dev_err(&port->dev, in mct_u232_read_int_callback()
590 "%s - usb_submit_urb failed with result %d\n", in mct_u232_read_int_callback()
598 struct usb_serial *serial = port->serial; in mct_u232_set_termios() local
600 struct ktermios *termios = &tty->termios; in mct_u232_set_termios()
601 unsigned int cflag = termios->c_cflag; in mct_u232_set_termios()
602 unsigned int old_cflag = old_termios->c_cflag; in mct_u232_set_termios()
608 spin_lock_irqsave(&priv->lock, flags); in mct_u232_set_termios()
609 control_state = priv->control_state; in mct_u232_set_termios()
610 spin_unlock_irqrestore(&priv->lock, flags); in mct_u232_set_termios()
615 * Do not attempt to cache old rates and skip settings, in mct_u232_set_termios()
622 dev_dbg(&port->dev, "%s: baud was B0\n", __func__); in mct_u232_set_termios()
627 mct_u232_set_baud_rate(tty, serial, port, tty_get_baud_rate(tty)); in mct_u232_set_termios()
630 dev_dbg(&port->dev, "%s: baud is B0\n", __func__); in mct_u232_set_termios()
658 dev_err(&port->dev, in mct_u232_set_termios()
659 "CSIZE was not CS5-CS8, using default of 8\n"); in mct_u232_set_termios()
664 termios->c_cflag &= ~CMSPAR; in mct_u232_set_termios()
673 spin_lock_irqsave(&priv->lock, flags); in mct_u232_set_termios()
674 priv->control_state = control_state; in mct_u232_set_termios()
675 priv->last_lcr = last_lcr; in mct_u232_set_termios()
676 spin_unlock_irqrestore(&priv->lock, flags); in mct_u232_set_termios()
681 struct usb_serial_port *port = tty->driver_data; in mct_u232_break_ctl()
686 spin_lock_irqsave(&priv->lock, flags); in mct_u232_break_ctl()
687 lcr = priv->last_lcr; in mct_u232_break_ctl()
691 spin_unlock_irqrestore(&priv->lock, flags); in mct_u232_break_ctl()
699 struct usb_serial_port *port = tty->driver_data; in mct_u232_tiocmget()
704 spin_lock_irqsave(&priv->lock, flags); in mct_u232_tiocmget()
705 control_state = priv->control_state; in mct_u232_tiocmget()
706 spin_unlock_irqrestore(&priv->lock, flags); in mct_u232_tiocmget()
714 struct usb_serial_port *port = tty->driver_data; in mct_u232_tiocmset()
719 spin_lock_irqsave(&priv->lock, flags); in mct_u232_tiocmset()
720 control_state = priv->control_state; in mct_u232_tiocmset()
731 priv->control_state = control_state; in mct_u232_tiocmset()
732 spin_unlock_irqrestore(&priv->lock, flags); in mct_u232_tiocmset()
738 struct usb_serial_port *port = tty->driver_data; in mct_u232_throttle()
742 spin_lock_irq(&priv->lock); in mct_u232_throttle()
743 priv->rx_flags |= THROTTLED; in mct_u232_throttle()
745 priv->control_state &= ~TIOCM_RTS; in mct_u232_throttle()
746 control_state = priv->control_state; in mct_u232_throttle()
747 spin_unlock_irq(&priv->lock); in mct_u232_throttle()
750 spin_unlock_irq(&priv->lock); in mct_u232_throttle()
756 struct usb_serial_port *port = tty->driver_data; in mct_u232_unthrottle()
760 spin_lock_irq(&priv->lock); in mct_u232_unthrottle()
761 if ((priv->rx_flags & THROTTLED) && C_CRTSCTS(tty)) { in mct_u232_unthrottle()
762 priv->rx_flags &= ~THROTTLED; in mct_u232_unthrottle()
763 priv->control_state |= TIOCM_RTS; in mct_u232_unthrottle()
764 control_state = priv->control_state; in mct_u232_unthrottle()
765 spin_unlock_irq(&priv->lock); in mct_u232_unthrottle()
768 spin_unlock_irq(&priv->lock); in mct_u232_unthrottle()