编写虚拟UART驱动程序

编程入门 行业动态 更新时间:2024-10-23 05:00:39

编写虚拟UART<a href=https://www.elefans.com/category/jswz/34/1770317.html style=驱动程序"/>

编写虚拟UART驱动程序

一、框架回顾

二、编写UART驱动要做的事

1.注册一个uart_driver
2. 对于每一个port,都会在设备树里面有一个节点
3. 设备树里的节点和platform_driver节点匹配
4. 当platform_dirver的probe函数被调用时,可以获得设备树里的信息,从而把每个串口设置成对应的uart_driver

三、虚拟的UART

为了做实验,我们还要创建一个虚拟文件:/proc/virt_uart_buf

  • 要发送数据给虚拟串口时,执行:echo "xxx" > /proc/virt_uart_buf
  • 要读取虚拟串口的数据时,执行:cat /proc/virt_uart_buf
    虚拟串口需要有接收中断(写入buff时),查看6ull的手册,第三章中断中,使用99是可157里面一样是保留的。

编写代码的思路:
在platform_driver的probe函数里,需要设置uart_port(提供uart_ops),然后注册uart_port
uart_ops需要提供设置串口的信息,需要设置读数据,需要设置写输入的方法

四、编程

4.1 编写设备树

/ {virtual_uart: virtual_uart_100ask {compatible = "100ask,virtual_uart";interrupt-controller;#interrupt-cells = <2>;interrupt-parent = <&intc>;interrupts = <GIC_SPI 99 IRQ_TYPE_LEVEL_HGIH>;};
};

4.2 编写uart_driver

4.3 编写platform_driver

#include <linux/init.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/serial_core.h>
#include <linux/sysrq.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/proc_fs.h>
#include <linux/tty_flip.h>
#include <linux/tty.h>
#include <linux/tty_flip.h>
#include <linux/fs.h>
#include <linux/uaccess.h>static struct uart_port *virtual_port;
static struct proc_dir_entry *uart_proc_file;#define BUF_LEN 1024
#define NEXT_PLACE(i) ((i+1)&0x3ff)
static unsigned char txbuf[1024];
static int tx_buf_r = 0;
static int tx_buf_w = 0;static unsigned char rxbuf[1024];
//static int rx_buf_r = 0;
static int rx_buf_w = 0;static struct uart_driver virtual_uart_drv = {.owner = THIS_MODULE,.driver_name = "VIRT_UART",.dev_name = "ttyVIRT",.major = 0,.minor = 0,.nr = 1,
};/* circle buffer */
static int is_txbuf_empty(void)
{return tx_buf_r == tx_buf_w;
}static int is_txbuf_full(void)
{return NEXT_PLACE(tx_buf_w) == tx_buf_r;
}static int txbuf_put(unsigned char val)
{if(is_txbuf_full())return -1;txbuf[tx_buf_w] = val;tx_buf_w = NEXT_PLACE(tx_buf_w);return 0;
}static int txbuf_get(unsigned char *pval)
{if(is_txbuf_empty())return -1;*pval =txbuf[tx_buf_r];tx_buf_r = NEXT_PLACE(tx_buf_r);return 0;
}static int txbuf_count(void)
{if(tx_buf_w >= tx_buf_r)return tx_buf_w - tx_buf_r;elsereturn BUF_LEN + tx_buf_w - tx_buf_r;
}static ssize_t virtual_uart_buf_read(struct file *file, char __user *buf, size_t size, loff_t *ppos)
{int cnt = txbuf_count();int i;unsigned char val;cnt = (cnt > size)?size:cnt;for(i=0;i<cnt;i++) {int ret;txbuf_get(&val);ret = copy_to_user(buf+i, &val, 1);}return cnt;
}static ssize_t virtual_uart_buf_write(struct file *file, const char __user *buf, size_t size, loff_t *off)
{rx_buf_w = copy_from_user(rxbuf, buf, size);irq_set_irqchip_state(virtual_port->irq, IRQCHIP_STATE_PENDING, 1);return size;
}static const struct file_operations virtual_uart_buf_fops = {.read  = virtual_uart_buf_read,.write = virtual_uart_buf_write,
};static unsigned int virtual_uart_tx_empty(struct uart_port *port)
{return 1;
}static void virtual_uart_start_tx(struct uart_port *port)
{struct circ_buf *xmit = &port->state->xmit;while(!uart_circ_empty(xmit) &&!uart_tx_stopped(port)) {/* save circ buffer into the txbuf *///txbuf[tx_buf_w++] = xmit->buf[xmit->tail];txbuf_put(xmit->buf[xmit->tail]);xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE -1);port->icount.tx++;}if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)uart_write_wakeup(port);
}static void
virtual_uart_set_termios(struct uart_port *port, struct ktermios *termios,struct ktermios *old)
{return;
}static int virtual_startup(struct uart_port *port)
{return 0;
}static void virtual_set_mctrl(struct uart_port *port, unsigned int mctrl)
{
}static unsigned int virtual_get_mctrl(struct uart_port *port)
{return 0;
}static void virtual_stop_tx(struct uart_port *port)
{
}static void virtual_stop_rx(struct uart_port *port)
{
}static void virtual_shutdown(struct uart_port *port)
{
}static const char *virtual_type(struct uart_port *port)
{return "100ASK_VIRT_UART";
}static const struct uart_ops  virtual_port_ops = {.tx_empty   = virtual_uart_tx_empty,.set_mctrl	= virtual_set_mctrl,.get_mctrl	= virtual_get_mctrl,.start_tx   = virtual_uart_start_tx,.stop_tx 	= virtual_stop_tx,.stop_rx	= virtual_stop_rx,
//	.enable_ms	= imx_enable_ms,
//	.break_ctl	= imx_break_ctl,.startup	= virtual_startup,.shutdown	= virtual_shutdown,
//	.flush_buffer	= imx_flush_buffer,.set_termios    = virtual_uart_set_termios,.type			= virtual_type,
//	.config_port	= imx_config_port,
//	.verify_port	= imx_verify_port,
};static irqreturn_t virtual_uart_rxint(int irq, void *dev_id)
{struct uart_port *port = dev_id;unsigned long flags;int i;spin_lock_irqsave(&port->lock, flags);for(i=0;i<rx_buf_w;i++) {port->icount.rx++;tty_insert_flip_char(&port->state->port, rxbuf[i], TTY_NORMAL);}rx_buf_w = 0;spin_unlock_irqrestore(&port->lock, flags);tty_flip_buffer_push(&port->state->port);return IRQ_HANDLED;
}static int virtual_uart_probe(struct platform_device *pdev)
{int rx_irq;int ret;uart_proc_file = proc_create("virtual_uart_buf", 0, NULL, &virtual_uart_buf_fops);virtual_port = devm_kzalloc(&pdev->dev, sizeof(struct uart_port), GFP_KERNEL);if(!virtual_port) {return -ENOMEM;}rx_irq = platform_get_irq(pdev, 0);ret = devm_request_irq(&pdev->dev, rx_irq, virtual_uart_rxint, 0,dev_name(&pdev->dev), virtual_port);virtual_port->dev = &pdev->dev;virtual_port->iotype = UPIO_MEM;virtual_port->irq = rx_irq;virtual_port->fifosize = 32;virtual_port->ops = &virtual_port_ops;virtual_port->flags = UPF_BOOT_AUTOCONF;return uart_add_one_port(&virtual_uart_drv, virtual_port);
}static int virtual_uart_remove(struct platform_device *pdev)
{uart_remove_one_port(&virtual_uart_drv, virtual_port);proc_remove(uart_proc_file);return 0;
}static const struct of_device_id virtual_uart_of_match[] = {{ patible = "100ask,virtual_uart", },{ },
};static struct platform_driver virtual_uart_platform_drv = {.probe  = virtual_uart_probe,.remove = virtual_uart_remove,.driver = {.name = "virtual_uart",.of_match_table = of_match_ptr(virtual_uart_of_match),},
};static int __init virtual_uart_init(void)
{int ret = uart_register_driver(&virtual_uart_drv);if(ret) return ret;ret = platform_driver_register(&virtual_uart_platform_drv);if(ret != 0)uart_unregister_driver(&virtual_uart_drv);return ret;
}static void __exit virtual_uart_exit(void)
{platform_driver_unregister(&virtual_uart_platform_drv);uart_unregister_driver(&virtual_uart_drv);
}module_init(virtual_uart_init);
module_exit(virtual_uart_exit);
MODULE_LICENSE("GPL");

4.4 实现uart_ops

4.5 实现/proc/virt_uart_buf

更多推荐

编写虚拟UART驱动程序

本文发布于:2023-12-03 08:35:00,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1653278.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:驱动程序   UART

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!