S5P6818_驱动篇(24)UART驱动
串口是很常用的一个外设,在 Linux 下通常通过串口和其他设备或传感器进行通信,根据电平的不同,串口分为 TTL 和 RS232。不管是什么样的接口电平,其驱动程序都是一样的,通过外接 RS485 这样的芯片就可以将串口转换为 RS485 信号,因此这些外设最终都归结为串口驱动。本章我们就来学习一下如何驱动UART串口。
UART 驱动框架
uart_driver 注册与注销
同 I2C、 SPI 一样, Linux 也提供了串口驱动框架,我们只需要按照相应的串口框架编写驱动程序即可。串口驱动没有什么主机端和设备端之分,就只有一个串口驱动,而且这个驱动也已经由SOC官方已经编写好了,我们真正要做的就是在设备树中添加所要使用的串口节点信息。当系统启动以后串口驱动和设备匹配成功,相应的串口就会被驱动起来,生成/dev/ttyxxxX(xxx=厂商命名,X=0….n)文件。虽然串口驱动不需要我们去写,但是串口驱动框架我们还是需要了解的, uart_driver 结构体表示 UART 驱动, uart_driver 定义在 include/linux/serial_core.h 文件中,内容如下:
struct uart_driver {struct module *owner;const char *driver_name;const char *dev_name;int major;int minor;int nr;struct console *cons;/** these are private; the low level driver should not* touch these; they should be initialised to NULL*/struct uart_state *state;struct tty_driver *tty_driver;
};
每个串口驱动都需要定义一个 uart_driver,加载驱动的时候通过 uart_register_driver 函数向系统注册这个 uart_driver,此函数原型如下:
int uart_register_driver(struct uart_driver *drv)
函数参数和返回值含义如下:
drv: 要注册的 uart_driver。
返回值: 0,成功;负值,失败。
注销驱动的时候也需要注销掉前面注册的 uart_driver,需要用到 uart_unregister_driver 函数,函数原型如下:
void uart_unregister_driver(struct uart_driver *drv)
函数参数和返回值含义如下:
drv: 要注销的 uart_driver。
返回值: 无。
uart_port 的添加与移除
uart_port 表示一个具体的 port, uart_port 定义在 include/linux/serial_core.h 文件,内容如下:
struct uart_port {spinlock_t lock; /* port lock */unsigned long iobase; /* in/out[bwl] */unsigned char __iomem *membase; /* read/write[bwl] */unsigned int (*serial_in)(struct uart_port *, int);void (*serial_out)(struct uart_port *, int, int);void (*set_termios)(struct uart_port *,struct ktermios *new,const struct ktermios *old);void (*set_ldisc)(struct uart_port *,struct ktermios *);unsigned int (*get_mctrl)(struct uart_port *);void (*set_mctrl)(struct uart_port *, unsigned int);unsigned int (*get_divisor)(struct uart_port *,unsigned int baud,unsigned int *frac);void (*set_divisor)(struct uart_port *,unsigned int baud,unsigned int quot,unsigned int quot_frac);int (*startup)(struct uart_port *port);void (*shutdown)(struct uart_port *port);void (*throttle)(struct uart_port *port);void (*unthrottle)(struct uart_port *port);int (*handle_irq)(struct uart_port *);void (*pm)(struct uart_port *, unsigned int state,unsigned int old);void (*handle_break)(struct uart_port *);int (*rs485_config)(struct uart_port *,struct ktermios *termios,struct serial_rs485 *rs485);int (*iso7816_config)(struct uart_port *,struct serial_iso7816 *iso7816);unsigned int irq; /* irq number */unsigned long irqflags; /* irq flags */unsigned int uartclk; /* base uart clock */unsigned int fifosize; /* tx fifo size */unsigned char x_char; /* xon/xoff char */unsigned char regshift; /* reg offset shift */unsigned char iotype; /* io access style */unsigned char quirks; /* internal quirks */#define UPIO_UNKNOWN ((unsigned char)~0U) /* UCHAR_MAX */
#define UPIO_PORT (SERIAL_IO_PORT) /* 8b I/O port access */
#define UPIO_HUB6 (SERIAL_IO_HUB6) /* Hub6 ISA card */
#define UPIO_MEM (SERIAL_IO_MEM) /* driver-specific */
#define UPIO_MEM32 (SERIAL_IO_MEM32) /* 32b little endian */
#define UPIO_AU (SERIAL_IO_AU) /* Au1x00 and RT288x type IO */
#define UPIO_TSI (SERIAL_IO_TSI) /* Tsi108/109 type IO */
#define UPIO_MEM32BE (SERIAL_IO_MEM32BE) /* 32b big endian */
#define UPIO_MEM16 (SERIAL_IO_MEM16) /* 16b little endian *//* quirks must be updated while holding port mutex */
#define UPQ_NO_TXEN_TEST BIT(0)unsigned int read_status_mask; /* driver specific */unsigned int ignore_status_mask; /* driver specific */struct uart_state *state; /* pointer to parent state */struct uart_icount icount; /* statistics */struct console *cons; /* struct console, if any *//* flags must be updated while holding port mutex */upf_t flags;/** These flags must be equivalent to the flags defined in* include/uapi/linux/tty_flags.h which are the userspace definitions* assigned from the serial_struct flags in uart_set_info()* [for bit definitions in the UPF_CHANGE_MASK]** Bits [0..ASYNCB_LAST_USER] are userspace defined/visible/changeable* The remaining bits are serial-core specific and not modifiable by* userspace.*/
#define UPF_FOURPORT ((__force upf_t) ASYNC_FOURPORT /* 1 */ )
#define UPF_SAK ((__force upf_t) ASYNC_SAK /* 2 */ )
#define UPF_SPD_HI ((__force upf_t) ASYNC_SPD_HI /* 4 */ )
#define UPF_SPD_VHI ((__force upf_t) ASYNC_SPD_VHI /* 5 */ )
#define UPF_SPD_CUST ((__force upf_t) ASYNC_SPD_CUST /* 0x0030 */ )
#define UPF_SPD_WARP ((__force upf_t) ASYNC_SPD_WARP /* 0x1010 */ )
#define UPF_SPD_MASK ((__force upf_t) ASYNC_SPD_MASK /* 0x1030 */ )
#define UPF_SKIP_TEST ((__force upf_t) ASYNC_SKIP_TEST /* 6 */ )
#define UPF_AUTO_IRQ ((__force upf_t) ASYNC_AUTO_IRQ /* 7 */ )
#define UPF_HARDPPS_CD ((__force upf_t) ASYNC_HARDPPS_CD /* 11 */ )
#define UPF_SPD_SHI ((__force upf_t) ASYNC_SPD_SHI /* 12 */ )
#define UPF_LOW_LATENCY ((__force upf_t) ASYNC_LOW_LATENCY /* 13 */ )
#define UPF_BUGGY_UART ((__force upf_t) ASYNC_BUGGY_UART /* 14 */ )
#define UPF_MAGIC_MULTIPLIER ((__force upf_t) ASYNC_MAGIC_MULTIPLIER /* 16 */ )#define UPF_NO_THRE_TEST ((__force upf_t) BIT_ULL(19))
/* Port has hardware-assisted h/w flow control */
#define UPF_AUTO_CTS ((__force upf_t) BIT_ULL(20))
#define UPF_AUTO_RTS ((__force upf_t) BIT_ULL(21))
#define UPF_HARD_FLOW ((__force upf_t) (UPF_AUTO_CTS | UPF_AUTO_RTS))
/* Port has hardware-assisted s/w flow control */
#define UPF_SOFT_FLOW ((__force upf_t) BIT_ULL(22))
#define UPF_CONS_FLOW ((__force upf_t) BIT_ULL(23))
#define UPF_SHARE_IRQ ((__force upf_t) BIT_ULL(24))
#define UPF_EXAR_EFR ((__force upf_t) BIT_ULL(25))
#define UPF_BUG_THRE ((__force upf_t) BIT_ULL(26))
/* The exact UART type is known and should not be probed. */
#define UPF_FIXED_TYPE ((__force upf_t) BIT_ULL(27))
#define UPF_BOOT_AUTOCONF ((__force upf_t) BIT_ULL(28))
#define UPF_FIXED_PORT ((__force upf_t) BIT_ULL(29))
#define UPF_DEAD ((__force upf_t) BIT_ULL(30))
#define UPF_IOREMAP ((__force upf_t) BIT_ULL(31))
#define UPF_FULL_PROBE ((__force upf_t) BIT_ULL(32))#define __UPF_CHANGE_MASK 0x17fff
#define UPF_CHANGE_MASK ((__force upf_t) __UPF_CHANGE_MASK)
#define UPF_USR_MASK ((__force upf_t) (UPF_SPD_MASK|UPF_LOW_LATENCY))#if __UPF_CHANGE_MASK > ASYNC_FLAGS
#error Change mask not equivalent to userspace-visible bit defines
#endif/** Must hold termios_rwsem, port mutex and port lock to change;* can hold any one lock to read.*/upstat_t status;#define UPSTAT_CTS_ENABLE ((__force upstat_t) (1 << 0))
#define UPSTAT_DCD_ENABLE ((__force upstat_t) (1 << 1))
#define UPSTAT_AUTORTS ((__force upstat_t) (1 << 2))
#define UPSTAT_AUTOCTS ((__force upstat_t) (1 << 3))
#define UPSTAT_AUTOXOFF ((__force upstat_t) (1 << 4))
#define UPSTAT_SYNC_FIFO ((__force upstat_t) (1 << 5))int hw_stopped; /* sw-assisted CTS flow state */unsigned int mctrl; /* current modem ctrl settings */unsigned int frame_time; /* frame timing in ns */unsigned int type; /* port type */const struct uart_ops *ops;unsigned int custom_divisor;unsigned int line; /* port index */unsigned int minor;resource_size_t mapbase; /* for ioremap */resource_size_t mapsize;struct device *dev; /* parent device */unsigned long sysrq; /* sysrq timeout */unsigned int sysrq_ch; /* char for sysrq */unsigned char has_sysrq;unsigned char sysrq_seq; /* index in sysrq_toggle_seq */unsigned char hub6; /* this should be in the 8250 driver */unsigned char suspended;unsigned char console_reinit;const char *name; /* port name */struct attribute_group *attr_group; /* port specific attributes */const struct attribute_group **tty_groups; /* all attributes (serial core use only) */struct serial_rs485 rs485;struct serial_rs485 rs485_supported; /* Supported mask for serial_rs485 */struct gpio_desc *rs485_term_gpio; /* enable RS485 bus termination */struct serial_iso7816 iso7816;void *private_data; /* generic platform data pointer */
};
uart_port 中最主要的就是ops, ops 包含了串口的具体驱动函数,这个我们稍后再看。每个 UART 都有一个 uart_port,那么 uart_port 是怎么和 uart_driver 结合起来的呢?这里要用到 uart_add_one_port 函数,函数原型如下:
int uart_add_one_port(struct uart_driver *drv, struct uart_port *uport)
函数参数和返回值含义如下:
drv:此 port 对应的 uart_driver。
uport: 要添加到 uart_driver 中的 port。
返回值: 0,成功;负值,失败。
卸载 UART 驱动的时候也需要将 uart_port 从相应的 uart_driver 中移除,需要用到uart_remove_one_port 函数,函数原型如下:
int uart_remove_one_port(struct uart_driver *drv, struct uart_port *uport)
函数参数和返回值含义如下:
drv:要卸载的 port 所对应的 uart_driver。
uport: 要卸载的 uart_port。
返回值: 0,成功;负值,失败。
uart_ops 实现
在上面讲解 uart_port 的时候说过, uart_port 中的 ops 成员变量很重要,因为 ops 包含了针对 UART 具体的驱动函数, Linux 系统收发数据最终调用的都是 ops 中的函数。 ops 是 uart_ops类型的结构体指针变量, uart_ops 定义在 include/linux/serial_core.h 文件中,内容如下:
/*** struct uart_ops -- interface between serial_core and the driver** This structure describes all the operations that can be done on the* physical hardware.** @tx_empty: ``unsigned int ()(struct uart_port *port)``** This function tests whether the transmitter fifo and shifter for the* @port is empty. If it is empty, this function should return* %TIOCSER_TEMT, otherwise return 0. If the port does not support this* operation, then it should return %TIOCSER_TEMT.** Locking: none.* Interrupts: caller dependent.* This call must not sleep** @set_mctrl: ``void ()(struct uart_port *port, unsigned int mctrl)``** This function sets the modem control lines for @port to the state* described by @mctrl. The relevant bits of @mctrl are:** - %TIOCM_RTS RTS signal.* - %TIOCM_DTR DTR signal.* - %TIOCM_OUT1 OUT1 signal.* - %TIOCM_OUT2 OUT2 signal.* - %TIOCM_LOOP Set the port into loopback mode.** If the appropriate bit is set, the signal should be driven* active. If the bit is clear, the signal should be driven* inactive.** Locking: @port->lock taken.* Interrupts: locally disabled.* This call must not sleep** @get_mctrl: ``unsigned int ()(struct uart_port *port)``** Returns the current state of modem control inputs of @port. The state* of the outputs should not be returned, since the core keeps track of* their state. The state information should include:** - %TIOCM_CAR state of DCD signal* - %TIOCM_CTS state of CTS signal* - %TIOCM_DSR state of DSR signal* - %TIOCM_RI state of RI signal** The bit is set if the signal is currently driven active. If* the port does not support CTS, DCD or DSR, the driver should* indicate that the signal is permanently active. If RI is* not available, the signal should not be indicated as active.** Locking: @port->lock taken.* Interrupts: locally disabled.* This call must not sleep** @stop_tx: ``void ()(struct uart_port *port)``** Stop transmitting characters. This might be due to the CTS line* becoming inactive or the tty layer indicating we want to stop* transmission due to an %XOFF character.** The driver should stop transmitting characters as soon as possible.** Locking: @port->lock taken.* Interrupts: locally disabled.* This call must not sleep** @start_tx: ``void ()(struct uart_port *port)``** Start transmitting characters.** Locking: @port->lock taken.* Interrupts: locally disabled.* This call must not sleep** @throttle: ``void ()(struct uart_port *port)``** Notify the serial driver that input buffers for the line discipline are* close to full, and it should somehow signal that no more characters* should be sent to the serial port.* This will be called only if hardware assisted flow control is enabled.** Locking: serialized with @unthrottle() and termios modification by the* tty layer.** @unthrottle: ``void ()(struct uart_port *port)``** Notify the serial driver that characters can now be sent to the serial* port without fear of overrunning the input buffers of the line* disciplines.** This will be called only if hardware assisted flow control is enabled.** Locking: serialized with @throttle() and termios modification by the* tty layer.** @send_xchar: ``void ()(struct uart_port *port, char ch)``** Transmit a high priority character, even if the port is stopped. This* is used to implement XON/XOFF flow control and tcflow(). If the serial* driver does not implement this function, the tty core will append the* character to the circular buffer and then call start_tx() / stop_tx()* to flush the data out.** Do not transmit if @ch == '\0' (%__DISABLED_CHAR).** Locking: none.* Interrupts: caller dependent.** @start_rx: ``void ()(struct uart_port *port)``** Start receiving characters.** Locking: @port->lock taken.* Interrupts: locally disabled.* This call must not sleep** @stop_rx: ``void ()(struct uart_port *port)``** Stop receiving characters; the @port is in the process of being closed.** Locking: @port->lock taken.* Interrupts: locally disabled.* This call must not sleep** @enable_ms: ``void ()(struct uart_port *port)``** Enable the modem status interrupts.** This method may be called multiple times. Modem status interrupts* should be disabled when the @shutdown() method is called.** Locking: @port->lock taken.* Interrupts: locally disabled.* This call must not sleep** @break_ctl: ``void ()(struct uart_port *port, int ctl)``** Control the transmission of a break signal. If @ctl is nonzero, the* break signal should be transmitted. The signal should be terminated* when another call is made with a zero @ctl.** Locking: caller holds tty_port->mutex** @startup: ``int ()(struct uart_port *port)``** Grab any interrupt resources and initialise any low level driver state.* Enable the port for reception. It should not activate RTS nor DTR;* this will be done via a separate call to @set_mctrl().** This method will only be called when the port is initially opened.** Locking: port_sem taken.* Interrupts: globally disabled.** @shutdown: ``void ()(struct uart_port *port)``** Disable the @port, disable any break condition that may be in effect,* and free any interrupt resources. It should not disable RTS nor DTR;* this will have already been done via a separate call to @set_mctrl().** Drivers must not access @port->state once this call has completed.** This method will only be called when there are no more users of this* @port.** Locking: port_sem taken.* Interrupts: caller dependent.** @flush_buffer: ``void ()(struct uart_port *port)``** Flush any write buffers, reset any DMA state and stop any ongoing DMA* transfers.** This will be called whenever the @port->state->xmit circular buffer is* cleared.** Locking: @port->lock taken.* Interrupts: locally disabled.* This call must not sleep** @set_termios: ``void ()(struct uart_port *port, struct ktermios *new,* struct ktermios *old)``** Change the @port parameters, including word length, parity, stop bits.* Update @port->read_status_mask and @port->ignore_status_mask to* indicate the types of events we are interested in receiving. Relevant* ktermios::c_cflag bits are:** - %CSIZE - word size* - %CSTOPB - 2 stop bits* - %PARENB - parity enable* - %PARODD - odd parity (when %PARENB is in force)* - %ADDRB - address bit (changed through uart_port::rs485_config()).* - %CREAD - enable reception of characters (if not set, still receive* characters from the port, but throw them away).* - %CRTSCTS - if set, enable CTS status change reporting.* - %CLOCAL - if not set, enable modem status change reporting.** Relevant ktermios::c_iflag bits are:** - %INPCK - enable frame and parity error events to be passed to the TTY* layer.* - %BRKINT / %PARMRK - both of these enable break events to be passed to* the TTY layer.* - %IGNPAR - ignore parity and framing errors.* - %IGNBRK - ignore break errors. If %IGNPAR is also set, ignore overrun* errors as well.** The interaction of the ktermios::c_iflag bits is as follows (parity* error given as an example):** ============ ======= ======= =========================================* Parity error INPCK IGNPAR* ============ ======= ======= =========================================* n/a 0 n/a character received, marked as %TTY_NORMAL* None 1 n/a character received, marked as %TTY_NORMAL* Yes 1 0 character received, marked as %TTY_PARITY* Yes 1 1 character discarded* ============ ======= ======= =========================================** Other flags may be used (eg, xon/xoff characters) if your hardware* supports hardware "soft" flow control.** Locking: caller holds tty_port->mutex* Interrupts: caller dependent.* This call must not sleep** @set_ldisc: ``void ()(struct uart_port *port, struct ktermios *termios)``** Notifier for discipline change. See* Documentation/driver-api/tty/tty_ldisc.rst.** Locking: caller holds tty_port->mutex** @pm: ``void ()(struct uart_port *port, unsigned int state,* unsigned int oldstate)``** Perform any power management related activities on the specified @port.* @state indicates the new state (defined by enum uart_pm_state),* @oldstate indicates the previous state.** This function should not be used to grab any resources.** This will be called when the @port is initially opened and finally* closed, except when the @port is also the system console. This will* occur even if %CONFIG_PM is not set.** Locking: none.* Interrupts: caller dependent.** @type: ``const char *()(struct uart_port *port)``** Return a pointer to a string constant describing the specified @port,* or return %NULL, in which case the string 'unknown' is substituted.** Locking: none.* Interrupts: caller dependent.** @release_port: ``void ()(struct uart_port *port)``** Release any memory and IO region resources currently in use by the* @port.** Locking: none.* Interrupts: caller dependent.** @request_port: ``int ()(struct uart_port *port)``** Request any memory and IO region resources required by the port. If any* fail, no resources should be registered when this function returns, and* it should return -%EBUSY on failure.** Locking: none.* Interrupts: caller dependent.** @config_port: ``void ()(struct uart_port *port, int type)``** Perform any autoconfiguration steps required for the @port. @type* contains a bit mask of the required configuration. %UART_CONFIG_TYPE* indicates that the port requires detection and identification.* @port->type should be set to the type found, or %PORT_UNKNOWN if no* port was detected.** %UART_CONFIG_IRQ indicates autoconfiguration of the interrupt signal,* which should be probed using standard kernel autoprobing techniques.* This is not necessary on platforms where ports have interrupts* internally hard wired (eg, system on a chip implementations).** Locking: none.* Interrupts: caller dependent.** @verify_port: ``int ()(struct uart_port *port,* struct serial_struct *serinfo)``** Verify the new serial port information contained within @serinfo is* suitable for this port type.** Locking: none.* Interrupts: caller dependent.** @ioctl: ``int ()(struct uart_port *port, unsigned int cmd,* unsigned long arg)``** Perform any port specific IOCTLs. IOCTL commands must be defined using* the standard numbering system found in <asm/ioctl.h>.** Locking: none.* Interrupts: caller dependent.** @poll_init: ``int ()(struct uart_port *port)``** Called by kgdb to perform the minimal hardware initialization needed to* support @poll_put_char() and @poll_get_char(). Unlike @startup(), this* should not request interrupts.** Locking: %tty_mutex and tty_port->mutex taken.* Interrupts: n/a.** @poll_put_char: ``void ()(struct uart_port *port, unsigned char ch)``** Called by kgdb to write a single character @ch directly to the serial* @port. It can and should block until there is space in the TX FIFO.** Locking: none.* Interrupts: caller dependent.* This call must not sleep** @poll_get_char: ``int ()(struct uart_port *port)``** Called by kgdb to read a single character directly from the serial* port. If data is available, it should be returned; otherwise the* function should return %NO_POLL_CHAR immediately.** Locking: none.* Interrupts: caller dependent.* This call must not sleep*/
struct uart_ops {unsigned int (*tx_empty)(struct uart_port *);void (*set_mctrl)(struct uart_port *, unsigned int mctrl);unsigned int (*get_mctrl)(struct uart_port *);void (*stop_tx)(struct uart_port *);void (*start_tx)(struct uart_port *);void (*throttle)(struct uart_port *);void (*unthrottle)(struct uart_port *);void (*send_xchar)(struct uart_port *, char ch);void (*stop_rx)(struct uart_port *);void (*start_rx)(struct uart_port *);void (*enable_ms)(struct uart_port *);void (*break_ctl)(struct uart_port *, int ctl);int (*startup)(struct uart_port *);void (*shutdown)(struct uart_port *);void (*flush_buffer)(struct uart_port *);void (*set_termios)(struct uart_port *, struct ktermios *new,const struct ktermios *old);void (*set_ldisc)(struct uart_port *, struct ktermios *);void (*pm)(struct uart_port *, unsigned int state,unsigned int oldstate);const char *(*type)(struct uart_port *);void (*release_port)(struct uart_port *);int (*request_port)(struct uart_port *);void (*config_port)(struct uart_port *, int);int (*verify_port)(struct uart_port *, struct serial_struct *);int (*ioctl)(struct uart_port *, unsigned int, unsigned long);
#ifdef CONFIG_CONSOLE_POLLint (*poll_init)(struct uart_port *);void (*poll_put_char)(struct uart_port *, unsigned char);int (*poll_get_char)(struct uart_port *);
#endif
};
UART 驱动编写人员需要实现 uart_ops,因为 uart_ops 是最底层的 UART 驱动接口,是实实在在的和 UART 寄存器打交道的。关于 uart_ops 结构体中的这些函数的具体含义请参考Documentation/serial/driver 这个文档。
移植 minicom
minicom 类似我们常用的串口调试助手,是 Linux 下很常用的一个串口工具,将 minicom移植到我们的开发板中,这样我们就可以借助 minicom 对串口进行读写操作。
1、移植 ncurses
minicom 需要用到 ncurses,依次需要先移植 ncurses,如果前面已经移植好了 ncurses,那么这里就不需要再次移植了,只需要在编译 minicom 的时候指定 ncurses 库和头文件目录 即可。
下载 ncurses 源码,然后进行解压,一切准备就绪以后就可以编译 ncureses 库了。进入到 ncureses 源码目录下,首先是配置 ncureses,输入如下命令:
./configure --prefix=/path/ncurses --host=arm-linuxgnueabihf --target=arm-linux-gnueabihf --with-shared --without-profile --disable-stripping --withoutprogs --with-manpages --without-tests
configure 就是配置脚本, --prefix 用于指定编译结果的保存目录。 --host 用于指定编译器前缀, --target 用于指定目标。配置成功以后输入“make”命令开始编译。编译成功以后输入“make install”命令安装。
2、移植 minicom
继续移植 minicom,获取 minicom 源码,先解压 minicom,进入到此目录中,然后配置 minicom,配置命令如下:
./configure CC=arm-linux-gnueabihf-gcc --prefix=/path/minicom --host=arm-linux-gnueabihf CPPFLAGS=-I/path/ncurses/include LDFLAGS=-L/path/ncurses/lib -enable-cfgdir=/etc/minicom
CC 表示要使用的 gcc 交叉编译器, --prefix 指定编译出来的文件存放目录, --host 指定交叉编译器前缀, CPPFLAGS 指定 ncurses 的头文件路径, LDFLAGS 指定 ncurses 的库路径。
配置成功以后执行make编译,完成后make install安装。