p2p|uart串口驱动

/dev/ttymxcX=UART1作为终端
两个重要结构体:uart_driver和uart_port 的
每个串口驱动都需要定义一个 uart_driver,
struct uart_driver {
struct module*owner;
const char*driver_name;
const char*dev_name;
intmajor;
intminor;
intnr;
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:int uart_register_driver(struct uart_driver *drv)注销驱动的时候也需要注销掉前面注册的 uart_driver:void uart_unregister_driver(struct uart_driver *drv) ——————————————————————————
uart_port(描述具体的串口端口 串口外设在内核中的具体的表现)
struct uart_port {
spinlock_tlock; /* port lock */
unsigned longiobase; /* 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,
struct ktermios *old);
void(*set_mctrl)(struct uart_port *, unsigned int);
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 serial_rs485 *rs485); ···
const struct uart_ops*ops; //包含了对串口操作的函数 需要我们实现

。。。。。。。。
}
向内核添加一个uart端口

int uart_add_one_port(struct uart_driver *drv, struct uart_port *uport) 卸载 int uart_remove_one_port(struct uart_driver *drv, struct uart_port *uport)—————————————————————————————— 从设备树开始 p2p|uart串口驱动
文章图片

根据属性找到匹配的驱动文件(可以看出串口驱动是和TTY联系在一起的) p2p|uart串口驱动
文章图片
static struct platform_driver serial_imx_driver = {
.probe= serial_imx_probe,//匹配成功后probe函数要执行 此为原版的驱动文件
.remove= serial_imx_remove,
.suspend= serial_imx_suspend,
.resume= serial_imx_resume,
.id_table= imx_uart_devtype,
.driver= {
.name= "imx-uart",
.of_match_table = imx_uart_dt_ids,
},
};
//模仿原版的驱动文件
为什么IMX6ULL的串口为dev/ttymxc0,1
int ret = uart_register_driver(&imx_reg);
->static struct uart_driver imx_reg = {
.owner= THIS_MODULE,
.driver_name= DRIVER_NAME,#define DRIVER_NAME "IMX-uart"
.dev_name= DEV_NAME,
.major= SERIAL_IMX_MAJOR,207
.minor= MINOR_START,16
.nr= ARRAY_SIZE(imx_ports),
.cons= IMX_CONSOLE,
};
->#define DEV_NAME"ttymxc"
uart_unregister_driver(&imx_reg);
_______________________________________
学习模仿probe函数
//struct imx_port {NXP自定义的
struct uart_portport; 。。。。。。。。。}

static int serial_imx_probe(struct platform_device *pdev)
{
struct imx_port *sport;
void __iomem *base;
int ret = 0;
struct resource *res;
int txirq, rxirq, rtsirq;
sport = devm_kzalloc//给imx_port 申请内存
serial_imx_probe_dt//处理设备树
platform_get_resource//获取内存
devm_ioremap_resource//得到外设基地址 (可以得到所有寄存器地址)
-》uart_port处理

sport->port.dev = &pdev->dev;
sport->port.mapbase = res->start;
sport->port.membase = base;
sport->port.type = PORT_IMX,
sport->port.iotype = UPIO_MEM;
sport->port.irq = rxirq;
sport->port.fifosize = 32;
sport->port.ops = &imx_pops;
ret = devm_request_irq(&pdev->dev, txirq, imx_txint, 0,
dev_name(&pdev->dev), sport);
devm_request_irq---串口接收中断,中断处理函数中获得串口接收到的数据,然后使用tty_flip_buffer_push将其放到tty里面

【p2p|uart串口驱动】static struct uart_ops imx_pops = {
.tx_empty= imx_tx_empty,//与寄存器相关
.set_mctrl= imx_set_mctrl,
.get_mctrl= imx_get_mctrl,
.stop_tx= imx_stop_tx,
.start_tx= imx_start_tx,
.stop_rx= imx_stop_rx,
.enable_ms= imx_enable_ms,
.break_ctl= imx_break_ctl,
.startup= imx_startup,
.shutdown= imx_shutdown,
.flush_buffer= imx_flush_buffer,
.set_termios= imx_set_termios,
.type= imx_type,
.config_port= imx_config_port,
.verify_port= imx_verify_port,
#if defined(CONFIG_CONSOLE_POLL)
.poll_init= imx_poll_init,
.poll_get_char= imx_poll_get_char,
.poll_put_char= imx_poll_put_char,
#endif
};

    推荐阅读