终端设备驱动:
终端设备分类:串行端口终端(/dev/ttySn), 伪端口(/dev/pty), 控制台终端(/dev/ttyn, /dev/console)。
终端设备驱动结构:包含tty核心,tty线路规程(以特殊的方式格式化从一个用户或硬件收到到数据,ppp或bluetooth),tty驱动。
tty设备发送数据流程:tty核心从用户获取数据---->tty线程规程驱动----->tty驱动----->硬件。接收数据,相反。
struct tty_struct {
int magic;
struct tty_driver *driver;
int index;
struct tty_ldisc ldisc;
struct mutex termios_mutex;
struct ktermios *termios,
*termios_locked;
char name[64];
struct pid *pgrp;
struct pid *session;
unsigned long flags;
int count;
struct winsize winsize;
unsigned char stopped:1,
hw_stopped:1,
flow_stopped:1,
packet:1;
unsigned char low_latency:1,
warned:1;
unsigned char ctrl_status;
unsigned int receive_room; /* Bytes free for queue */
struct tty_struct *link;
struct fasync_struct *fasync;
struct tty_bufhead buf;
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.
*/
unsigned int column;
unsigned char lnext:1,
erasing:1,
raw:1,
real_raw:1,
icanon:1;
unsigned char closing: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))];
int canon_data;
unsigned long canon_head;
unsigned int canon_column;
struct mutex atomic_read_lock;
struct mutex atomic_write_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;
};
tty设备驱动的主体工作是填充tty_driver结构体:
struct tty_driver {
int magic; /* magic number for this structure ,在alloc_tty_driver()中被初始化*/
struct kref kref; /* Reference management */
struct cdev 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结构体:
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); //tty核心输入缓冲满时调用
void (*unthrottle)(struct tty_struct * tty); //tty核心输入缓冲已被清空时调用
void (*stop)(struct tty_struct *tty); //停止tty驱动发数据给设备
void (*start)(struct tty_struct *tty); //恢复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);
int (*get_icount)(struct tty_struct *tty,
struct serial_icounter_struct *icount);
#ifdef CONFIG_CONSOLE_POLL
int (*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);
#endif
const struct file_operations *proc_fops;
};
1.分配tty驱动:
struct tty_driver *alloc_tty_driver(int lines);line为要分配到设备数量。
2.注册tty驱动:
int tty_register_driver(struct tty_driver *driver);
3.注销tty驱动:
int tty_unregister_driver(struct tty_driver *driver);
4.注册tty设备:
void tty_register_device(struct tty_driver *driver, unsigned index, struct device *device);用于注册关联于tty_driver的设备。
5.注销tty设备:
void tty_unregister_device(struct tty_driver *driver, unsigned index);
6.设置tty驱动操作:
void tty_set_operations(struct tty_driver *driver, struct tty_operations *op);
终端设备驱动应该包含:
1.模块加载和卸载函数:完成注册和注销tty_driver, 初始化和释放终端设备对应的tty_driver结构体成员及硬件资源。
2.实现tty_operations结构体中的函数:open, close, write,tiocmget, tiocmset等。
tty线路设置:
改变tty设备的线路设置或获取当前线路设置的两种方式:
1.调用用户空间的termios库函数。
int tcgetattr(int fd, struct termios *termios_p); //获取终端设备的操作模式
int tcsetattr(int fd, int optional_actions, struct termios *termios_p); //设置终端设备的操作模式
输入/输出波特率的获取和设置:
speed_t cfgetospeed(struct termios *termios_p); //获得输出波特率
speed_t cfgetispeed(struct termios *termios_p); //获得输入波特率
int cfsetospeed(struct termios *termios_p, speed_t speed); //设置输出波特率
int cfsetispeed(struct termios *termios_p, speed_t speed); //设置输入波特率
线路控制函数:
int tcdrain(int fd); //等待所有输出都被发送
int tcflush(int fd, int queue_selector); //flush输入/输出缓存
int tcflow(int fd, int action); //对输入和输出流进行控制
int tcsendbreak(int fd, int duration); //发送break
2.对tty设备节点进行ioctl()调用
termios库函数会被转化为对tty设备节点的ioctl()调用。
UART设备驱动:
linux内涵在serial_core.c文件中实现了UART设备的通用tty驱动层(串口核心层)。因此UART驱动的任务就变为实现serial_core.c中定义的一组uart_xxx接口。
串口核心层为串口设备驱动提供了3个结构体: uart_driver, uart_port, uart_ops。
struct uart_driver {
struct module *owner;
const char *driver_name;
const char *dev_name;
int major;
int minor;
int nr;
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驱动注册/注销函数:
int uart_register_driver(struct uart_driver *drv);
void uart_unregister_driver(struct uart_driver *drv);
这两个函数的实现,包含了tty_register_driver()和tty_unregister_driver()。
struct uart_port {
spinlock_t lock; /* port lock */
unsigned long iobase; /* in/out[bwl] */IO端口基地址
unsigned char __iomem *membase; /* read/write[bwl] */IO内存基地址
unsigned int (*serial_in)(struct uart_port *, int);
void (*serial_out)(struct uart_port *, int, int);
unsigned int irq; /* irq number */
unsigned long irqflags; /* irq flags */
unsigned int uartclk; /* base uart clock */
unsigned int fifosize; /* tx fifo size */
unsigned char x_char; /* xon/xoff char */
unsigned char regshift; /* reg offset shift */
unsigned char iotype; /* io access style */
unsigned char unused1;
#define UPIO_PORT (0)
#define UPIO_HUB6 (1)
#define UPIO_MEM (2)
#define UPIO_MEM32 (3)
#define UPIO_AU (4) /* Au1x00 type IO */
#define UPIO_TSI (5) /* Tsi108/109 type IO */
#define UPIO_DWAPB (6) /* DesignWare APB UART */
#define UPIO_RM9000 (7) /* RM9000 type IO */
unsigned int read_status_mask; /* driver specific */驱动特定的读状态掩码
unsigned int ignore_status_mask; /* driver specific */驱动特定的忽略状态掩码
struct uart_state *state; /* pointer to parent state */
struct uart_icount icount; /* statistics */
struct console *cons; /* struct console, if any */
#if defined(CONFIG_SERIAL_CORE_CONSOLE) || defined(SUPPORT_SYSRQ)
unsigned long sysrq; /* sysrq timeout */
#endif
upf_t flags;
#define UPF_FOURPORT ((__force upf_t) (1 << 1))
#define UPF_SAK ((__force upf_t) (1 << 2))
#define UPF_SPD_MASK ((__force upf_t) (0x1030))
#define UPF_SPD_HI ((__force upf_t) (0x0010))
#define UPF_SPD_VHI ((__force upf_t) (0x0020))
#define UPF_SPD_CUST ((__force upf_t) (0x0030))
#define UPF_SPD_SHI ((__force upf_t) (0x1000))
#define UPF_SPD_WARP ((__force upf_t) (0x1010))
#define UPF_SKIP_TEST ((__force upf_t) (1 << 6))
#define UPF_AUTO_IRQ ((__force upf_t) (1 << 7))
#define UPF_HARDPPS_CD ((__force upf_t) (1 << 11))
#define UPF_LOW_LATENCY ((__force upf_t) (1 << 13))
#define UPF_BUGGY_UART ((__force upf_t) (1 << 14))
#define UPF_NO_TXEN_TEST ((__force upf_t) (1 << 15))
#define UPF_MAGIC_MULTIPLIER ((__force upf_t) (1 << 16))
#define UPF_CONS_FLOW ((__force upf_t) (1 << 23))
#define UPF_SHARE_IRQ ((__force upf_t) (1 << 24))
/* The exact UART type is known and should not be probed. */
#define UPF_FIXED_TYPE ((__force upf_t) (1 << 27))
#define UPF_BOOT_AUTOCONF ((__force upf_t) (1 << 28))
#define UPF_FIXED_PORT ((__force upf_t) (1 << 29))
#define UPF_DEAD ((__force upf_t) (1 << 30))
#define UPF_IOREMAP ((__force upf_t) (1 << 31))
#define UPF_CHANGE_MASK ((__force upf_t) (0x17fff))
#define UPF_USR_MASK ((__force upf_t) (UPF_SPD_MASK|UPF_LOW_LATENCY))
unsigned int mctrl; /* current modem ctrl settings */
unsigned int timeout; /* character-based timeout */
unsigned int type; /* port type */
const struct uart_ops *ops;
unsigned int custom_divisor;
unsigned int line; /* port index */
resource_size_t mapbase; /* for ioremap */
struct device *dev; /* parent device */
unsigned char hub6; /* this should be in the 8250 driver */
unsigned char suspended;
unsigned char unused[2];
void *private_data; /* generic platform data pointer */
};
uart_port用于描述一个UART端口到IO端口或IO内存地址,FIFO大小,端口类型等信息。
添加/删除端口函数:
int uart_add_one_port(struct uart_driver *drv, struct uart_port *port);
int uart_remove_one_port(struct uart_driver *drv, struct uart_port *port);
struct uart_ops {
unsigned int (*tx_empty)(struct uart_port *);
void (*set_mctrl)(struct uart_port *, unsigned int mctrl);
unsigned int (*get_mctrl)(struct uart_port *);
void (*stop_tx)(struct uart_port *);
void (*start_tx)(struct uart_port *);
void (*send_xchar)(struct uart_port *, char ch);
void (*stop_rx)(struct uart_port *);
void (*enable_ms)(struct uart_port *);
void (*break_ctl)(struct uart_port *, int ctl);
int (*startup)(struct uart_port *);
void (*shutdown)(struct uart_port *);
void (*flush_buffer)(struct uart_port *);
void (*set_termios)(struct uart_port *, struct ktermios *new,
struct ktermios *old);
void (*set_ldisc)(struct uart_port *);
void (*pm)(struct uart_port *, unsigned int state,
unsigned int oldstate);
int (*set_wake)(struct uart_port *, unsigned int state);
/*
* Return a string describing the type of the port
*/
const char *(*type)(struct uart_port *);
/*
* Release IO and memory resources used by the port.
* This includes iounmap if necessary.
*/
void (*release_port)(struct uart_port *);
/*
* Request IO and memory resources used by the port.
* This includes iomapping the port if necessary.
*/
int (*request_port)(struct uart_port *);
void (*config_port)(struct uart_port *, int);
int (*verify_port)(struct uart_port *, struct serial_struct *);
int (*ioctl)(struct uart_port *, unsigned int, unsigned long);
#ifdef CONFIG_CONSOLE_POLL
void (*poll_put_char)(struct uart_port *, unsigned char);
int (*poll_get_char)(struct uart_port *);
#endif
};
uart_ops定义了对UART的一系列操作,包括发送,接收及线路设置等。
struct tty_struct {
int
magic;
struct kref kref;
struct tty_driver *driver;
const struct tty_operations *ops;
int index;
/* The ldisc objects are protected by tty_ldisc_lock at the moment */
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 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))];
int canon_data;
unsigned long canon_head;
unsigned int canon_column;
struct mutex atomic_read_lock;
struct mutex atomic_write_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;
};