ARM-Linux S5PV210 UART驱动(2)---- 终端设备驱动

news/2024/11/29 20:38:17/

  在Linux中,UART串口驱动完全遵循tty驱动的框架结构,但是进行了底层操作的再次封装,所以先介绍tty终端设备驱动。

一、终端设备

  1.串行端口终端(/dev/ttySACn)

  2.伪终端(/dev/pty/)

  3.控制台终端(/dev/ttyn,/dev/console)

二、驱动结构

  1.tty分层结构如下图所示:

  

     包含tty核心、tty线路规程、tty驱动,其中tty规程的工作是以特殊的方式格式化从一个用户或者硬件接收到的数据,常采用一个协议转换的形式,如PPP、Bluetooth。

 

  2.tty主要源文件关系及数据流向如下图:

特定的tty设备驱动的主体工作是填充tty_driver结构体中的成员,实现tty_operations结构体中的一系列成员函数

struct tty_driver {int    magic;        /* magic number for this structure */struct kref kref;    /* Reference management */struct cdev cdev;struct module    *owner;const char    *driver_name;//驱动名字const char    *name;//驱动设备结点名字int    name_base;    /* offset of printed name */int    major;        /* major device number */int    minor_start;    /* start of minor device number */int    minor_num;    /* number of *possible* devices */int    num;        /* number of devices allocated */short    type;        /* type of tty driver */short    subtype;    /* subtype of tty driver */struct ktermios init_termios; /* Initial termios */int    flags;        /* tty driver flags */struct proc_dir_entry *proc_entry; /* /proc fs entry */struct tty_driver *other; /* only used for the PTY driver *//** Pointer to the tty data structures*/struct tty_struct **ttys;struct ktermios **termios;struct ktermios **termios_locked;void *driver_state;/** Driver methods*/const struct tty_operations *ops;struct list_head tty_drivers;
};

 tty_operations中的成员函数需在特定设备tty驱动模块初始化函数中被赋值;

 tty_struct结构体被tty核心用来保存当前tty端口的状态。

struct tty_operations {struct tty_struct * (*lookup)(struct tty_driver *driver,struct inode *inode, int idx);int  (*install)(struct tty_driver *driver, struct tty_struct *tty);void (*remove)(struct tty_driver *driver, struct tty_struct *tty);int  (*open)(struct tty_struct * tty, struct file * filp);void (*close)(struct tty_struct * tty, struct file * filp);void (*shutdown)(struct tty_struct *tty);void (*cleanup)(struct tty_struct *tty);int  (*write)(struct tty_struct * tty,const unsigned char *buf, int count);int  (*put_char)(struct tty_struct *tty, unsigned char ch);void (*flush_chars)(struct tty_struct *tty);int  (*write_room)(struct tty_struct *tty);int  (*chars_in_buffer)(struct tty_struct *tty);int  (*ioctl)(struct tty_struct *tty, struct file * file,unsigned int cmd, unsigned long arg);long (*compat_ioctl)(struct tty_struct *tty, struct file * file,unsigned int cmd, unsigned long arg);void (*set_termios)(struct tty_struct *tty, struct ktermios * old);void (*throttle)(struct tty_struct * tty);void (*unthrottle)(struct tty_struct * tty);void (*stop)(struct tty_struct *tty);void (*start)(struct tty_struct *tty);void (*hangup)(struct tty_struct *tty);int (*break_ctl)(struct tty_struct *tty, int state);void (*flush_buffer)(struct tty_struct *tty);void (*set_ldisc)(struct tty_struct *tty);void (*wait_until_sent)(struct tty_struct *tty, int timeout);void (*send_xchar)(struct tty_struct *tty, char ch);int (*tiocmget)(struct tty_struct *tty, struct file *file);int (*tiocmset)(struct tty_struct *tty, struct file *file,unsigned int set, unsigned int clear);int (*resize)(struct tty_struct *tty, struct winsize *ws);int (*set_termiox)(struct tty_struct *tty, struct termiox *tnew);
#ifdef CONFIG_CONSOLE_POLLint (*poll_init)(struct tty_driver *driver, int line, char *options);int (*poll_get_char)(struct tty_driver *driver, int line);void (*poll_put_char)(struct tty_driver *driver, int line, char ch);
#endifconst struct file_operations *proc_fops;
};
struct tty_operations
struct tty_struct {int    magic;struct kref kref;struct tty_driver *driver;const struct tty_operations *ops;int index;/* Protects ldisc changes: Lock tty not pty */struct mutex ldisc_mutex;struct tty_ldisc *ldisc;struct mutex termios_mutex;spinlock_t ctrl_lock;/* Termios values are protected by the termios mutex */struct ktermios *termios, *termios_locked;struct termiox *termiox;    /* May be NULL for unsupported */char name[64];struct pid *pgrp;        /* Protected by ctrl lock */struct pid *session;unsigned long flags;int count;struct winsize winsize;        /* termios mutex */unsigned char stopped:1, hw_stopped:1, flow_stopped:1, packet:1;unsigned char low_latency:1, warned:1;unsigned char ctrl_status;    /* ctrl_lock */unsigned int receive_room;    /* Bytes free for queue */struct tty_struct *link;struct fasync_struct *fasync;struct tty_bufhead buf;        /* Locked internally */int alt_speed;        /* For magic substitution of 38400 bps */wait_queue_head_t write_wait;wait_queue_head_t read_wait;struct work_struct hangup_work;void *disc_data;void *driver_data;struct list_head tty_files;#define N_TTY_BUF_SIZE 4096/** The following is data for the N_TTY line discipline.  For* historical reasons, this is included in the tty structure.* Mostly locked by the BKL.*/unsigned int column;unsigned char lnext:1, erasing:1, raw:1, real_raw:1, icanon:1;unsigned char closing:1;unsigned char echo_overrun:1;unsigned short minimum_to_wake;unsigned long overrun_time;int num_overrun;unsigned long process_char_map[256/(8*sizeof(unsigned long))];char *read_buf;int read_head;int read_tail;int read_cnt;unsigned long read_flags[N_TTY_BUF_SIZE/(8*sizeof(unsigned long))];unsigned char *echo_buf;unsigned int echo_pos;unsigned int echo_cnt;int canon_data;unsigned long canon_head;unsigned int canon_column;struct mutex atomic_read_lock;struct mutex atomic_write_lock;struct mutex output_lock;struct mutex echo_lock;unsigned char *write_buf;int write_cnt;spinlock_t read_lock;/* If the tty has a pending do_SAK, queue it here - akpm */struct work_struct SAK_work;struct tty_port *port;
};
struct tty_struct

 

