串口控制器都是大同小异,用3条地址线就可以完全对串口控制器进行控制。针对ST554芯片来说,控制寄存器主要有THR(发送保持寄存器),RHR(接收保持寄存器),IER(中断使能寄存器),FCR(缓冲控制寄存器),LCR(控制寄存器),LSR(状态寄存器),MCR(模式控制寄存器),MSR(模式状态寄存器),DLL,DLM和测试寄存器等。
代码演示为linux-2.6.18。一般情况下,我们只要修改结构体uart_8250_port的赋值和中断处理函数。在uart_8250_port中的uart_port结构是比较重要的,有些变量需要根据自己的需求进行修改,如下所示。
up->port.iobase = old_serial_port[i].port;
up->port.irq = irq_canonicalize(old_serial_port[i].irq); up->port.uartclk = old_serial_port[i].baud_base * 16; up->port.flags = old_serial_port[i].flags; up->port.hub6 = old_serial_port[i].hub6; up->port.membase = old_serial_port[i].iomem_base; up->port.iotype = old_serial_port[i].io_type; up->port.regshift = old_serial_port[i].iomem_reg_shift;
其中包括串口设备在虚拟地址中的地址映射起始地址,物理起始地址,中断号,始终频率等参数。注意如果需要申请多个同样的串口时,
只要修改nr_uarts变量和UART_NR就可以了。
struct uart_8250_port { struct uart_port port; struct timer_list timer; /* "no irq" timer */ struct list_head list; /* ports on this IRQ */ unsigned short capabilities; /* port capabilities */ unsigned short bugs; /* port bugs */ unsigned int tx_loadsz; /* transmit fifo load size */ unsigned char acr; unsigned char ier; unsigned char lcr; unsigned char mcr; unsigned char mcr_mask; /* mask of user bits */ unsigned char mcr_force; /* mask of forced bits */ unsigned char lsr_break_flag; /* * We provide a per-port pm hook. */ void (*pm)(struct uart_port *port, unsigned int state, unsigned int old);};
串口中的驱动分两层,首先是基于控制台的驱动,即下面的SERIAL8250_CONSOLE,还有一个就是基于UART的驱动,也就是我
们在实际使用串口时,使用的驱动代码,如串口的设置set_termios,读写stop_tx,start_tx,stop_rx等函数。
static struct uart_ops serial8250_pops = { .tx_empty = serial8250_tx_empty, .set_mctrl = serial8250_set_mctrl, .get_mctrl = serial8250_get_mctrl, .stop_tx = serial8250_stop_tx, .start_tx = serial8250_start_tx, .stop_rx = serial8250_stop_rx, .enable_ms = serial8250_enable_ms, .break_ctl = serial8250_break_ctl, .startup = serial8250_startup, .shutdown = serial8250_shutdown, .set_termios = serial8250_set_termios, .pm = serial8250_pm, .type = serial8250_type, .release_port = serial8250_release_port, .request_port = serial8250_request_port, .config_port = serial8250_config_port, .verify_port = serial8250_verify_port, };
static struct uart_driver serial8250_reg = { .owner = THIS_MODULE, .driver_name = "serial", .dev_name = "ttyS", .major = TTY_MAJOR, .minor = 64, .nr = UART_NR, .cons = SERIAL8250_CONSOLE, };在串口的操作中,除了一些初始化的操作外,最重要的就是串口的读和写了。串口的写有两种方式,一种是查询方式,另外一种是中断
方式,当上层发送写的请求时,串口驱动先检查(看LSR中TE和THE)是否符合串口的写,如果符合写的条件,开始写入串口控制器的FIFO,
写完一次等待发送中断,表示上一次的数据已经发送成功,可以继续送入发送的数据。
而在串口的读操作中,是通过中断方式实现,如果有数据接收到,串口控制器会发送接收中断,驱动在中断处理函数中接收到数据,返回
上层。