linux-tty

由于没有经过完整测试代码中可能会有不足之出,如有网友发现还请斧正
这是一个学习文档,所有代码仅供学习使用,请勿在生产环境中使用
代码在ubuntu 18.04下经过测试

tty驱动

tty驱动是一个应用很广泛的一类驱动,对于理解驱动模型也有很好的帮助,在此写下一个简单的tty设备驱动用于测试

完成一个很简单的功能,类似与一个回环驱动,写入什么数据就返回什么数据,实际驱动中修改相应的发送和接收函数即可

测试代码

测试代码很简单,类似一个串口测试程序,open read write close四步曲

打开设备,设置设备,写入数据,读取数据

#define max_buffer_size 100 /*recv buffer size */
int open_serial(int k)
{
    int ret;
    ret = open("/dev/ttytiny", O_RDWR | O_NOCTTY);
    if (ret == -1) {
        perror("open error");
        exit(-1);
    } else
        printf("Open %s success\n", pathname);
    return ret;
}

int main()
{
    int fd;
    ssize_t n;
    char recv[max_buffer_size] = { 0 };
    struct termios opt;
    char write_buf[] = "abcdefghijklmnopqrstuvwxyz1234567890";

    fd = open_serial(0);    /*open device 0 */

    tcgetattr(fd, &opt);
    cfmakeraw(&opt);
    tcsetattr(fd, TCSANOW, &opt);

    n = write(fd, write_buf, sizeof write_buf);
    printf("write ret:%ld\n", n);

    printf("ready for receiving data...\n");
    n = read(fd, recv, sizeof(recv));

    if (n == -1) {
        perror("read error");
        exit(-1);
    }

    printf("data receive:%ld\n", n);
    printf("The data received is %s\n", recv);
    if (close(fd) == -1)
        perror("close error");
    return 0;
}

驱动代码

由于驱动代码有点多,这里只留下了关键的代码,具体代码可以参考代码库中的文件

代码没有做一些出错处理,实际应用中请增加相关容错代码

代码中设计了一个fifo,写入的时候将数据 复制到fifo,读取的时候从fifo中读取相应的数据

设计一个timer在写入的时候启动timer,在timer的回调函数中将数据写入tty的缓冲区,在早期的内核版本中timer的设置方式可能不一样,该代码在ubuntu 18.04的内核进行编写测试

在tty驱动中没有read函数,通过flip将数据压入tty的buffer

struct tiny_tty {
    struct tty_port port;
    struct kfifo fifo;
    int index;
    struct timer_list timer;
};

struct tiny_tty tty0;
struct tty_driver *tiny_tty_driver;

static int tiny_write(struct tty_struct *tty, const unsigned char *buf,
              int count)
{
    int ret = kfifo_in(&tty0.fifo, buf, count);
    mod_timer(&tty0.timer, jiffies + HZ / 100);
    return ret;
}

static const struct tty_operations tiny_ops = {
    .open = tiny_open,
    .close = tiny_close,
    .write = tiny_write,
    .write_room = tiny_write_room,
};

void callback(struct timer_list *timer_list)
{
    struct tiny_tty *t;
    char buf[100];
    int cnt = 0;

    t = container_of(timer_list, struct tiny_tty, timer);
    cnt = kfifo_out(&t->fifo, buf, sizeof buf);
    if (cnt > 0) {
        printk(KERN_INFO "%s flip\n", __func__);
        tty_insert_flip_string(&t->port, buf, cnt);
        tty_flip_buffer_push(&t->port);
    }
}

static int __init tiny_tty_init(void)
{
    int result;

    printk(KERN_ALERT "TINY device init\n");

    tiny_tty_driver = alloc_tty_driver(1);
    if (!tiny_tty_driver)
        return -ENOMEM;

    tiny_tty_driver->owner = THIS_MODULE;
    tiny_tty_driver->driver_name = "usbtiny";
    tiny_tty_driver->name = "ttytiny";/*在dev目录下产生的设备文件名*/
    tiny_tty_driver->major = 0;
    tiny_tty_driver->minor_start = 0;
    tiny_tty_driver->type = TTY_DRIVER_TYPE_SERIAL;
    tiny_tty_driver->subtype = SERIAL_TYPE_NORMAL;
    tiny_tty_driver->flags =
        TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV |
        TTY_DRIVER_UNNUMBERED_NODE;/*这个设置只产生一个设备 即ttytiny 不产生类似于 ttyusb0的序列设备,该区动也只能注册一个ttytiny设备*/
    tiny_tty_driver->init_termios = tty_std_termios;
    tiny_tty_driver->init_termios.c_cflag =
        B9600 | CS8 | CREAD | HUPCL | CLOCAL;

    tty_set_operations(tiny_tty_driver, &tiny_ops);
    result = tty_register_driver(tiny_tty_driver);
    
    tty0.index = 0;
    tty_port_init(&(tty0.port));
    tty_port_register_device(&tty0.port, tiny_tty_driver, tty0.index, NULL);
    timer_setup(&tty0.timer, callback, 1);

    result = kfifo_alloc(&tty0.fifo, 1024, GFP_KERNEL);
    if (result != 0) {
        pr_err("kfifo_alloc error:%d\n", result);
    }

    return result;
}

static void __exit tiny_tty_exit(void)
{
    /* 删除 timer */
    del_timer(&tty0.timer);
    printk(KERN_ALERT "del_timer \n");

    /* 删除device */
    tty_unregister_device(tiny_tty_driver, tty0.index);
    printk(KERN_ALERT "tty_unregister_device \n");

    /* 删除driver */
    tty_unregister_driver(tiny_tty_driver);
    printk(KERN_ALERT "TINY device tty_unregister_driver\n");
}

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容