|
|
@@ -1,1763 +0,0 @@
|
|
|
-// SPDX-License-Identifier: GPL-2.0
|
|
|
-/*
|
|
|
- * Silicon Laboratories CP210x USB to RS232 serial adaptor driver
|
|
|
- *
|
|
|
- * Copyright (C) 2005 Craig Shelley (craig@microtron.org.uk)
|
|
|
- *
|
|
|
- * Support to set flow control line levels using TIOCMGET and TIOCMSET
|
|
|
- * thanks to Karl Hiramoto karl@hiramoto.org. RTSCTS hardware flow
|
|
|
- * control thanks to Munir Nassar nassarmu@real-time.com
|
|
|
- *
|
|
|
- */
|
|
|
-
|
|
|
-#include <stdint.h>
|
|
|
-#include <stdlib.h>
|
|
|
-
|
|
|
-#include <string.h>
|
|
|
-#include <limits.h>
|
|
|
-
|
|
|
-#include "usbh_cp210x.h"
|
|
|
-
|
|
|
-#define u16 uint16_t
|
|
|
-#define u32 uint32_t
|
|
|
-#define u8 uint8_t
|
|
|
-
|
|
|
-#ifndef container_of
|
|
|
-#define container_of(p, t, m) \
|
|
|
- ((t *)((char *)p - (char *)(&(((t *)0)->m))))
|
|
|
-#endif
|
|
|
-
|
|
|
-#define dev_dbg(...) do {} while (0)
|
|
|
-#define dev_err USB_LOG_ERR
|
|
|
-#define dev_warn USB_LOG_WRN
|
|
|
-
|
|
|
-#warning FIXME: le32_to_cpu
|
|
|
-#define le32_to_cpu(le32_val) (le32_val)
|
|
|
-#define le16_to_cpu(v) (v)
|
|
|
-#define cpu_to_le32(v) (v)
|
|
|
-
|
|
|
-
|
|
|
-#define USB_CTRL_SET_TIMEOUT 1
|
|
|
-#define USB_CTRL_GET_TIMEOUT 1
|
|
|
-
|
|
|
-#define TIOCSTI 0x5412
|
|
|
-#define TIOCMGET 0x5415
|
|
|
-#define TIOCMBIS 0x5416
|
|
|
-#define TIOCMBIC 0x5417
|
|
|
-#define TIOCMSET 0x5418
|
|
|
-#define TIOCM_LE 0x001
|
|
|
-#define TIOCM_DTR 0x002
|
|
|
-#define TIOCM_RTS 0x004
|
|
|
-#define TIOCM_ST 0x008
|
|
|
-#define TIOCM_SR 0x010
|
|
|
-#define TIOCM_CTS 0x020
|
|
|
-#define TIOCM_CAR 0x040
|
|
|
-#define TIOCM_RNG 0x080
|
|
|
-#define TIOCM_DSR 0x100
|
|
|
-#define TIOCM_CD TIOCM_CAR
|
|
|
-#define TIOCM_RI TIOCM_RNG
|
|
|
-#define TIOCM_OUT1 0x2000
|
|
|
-#define TIOCM_OUT2 0x4000
|
|
|
-#define TIOCM_LOOP 0x8000
|
|
|
-
|
|
|
-/* c_cc characters */
|
|
|
-#define VEOF 0
|
|
|
-#define VEOL 1
|
|
|
-#define VEOL2 2
|
|
|
-#define VERASE 3
|
|
|
-#define VWERASE 4
|
|
|
-#define VKILL 5
|
|
|
-#define VREPRINT 6
|
|
|
-#define VSWTC 7
|
|
|
-#define VINTR 8
|
|
|
-#define VQUIT 9
|
|
|
-#define VSUSP 10
|
|
|
-#define VSTART 12
|
|
|
-#define VSTOP 13
|
|
|
-#define VLNEXT 14
|
|
|
-#define VDISCARD 15
|
|
|
-#define VMIN 16
|
|
|
-#define VTIME 17
|
|
|
-
|
|
|
-/* c_iflag bits */
|
|
|
-#define IGNBRK 0000001
|
|
|
-#define BRKINT 0000002
|
|
|
-#define IGNPAR 0000004
|
|
|
-#define PARMRK 0000010
|
|
|
-#define INPCK 0000020
|
|
|
-#define ISTRIP 0000040
|
|
|
-#define INLCR 0000100
|
|
|
-#define IGNCR 0000200
|
|
|
-#define ICRNL 0000400
|
|
|
-#define IXON 0001000
|
|
|
-#define IXOFF 0002000
|
|
|
-#define IXANY 0004000
|
|
|
-#define IUCLC 0010000
|
|
|
-#define IMAXBEL 0020000
|
|
|
-#define IUTF8 0040000
|
|
|
-
|
|
|
-/* c_oflag bits */
|
|
|
-#define OPOST 0000001
|
|
|
-#define ONLCR 0000002
|
|
|
-#define OLCUC 0000004
|
|
|
-
|
|
|
-#define OCRNL 0000010
|
|
|
-#define ONOCR 0000020
|
|
|
-#define ONLRET 0000040
|
|
|
-
|
|
|
-#define OFILL 00000100
|
|
|
-#define OFDEL 00000200
|
|
|
-#define NLDLY 00001400
|
|
|
-#define NL0 00000000
|
|
|
-#define NL1 00000400
|
|
|
-#define NL2 00001000
|
|
|
-#define NL3 00001400
|
|
|
-#define TABDLY 00006000
|
|
|
-#define TAB0 00000000
|
|
|
-#define TAB1 00002000
|
|
|
-#define TAB2 00004000
|
|
|
-#define TAB3 00006000
|
|
|
-#define CRDLY 00030000
|
|
|
-#define CR0 00000000
|
|
|
-#define CR1 00010000
|
|
|
-#define CR2 00020000
|
|
|
-#define CR3 00030000
|
|
|
-#define FFDLY 00040000
|
|
|
-#define FF0 00000000
|
|
|
-#define FF1 00040000
|
|
|
-#define BSDLY 00100000
|
|
|
-#define BS0 00000000
|
|
|
-#define BS1 00100000
|
|
|
-#define VTDLY 00200000
|
|
|
-#define VT0 00000000
|
|
|
-#define VT1 00200000
|
|
|
-/*
|
|
|
- * Should be equivalent to TAB3, see description of TAB3 in
|
|
|
- * POSIX.1-2008, Ch. 11.2.3 "Output Modes"
|
|
|
- */
|
|
|
-#define XTABS TAB3
|
|
|
-
|
|
|
-/* c_cflag bit meaning */
|
|
|
-#define CBAUD 0000037
|
|
|
-#define B0 0000000 /* hang up */
|
|
|
-#define B50 0000001
|
|
|
-#define B75 0000002
|
|
|
-#define B110 0000003
|
|
|
-#define B134 0000004
|
|
|
-#define B150 0000005
|
|
|
-#define B200 0000006
|
|
|
-#define B300 0000007
|
|
|
-#define B600 0000010
|
|
|
-#define B1200 0000011
|
|
|
-#define B1800 0000012
|
|
|
-#define B2400 0000013
|
|
|
-#define B4800 0000014
|
|
|
-#define B9600 0000015
|
|
|
-#define B19200 0000016
|
|
|
-#define B38400 0000017
|
|
|
-#define EXTA B19200
|
|
|
-#define EXTB B38400
|
|
|
-#define CBAUDEX 0000000
|
|
|
-#define B57600 00020
|
|
|
-#define B115200 00021
|
|
|
-#define B230400 00022
|
|
|
-#define B460800 00023
|
|
|
-#define B500000 00024
|
|
|
-#define B576000 00025
|
|
|
-#define B921600 00026
|
|
|
-#define B1000000 00027
|
|
|
-#define B1152000 00030
|
|
|
-#define B1500000 00031
|
|
|
-#define B2000000 00032
|
|
|
-#define B2500000 00033
|
|
|
-#define B3000000 00034
|
|
|
-#define B3500000 00035
|
|
|
-#define B4000000 00036
|
|
|
-#define BOTHER 00037
|
|
|
-
|
|
|
-#define CSIZE 00001400
|
|
|
-#define CS5 00000000
|
|
|
-#define CS6 00000400
|
|
|
-#define CS7 00001000
|
|
|
-#define CS8 00001400
|
|
|
-
|
|
|
-#define CSTOPB 00002000
|
|
|
-#define CREAD 00004000
|
|
|
-#define PARENB 00010000
|
|
|
-#define PARODD 00020000
|
|
|
-#define HUPCL 00040000
|
|
|
-
|
|
|
-#define CLOCAL 00100000
|
|
|
-#define CMSPAR 010000000000 /* mark or space (stick) parity */
|
|
|
-#define CRTSCTS 020000000000 /* flow control */
|
|
|
-
|
|
|
-#define CIBAUD 07600000
|
|
|
-#define IBSHIFT 16
|
|
|
-
|
|
|
-/* c_lflag bits */
|
|
|
-#define ISIG 0x00000080
|
|
|
-#define ICANON 0x00000100
|
|
|
-#define XCASE 0x00004000
|
|
|
-#define ECHO 0x00000008
|
|
|
-#define ECHOE 0x00000002
|
|
|
-#define ECHOK 0x00000004
|
|
|
-#define ECHONL 0x00000010
|
|
|
-#define NOFLSH 0x80000000
|
|
|
-#define TOSTOP 0x00400000
|
|
|
-#define ECHOCTL 0x00000040
|
|
|
-#define ECHOPRT 0x00000020
|
|
|
-#define ECHOKE 0x00000001
|
|
|
-#define FLUSHO 0x00800000
|
|
|
-#define PENDIN 0x20000000
|
|
|
-#define IEXTEN 0x00000400
|
|
|
-#define EXTPROC 0x10000000
|
|
|
-
|
|
|
-/* Values for the ACTION argument to `tcflow'. */
|
|
|
-#define TCOOFF 0
|
|
|
-#define TCOON 1
|
|
|
-#define TCIOFF 2
|
|
|
-#define TCION 3
|
|
|
-
|
|
|
-/* Values for the QUEUE_SELECTOR argument to `tcflush'. */
|
|
|
-#define TCIFLUSH 0
|
|
|
-#define TCOFLUSH 1
|
|
|
-#define TCIOFLUSH 2
|
|
|
-
|
|
|
-/* Values for the OPTIONAL_ACTIONS argument to `tcsetattr'. */
|
|
|
-#define TCSANOW 0
|
|
|
-#define TCSADRAIN 1
|
|
|
-#define TCSAFLUSH 2
|
|
|
-
|
|
|
-/* c_cc characters */
|
|
|
-#define VEOF 0
|
|
|
-#define VEOL 1
|
|
|
-#define VEOL2 2
|
|
|
-#define VERASE 3
|
|
|
-#define VWERASE 4
|
|
|
-#define VKILL 5
|
|
|
-#define VREPRINT 6
|
|
|
-#define VSWTC 7
|
|
|
-#define VINTR 8
|
|
|
-#define VQUIT 9
|
|
|
-#define VSUSP 10
|
|
|
-#define VSTART 12
|
|
|
-#define VSTOP 13
|
|
|
-#define VLNEXT 14
|
|
|
-#define VDISCARD 15
|
|
|
-#define VMIN 16
|
|
|
-#define VTIME 17
|
|
|
-
|
|
|
-/* c_iflag bits */
|
|
|
-#define IGNBRK 0000001
|
|
|
-#define BRKINT 0000002
|
|
|
-#define IGNPAR 0000004
|
|
|
-#define PARMRK 0000010
|
|
|
-#define INPCK 0000020
|
|
|
-#define ISTRIP 0000040
|
|
|
-#define INLCR 0000100
|
|
|
-#define IGNCR 0000200
|
|
|
-#define ICRNL 0000400
|
|
|
-#define IXON 0001000
|
|
|
-#define IXOFF 0002000
|
|
|
-#define IXANY 0004000
|
|
|
-#define IUCLC 0010000
|
|
|
-#define IMAXBEL 0020000
|
|
|
-#define IUTF8 0040000
|
|
|
-
|
|
|
-/* c_oflag bits */
|
|
|
-#define OPOST 0000001
|
|
|
-#define ONLCR 0000002
|
|
|
-#define OLCUC 0000004
|
|
|
-
|
|
|
-#define OCRNL 0000010
|
|
|
-#define ONOCR 0000020
|
|
|
-#define ONLRET 0000040
|
|
|
-
|
|
|
-#define OFILL 00000100
|
|
|
-#define OFDEL 00000200
|
|
|
-#define NLDLY 00001400
|
|
|
-#define NL0 00000000
|
|
|
-#define NL1 00000400
|
|
|
-#define NL2 00001000
|
|
|
-#define NL3 00001400
|
|
|
-#define TABDLY 00006000
|
|
|
-#define TAB0 00000000
|
|
|
-#define TAB1 00002000
|
|
|
-#define TAB2 00004000
|
|
|
-#define TAB3 00006000
|
|
|
-#define CRDLY 00030000
|
|
|
-#define CR0 00000000
|
|
|
-#define CR1 00010000
|
|
|
-#define CR2 00020000
|
|
|
-#define CR3 00030000
|
|
|
-#define FFDLY 00040000
|
|
|
-#define FF0 00000000
|
|
|
-#define FF1 00040000
|
|
|
-#define BSDLY 00100000
|
|
|
-#define BS0 00000000
|
|
|
-#define BS1 00100000
|
|
|
-#define VTDLY 00200000
|
|
|
-#define VT0 00000000
|
|
|
-#define VT1 00200000
|
|
|
-/*
|
|
|
- * Should be equivalent to TAB3, see description of TAB3 in
|
|
|
- * POSIX.1-2008, Ch. 11.2.3 "Output Modes"
|
|
|
- */
|
|
|
-#define XTABS TAB3
|
|
|
-
|
|
|
-/* c_cflag bit meaning */
|
|
|
-#define CBAUD 0000037
|
|
|
-#define B0 0000000 /* hang up */
|
|
|
-#define B50 0000001
|
|
|
-#define B75 0000002
|
|
|
-#define B110 0000003
|
|
|
-#define B134 0000004
|
|
|
-#define B150 0000005
|
|
|
-#define B200 0000006
|
|
|
-#define B300 0000007
|
|
|
-#define B600 0000010
|
|
|
-#define B1200 0000011
|
|
|
-#define B1800 0000012
|
|
|
-#define B2400 0000013
|
|
|
-#define B4800 0000014
|
|
|
-#define B9600 0000015
|
|
|
-#define B19200 0000016
|
|
|
-#define B38400 0000017
|
|
|
-#define EXTA B19200
|
|
|
-#define EXTB B38400
|
|
|
-#define CBAUDEX 0000000
|
|
|
-#define B57600 00020
|
|
|
-#define B115200 00021
|
|
|
-#define B230400 00022
|
|
|
-#define B460800 00023
|
|
|
-#define B500000 00024
|
|
|
-#define B576000 00025
|
|
|
-#define B921600 00026
|
|
|
-#define B1000000 00027
|
|
|
-#define B1152000 00030
|
|
|
-#define B1500000 00031
|
|
|
-#define B2000000 00032
|
|
|
-#define B2500000 00033
|
|
|
-#define B3000000 00034
|
|
|
-#define B3500000 00035
|
|
|
-#define B4000000 00036
|
|
|
-#define BOTHER 00037
|
|
|
-
|
|
|
-#define CSIZE 00001400
|
|
|
-#define CS5 00000000
|
|
|
-#define CS6 00000400
|
|
|
-#define CS7 00001000
|
|
|
-#define CS8 00001400
|
|
|
-
|
|
|
-#define CSTOPB 00002000
|
|
|
-#define CREAD 00004000
|
|
|
-#define PARENB 00010000
|
|
|
-#define PARODD 00020000
|
|
|
-#define HUPCL 00040000
|
|
|
-
|
|
|
-#define CLOCAL 00100000
|
|
|
-#define CMSPAR 010000000000 /* mark or space (stick) parity */
|
|
|
-#define CRTSCTS 020000000000 /* flow control */
|
|
|
-
|
|
|
-#define CIBAUD 07600000
|
|
|
-#define IBSHIFT 16
|
|
|
-
|
|
|
-/* c_lflag bits */
|
|
|
-#define ISIG 0x00000080
|
|
|
-#define ICANON 0x00000100
|
|
|
-#define XCASE 0x00004000
|
|
|
-#define ECHO 0x00000008
|
|
|
-#define ECHOE 0x00000002
|
|
|
-#define ECHOK 0x00000004
|
|
|
-#define ECHONL 0x00000010
|
|
|
-#define NOFLSH 0x80000000
|
|
|
-#define TOSTOP 0x00400000
|
|
|
-#define ECHOCTL 0x00000040
|
|
|
-#define ECHOPRT 0x00000020
|
|
|
-#define ECHOKE 0x00000001
|
|
|
-#define FLUSHO 0x00800000
|
|
|
-#define PENDIN 0x20000000
|
|
|
-#define IEXTEN 0x00000400
|
|
|
-#define EXTPROC 0x10000000
|
|
|
-
|
|
|
-/* Values for the ACTION argument to `tcflow'. */
|
|
|
-#define TCOOFF 0
|
|
|
-#define TCOON 1
|
|
|
-#define TCIOFF 2
|
|
|
-#define TCION 3
|
|
|
-
|
|
|
-/* Values for the QUEUE_SELECTOR argument to `tcflush'. */
|
|
|
-#define TCIFLUSH 0
|
|
|
-#define TCOFLUSH 1
|
|
|
-#define TCIOFLUSH 2
|
|
|
-
|
|
|
-/* Values for the OPTIONAL_ACTIONS argument to `tcsetattr'. */
|
|
|
-#define TCSANOW 0
|
|
|
-#define TCSADRAIN 1
|
|
|
-#define TCSAFLUSH 2
|
|
|
-
|
|
|
-/* c_cc characters */
|
|
|
-#define VEOF 0
|
|
|
-#define VEOL 1
|
|
|
-#define VEOL2 2
|
|
|
-#define VERASE 3
|
|
|
-#define VWERASE 4
|
|
|
-#define VKILL 5
|
|
|
-#define VREPRINT 6
|
|
|
-#define VSWTC 7
|
|
|
-#define VINTR 8
|
|
|
-#define VQUIT 9
|
|
|
-#define VSUSP 10
|
|
|
-#define VSTART 12
|
|
|
-#define VSTOP 13
|
|
|
-#define VLNEXT 14
|
|
|
-#define VDISCARD 15
|
|
|
-#define VMIN 16
|
|
|
-#define VTIME 17
|
|
|
-
|
|
|
-/* c_iflag bits */
|
|
|
-#define IGNBRK 0000001
|
|
|
-#define BRKINT 0000002
|
|
|
-#define IGNPAR 0000004
|
|
|
-#define PARMRK 0000010
|
|
|
-#define INPCK 0000020
|
|
|
-#define ISTRIP 0000040
|
|
|
-#define INLCR 0000100
|
|
|
-#define IGNCR 0000200
|
|
|
-#define ICRNL 0000400
|
|
|
-#define IXON 0001000
|
|
|
-#define IXOFF 0002000
|
|
|
-#define IXANY 0004000
|
|
|
-#define IUCLC 0010000
|
|
|
-#define IMAXBEL 0020000
|
|
|
-#define IUTF8 0040000
|
|
|
-
|
|
|
-/* c_oflag bits */
|
|
|
-#define OPOST 0000001
|
|
|
-#define ONLCR 0000002
|
|
|
-#define OLCUC 0000004
|
|
|
-
|
|
|
-#define OCRNL 0000010
|
|
|
-#define ONOCR 0000020
|
|
|
-#define ONLRET 0000040
|
|
|
-
|
|
|
-#define OFILL 00000100
|
|
|
-#define OFDEL 00000200
|
|
|
-#define NLDLY 00001400
|
|
|
-#define NL0 00000000
|
|
|
-#define NL1 00000400
|
|
|
-#define NL2 00001000
|
|
|
-#define NL3 00001400
|
|
|
-#define TABDLY 00006000
|
|
|
-#define TAB0 00000000
|
|
|
-#define TAB1 00002000
|
|
|
-#define TAB2 00004000
|
|
|
-#define TAB3 00006000
|
|
|
-#define CRDLY 00030000
|
|
|
-#define CR0 00000000
|
|
|
-#define CR1 00010000
|
|
|
-#define CR2 00020000
|
|
|
-#define CR3 00030000
|
|
|
-#define FFDLY 00040000
|
|
|
-#define FF0 00000000
|
|
|
-#define FF1 00040000
|
|
|
-#define BSDLY 00100000
|
|
|
-#define BS0 00000000
|
|
|
-#define BS1 00100000
|
|
|
-#define VTDLY 00200000
|
|
|
-#define VT0 00000000
|
|
|
-#define VT1 00200000
|
|
|
-/*
|
|
|
- * Should be equivalent to TAB3, see description of TAB3 in
|
|
|
- * POSIX.1-2008, Ch. 11.2.3 "Output Modes"
|
|
|
- */
|
|
|
-#define XTABS TAB3
|
|
|
-
|
|
|
-/* c_cflag bit meaning */
|
|
|
-#define CBAUD 0000037
|
|
|
-#define B0 0000000 /* hang up */
|
|
|
-#define B50 0000001
|
|
|
-#define B75 0000002
|
|
|
-#define B110 0000003
|
|
|
-#define B134 0000004
|
|
|
-#define B150 0000005
|
|
|
-#define B200 0000006
|
|
|
-#define B300 0000007
|
|
|
-#define B600 0000010
|
|
|
-#define B1200 0000011
|
|
|
-#define B1800 0000012
|
|
|
-#define B2400 0000013
|
|
|
-#define B4800 0000014
|
|
|
-#define B9600 0000015
|
|
|
-#define B19200 0000016
|
|
|
-#define B38400 0000017
|
|
|
-#define EXTA B19200
|
|
|
-#define EXTB B38400
|
|
|
-#define CBAUDEX 0000000
|
|
|
-#define B57600 00020
|
|
|
-#define B115200 00021
|
|
|
-#define B230400 00022
|
|
|
-#define B460800 00023
|
|
|
-#define B500000 00024
|
|
|
-#define B576000 00025
|
|
|
-#define B921600 00026
|
|
|
-#define B1000000 00027
|
|
|
-#define B1152000 00030
|
|
|
-#define B1500000 00031
|
|
|
-#define B2000000 00032
|
|
|
-#define B2500000 00033
|
|
|
-#define B3000000 00034
|
|
|
-#define B3500000 00035
|
|
|
-#define B4000000 00036
|
|
|
-#define BOTHER 00037
|
|
|
-
|
|
|
-#define CSIZE 00001400
|
|
|
-#define CS5 00000000
|
|
|
-#define CS6 00000400
|
|
|
-#define CS7 00001000
|
|
|
-#define CS8 00001400
|
|
|
-
|
|
|
-#define CSTOPB 00002000
|
|
|
-#define CREAD 00004000
|
|
|
-#define PARENB 00010000
|
|
|
-#define PARODD 00020000
|
|
|
-#define HUPCL 00040000
|
|
|
-
|
|
|
-#define CLOCAL 00100000
|
|
|
-#define CMSPAR 010000000000 /* mark or space (stick) parity */
|
|
|
-#define CRTSCTS 020000000000 /* flow control */
|
|
|
-
|
|
|
-#define CIBAUD 07600000
|
|
|
-#define IBSHIFT 16
|
|
|
-
|
|
|
-/* c_lflag bits */
|
|
|
-#define ISIG 0x00000080
|
|
|
-#define ICANON 0x00000100
|
|
|
-#define XCASE 0x00004000
|
|
|
-#define ECHO 0x00000008
|
|
|
-#define ECHOE 0x00000002
|
|
|
-#define ECHOK 0x00000004
|
|
|
-#define ECHONL 0x00000010
|
|
|
-#define NOFLSH 0x80000000
|
|
|
-#define TOSTOP 0x00400000
|
|
|
-#define ECHOCTL 0x00000040
|
|
|
-#define ECHOPRT 0x00000020
|
|
|
-#define ECHOKE 0x00000001
|
|
|
-#define FLUSHO 0x00800000
|
|
|
-#define PENDIN 0x20000000
|
|
|
-#define IEXTEN 0x00000400
|
|
|
-#define EXTPROC 0x10000000
|
|
|
-
|
|
|
-/* Values for the ACTION argument to `tcflow'. */
|
|
|
-#define TCOOFF 0
|
|
|
-#define TCOON 1
|
|
|
-#define TCIOFF 2
|
|
|
-#define TCION 3
|
|
|
-
|
|
|
-/* Values for the QUEUE_SELECTOR argument to `tcflush'. */
|
|
|
-#define TCIFLUSH 0
|
|
|
-#define TCOFLUSH 1
|
|
|
-#define TCIOFLUSH 2
|
|
|
-
|
|
|
-/* Values for the OPTIONAL_ACTIONS argument to `tcsetattr'. */
|
|
|
-#define TCSANOW 0
|
|
|
-#define TCSADRAIN 1
|
|
|
-#define TCSAFLUSH 2
|
|
|
-
|
|
|
-#define __packed
|
|
|
-
|
|
|
-#undef ARRAY_SIZE
|
|
|
-#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
|
|
|
-
|
|
|
-#define min(a, b) ((a) < (b) ? (a) : (b))
|
|
|
-#define max(a, b) ((a) > (b) ? (a) : (b))
|
|
|
-
|
|
|
-#define clamp(val, lo, hi) min(max(val, lo), hi)
|
|
|
-
|
|
|
-#define BITS_PER_LONG 32
|
|
|
-
|
|
|
-#define GENMASK(h, l) \
|
|
|
- (((~0UL) - (1UL << (l)) + 1) & (~0UL >> (BITS_PER_LONG - 1 - (h))))
|
|
|
-
|
|
|
-#define DIV_ROUND_CLOSEST(x, d) (((x) + ((d) / 2)) / (d))
|
|
|
-
|
|
|
-#define true 1
|
|
|
-#define false 0
|
|
|
-
|
|
|
-static uint16_t swab16(uint16_t v)
|
|
|
-{
|
|
|
- return ((v & 0xff) << 8) | ((v & 0xff00) >> 8);
|
|
|
-}
|
|
|
-
|
|
|
-int usb_rcvctrlpipe(struct usb_serial_port *port, int useless)
|
|
|
-{
|
|
|
- return port->ctrlpipe_rx;
|
|
|
-}
|
|
|
-int usb_sndctrlpipe(struct usb_serial_port *port, int useless)
|
|
|
-{
|
|
|
- return port->ctrlpipe_tx;
|
|
|
-}
|
|
|
-
|
|
|
-void cp210x_get_termios(struct tty_struct *tty);
|
|
|
-void cp210x_change_speed(struct tty_struct *tty);
|
|
|
-
|
|
|
-void cp210x_get_termios(struct tty_struct *tty);
|
|
|
-void cp210x_get_termios_port(struct usb_serial_port *port, tcflag_t *cflagp, unsigned int *baudp);
|
|
|
-
|
|
|
-int usb_control_msg(struct usb_serial_port *port, int pipe, int req, u8 type, u16 val, u8 interface_num, void *dmabuf, int bufsize, int flags);
|
|
|
-
|
|
|
-/* Config request types */
|
|
|
-#define REQTYPE_HOST_TO_INTERFACE 0x41
|
|
|
-#define REQTYPE_INTERFACE_TO_HOST 0xc1
|
|
|
-#define REQTYPE_HOST_TO_DEVICE 0x40
|
|
|
-#define REQTYPE_DEVICE_TO_HOST 0xc0
|
|
|
-
|
|
|
-/* Config request codes */
|
|
|
-#define CP210X_IFC_ENABLE 0x00
|
|
|
-#define CP210X_SET_BAUDDIV 0x01
|
|
|
-#define CP210X_GET_BAUDDIV 0x02
|
|
|
-#define CP210X_SET_LINE_CTL 0x03
|
|
|
-#define CP210X_GET_LINE_CTL 0x04
|
|
|
-#define CP210X_SET_BREAK 0x05
|
|
|
-#define CP210X_IMM_CHAR 0x06
|
|
|
-#define CP210X_SET_MHS 0x07
|
|
|
-#define CP210X_GET_MDMSTS 0x08
|
|
|
-#define CP210X_SET_XON 0x09
|
|
|
-#define CP210X_SET_XOFF 0x0A
|
|
|
-#define CP210X_SET_EVENTMASK 0x0B
|
|
|
-#define CP210X_GET_EVENTMASK 0x0C
|
|
|
-#define CP210X_SET_CHAR 0x0D
|
|
|
-#define CP210X_GET_CHARS 0x0E
|
|
|
-#define CP210X_GET_PROPS 0x0F
|
|
|
-#define CP210X_GET_COMM_STATUS 0x10
|
|
|
-#define CP210X_RESET 0x11
|
|
|
-#define CP210X_PURGE 0x12
|
|
|
-#define CP210X_SET_FLOW 0x13
|
|
|
-#define CP210X_GET_FLOW 0x14
|
|
|
-#define CP210X_EMBED_EVENTS 0x15
|
|
|
-#define CP210X_GET_EVENTSTATE 0x16
|
|
|
-#define CP210X_SET_CHARS 0x19
|
|
|
-#define CP210X_GET_BAUDRATE 0x1D
|
|
|
-#define CP210X_SET_BAUDRATE 0x1E
|
|
|
-#define CP210X_VENDOR_SPECIFIC 0xFF
|
|
|
-
|
|
|
-/* CP210X_IFC_ENABLE */
|
|
|
-#define UART_ENABLE 0x0001
|
|
|
-#define UART_DISABLE 0x0000
|
|
|
-
|
|
|
-/* CP210X_(SET|GET)_BAUDDIV */
|
|
|
-#define BAUD_RATE_GEN_FREQ 0x384000
|
|
|
-
|
|
|
-/* CP210X_(SET|GET)_LINE_CTL */
|
|
|
-#define BITS_DATA_MASK 0X0f00
|
|
|
-#define BITS_DATA_5 0X0500
|
|
|
-#define BITS_DATA_6 0X0600
|
|
|
-#define BITS_DATA_7 0X0700
|
|
|
-#define BITS_DATA_8 0X0800
|
|
|
-#define BITS_DATA_9 0X0900
|
|
|
-
|
|
|
-#define BITS_PARITY_MASK 0x00f0
|
|
|
-#define BITS_PARITY_NONE 0x0000
|
|
|
-#define BITS_PARITY_ODD 0x0010
|
|
|
-#define BITS_PARITY_EVEN 0x0020
|
|
|
-#define BITS_PARITY_MARK 0x0030
|
|
|
-#define BITS_PARITY_SPACE 0x0040
|
|
|
-
|
|
|
-#define BITS_STOP_MASK 0x000f
|
|
|
-#define BITS_STOP_1 0x0000
|
|
|
-#define BITS_STOP_1_5 0x0001
|
|
|
-#define BITS_STOP_2 0x0002
|
|
|
-
|
|
|
-/* CP210X_SET_BREAK */
|
|
|
-#define BREAK_ON 0x0001
|
|
|
-#define BREAK_OFF 0x0000
|
|
|
-
|
|
|
-/* CP210X_(SET_MHS|GET_MDMSTS) */
|
|
|
-#define CONTROL_DTR 0x0001
|
|
|
-#define CONTROL_RTS 0x0002
|
|
|
-#define CONTROL_CTS 0x0010
|
|
|
-#define CONTROL_DSR 0x0020
|
|
|
-#define CONTROL_RING 0x0040
|
|
|
-#define CONTROL_DCD 0x0080
|
|
|
-#define CONTROL_WRITE_DTR 0x0100
|
|
|
-#define CONTROL_WRITE_RTS 0x0200
|
|
|
-
|
|
|
-/* CP210X_VENDOR_SPECIFIC values */
|
|
|
-#define CP210X_READ_2NCONFIG 0x000E
|
|
|
-#define CP210X_READ_LATCH 0x00C2
|
|
|
-#define CP210X_GET_PARTNUM 0x370B
|
|
|
-#define CP210X_GET_PORTCONFIG 0x370C
|
|
|
-#define CP210X_GET_DEVICEMODE 0x3711
|
|
|
-#define CP210X_WRITE_LATCH 0x37E1
|
|
|
-
|
|
|
-/* Part number definitions */
|
|
|
-#define CP210X_PARTNUM_CP2101 0x01
|
|
|
-#define CP210X_PARTNUM_CP2102 0x02
|
|
|
-#define CP210X_PARTNUM_CP2103 0x03
|
|
|
-#define CP210X_PARTNUM_CP2104 0x04
|
|
|
-#define CP210X_PARTNUM_CP2105 0x05
|
|
|
-#define CP210X_PARTNUM_CP2108 0x08
|
|
|
-#define CP210X_PARTNUM_CP2102N_QFN28 0x20
|
|
|
-#define CP210X_PARTNUM_CP2102N_QFN24 0x21
|
|
|
-#define CP210X_PARTNUM_CP2102N_QFN20 0x22
|
|
|
-#define CP210X_PARTNUM_UNKNOWN 0xFF
|
|
|
-
|
|
|
-#define __le32 int32_t
|
|
|
-/* CP210X_GET_COMM_STATUS returns these 0x13 bytes */
|
|
|
-struct cp210x_comm_status {
|
|
|
- __le32 ulErrors;
|
|
|
- __le32 ulHoldReasons;
|
|
|
- __le32 ulAmountInInQueue;
|
|
|
- __le32 ulAmountInOutQueue;
|
|
|
- u8 bEofReceived;
|
|
|
- u8 bWaitForImmediate;
|
|
|
- u8 bReserved;
|
|
|
-} __packed;
|
|
|
-
|
|
|
-/*
|
|
|
- * CP210X_PURGE - 16 bits passed in wValue of USB request.
|
|
|
- * SiLabs app note AN571 gives a strange description of the 4 bits:
|
|
|
- * bit 0 or bit 2 clears the transmit queue and 1 or 3 receive.
|
|
|
- * writing 1 to all, however, purges cp2108 well enough to avoid the hang.
|
|
|
- */
|
|
|
-#define PURGE_ALL 0x000f
|
|
|
-
|
|
|
-/* CP210X_GET_FLOW/CP210X_SET_FLOW read/write these 0x10 bytes */
|
|
|
-struct cp210x_flow_ctl {
|
|
|
- __le32 ulControlHandshake;
|
|
|
- __le32 ulFlowReplace;
|
|
|
- __le32 ulXonLimit;
|
|
|
- __le32 ulXoffLimit;
|
|
|
-} __packed;
|
|
|
-
|
|
|
-#undef BIT
|
|
|
-#undef BIT_ULL
|
|
|
-#undef BIT_MASK
|
|
|
-#undef BIT_WORD
|
|
|
-#undef BIT_ULL_MASK
|
|
|
-#undef BITS_PER_BYTE
|
|
|
-#define BIT(nr) (1UL << (nr))
|
|
|
-#define BIT_ULL(nr) (1ULL << (nr))
|
|
|
-#define BIT_MASK(nr) (1UL << ((nr) % BITS_PER_LONG))
|
|
|
-#define BIT_WORD(nr) ((nr) / BITS_PER_LONG)
|
|
|
-#define BIT_ULL_MASK(nr) (1ULL << ((nr) % BITS_PER_LONG_LONG))
|
|
|
-#define BIT_ULL_WORD(nr) ((nr) / BITS_PER_LONG_LONG)
|
|
|
-#define BITS_PER_BYTE 8
|
|
|
-
|
|
|
-/* cp210x_flow_ctl::ulControlHandshake */
|
|
|
-#define CP210X_SERIAL_DTR_MASK GENMASK(1, 0)
|
|
|
-#define CP210X_SERIAL_DTR_SHIFT(_mode) (_mode)
|
|
|
-#define CP210X_SERIAL_CTS_HANDSHAKE BIT(3)
|
|
|
-#define CP210X_SERIAL_DSR_HANDSHAKE BIT(4)
|
|
|
-#define CP210X_SERIAL_DCD_HANDSHAKE BIT(5)
|
|
|
-#define CP210X_SERIAL_DSR_SENSITIVITY BIT(6)
|
|
|
-
|
|
|
-/* values for cp210x_flow_ctl::ulControlHandshake::CP210X_SERIAL_DTR_MASK */
|
|
|
-#define CP210X_SERIAL_DTR_INACTIVE 0
|
|
|
-#define CP210X_SERIAL_DTR_ACTIVE 1
|
|
|
-#define CP210X_SERIAL_DTR_FLOW_CTL 2
|
|
|
-
|
|
|
-/* cp210x_flow_ctl::ulFlowReplace */
|
|
|
-#define CP210X_SERIAL_AUTO_TRANSMIT BIT(0)
|
|
|
-#define CP210X_SERIAL_AUTO_RECEIVE BIT(1)
|
|
|
-#define CP210X_SERIAL_ERROR_CHAR BIT(2)
|
|
|
-#define CP210X_SERIAL_NULL_STRIPPING BIT(3)
|
|
|
-#define CP210X_SERIAL_BREAK_CHAR BIT(4)
|
|
|
-#define CP210X_SERIAL_RTS_MASK GENMASK(7, 6)
|
|
|
-#define CP210X_SERIAL_RTS_SHIFT(_mode) (_mode << 6)
|
|
|
-#define CP210X_SERIAL_XOFF_CONTINUE BIT(31)
|
|
|
-
|
|
|
-/* values for cp210x_flow_ctl::ulFlowReplace::CP210X_SERIAL_RTS_MASK */
|
|
|
-#define CP210X_SERIAL_RTS_INACTIVE 0
|
|
|
-#define CP210X_SERIAL_RTS_ACTIVE 1
|
|
|
-#define CP210X_SERIAL_RTS_FLOW_CTL 2
|
|
|
-
|
|
|
-/* CP210X_VENDOR_SPECIFIC, CP210X_GET_DEVICEMODE call reads these 0x2 bytes. */
|
|
|
-struct cp210x_pin_mode {
|
|
|
- u8 eci;
|
|
|
- u8 sci;
|
|
|
-} __packed;
|
|
|
-
|
|
|
-#define CP210X_PIN_MODE_MODEM 0
|
|
|
-#define CP210X_PIN_MODE_GPIO BIT(0)
|
|
|
-
|
|
|
-/*
|
|
|
- * CP210X_VENDOR_SPECIFIC, CP210X_GET_PORTCONFIG call reads these 0xf bytes.
|
|
|
- * Structure needs padding due to unused/unspecified bytes.
|
|
|
- */
|
|
|
-#define __le16 int16_t
|
|
|
-
|
|
|
-struct cp210x_config {
|
|
|
- __le16 gpio_mode;
|
|
|
- u8 __pad0[2];
|
|
|
- __le16 reset_state;
|
|
|
- u8 __pad1[4];
|
|
|
- __le16 suspend_state;
|
|
|
- u8 sci_cfg;
|
|
|
- u8 eci_cfg;
|
|
|
- u8 device_cfg;
|
|
|
-} __packed;
|
|
|
-
|
|
|
-/* GPIO modes */
|
|
|
-#define CP210X_SCI_GPIO_MODE_OFFSET 9
|
|
|
-#define CP210X_SCI_GPIO_MODE_MASK GENMASK(11, 9)
|
|
|
-
|
|
|
-#define CP210X_ECI_GPIO_MODE_OFFSET 2
|
|
|
-#define CP210X_ECI_GPIO_MODE_MASK GENMASK(3, 2)
|
|
|
-
|
|
|
-/* CP2105 port configuration values */
|
|
|
-#define CP2105_GPIO0_TXLED_MODE BIT(0)
|
|
|
-#define CP2105_GPIO1_RXLED_MODE BIT(1)
|
|
|
-#define CP2105_GPIO1_RS485_MODE BIT(2)
|
|
|
-
|
|
|
-/* CP2102N configuration array indices */
|
|
|
-#define CP210X_2NCONFIG_CONFIG_VERSION_IDX 2
|
|
|
-#define CP210X_2NCONFIG_GPIO_MODE_IDX 581
|
|
|
-#define CP210X_2NCONFIG_GPIO_RSTLATCH_IDX 587
|
|
|
-#define CP210X_2NCONFIG_GPIO_CONTROL_IDX 600
|
|
|
-
|
|
|
-/* CP210X_VENDOR_SPECIFIC, CP210X_WRITE_LATCH call writes these 0x2 bytes. */
|
|
|
-struct cp210x_gpio_write {
|
|
|
- u8 mask;
|
|
|
- u8 state;
|
|
|
-} __packed;
|
|
|
-
|
|
|
-/*
|
|
|
- * Helper to get interface number when we only have struct usb_serial.
|
|
|
- */
|
|
|
-static u8 cp210x_interface_num(struct usb_serial_port *port)
|
|
|
-{
|
|
|
- return port->bInterfaceNumber;
|
|
|
-}
|
|
|
-
|
|
|
-/*
|
|
|
- * Reads a variable-sized block of CP210X_ registers, identified by req.
|
|
|
- * Returns data into buf in native USB byte order.
|
|
|
- */
|
|
|
-static int cp210x_read_reg_block(struct usb_serial_port *port, u8 req,
|
|
|
- void *buf, int bufsize)
|
|
|
-{
|
|
|
- int result;
|
|
|
-
|
|
|
- result = usb_control_msg(port, usb_rcvctrlpipe(port, 0),
|
|
|
- req, REQTYPE_INTERFACE_TO_HOST, 0,
|
|
|
- port->bInterfaceNumber, buf, bufsize,
|
|
|
- USB_CTRL_SET_TIMEOUT);
|
|
|
- if (result == bufsize) {
|
|
|
- result = 0;
|
|
|
- } else {
|
|
|
- dev_err("failed get req 0x%x size %d status: %d\n",
|
|
|
- (uint8_t)req, bufsize, result);
|
|
|
- if (result >= 0)
|
|
|
- result = -EIO;
|
|
|
-
|
|
|
- /*
|
|
|
- * FIXME Some callers don't bother to check for error,
|
|
|
- * at least give them consistent junk until they are fixed
|
|
|
- */
|
|
|
- memset(buf, 0, bufsize);
|
|
|
- }
|
|
|
-
|
|
|
- return result;
|
|
|
-}
|
|
|
-
|
|
|
-/*
|
|
|
- * Reads any 32-bit CP210X_ register identified by req.
|
|
|
- */
|
|
|
-static int cp210x_read_u32_reg(struct usb_serial_port *port, u8 req, u32 *val)
|
|
|
-{
|
|
|
- __le32 le32_val;
|
|
|
- int err;
|
|
|
-
|
|
|
- err = cp210x_read_reg_block(port, req, &le32_val, sizeof(le32_val));
|
|
|
- if (err) {
|
|
|
- /*
|
|
|
- * FIXME Some callers don't bother to check for error,
|
|
|
- * at least give them consistent junk until they are fixed
|
|
|
- */
|
|
|
- *val = 0;
|
|
|
- return err;
|
|
|
- }
|
|
|
-
|
|
|
- *val = le32_to_cpu(le32_val);
|
|
|
-
|
|
|
- return 0;
|
|
|
-}
|
|
|
-
|
|
|
-/*
|
|
|
- * Reads any 16-bit CP210X_ register identified by req.
|
|
|
- */
|
|
|
-static int cp210x_read_u16_reg(struct usb_serial_port *port, u8 req, u16 *val)
|
|
|
-{
|
|
|
- __le16 le16_val;
|
|
|
- int err;
|
|
|
-
|
|
|
- err = cp210x_read_reg_block(port, req, &le16_val, sizeof(le16_val));
|
|
|
- if (err)
|
|
|
- return err;
|
|
|
-
|
|
|
- *val = le16_to_cpu(le16_val);
|
|
|
-
|
|
|
- return 0;
|
|
|
-}
|
|
|
-
|
|
|
-/*
|
|
|
- * Reads any 8-bit CP210X_ register identified by req.
|
|
|
- */
|
|
|
-static int cp210x_read_u8_reg(struct usb_serial_port *port, u8 req, u8 *val)
|
|
|
-{
|
|
|
- return cp210x_read_reg_block(port, req, val, sizeof(*val));
|
|
|
-}
|
|
|
-
|
|
|
-/*
|
|
|
- * Reads a variable-sized vendor block of CP210X_ registers, identified by val.
|
|
|
- * Returns data into buf in native USB byte order.
|
|
|
- */
|
|
|
-static int cp210x_read_vendor_block(struct usb_serial_port *port, u8 type, u16 val,
|
|
|
- void *buf, int bufsize)
|
|
|
-{
|
|
|
- int result;
|
|
|
-
|
|
|
- result = usb_control_msg(port, usb_rcvctrlpipe(port, 0),
|
|
|
- CP210X_VENDOR_SPECIFIC, type, val,
|
|
|
- cp210x_interface_num(port), buf, bufsize,
|
|
|
- USB_CTRL_GET_TIMEOUT);
|
|
|
- if (result == bufsize) {
|
|
|
- return 0;
|
|
|
- } else {
|
|
|
- if (result >= 0)
|
|
|
- return -1;
|
|
|
- }
|
|
|
-
|
|
|
- return -2;
|
|
|
-}
|
|
|
-
|
|
|
-/*
|
|
|
- * Writes any 16-bit CP210X_ register (req) whose value is passed
|
|
|
- * entirely in the wValue field of the USB request.
|
|
|
- */
|
|
|
-static int cp210x_write_u16_reg(struct usb_serial_port *port, u8 req, u16 val)
|
|
|
-{
|
|
|
- int result;
|
|
|
-
|
|
|
- result = usb_control_msg(port, usb_sndctrlpipe(port, 0),
|
|
|
- req, REQTYPE_HOST_TO_INTERFACE, val,
|
|
|
- port->bInterfaceNumber, NULL, 0,
|
|
|
- USB_CTRL_SET_TIMEOUT);
|
|
|
- if (result < 0) {
|
|
|
- USB_LOG_ERR("failed set request 0x%x status: %d\n",
|
|
|
- req, result);
|
|
|
- }
|
|
|
-
|
|
|
- return result;
|
|
|
-}
|
|
|
-
|
|
|
-/*
|
|
|
- * Writes a variable-sized block of CP210X_ registers, identified by req.
|
|
|
- * Data in buf must be in native USB byte order.
|
|
|
- */
|
|
|
-static int cp210x_write_reg_block(struct usb_serial_port *port, u8 req,
|
|
|
- void *buf, int bufsize)
|
|
|
-{
|
|
|
- int result;
|
|
|
-
|
|
|
- result = usb_control_msg(port, usb_sndctrlpipe(port, 0),
|
|
|
- req, REQTYPE_HOST_TO_INTERFACE, 0,
|
|
|
- port->bInterfaceNumber, buf, bufsize,
|
|
|
- USB_CTRL_SET_TIMEOUT);
|
|
|
-
|
|
|
- if (result == bufsize) {
|
|
|
- result = 0;
|
|
|
- } else {
|
|
|
- USB_LOG_ERR("failed set req 0x%x size %d status: %d\n",
|
|
|
- req, bufsize, result);
|
|
|
- if (result >= 0)
|
|
|
- result = -EIO;
|
|
|
- }
|
|
|
-
|
|
|
- return result;
|
|
|
-}
|
|
|
-
|
|
|
-/*
|
|
|
- * Writes any 32-bit CP210X_ register identified by req.
|
|
|
- */
|
|
|
-static int cp210x_write_u32_reg(struct usb_serial_port *port, u8 req, u32 val)
|
|
|
-{
|
|
|
- __le32 le32_val;
|
|
|
-
|
|
|
- le32_val = cpu_to_le32(val);
|
|
|
-
|
|
|
- return cp210x_write_reg_block(port, req, &le32_val, sizeof(le32_val));
|
|
|
-}
|
|
|
-
|
|
|
-/*
|
|
|
- * Detect CP2108 GET_LINE_CTL bug and activate workaround.
|
|
|
- * Write a known good value 0x800, read it back.
|
|
|
- * If it comes back swapped the bug is detected.
|
|
|
- * Preserve the original register value.
|
|
|
- */
|
|
|
-static int cp210x_detect_swapped_line_ctl(struct usb_serial_port *port)
|
|
|
-{
|
|
|
- u16 line_ctl_save;
|
|
|
- u16 line_ctl_test;
|
|
|
- int err;
|
|
|
-
|
|
|
- err = cp210x_read_u16_reg(port, CP210X_GET_LINE_CTL, &line_ctl_save);
|
|
|
- if (err) {
|
|
|
- USB_LOG_ERR("Error, read reg GET_LINE_CTL\n");
|
|
|
- return err;
|
|
|
- }
|
|
|
-
|
|
|
- err = cp210x_write_u16_reg(port, CP210X_SET_LINE_CTL, 0x800);
|
|
|
- if (err) {
|
|
|
- USB_LOG_ERR("Error, write reg SET_LINE_CTL\n");
|
|
|
- return err;
|
|
|
- }
|
|
|
-
|
|
|
- err = cp210x_read_u16_reg(port, CP210X_GET_LINE_CTL, &line_ctl_test);
|
|
|
- if (err) {
|
|
|
- USB_LOG_ERR("Error, read reg GET_LINE_CTL\n");
|
|
|
- return err;
|
|
|
- }
|
|
|
-
|
|
|
- if (line_ctl_test == 8) {
|
|
|
- port->has_swapped_line_ctl = true;
|
|
|
- line_ctl_save = swab16(line_ctl_save);
|
|
|
- }
|
|
|
-
|
|
|
- return cp210x_write_u16_reg(port, CP210X_SET_LINE_CTL, line_ctl_save);
|
|
|
-}
|
|
|
-
|
|
|
-/*
|
|
|
- * Must always be called instead of cp210x_read_u16_reg(CP210X_GET_LINE_CTL)
|
|
|
- * to workaround cp2108 bug and get correct value.
|
|
|
- */
|
|
|
-static int cp210x_get_line_ctl(struct usb_serial_port *port, u16 *ctl)
|
|
|
-{
|
|
|
- int err;
|
|
|
-
|
|
|
- err = cp210x_read_u16_reg(port, CP210X_GET_LINE_CTL, ctl);
|
|
|
- if (err)
|
|
|
- return err;
|
|
|
-
|
|
|
- /* Workaround swapped bytes in 16-bit value from CP210X_GET_LINE_CTL */
|
|
|
- if (port->has_swapped_line_ctl)
|
|
|
- *ctl = swab16(*ctl);
|
|
|
-
|
|
|
- return 0;
|
|
|
-}
|
|
|
-
|
|
|
-int cp210x_open(struct tty_struct *tty)
|
|
|
-{
|
|
|
- int result;
|
|
|
- struct usb_serial_port *port = &tty->driver_data;
|
|
|
-
|
|
|
- result = cp210x_write_u16_reg(port, CP210X_IFC_ENABLE, UART_ENABLE);
|
|
|
- if (result) {
|
|
|
- USB_LOG_ERR("%s - Unable to enable UART\n", __func__);
|
|
|
- return result;
|
|
|
- }
|
|
|
-
|
|
|
- /* Configure the termios structure */
|
|
|
- cp210x_get_termios(tty);
|
|
|
-
|
|
|
- /* The baud rate must be initialised on cp2104 */
|
|
|
- if (tty)
|
|
|
- cp210x_change_speed(tty);
|
|
|
-
|
|
|
- return 0;
|
|
|
-}
|
|
|
-
|
|
|
-void cp210x_close(struct usb_serial_port *port)
|
|
|
-{
|
|
|
- /* Clear both queues; cp2108 needs this to avoid an occasional hang */
|
|
|
- cp210x_write_u16_reg(port, CP210X_PURGE, PURGE_ALL);
|
|
|
-
|
|
|
- cp210x_write_u16_reg(port, CP210X_IFC_ENABLE, UART_DISABLE);
|
|
|
-}
|
|
|
-
|
|
|
-/*
|
|
|
- * Read how many bytes are waiting in the TX queue.
|
|
|
- */
|
|
|
-static int cp210x_get_tx_queue_byte_count(struct usb_serial_port *port,
|
|
|
- u32 *count)
|
|
|
-{
|
|
|
- struct cp210x_comm_status sts;
|
|
|
- int result;
|
|
|
-
|
|
|
- result = usb_control_msg(port, usb_rcvctrlpipe(port, 0),
|
|
|
- CP210X_GET_COMM_STATUS, REQTYPE_INTERFACE_TO_HOST,
|
|
|
- 0, port->bInterfaceNumber, &sts, sizeof(sts),
|
|
|
- USB_CTRL_GET_TIMEOUT);
|
|
|
- if (result == sizeof(sts)) {
|
|
|
- *count = le32_to_cpu(sts.ulAmountInOutQueue);
|
|
|
- result = 0;
|
|
|
- } else {
|
|
|
- dev_err("failed to get comm status: %d\n", result);
|
|
|
- if (result >= 0)
|
|
|
- result = -EIO;
|
|
|
- }
|
|
|
-
|
|
|
- return result;
|
|
|
-}
|
|
|
-
|
|
|
-bool cp210x_tx_empty(struct usb_serial_port *port)
|
|
|
-{
|
|
|
- int err;
|
|
|
- u32 count;
|
|
|
-
|
|
|
- err = cp210x_get_tx_queue_byte_count(port, &count);
|
|
|
- if (err)
|
|
|
- return true;
|
|
|
-
|
|
|
- return !count;
|
|
|
-}
|
|
|
-
|
|
|
-/*
|
|
|
- * cp210x_get_termios
|
|
|
- * Reads the baud rate, data bits, parity, stop bits and flow control mode
|
|
|
- * from the device, corrects any unsupported values, and configures the
|
|
|
- * termios structure to reflect the state of the device
|
|
|
- */
|
|
|
-void cp210x_get_termios(struct tty_struct *tty)
|
|
|
-{
|
|
|
- unsigned int baud;
|
|
|
- struct usb_serial_port *port = &tty->driver_data;
|
|
|
-
|
|
|
- if (tty) {
|
|
|
- cp210x_get_termios_port(&tty->driver_data,
|
|
|
- &tty->termios.c_cflag, &baud);
|
|
|
- } else {
|
|
|
- tcflag_t cflag;
|
|
|
- cflag = 0;
|
|
|
- cp210x_get_termios_port(port, &cflag, &baud);
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-/*
|
|
|
- * cp210x_get_termios_port
|
|
|
- * This is the heart of cp210x_get_termios which always uses a &usb_serial_port.
|
|
|
- */
|
|
|
-void cp210x_get_termios_port(struct usb_serial_port *port, tcflag_t *cflagp, unsigned int *baudp)
|
|
|
-{
|
|
|
- tcflag_t cflag;
|
|
|
- struct cp210x_flow_ctl flow_ctl;
|
|
|
- u32 baud;
|
|
|
- u16 bits;
|
|
|
- u32 ctl_hs;
|
|
|
-
|
|
|
- cp210x_read_u32_reg(port, CP210X_GET_BAUDRATE, &baud);
|
|
|
-
|
|
|
- dev_dbg("%s - baud rate = %d\n", __func__, baud);
|
|
|
- *baudp = baud;
|
|
|
-
|
|
|
- cflag = *cflagp;
|
|
|
-
|
|
|
- cp210x_get_line_ctl(port, &bits);
|
|
|
- cflag &= ~CSIZE;
|
|
|
- switch (bits & BITS_DATA_MASK) {
|
|
|
- case BITS_DATA_5:
|
|
|
- dev_dbg("%s - data bits = 5\n", __func__);
|
|
|
- cflag |= CS5;
|
|
|
- break;
|
|
|
- case BITS_DATA_6:
|
|
|
- dev_dbg("%s - data bits = 6\n", __func__);
|
|
|
- cflag |= CS6;
|
|
|
- break;
|
|
|
- case BITS_DATA_7:
|
|
|
- dev_dbg("%s - data bits = 7\n", __func__);
|
|
|
- cflag |= CS7;
|
|
|
- break;
|
|
|
- case BITS_DATA_8:
|
|
|
- dev_dbg("%s - data bits = 8\n", __func__);
|
|
|
- cflag |= CS8;
|
|
|
- break;
|
|
|
- case BITS_DATA_9:
|
|
|
- dev_dbg("%s - data bits = 9 (not supported, using 8 data bits)\n", __func__);
|
|
|
- cflag |= CS8;
|
|
|
- bits &= ~BITS_DATA_MASK;
|
|
|
- bits |= BITS_DATA_8;
|
|
|
- cp210x_write_u16_reg(port, CP210X_SET_LINE_CTL, bits);
|
|
|
- break;
|
|
|
- default:
|
|
|
- dev_dbg("%s - Unknown number of data bits, using 8\n", __func__);
|
|
|
- cflag |= CS8;
|
|
|
- bits &= ~BITS_DATA_MASK;
|
|
|
- bits |= BITS_DATA_8;
|
|
|
- cp210x_write_u16_reg(port, CP210X_SET_LINE_CTL, bits);
|
|
|
- break;
|
|
|
- }
|
|
|
-
|
|
|
- switch (bits & BITS_PARITY_MASK) {
|
|
|
- case BITS_PARITY_NONE:
|
|
|
- dev_dbg("%s - parity = NONE\n", __func__);
|
|
|
- cflag &= ~PARENB;
|
|
|
- break;
|
|
|
- case BITS_PARITY_ODD:
|
|
|
- dev_dbg("%s - parity = ODD\n", __func__);
|
|
|
- cflag |= (PARENB | PARODD);
|
|
|
- break;
|
|
|
- case BITS_PARITY_EVEN:
|
|
|
- dev_dbg("%s - parity = EVEN\n", __func__);
|
|
|
- cflag &= ~PARODD;
|
|
|
- cflag |= PARENB;
|
|
|
- break;
|
|
|
- case BITS_PARITY_MARK:
|
|
|
- dev_dbg("%s - parity = MARK\n", __func__);
|
|
|
- cflag |= (PARENB | PARODD | CMSPAR);
|
|
|
- break;
|
|
|
- case BITS_PARITY_SPACE:
|
|
|
- dev_dbg("%s - parity = SPACE\n", __func__);
|
|
|
- cflag &= ~PARODD;
|
|
|
- cflag |= (PARENB | CMSPAR);
|
|
|
- break;
|
|
|
- default:
|
|
|
- dev_dbg("%s - Unknown parity mode, disabling parity\n", __func__);
|
|
|
- cflag &= ~PARENB;
|
|
|
- bits &= ~BITS_PARITY_MASK;
|
|
|
- cp210x_write_u16_reg(port, CP210X_SET_LINE_CTL, bits);
|
|
|
- break;
|
|
|
- }
|
|
|
-
|
|
|
- cflag &= ~CSTOPB;
|
|
|
- switch (bits & BITS_STOP_MASK) {
|
|
|
- case BITS_STOP_1:
|
|
|
- dev_dbg("%s - stop bits = 1\n", __func__);
|
|
|
- break;
|
|
|
- case BITS_STOP_1_5:
|
|
|
- dev_dbg("%s - stop bits = 1.5 (not supported, using 1 stop bit)\n", __func__);
|
|
|
- bits &= ~BITS_STOP_MASK;
|
|
|
- cp210x_write_u16_reg(port, CP210X_SET_LINE_CTL, bits);
|
|
|
- break;
|
|
|
- case BITS_STOP_2:
|
|
|
- dev_dbg("%s - stop bits = 2\n", __func__);
|
|
|
- cflag |= CSTOPB;
|
|
|
- break;
|
|
|
- default:
|
|
|
- dev_dbg("%s - Unknown number of stop bits, using 1 stop bit\n", __func__);
|
|
|
- bits &= ~BITS_STOP_MASK;
|
|
|
- cp210x_write_u16_reg(port, CP210X_SET_LINE_CTL, bits);
|
|
|
- break;
|
|
|
- }
|
|
|
-
|
|
|
- cp210x_read_reg_block(port, CP210X_GET_FLOW, &flow_ctl,
|
|
|
- sizeof(flow_ctl));
|
|
|
- ctl_hs = le32_to_cpu(flow_ctl.ulControlHandshake);
|
|
|
- if (ctl_hs & CP210X_SERIAL_CTS_HANDSHAKE) {
|
|
|
- dev_dbg("%s - flow control = CRTSCTS\n", __func__);
|
|
|
- cflag |= CRTSCTS;
|
|
|
- } else {
|
|
|
- dev_dbg("%s - flow control = NONE\n", __func__);
|
|
|
- cflag &= ~CRTSCTS;
|
|
|
- }
|
|
|
-
|
|
|
- *cflagp = cflag;
|
|
|
-}
|
|
|
-
|
|
|
-struct cp210x_rate {
|
|
|
- speed_t rate;
|
|
|
- speed_t high;
|
|
|
-};
|
|
|
-
|
|
|
-static const struct cp210x_rate cp210x_an205_table1[] = {
|
|
|
- { 300, 300 },
|
|
|
- { 600, 600 },
|
|
|
- { 1200, 1200 },
|
|
|
- { 1800, 1800 },
|
|
|
- { 2400, 2400 },
|
|
|
- { 4000, 4000 },
|
|
|
- { 4800, 4803 },
|
|
|
- { 7200, 7207 },
|
|
|
- { 9600, 9612 },
|
|
|
- { 14400, 14428 },
|
|
|
- { 16000, 16062 },
|
|
|
- { 19200, 19250 },
|
|
|
- { 28800, 28912 },
|
|
|
- { 38400, 38601 },
|
|
|
- { 51200, 51558 },
|
|
|
- { 56000, 56280 },
|
|
|
- { 57600, 58053 },
|
|
|
- { 64000, 64111 },
|
|
|
- { 76800, 77608 },
|
|
|
- { 115200, 117028 },
|
|
|
- { 128000, 129347 },
|
|
|
- { 153600, 156868 },
|
|
|
- { 230400, 237832 },
|
|
|
- { 250000, 254234 },
|
|
|
- { 256000, 273066 },
|
|
|
- { 460800, 491520 },
|
|
|
- { 500000, 567138 },
|
|
|
- { 576000, 670254 },
|
|
|
- { 921600, UINT_MAX }
|
|
|
-};
|
|
|
-
|
|
|
-/*
|
|
|
- * Quantises the baud rate as per AN205 Table 1
|
|
|
- */
|
|
|
-static speed_t cp210x_get_an205_rate(speed_t baud)
|
|
|
-{
|
|
|
- int i;
|
|
|
-
|
|
|
- for (i = 0; i < ARRAY_SIZE(cp210x_an205_table1); ++i) {
|
|
|
- if (baud <= cp210x_an205_table1[i].high)
|
|
|
- break;
|
|
|
- }
|
|
|
-
|
|
|
- return cp210x_an205_table1[i].rate;
|
|
|
-}
|
|
|
-
|
|
|
-static speed_t cp210x_get_actual_rate(struct usb_serial_port *port, speed_t baud)
|
|
|
-{
|
|
|
- unsigned int prescale = 1;
|
|
|
- unsigned int div;
|
|
|
-
|
|
|
- baud = clamp(baud, 300u, port->max_speed);
|
|
|
-
|
|
|
- if (baud <= 365)
|
|
|
- prescale = 4;
|
|
|
-
|
|
|
- div = DIV_ROUND_CLOSEST(48000000, 2 * prescale * baud);
|
|
|
- baud = 48000000 / (2 * prescale * div);
|
|
|
-
|
|
|
- return baud;
|
|
|
-}
|
|
|
-
|
|
|
-/*
|
|
|
- * CP2101 supports the following baud rates:
|
|
|
- *
|
|
|
- * 300, 600, 1200, 1800, 2400, 4800, 7200, 9600, 14400, 19200, 28800,
|
|
|
- * 38400, 56000, 57600, 115200, 128000, 230400, 460800, 921600
|
|
|
- *
|
|
|
- * CP2102 and CP2103 support the following additional rates:
|
|
|
- *
|
|
|
- * 4000, 16000, 51200, 64000, 76800, 153600, 250000, 256000, 500000,
|
|
|
- * 576000
|
|
|
- *
|
|
|
- * The device will map a requested rate to a supported one, but the result
|
|
|
- * of requests for rates greater than 1053257 is undefined (see AN205).
|
|
|
- *
|
|
|
- * CP2104, CP2105 and CP2110 support most rates up to 2M, 921k and 1M baud,
|
|
|
- * respectively, with an error less than 1%. The actual rates are determined
|
|
|
- * by
|
|
|
- *
|
|
|
- * div = round(freq / (2 x prescale x request))
|
|
|
- * actual = freq / (2 x prescale x div)
|
|
|
- *
|
|
|
- * For CP2104 and CP2105 freq is 48Mhz and prescale is 4 for request <= 365bps
|
|
|
- * or 1 otherwise.
|
|
|
- * For CP2110 freq is 24Mhz and prescale is 4 for request <= 300bps or 1
|
|
|
- * otherwise.
|
|
|
- */
|
|
|
-void cp210x_change_speed(struct tty_struct *tty)
|
|
|
-{
|
|
|
- struct usb_serial_port *port = &tty->driver_data;
|
|
|
- u32 baud;
|
|
|
-
|
|
|
- baud = tty->termios.c_ospeed;
|
|
|
-
|
|
|
- /*
|
|
|
- * This maps the requested rate to the actual rate, a valid rate on
|
|
|
- * cp2102 or cp2103, or to an arbitrary rate in [1M, max_speed].
|
|
|
- *
|
|
|
- * NOTE: B0 is not implemented.
|
|
|
- */
|
|
|
- if (port->use_actual_rate)
|
|
|
- baud = cp210x_get_actual_rate(port, baud);
|
|
|
- else if (baud < 1000000)
|
|
|
- baud = cp210x_get_an205_rate(baud);
|
|
|
- else if (baud > port->max_speed)
|
|
|
- baud = port->max_speed;
|
|
|
-
|
|
|
- dev_dbg("%s - setting baud rate to %u\n", __func__, baud);
|
|
|
- if (cp210x_write_u32_reg(port, CP210X_SET_BAUDRATE, baud)) {
|
|
|
- dev_warn("failed to set baud rate to %u\n", baud);
|
|
|
- baud = 9600;
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-void cp210x_set_termios(struct tty_struct *tty)
|
|
|
-{
|
|
|
- unsigned int cflag;
|
|
|
- u16 bits;
|
|
|
- struct usb_serial_port *port = &tty->driver_data;
|
|
|
-
|
|
|
- cflag = tty->termios.c_cflag;
|
|
|
-
|
|
|
- cp210x_change_speed(tty);
|
|
|
-
|
|
|
- /* If the number of data bits is to be updated */
|
|
|
- cp210x_get_line_ctl(port, &bits);
|
|
|
- bits &= ~BITS_DATA_MASK;
|
|
|
- switch (cflag & CSIZE) {
|
|
|
- case CS5:
|
|
|
- bits |= BITS_DATA_5;
|
|
|
- dev_dbg("%s - data bits = 5\n", __func__);
|
|
|
- break;
|
|
|
- case CS6:
|
|
|
- bits |= BITS_DATA_6;
|
|
|
- dev_dbg("%s - data bits = 6\n", __func__);
|
|
|
- break;
|
|
|
- case CS7:
|
|
|
- bits |= BITS_DATA_7;
|
|
|
- dev_dbg("%s - data bits = 7\n", __func__);
|
|
|
- break;
|
|
|
- case CS8:
|
|
|
- default:
|
|
|
- bits |= BITS_DATA_8;
|
|
|
- dev_dbg("%s - data bits = 8\n", __func__);
|
|
|
- break;
|
|
|
- }
|
|
|
- if (cp210x_write_u16_reg(port, CP210X_SET_LINE_CTL, bits))
|
|
|
- dev_dbg("Number of data bits requested not supported by device%s\n", "");
|
|
|
-
|
|
|
- cp210x_get_line_ctl(port, &bits);
|
|
|
- bits &= ~BITS_PARITY_MASK;
|
|
|
- if (cflag & PARENB) {
|
|
|
- if (cflag & CMSPAR) {
|
|
|
- if (cflag & PARODD) {
|
|
|
- bits |= BITS_PARITY_MARK;
|
|
|
- dev_dbg("%s - parity = MARK\n", __func__);
|
|
|
- } else {
|
|
|
- bits |= BITS_PARITY_SPACE;
|
|
|
- dev_dbg(, "%s - parity = SPACE\n", __func__);
|
|
|
- }
|
|
|
- } else {
|
|
|
- if (cflag & PARODD) {
|
|
|
- bits |= BITS_PARITY_ODD;
|
|
|
- dev_dbg("%s - parity = ODD\n", __func__);
|
|
|
- } else {
|
|
|
- bits |= BITS_PARITY_EVEN;
|
|
|
- dev_dbg("%s - parity = EVEN\n", __func__);
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- if (cp210x_write_u16_reg(port, CP210X_SET_LINE_CTL, bits))
|
|
|
- dev_dbg("Parity mode not supported by device%s\n", "");
|
|
|
-
|
|
|
- cp210x_get_line_ctl(port, &bits);
|
|
|
- bits &= ~BITS_STOP_MASK;
|
|
|
- if (cflag & CSTOPB) {
|
|
|
- bits |= BITS_STOP_2;
|
|
|
- dev_dbg("%s - stop bits = 2\n", __func__);
|
|
|
- } else {
|
|
|
- bits |= BITS_STOP_1;
|
|
|
- dev_dbg("%s - stop bits = 1\n", __func__);
|
|
|
- }
|
|
|
- if (cp210x_write_u16_reg(port, CP210X_SET_LINE_CTL, bits))
|
|
|
- dev_dbg("Number of stop bits requested not supported by device%s\n", "");
|
|
|
-
|
|
|
- {
|
|
|
- struct cp210x_flow_ctl flow_ctl;
|
|
|
- u32 ctl_hs;
|
|
|
- u32 flow_repl;
|
|
|
-
|
|
|
- cp210x_read_reg_block(port, CP210X_GET_FLOW, &flow_ctl,
|
|
|
- sizeof(flow_ctl));
|
|
|
- ctl_hs = le32_to_cpu(flow_ctl.ulControlHandshake);
|
|
|
- flow_repl = le32_to_cpu(flow_ctl.ulFlowReplace);
|
|
|
- dev_dbg("%s - read ulControlHandshake=0x%08x, ulFlowReplace=0x%08x\n",
|
|
|
- __func__, ctl_hs, flow_repl);
|
|
|
-
|
|
|
- ctl_hs &= ~CP210X_SERIAL_DSR_HANDSHAKE;
|
|
|
- ctl_hs &= ~CP210X_SERIAL_DCD_HANDSHAKE;
|
|
|
- ctl_hs &= ~CP210X_SERIAL_DSR_SENSITIVITY;
|
|
|
- ctl_hs &= ~CP210X_SERIAL_DTR_MASK;
|
|
|
- ctl_hs |= CP210X_SERIAL_DTR_SHIFT(CP210X_SERIAL_DTR_ACTIVE);
|
|
|
- if (cflag & CRTSCTS) {
|
|
|
- ctl_hs |= CP210X_SERIAL_CTS_HANDSHAKE;
|
|
|
-
|
|
|
- flow_repl &= ~CP210X_SERIAL_RTS_MASK;
|
|
|
- flow_repl |= CP210X_SERIAL_RTS_SHIFT(
|
|
|
- CP210X_SERIAL_RTS_FLOW_CTL);
|
|
|
- dev_dbg("%s - flow control = CRTSCTS\n", __func__);
|
|
|
- } else {
|
|
|
- ctl_hs &= ~CP210X_SERIAL_CTS_HANDSHAKE;
|
|
|
-
|
|
|
- flow_repl &= ~CP210X_SERIAL_RTS_MASK;
|
|
|
- flow_repl |= CP210X_SERIAL_RTS_SHIFT(
|
|
|
- CP210X_SERIAL_RTS_ACTIVE);
|
|
|
- dev_dbg("%s - flow control = NONE\n", __func__);
|
|
|
- }
|
|
|
-
|
|
|
- dev_dbg("%s - write ulControlHandshake=0x%08x, ulFlowReplace=0x%08x\n",
|
|
|
- __func__, ctl_hs, flow_repl);
|
|
|
- flow_ctl.ulControlHandshake = cpu_to_le32(ctl_hs);
|
|
|
- flow_ctl.ulFlowReplace = cpu_to_le32(flow_repl);
|
|
|
- cp210x_write_reg_block(port, CP210X_SET_FLOW, &flow_ctl,
|
|
|
- sizeof(flow_ctl));
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-int cp210x_tiocmset_port(struct usb_serial_port *port, unsigned int set, unsigned int clear);
|
|
|
-
|
|
|
-int cp210x_tiocmset(struct tty_struct *tty,
|
|
|
- unsigned int set, unsigned int clear)
|
|
|
-{
|
|
|
- struct usb_serial_port *port = 0;
|
|
|
- return cp210x_tiocmset_port(port, set, clear);
|
|
|
-}
|
|
|
-
|
|
|
-int cp210x_tiocmset_port(struct usb_serial_port *port, unsigned int set, unsigned int clear)
|
|
|
-{
|
|
|
- u16 control = 0;
|
|
|
-
|
|
|
- if (set & TIOCM_RTS) {
|
|
|
- control |= CONTROL_RTS;
|
|
|
- control |= CONTROL_WRITE_RTS;
|
|
|
- }
|
|
|
- if (set & TIOCM_DTR) {
|
|
|
- control |= CONTROL_DTR;
|
|
|
- control |= CONTROL_WRITE_DTR;
|
|
|
- }
|
|
|
- if (clear & TIOCM_RTS) {
|
|
|
- control &= ~CONTROL_RTS;
|
|
|
- control |= CONTROL_WRITE_RTS;
|
|
|
- }
|
|
|
- if (clear & TIOCM_DTR) {
|
|
|
- control &= ~CONTROL_DTR;
|
|
|
- control |= CONTROL_WRITE_DTR;
|
|
|
- }
|
|
|
-
|
|
|
- return cp210x_write_u16_reg(port, CP210X_SET_MHS, control);
|
|
|
-}
|
|
|
-
|
|
|
-void cp210x_dtr_rts(struct usb_serial_port *p, int on)
|
|
|
-{
|
|
|
- if (on)
|
|
|
- cp210x_tiocmset_port(p, TIOCM_DTR | TIOCM_RTS, 0);
|
|
|
- else
|
|
|
- cp210x_tiocmset_port(p, 0, TIOCM_DTR | TIOCM_RTS);
|
|
|
-}
|
|
|
-
|
|
|
-int cp210x_tiocmget(struct tty_struct *tty)
|
|
|
-{
|
|
|
- struct usb_serial_port *port = &tty->driver_data;
|
|
|
- u8 control;
|
|
|
- int result;
|
|
|
-
|
|
|
- result = cp210x_read_u8_reg(port, CP210X_GET_MDMSTS, &control);
|
|
|
- if (result)
|
|
|
- return result;
|
|
|
-
|
|
|
- result = ((control & CONTROL_DTR) ? TIOCM_DTR : 0) | ((control & CONTROL_RTS) ? TIOCM_RTS : 0) | ((control & CONTROL_CTS) ? TIOCM_CTS : 0) | ((control & CONTROL_DSR) ? TIOCM_DSR : 0) | ((control & CONTROL_RING) ? TIOCM_RI : 0) | ((control & CONTROL_DCD) ? TIOCM_CD : 0);
|
|
|
-
|
|
|
- dev_dbg("%s - control = 0x%.2x\n", __func__, control);
|
|
|
-
|
|
|
- return result;
|
|
|
-}
|
|
|
-
|
|
|
-void cp210x_break_ctl(struct tty_struct *tty, int break_state)
|
|
|
-{
|
|
|
- struct usb_serial_port *port = &tty->driver_data;
|
|
|
- u16 state;
|
|
|
-
|
|
|
- if (break_state == 0)
|
|
|
- state = BREAK_OFF;
|
|
|
- else
|
|
|
- state = BREAK_ON;
|
|
|
- dev_dbg("%s - turning break %s\n", __func__,
|
|
|
- state == BREAK_OFF ? "off" : "on");
|
|
|
- cp210x_write_u16_reg(port, CP210X_SET_BREAK, state);
|
|
|
-}
|
|
|
-
|
|
|
-int cp210x_port_probe(struct usb_serial_port *port)
|
|
|
-{
|
|
|
- int ret;
|
|
|
-
|
|
|
- ret = cp210x_detect_swapped_line_ctl(port);
|
|
|
- if (ret) {
|
|
|
- return ret;
|
|
|
- }
|
|
|
-
|
|
|
- return 0;
|
|
|
-}
|
|
|
-
|
|
|
-void cp210x_init_max_speed(struct usb_serial_port *port)
|
|
|
-{
|
|
|
- bool use_actual_rate = false;
|
|
|
- speed_t max;
|
|
|
-
|
|
|
- switch (port->partnum) {
|
|
|
- case CP210X_PARTNUM_CP2101:
|
|
|
- max = 921600;
|
|
|
- break;
|
|
|
- case CP210X_PARTNUM_CP2102:
|
|
|
- case CP210X_PARTNUM_CP2103:
|
|
|
- //max = 1000000;
|
|
|
- max = 9600;
|
|
|
- break;
|
|
|
- case CP210X_PARTNUM_CP2104:
|
|
|
- use_actual_rate = true;
|
|
|
- max = 2000000;
|
|
|
- break;
|
|
|
- case CP210X_PARTNUM_CP2108:
|
|
|
- max = 2000000;
|
|
|
- break;
|
|
|
- case CP210X_PARTNUM_CP2105:
|
|
|
- if (cp210x_interface_num(port) == 0) {
|
|
|
- use_actual_rate = true;
|
|
|
- max = 2000000; /* ECI */
|
|
|
- } else {
|
|
|
- max = 921600; /* SCI */
|
|
|
- }
|
|
|
- break;
|
|
|
- case CP210X_PARTNUM_CP2102N_QFN28:
|
|
|
- case CP210X_PARTNUM_CP2102N_QFN24:
|
|
|
- case CP210X_PARTNUM_CP2102N_QFN20:
|
|
|
- use_actual_rate = true;
|
|
|
- max = 3000000;
|
|
|
- break;
|
|
|
- default:
|
|
|
- max = 2000000;
|
|
|
- break;
|
|
|
- }
|
|
|
-
|
|
|
- max = 9600;
|
|
|
-
|
|
|
- port->max_speed = max;
|
|
|
- port->use_actual_rate = use_actual_rate;
|
|
|
- dev_dbg("max_speed=%d\n", max);
|
|
|
- dev_dbg("use_actual_rate=%d\n", use_actual_rate);
|
|
|
-}
|
|
|
-
|
|
|
-int cp210x_attach(struct usb_serial_port *port)
|
|
|
-{
|
|
|
- int result;
|
|
|
- port->partnum = CP210X_PARTNUM_UNKNOWN;
|
|
|
-
|
|
|
- result = cp210x_read_vendor_block(port, REQTYPE_DEVICE_TO_HOST,
|
|
|
- CP210X_GET_PARTNUM, &port->partnum,
|
|
|
- sizeof(port->partnum));
|
|
|
- if (result < 0) {
|
|
|
- dev_warn(
|
|
|
- "querying part number failed%s\n", "");
|
|
|
- port->partnum = CP210X_PARTNUM_UNKNOWN;
|
|
|
- }
|
|
|
-
|
|
|
- switch (port->partnum) {
|
|
|
- case CP210X_PARTNUM_CP2101:
|
|
|
- case CP210X_PARTNUM_CP2102:
|
|
|
- case CP210X_PARTNUM_CP2103:
|
|
|
- case CP210X_PARTNUM_CP2104:
|
|
|
- case CP210X_PARTNUM_CP2108:
|
|
|
- case CP210X_PARTNUM_CP2105:
|
|
|
- case CP210X_PARTNUM_CP2102N_QFN28:
|
|
|
- case CP210X_PARTNUM_CP2102N_QFN24:
|
|
|
- case CP210X_PARTNUM_CP2102N_QFN20:
|
|
|
- cp210x_init_max_speed(port);
|
|
|
- return 0;
|
|
|
- default:
|
|
|
- return -1;
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-int usb_control_msg(struct usb_serial_port *port, int pipe, int req, u8 type, u16 val, u8 interface_num, void *dmabuf, int bufsize, int flags)
|
|
|
-{
|
|
|
- struct usbh_cp210x *p_device = container_of(port, struct usbh_cp210x, drv_data.driver_data);
|
|
|
- struct usb_setup_packet *setup = p_device->hport->setup;
|
|
|
-
|
|
|
- setup->bmRequestType = type;
|
|
|
- setup->bRequest = req;
|
|
|
- setup->wValue = val;
|
|
|
- setup->wIndex = interface_num;
|
|
|
- setup->wLength = bufsize;
|
|
|
- int len = usbh_control_transfer(p_device->hport->ep0, setup, dmabuf);
|
|
|
- if (len > 0) {
|
|
|
- return len - 8;
|
|
|
- }
|
|
|
- return len;
|
|
|
-}
|
|
|
-
|
|
|
-static int __usbh_cp210x_connect(struct usbh_hubport *hport, uint8_t intf)
|
|
|
-{
|
|
|
- struct usb_endpoint_descriptor *ep_desc;
|
|
|
- struct usbh_cp210x *p_cp210x = usb_malloc(sizeof(struct usbh_cp210x));
|
|
|
- if (0 == p_cp210x) {
|
|
|
- return -ENOSYS;
|
|
|
- }
|
|
|
- memset(p_cp210x, 0x00, sizeof(*p_cp210x));
|
|
|
- p_cp210x->hport = hport;
|
|
|
- p_cp210x->intf = intf;
|
|
|
- p_cp210x->index = hport->port - 1;
|
|
|
- hport->config.intf[intf].priv = p_cp210x;
|
|
|
-
|
|
|
- p_cp210x->drv_data.driver_data.bInterfaceNumber = 1;
|
|
|
- p_cp210x->drv_data.driver_data.ctrlpipe_rx = 0x80;
|
|
|
- p_cp210x->drv_data.driver_data.ctrlpipe_tx = 0x00;
|
|
|
- p_cp210x->drv_data.driver_data.max_speed = 9600;
|
|
|
- p_cp210x->drv_data.driver_data.use_actual_rate = 1;
|
|
|
- p_cp210x->drv_data.driver_data.bInterfaceNumber = 1;
|
|
|
- p_cp210x->drv_data.driver_data.has_swapped_line_ctl = 0;
|
|
|
-
|
|
|
- USB_LOG_INFO("%s hub %d port %d\n", "---- attach ----", hport->parent->index, hport->port);
|
|
|
- if (0 != cp210x_attach(&p_cp210x->drv_data.driver_data)) {
|
|
|
- USB_LOG_INFO("%s\n", "Device NOT supported!");
|
|
|
- return -EIO;
|
|
|
- }
|
|
|
- cp210x_port_probe(&p_cp210x->drv_data.driver_data);
|
|
|
- cp210x_open(&p_cp210x->drv_data);
|
|
|
- cp210x_break_ctl(&p_cp210x->drv_data, 0);
|
|
|
-
|
|
|
- memset(&p_cp210x->drv_data.termios, 0, sizeof(p_cp210x->drv_data.termios));
|
|
|
- p_cp210x->drv_data.termios.c_iflag = 0;
|
|
|
- p_cp210x->drv_data.termios.c_oflag = 0;
|
|
|
- p_cp210x->drv_data.termios.c_cflag = CS8;
|
|
|
- p_cp210x->drv_data.termios.c_lflag = 0;
|
|
|
- p_cp210x->drv_data.termios.c_cc[0] = 0;
|
|
|
- p_cp210x->drv_data.termios.c_ospeed = 9600;
|
|
|
- cp210x_set_termios(&p_cp210x->drv_data);
|
|
|
-
|
|
|
- for (uint8_t i = 0; i < hport->config.intf[intf].altsetting[0].intf_desc.bNumEndpoints; i++) {
|
|
|
- ep_desc = &hport->config.intf[intf].altsetting[0].ep[i].ep_desc;
|
|
|
- if (ep_desc->bEndpointAddress & 0x80) {
|
|
|
- usbh_hport_activate_epx(&p_cp210x->bulkin, hport, ep_desc);
|
|
|
- } else {
|
|
|
- usbh_hport_activate_epx(&p_cp210x->bulkout, hport, ep_desc);
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- drv_usbh_cp210x_run(p_cp210x);
|
|
|
-
|
|
|
- return 0;
|
|
|
-}
|
|
|
-
|
|
|
-__WEAK void drv_usbh_cp210x_run(struct usbh_cp210x *p_device)
|
|
|
-{
|
|
|
-}
|
|
|
-
|
|
|
-__WEAK void drv_usbh_cp210x_stop(struct usbh_cp210x *p_device)
|
|
|
-{
|
|
|
-}
|
|
|
-
|
|
|
-static int __usbh_cp210x_disconnect(struct usbh_hubport *hport, uint8_t intf)
|
|
|
-{
|
|
|
- struct usbh_cp210x *p_device = (struct usbh_cp210x *)hport->config.intf[intf].priv;
|
|
|
- if (p_device) {
|
|
|
- drv_usbh_cp210x_stop(p_device);
|
|
|
- if (p_device->bulkin) {
|
|
|
- usbh_pipe_free(p_device->bulkin);
|
|
|
- }
|
|
|
- if (p_device->bulkout) {
|
|
|
- usbh_pipe_free(p_device->bulkout);
|
|
|
- }
|
|
|
- memset(p_device, 0, sizeof(*p_device));
|
|
|
- usb_free(p_device);
|
|
|
- }
|
|
|
- return 0;
|
|
|
-}
|
|
|
-
|
|
|
-static const struct usbh_class_driver cp210x_class_driver = {
|
|
|
- .driver_name = "cp210x",
|
|
|
- .connect = __usbh_cp210x_connect,
|
|
|
- .disconnect = __usbh_cp210x_disconnect
|
|
|
-};
|
|
|
-
|
|
|
-CLASS_INFO_DEFINE const struct usbh_class_info cp210x_class_info = {
|
|
|
- .match_flags = USB_CLASS_MATCH_INTF_CLASS | USB_CLASS_MATCH_INTF_SUBCLASS | USB_CLASS_MATCH_INTF_PROTOCOL,
|
|
|
- .class = 0xff, // usbh_cp210x_static_device_CLASS_MASS_STORAGE,
|
|
|
- .subclass = 0x00, //MSC_SUBCLASS_SCSI,
|
|
|
- .protocol = 0x00, //MSC_PROTOCOL_BULK_ONLY,
|
|
|
- .vid = 0x00,
|
|
|
- .pid = 0x00,
|
|
|
- .class_driver = &cp210x_class_driver
|
|
|
-};
|