tty_io.c:

【1】定义了tty 设备通用的file_operations结构体:

static const struct file_operations tty_fops = {.llseek        = no_llseek,.read        = tty_read,.write        = tty_write,.poll        = tty_poll,.unlocked_ioctl    = tty_ioctl,.compat_ioctl    = tty_compat_ioctl,.open        = tty_open,.release    = tty_release,.fasync        = tty_fasync,
};

 

【2】实现了接口函数alloc_tty_driver()用于分配tty驱动:

/*tty driver 的所有操作都包含在 tty_driver 中。内核即供了一个名叫 alloc_tty_driver()
来分配这个 tty_driver。当然我们也可以在自己的驱动中将它定义成一个静态的结构。对
tty_driver 进行一些必要的初始化之后,调用 tty_register_driver()将其注册. */
struct tty_driver *alloc_tty_driver(int lines)
{struct tty_driver *driver;driver = kzalloc(sizeof(struct tty_driver), GFP_KERNEL);if (driver) {kref_init(&driver->kref);driver->magic = TTY_DRIVER_MAGIC;driver->num = lines;/* later we'll move allocation of tables here */}return driver;
}

 

【3】实现了接口函数tty_set_operations()用于设置tty驱动操作:

/*将tty_operations结构体中的函数指针拷贝给tty_driver对应的函数指针*/
void tty_set_operations(struct tty_driver *driver,const struct tty_operations *op)
{driver->ops = op;
};

 

【4】实现了接口函数tty_register_driver()用于注册tty设备:

