diff options
Diffstat (limited to 'drivers/usb/serial/ftdi_sio.c')
-rw-r--r-- | drivers/usb/serial/ftdi_sio.c | 105 |
1 files changed, 75 insertions, 30 deletions
diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c index 5fc13e717911..bd4298bb6750 100644 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c | |||
@@ -73,6 +73,7 @@ struct ftdi_private { | |||
73 | */ | 73 | */ |
74 | int flags; /* some ASYNC_xxxx flags are supported */ | 74 | int flags; /* some ASYNC_xxxx flags are supported */ |
75 | unsigned long last_dtr_rts; /* saved modem control outputs */ | 75 | unsigned long last_dtr_rts; /* saved modem control outputs */ |
76 | struct async_icount icount; | ||
76 | wait_queue_head_t delta_msr_wait; /* Used for TIOCMIWAIT */ | 77 | wait_queue_head_t delta_msr_wait; /* Used for TIOCMIWAIT */ |
77 | char prev_status, diff_status; /* Used for TIOCMIWAIT */ | 78 | char prev_status, diff_status; /* Used for TIOCMIWAIT */ |
78 | char transmit_empty; /* If transmitter is empty or not */ | 79 | char transmit_empty; /* If transmitter is empty or not */ |
@@ -207,6 +208,8 @@ static struct usb_device_id id_table_combined [] = { | |||
207 | { USB_DEVICE(FTDI_VID, FTDI_XF_640_PID) }, | 208 | { USB_DEVICE(FTDI_VID, FTDI_XF_640_PID) }, |
208 | { USB_DEVICE(FTDI_VID, FTDI_XF_642_PID) }, | 209 | { USB_DEVICE(FTDI_VID, FTDI_XF_642_PID) }, |
209 | { USB_DEVICE(FTDI_VID, FTDI_DSS20_PID) }, | 210 | { USB_DEVICE(FTDI_VID, FTDI_DSS20_PID) }, |
211 | { USB_DEVICE(FTDI_VID, FTDI_URBAN_0_PID) }, | ||
212 | { USB_DEVICE(FTDI_VID, FTDI_URBAN_1_PID) }, | ||
210 | { USB_DEVICE(FTDI_NF_RIC_VID, FTDI_NF_RIC_PID) }, | 213 | { USB_DEVICE(FTDI_NF_RIC_VID, FTDI_NF_RIC_PID) }, |
211 | { USB_DEVICE(FTDI_VID, FTDI_VNHCPCUSB_D_PID) }, | 214 | { USB_DEVICE(FTDI_VID, FTDI_VNHCPCUSB_D_PID) }, |
212 | { USB_DEVICE(FTDI_VID, FTDI_MTXORB_0_PID) }, | 215 | { USB_DEVICE(FTDI_VID, FTDI_MTXORB_0_PID) }, |
@@ -745,6 +748,8 @@ static struct usb_device_id id_table_combined [] = { | |||
745 | .driver_info = (kernel_ulong_t)&ftdi_jtag_quirk }, | 748 | .driver_info = (kernel_ulong_t)&ftdi_jtag_quirk }, |
746 | { USB_DEVICE(FTDI_VID, LMI_LM3S_EVAL_BOARD_PID), | 749 | { USB_DEVICE(FTDI_VID, LMI_LM3S_EVAL_BOARD_PID), |
747 | .driver_info = (kernel_ulong_t)&ftdi_jtag_quirk }, | 750 | .driver_info = (kernel_ulong_t)&ftdi_jtag_quirk }, |
751 | { USB_DEVICE(FTDI_VID, LMI_LM3S_ICDI_BOARD_PID), | ||
752 | .driver_info = (kernel_ulong_t)&ftdi_jtag_quirk }, | ||
748 | { USB_DEVICE(FTDI_VID, FTDI_TURTELIZER_PID), | 753 | { USB_DEVICE(FTDI_VID, FTDI_TURTELIZER_PID), |
749 | .driver_info = (kernel_ulong_t)&ftdi_jtag_quirk }, | 754 | .driver_info = (kernel_ulong_t)&ftdi_jtag_quirk }, |
750 | { USB_DEVICE(RATOC_VENDOR_ID, RATOC_PRODUCT_ID_USB60F) }, | 755 | { USB_DEVICE(RATOC_VENDOR_ID, RATOC_PRODUCT_ID_USB60F) }, |
@@ -885,6 +890,8 @@ static void ftdi_set_termios(struct tty_struct *tty, | |||
885 | static int ftdi_tiocmget(struct tty_struct *tty); | 890 | static int ftdi_tiocmget(struct tty_struct *tty); |
886 | static int ftdi_tiocmset(struct tty_struct *tty, | 891 | static int ftdi_tiocmset(struct tty_struct *tty, |
887 | unsigned int set, unsigned int clear); | 892 | unsigned int set, unsigned int clear); |
893 | static int ftdi_get_icount(struct tty_struct *tty, | ||
894 | struct serial_icounter_struct *icount); | ||
888 | static int ftdi_ioctl(struct tty_struct *tty, | 895 | static int ftdi_ioctl(struct tty_struct *tty, |
889 | unsigned int cmd, unsigned long arg); | 896 | unsigned int cmd, unsigned long arg); |
890 | static void ftdi_break_ctl(struct tty_struct *tty, int break_state); | 897 | static void ftdi_break_ctl(struct tty_struct *tty, int break_state); |
@@ -919,6 +926,7 @@ static struct usb_serial_driver ftdi_sio_device = { | |||
919 | .prepare_write_buffer = ftdi_prepare_write_buffer, | 926 | .prepare_write_buffer = ftdi_prepare_write_buffer, |
920 | .tiocmget = ftdi_tiocmget, | 927 | .tiocmget = ftdi_tiocmget, |
921 | .tiocmset = ftdi_tiocmset, | 928 | .tiocmset = ftdi_tiocmset, |
929 | .get_icount = ftdi_get_icount, | ||
922 | .ioctl = ftdi_ioctl, | 930 | .ioctl = ftdi_ioctl, |
923 | .set_termios = ftdi_set_termios, | 931 | .set_termios = ftdi_set_termios, |
924 | .break_ctl = ftdi_break_ctl, | 932 | .break_ctl = ftdi_break_ctl, |
@@ -1486,7 +1494,7 @@ static void ftdi_set_max_packet_size(struct usb_serial_port *port) | |||
1486 | } | 1494 | } |
1487 | 1495 | ||
1488 | /* set max packet size based on descriptor */ | 1496 | /* set max packet size based on descriptor */ |
1489 | priv->max_packet_size = le16_to_cpu(ep_desc->wMaxPacketSize); | 1497 | priv->max_packet_size = usb_endpoint_maxp(ep_desc); |
1490 | 1498 | ||
1491 | dev_info(&udev->dev, "Setting MaxPacketSize %d\n", priv->max_packet_size); | 1499 | dev_info(&udev->dev, "Setting MaxPacketSize %d\n", priv->max_packet_size); |
1492 | } | 1500 | } |
@@ -1646,6 +1654,7 @@ static int ftdi_sio_port_probe(struct usb_serial_port *port) | |||
1646 | 1654 | ||
1647 | kref_init(&priv->kref); | 1655 | kref_init(&priv->kref); |
1648 | mutex_init(&priv->cfg_lock); | 1656 | mutex_init(&priv->cfg_lock); |
1657 | memset(&priv->icount, 0x00, sizeof(priv->icount)); | ||
1649 | init_waitqueue_head(&priv->delta_msr_wait); | 1658 | init_waitqueue_head(&priv->delta_msr_wait); |
1650 | 1659 | ||
1651 | priv->flags = ASYNC_LOW_LATENCY; | 1660 | priv->flags = ASYNC_LOW_LATENCY; |
@@ -1909,6 +1918,7 @@ static int ftdi_prepare_write_buffer(struct usb_serial_port *port, | |||
1909 | c = kfifo_out(&port->write_fifo, &buffer[i + 1], len); | 1918 | c = kfifo_out(&port->write_fifo, &buffer[i + 1], len); |
1910 | if (!c) | 1919 | if (!c) |
1911 | break; | 1920 | break; |
1921 | priv->icount.tx += c; | ||
1912 | buffer[i] = (c << 2) + 1; | 1922 | buffer[i] = (c << 2) + 1; |
1913 | count += c + 1; | 1923 | count += c + 1; |
1914 | } | 1924 | } |
@@ -1916,6 +1926,7 @@ static int ftdi_prepare_write_buffer(struct usb_serial_port *port, | |||
1916 | } else { | 1926 | } else { |
1917 | count = kfifo_out_locked(&port->write_fifo, dest, size, | 1927 | count = kfifo_out_locked(&port->write_fifo, dest, size, |
1918 | &port->lock); | 1928 | &port->lock); |
1929 | priv->icount.tx += count; | ||
1919 | } | 1930 | } |
1920 | 1931 | ||
1921 | return count; | 1932 | return count; |
@@ -1943,6 +1954,14 @@ static int ftdi_process_packet(struct tty_struct *tty, | |||
1943 | N.B. packet may be processed more than once, but differences | 1954 | N.B. packet may be processed more than once, but differences |
1944 | are only processed once. */ | 1955 | are only processed once. */ |
1945 | status = packet[0] & FTDI_STATUS_B0_MASK; | 1956 | status = packet[0] & FTDI_STATUS_B0_MASK; |
1957 | if (status & FTDI_RS0_CTS) | ||
1958 | priv->icount.cts++; | ||
1959 | if (status & FTDI_RS0_DSR) | ||
1960 | priv->icount.dsr++; | ||
1961 | if (status & FTDI_RS0_RI) | ||
1962 | priv->icount.rng++; | ||
1963 | if (status & FTDI_RS0_RLSD) | ||
1964 | priv->icount.dcd++; | ||
1946 | if (status != priv->prev_status) { | 1965 | if (status != priv->prev_status) { |
1947 | priv->diff_status |= status ^ priv->prev_status; | 1966 | priv->diff_status |= status ^ priv->prev_status; |
1948 | wake_up_interruptible(&priv->delta_msr_wait); | 1967 | wake_up_interruptible(&priv->delta_msr_wait); |
@@ -1955,15 +1974,20 @@ static int ftdi_process_packet(struct tty_struct *tty, | |||
1955 | * over framing errors */ | 1974 | * over framing errors */ |
1956 | if (packet[1] & FTDI_RS_BI) { | 1975 | if (packet[1] & FTDI_RS_BI) { |
1957 | flag = TTY_BREAK; | 1976 | flag = TTY_BREAK; |
1977 | priv->icount.brk++; | ||
1958 | usb_serial_handle_break(port); | 1978 | usb_serial_handle_break(port); |
1959 | } else if (packet[1] & FTDI_RS_PE) { | 1979 | } else if (packet[1] & FTDI_RS_PE) { |
1960 | flag = TTY_PARITY; | 1980 | flag = TTY_PARITY; |
1981 | priv->icount.parity++; | ||
1961 | } else if (packet[1] & FTDI_RS_FE) { | 1982 | } else if (packet[1] & FTDI_RS_FE) { |
1962 | flag = TTY_FRAME; | 1983 | flag = TTY_FRAME; |
1984 | priv->icount.frame++; | ||
1963 | } | 1985 | } |
1964 | /* Overrun is special, not associated with a char */ | 1986 | /* Overrun is special, not associated with a char */ |
1965 | if (packet[1] & FTDI_RS_OE) | 1987 | if (packet[1] & FTDI_RS_OE) { |
1988 | priv->icount.overrun++; | ||
1966 | tty_insert_flip_char(tty, 0, TTY_OVERRUN); | 1989 | tty_insert_flip_char(tty, 0, TTY_OVERRUN); |
1990 | } | ||
1967 | } | 1991 | } |
1968 | 1992 | ||
1969 | /* save if the transmitter is empty or not */ | 1993 | /* save if the transmitter is empty or not */ |
@@ -1975,6 +1999,7 @@ static int ftdi_process_packet(struct tty_struct *tty, | |||
1975 | len -= 2; | 1999 | len -= 2; |
1976 | if (!len) | 2000 | if (!len) |
1977 | return 0; /* status only */ | 2001 | return 0; /* status only */ |
2002 | priv->icount.rx += len; | ||
1978 | ch = packet + 2; | 2003 | ch = packet + 2; |
1979 | 2004 | ||
1980 | if (port->port.console && port->sysrq) { | 2005 | if (port->port.console && port->sysrq) { |
@@ -2079,13 +2104,19 @@ static void ftdi_set_termios(struct tty_struct *tty, | |||
2079 | 2104 | ||
2080 | cflag = termios->c_cflag; | 2105 | cflag = termios->c_cflag; |
2081 | 2106 | ||
2082 | /* FIXME -For this cut I don't care if the line is really changing or | 2107 | if (old_termios->c_cflag == termios->c_cflag |
2083 | not - so just do the change regardless - should be able to | 2108 | && old_termios->c_ispeed == termios->c_ispeed |
2084 | compare old_termios and tty->termios */ | 2109 | && old_termios->c_ospeed == termios->c_ospeed) |
2110 | goto no_c_cflag_changes; | ||
2111 | |||
2085 | /* NOTE These routines can get interrupted by | 2112 | /* NOTE These routines can get interrupted by |
2086 | ftdi_sio_read_bulk_callback - need to examine what this means - | 2113 | ftdi_sio_read_bulk_callback - need to examine what this means - |
2087 | don't see any problems yet */ | 2114 | don't see any problems yet */ |
2088 | 2115 | ||
2116 | if ((old_termios->c_cflag & (CSIZE|PARODD|PARENB|CMSPAR|CSTOPB)) == | ||
2117 | (termios->c_cflag & (CSIZE|PARODD|PARENB|CMSPAR|CSTOPB))) | ||
2118 | goto no_data_parity_stop_changes; | ||
2119 | |||
2089 | /* Set number of data bits, parity, stop bits */ | 2120 | /* Set number of data bits, parity, stop bits */ |
2090 | 2121 | ||
2091 | urb_value = 0; | 2122 | urb_value = 0; |
@@ -2126,6 +2157,7 @@ static void ftdi_set_termios(struct tty_struct *tty, | |||
2126 | } | 2157 | } |
2127 | 2158 | ||
2128 | /* Now do the baudrate */ | 2159 | /* Now do the baudrate */ |
2160 | no_data_parity_stop_changes: | ||
2129 | if ((cflag & CBAUD) == B0) { | 2161 | if ((cflag & CBAUD) == B0) { |
2130 | /* Disable flow control */ | 2162 | /* Disable flow control */ |
2131 | if (usb_control_msg(dev, usb_sndctrlpipe(dev, 0), | 2163 | if (usb_control_msg(dev, usb_sndctrlpipe(dev, 0), |
@@ -2153,6 +2185,7 @@ static void ftdi_set_termios(struct tty_struct *tty, | |||
2153 | 2185 | ||
2154 | /* Set flow control */ | 2186 | /* Set flow control */ |
2155 | /* Note device also supports DTR/CD (ugh) and Xon/Xoff in hardware */ | 2187 | /* Note device also supports DTR/CD (ugh) and Xon/Xoff in hardware */ |
2188 | no_c_cflag_changes: | ||
2156 | if (cflag & CRTSCTS) { | 2189 | if (cflag & CRTSCTS) { |
2157 | dbg("%s Setting to CRTSCTS flow control", __func__); | 2190 | dbg("%s Setting to CRTSCTS flow control", __func__); |
2158 | if (usb_control_msg(dev, | 2191 | if (usb_control_msg(dev, |
@@ -2277,11 +2310,34 @@ static int ftdi_tiocmset(struct tty_struct *tty, | |||
2277 | return update_mctrl(port, set, clear); | 2310 | return update_mctrl(port, set, clear); |
2278 | } | 2311 | } |
2279 | 2312 | ||
2313 | static int ftdi_get_icount(struct tty_struct *tty, | ||
2314 | struct serial_icounter_struct *icount) | ||
2315 | { | ||
2316 | struct usb_serial_port *port = tty->driver_data; | ||
2317 | struct ftdi_private *priv = usb_get_serial_port_data(port); | ||
2318 | struct async_icount *ic = &priv->icount; | ||
2319 | |||
2320 | icount->cts = ic->cts; | ||
2321 | icount->dsr = ic->dsr; | ||
2322 | icount->rng = ic->rng; | ||
2323 | icount->dcd = ic->dcd; | ||
2324 | icount->tx = ic->tx; | ||
2325 | icount->rx = ic->rx; | ||
2326 | icount->frame = ic->frame; | ||
2327 | icount->parity = ic->parity; | ||
2328 | icount->overrun = ic->overrun; | ||
2329 | icount->brk = ic->brk; | ||
2330 | icount->buf_overrun = ic->buf_overrun; | ||
2331 | return 0; | ||
2332 | } | ||
2333 | |||
2280 | static int ftdi_ioctl(struct tty_struct *tty, | 2334 | static int ftdi_ioctl(struct tty_struct *tty, |
2281 | unsigned int cmd, unsigned long arg) | 2335 | unsigned int cmd, unsigned long arg) |
2282 | { | 2336 | { |
2283 | struct usb_serial_port *port = tty->driver_data; | 2337 | struct usb_serial_port *port = tty->driver_data; |
2284 | struct ftdi_private *priv = usb_get_serial_port_data(port); | 2338 | struct ftdi_private *priv = usb_get_serial_port_data(port); |
2339 | struct async_icount cnow; | ||
2340 | struct async_icount cprev; | ||
2285 | 2341 | ||
2286 | dbg("%s cmd 0x%04x", __func__, cmd); | 2342 | dbg("%s cmd 0x%04x", __func__, cmd); |
2287 | 2343 | ||
@@ -2301,41 +2357,30 @@ static int ftdi_ioctl(struct tty_struct *tty, | |||
2301 | * - mask passed in arg for lines of interest | 2357 | * - mask passed in arg for lines of interest |
2302 | * (use |'ed TIOCM_RNG/DSR/CD/CTS for masking) | 2358 | * (use |'ed TIOCM_RNG/DSR/CD/CTS for masking) |
2303 | * Caller should use TIOCGICOUNT to see which one it was. | 2359 | * Caller should use TIOCGICOUNT to see which one it was. |
2304 | * (except that the driver doesn't support it !) | ||
2305 | * | 2360 | * |
2306 | * This code is borrowed from linux/drivers/char/serial.c | 2361 | * This code is borrowed from linux/drivers/char/serial.c |
2307 | */ | 2362 | */ |
2308 | case TIOCMIWAIT: | 2363 | case TIOCMIWAIT: |
2309 | while (priv != NULL) { | 2364 | cprev = priv->icount; |
2365 | while (1) { | ||
2310 | interruptible_sleep_on(&priv->delta_msr_wait); | 2366 | interruptible_sleep_on(&priv->delta_msr_wait); |
2311 | /* see if a signal did it */ | 2367 | /* see if a signal did it */ |
2312 | if (signal_pending(current)) | 2368 | if (signal_pending(current)) |
2313 | return -ERESTARTSYS; | 2369 | return -ERESTARTSYS; |
2314 | else { | 2370 | cnow = priv->icount; |
2315 | char diff = priv->diff_status; | 2371 | if (cnow.rng == cprev.rng && cnow.dsr == cprev.dsr && |
2316 | 2372 | cnow.dcd == cprev.dcd && cnow.cts == cprev.cts) | |
2317 | if (diff == 0) | 2373 | return -EIO; /* no change => error */ |
2318 | return -EIO; /* no change => error */ | 2374 | if (((arg & TIOCM_RNG) && (cnow.rng != cprev.rng)) || |
2319 | 2375 | ((arg & TIOCM_DSR) && (cnow.dsr != cprev.dsr)) || | |
2320 | /* Consume all events */ | 2376 | ((arg & TIOCM_CD) && (cnow.dcd != cprev.dcd)) || |
2321 | priv->diff_status = 0; | 2377 | ((arg & TIOCM_CTS) && (cnow.cts != cprev.cts))) { |
2322 | 2378 | return 0; | |
2323 | /* Return 0 if caller wanted to know about | ||
2324 | these bits */ | ||
2325 | if (((arg & TIOCM_RNG) && (diff & FTDI_RS0_RI)) || | ||
2326 | ((arg & TIOCM_DSR) && (diff & FTDI_RS0_DSR)) || | ||
2327 | ((arg & TIOCM_CD) && (diff & FTDI_RS0_RLSD)) || | ||
2328 | ((arg & TIOCM_CTS) && (diff & FTDI_RS0_CTS))) { | ||
2329 | return 0; | ||
2330 | } | ||
2331 | /* | ||
2332 | * Otherwise caller can't care less about what | ||
2333 | * happened,and so we continue to wait for more | ||
2334 | * events. | ||
2335 | */ | ||
2336 | } | 2379 | } |
2380 | cprev = cnow; | ||
2337 | } | 2381 | } |
2338 | return 0; | 2382 | /* not reached */ |
2383 | break; | ||
2339 | case TIOCSERGETLSR: | 2384 | case TIOCSERGETLSR: |
2340 | return get_lsr_info(port, (struct serial_struct __user *)arg); | 2385 | return get_lsr_info(port, (struct serial_struct __user *)arg); |
2341 | break; | 2386 | break; |