Linux下自定义虚拟串口驱动

为了解决在海思HI3520D SOC上无多余串口的问题,作者创建了一个虚拟串口驱动,使得内核能欺骗上层应用认为打开的是真实串口。驱动按照Linux UART框架编写,并包含一个设备节点供虚拟串口管理进程使用。经过调试,驱动的select读写功能正常,并实现了异步通知来管理实际串口通信。
摘要由CSDN通过智能技术生成

前些天给新的板子修改BUG的时候,发现这块板子的串口是接在板载MCU上,我们的主SOC(海思HI3520D)上已经没有多余的串口。于是问题来了… 我们很多的上层应用都是通过串口和传感器通讯的,而且程序都是默认使用SOC上的串口,即打开/dev/ttyAMAx,然后调用Linux的select系统调用去和传感器交互数据的,代码都是C++写的,如果要做到兼容,必须修改基类的方法,这不符合软件的开闭原则…. 所以我打算写一个虚拟串口驱动,让内核去欺骗上层应用:”喂,你打开的真的是一个串口哦”。然后再定义一个虚拟串口管理进程,让这个进程去和单片机通讯进行实际串口收发。

驱动代码

今天先上一个尚未测试的驱动代码,按照linux uart框架写的,并且添加了一个给虚拟串口管理进程使用设备节点。这段代码可能会因为内核版本不同而编译不过,目前在3.16.0-30-generic内核版本下编译成功。

明天开始调试…. (2015-11-28)
今天终于完成了单元测试,虚拟串口的select读写均正常,另外使用了异步通知的方式来通知管理者进程,去更新实际的串口,先上一串调试通过的代码。(2015-12-1)
添加了多串口的支持,修正了资源竞争的问题。(2015-12-2)

/*
* Dummy serial driver by sdliu <sdliu@hongdian.com>
* The real hardware was installed in the MCU which is attached to our SOC(HI3520D).
* This driver depends on a serial manager which will process in the userspace
*/

#include <linux/module.h>
#include <linux/ioport.h>
#include <linux/init.h>
#include <linux/console.h>
#include <linux/sysrq.h>
#include <linux/device.h>
#include <linux/tty.h>
#include <linux/tty_flip.h>
#include <linux/serial_core.h>
#include <linux/serial.h>
#include <linux/amba/bus.h>
#include <linux/amba/serial.h>
#include <linux/clk.h>
#include <linux/slab.h>
#include <linux/dmaengine.h>
#include <linux/dma-mapping.h>
#include <linux/scatterlist.h>
#include <linux/delay.h>
#include <linux/poll.h>
#include <linux/tty_flip.h>
#include <linux/circ_buf.h>

#include <asm/io.h>
#include <linux/platform_device.h>

// #include <asm/sizes.h>

#define prt_dbg
#ifdef prt_dbg
#define drintk printk
#else
#define drintk(...) 
#endif

#define DUMMY_SERIAL_NR         4

static int dummy_serial_major = 0;
static int dummy_serial_minor_start = 0;
static struct dummy_uart_port *dummy_array[DUMMY_SERIAL_NR];

unsigned int dummy_serial_nr = 1;
module_param(dummy_serial_nr, uint, S_IRUGO);

// static DECLARE_WAIT_QUEUE_HEAD(dummy_wq); 

int dummy_fasync(int fd, struct file *filp, int mode);

struct dummy_port_data {
    // unsigned char port_idx;

    unsigned long tx_fifo_size;
    unsigned long rx_fifo_size;
};

struct dummy_uart_port {
    struct uart_port port;

    struct dummy_port_data *port_data;

    char type[12];

    unsigned char *tx_fifo;
    unsigned char *rx_fifo;

    unsigned long tx_len;
    unsigned long rx_len;

    unsigned int mctrl;
    unsigned int baud;

    struct ktermios termios;
    struct fasync_struct *async_queue;
    struct semaphore async_sem;

    struct completion manager_activie;
    struct completion write_ok; 
    wait_queue_head_t poll_wq; 

    int manager_reset;

    int is_default_termios : 1;
    unsigned long status;

    struct cdev c_dev;
    int index;
};



static struct class *dummy_class;

static unsigned int dummy_tx_empty(struct uart_port *port)
{

    struct dummy_uart_port *dummy = (struct dummy_uart_port *)port;

    drintk("dummy_tx_empty %d\n", dummy->tx_len);

    // return TIOCSER_TEMT;
    return dummy->tx_len > 0 ? 0 : TIOCSER_TEMT;
}

static void dummy_set_mctrl(struct uart_port *port, unsigned int mctrl)
{
    struct dummy_ua
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值