/** Called by a tty driver to register itself.
* 注册 tty 驱动成功时返回 0;参数为由 alloc_tty_driver()分配的 tty_driver 结构体指针。
*这个函数操作比较简单。就是为 tty_driver 创建字符设备。然后将字符设备的操作集指定
*为 tty_fops.并且将 tty_driver 挂载到 tty_drivers 链表中。以设备号为关键字找到对应
*的 driver. */
int tty_register_driver(struct tty_driver *driver)
{int error;int i;dev_t dev;void **p = NULL;/*TTY_DRIVER_DEVPTS_MEM:使用 devpts 进行动态内存映射*/if (!(driver->flags & TTY_DRIVER_DEVPTS_MEM) && driver->num) {p = kzalloc(driver->num * 2 * sizeof(void *), GFP_KERNEL);if (!p)return -ENOMEM;}if (!driver->major) {/*如果没有指定 driver->major,动态申请字符设备号 */error = alloc_chrdev_region(&dev, driver->minor_start,driver->num, driver->name);if (!error) {driver->major = MAJOR(dev);driver->minor_start = MINOR(dev);}} else {/*否则根据主设备号申请字符设备号*/dev = MKDEV(driver->major, driver->minor_start);error = register_chrdev_region(dev, driver->num, driver->name);}if (error < 0) {kfree(p);/*如果失败则释放申请的内存空间*/return error;}if (p) {/*设置tty数据结构指针*/driver->ttys = (struct tty_struct **)p;/*tty_struct结构体被tty核心用来保存当前端口的状态*/driver->termios = (struct ktermios **)(p + driver->num);/*ktermios保存当前的线路设置*/} else {driver->ttys = NULL;driver->termios = NULL;}//注册字符设备cdev_init(&driver->cdev, &tty_fops);driver->cdev.owner = driver->owner;error = cdev_add(&driver->cdev, dev, driver->num);if (error) {unregister_chrdev_region(dev, driver->num);driver->ttys = NULL;driver->termios = NULL;kfree(p);return error;}mutex_lock(&tty_mutex);list_add(&driver->tty_drivers, &tty_drivers);/*将 tty_driver 挂载到 tty_drivers 链表中*/mutex_unlock(&tty_mutex);/*如果没有指定 TTY_DRIVER_DYNAMIC_DEV.即动态设备管理 */if (!(driver->flags & TTY_DRIVER_DYNAMIC_DEV)) {for (i = 0; i < driver->num; i++)tty_register_device(driver, i, NULL);/*注册tty设备*/}/** This function is called by tty_register_driver() to handle* registering the driver's /proc handler into /proc/tty/driver/<foo>*/proc_tty_register_driver(driver);driver->flags |= TTY_DRIVER_INSTALLED;return 0;
}

 

转载于:https://www.cnblogs.com/hello2mhb/p/3333474.html


http://www.ppmy.cn/news/252095.html

相关文章

打印文件出现xps_什么是XPS文件?Windows为什么要我将其打印到一个文件?

打印文件出现xps The XPS format is Microsoft’s alternative to PDF. It was introduced in Windows Vista, but never gained much traction. However, modern versions of Windows continue to include better support for XPS files than PDF files. XPS格式是Microsoft替…

USRP系列(二):USRP作用、组件及产品系列介绍

USRP系列&#xff08;二&#xff09;&#xff1a;USRP作用、组件及产品系列介绍 USRP系列&#xff08;一&#xff09;&#xff1a;软件定义无线电&#xff08;SDR&#xff09; USRP系列&#xff08;三&#xff09;&#xff1a;NI 与Ettus Research的USRP区别 USRP系列&#xf…

【Maven】Maven入门,Java界的Anaconda!

1 Maven介绍 官方文档&#xff1a;Apache Maven 的本质是一个软件项目管理和理解工具。基于项目对象模型 (Project Object Model&#xff0c;POM) 的概念&#xff0c;Maven 可以从一条中心信息管理项目的构建、报告和文档。 就像Python和Anaconda的关系&#x1f92d; 可以帮助…

【29JavaScript 表单】掌握 JavaScript 表单操作:获取、验证和动态处理,提升用户交互体验

JavaScript 表单 表单是网页中常用的元素之一&#xff0c;用于收集用户输入的数据。JavaScript 提供了丰富的方法和属性来操作和验证表单数据。本文将详细介绍 JavaScript 中与表单相关的操作。 获取表单元素 通过 JavaScript 可以轻松获取表单中的各个元素&#xff0c;并对…

在没有串口设备的时候如何让电脑能调试串口设备

1.设备&#xff1a;电脑。 2.软件&#xff1a;Configure Virtual Serial Port Driver。 3.软件&#xff1a;串口调试助手。 4.自己的开发工具。 一&#xff0c;建立虚拟串口 打开Configure Virtual Serial Port Driver建立两个虚拟串口。&#xff08;默认软件可以适用14天&…

串口设备的类型

RS232、RS422和RS485这三种串口都是串行数据接口标准&#xff0c;由电子工业协会&#xff08;EIA&#xff09;制订并发布。 为保证不同厂家产品之间的相互兼容&#xff0c;1962年RS232发布。 但RS232通信距离短、速率低&#xff0c;为了弥补这方面的不足&#xff0c;RS422就诞生…

查看设备串口列表和串口上电使能

查看设备串口列表 adb shell ls dev/ttys (或者直接问供应商) 用ls命令行时出现如下错误&#xff1a;不是内部或外部命令 解决方法&#xff1a;新建文件&#xff1a;ls.bat&#xff0c;输入以下代码&#xff1a; echo off dir 拷贝到 C/Windows下 串口上电使能 adb sh…

Qt 串口获取串口设备名称

前言 最近在用QT弄一个串口上位机&#xff0c;以前用QT做的串口工具在选择串口的时候只能通过串口号选择&#xff0c;在有多个串口设备的时候不是很方便&#xff0c;所以这次就想着搞成选择的时候可以显示串口设备名称的方式。 1、实现效果 目前家里就只有一个CH340的串口设备…