linux串口终端驱动——s3c6410平台(三)

时间:2021-12-06 02:20:54

接着上一篇linux串口终端驱动——s3c6410平台(二)继续分析

上一篇关注的是tty上层字符层面的操作和注册,这一篇主要关注线程的注册,如何与上层建筑联系起来。

一、 tty_ldisc.c提供了tty_register_ldisc()接口用于注册线路规程,例如/driver/char/n_tty.c文件则针对N_TTY线路规程实现了具体的tty_disc结构体中的成员。

tty_register_ldisc(N_TTY, &tty_ldisc_N_TTY)

其中有

#define N_TTY 0

struct tty_ldisc_ops tty_ldisc_N_TTY = {
.magic           = TTY_LDISC_MAGIC,
.name            = "n_tty",
.open            = n_tty_open,
.close           = n_tty_close,
.flush_buffer    = n_tty_flush_buffer,
.chars_in_buffer = n_tty_chars_in_buffer,
.read            = n_tty_read,
.write           = n_tty_write,
.ioctl           = n_tty_ioctl,
.set_termios     = n_tty_set_termios,
.poll            = n_tty_poll,
.receive_buf     = n_tty_receive_buf,
.write_wakeup    = n_tty_write_wakeup
};

对应的原型为

struct tty_ldisc_ops {
int magic;
char *name;
int num;
int flags;

/*
* The following routines are called from above.
*/
int (*open)(struct tty_struct *);
void (*close)(struct tty_struct *);
void (*flush_buffer)(struct tty_struct *tty);
ssize_t (*chars_in_buffer)(struct tty_struct *tty);
ssize_t (*read)(struct tty_struct * tty, struct file * file,
unsigned char __user * buf, size_t nr);
ssize_t (*write)(struct tty_struct * tty, struct file * file,
const unsigned char * buf, size_t nr);
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);
unsigned int (*poll)(struct tty_struct *, struct file *,
    struct poll_table_struct *);
int (*hangup)(struct tty_struct *tty);
/*
* The following routines are called from below.
*/
void (*receive_buf)(struct tty_struct *, const unsigned char *cp,
      char *fp, int count);

void(*write_wakeup)(struct tty_struct *);
struct  module *owner;
int refcount;
};


struct tty_ldisc {
struct tty_ldisc_ops *ops;
int refcount;
};

二、而tty_register_ldisc函数则把具体的struct tty_disc添加到线程安装表中的对应编号处,本例为0出,因为N_TTY为0注:这里还没有和tty上层连接起来,只是添加到了线程规划表中。

源码如下:

/* Line disc dispatch table */
static struct tty_ldisc_ops *tty_ldiscs[NR_LDISCS];

所有安装线程表

/**
 *tty_register_ldisc-install a line discipline安装一个线程规划
 *@disc: ldisc number ldisc的编号
 *@new_ldisc: pointer to the ldisc object指向新安装的ldsic的操作函数
 *
 *Installs a new line discipline into the kernel. The discipline
 *is set up as unreferenced and then made available to the kernel
 *from this point onwards.
 *
 *Locking:加锁保护
 *takes tty_ldisc_lock to guard against ldisc races
 */
int tty_register_ldisc(int disc, struct tty_ldisc_ops *new_ldisc)

对照tty_register_ldisc(N_TTY, &tty_ldisc_N_TTY)和

static struct tty_ldisc_ops *tty_ldiscs[NR_LDISCS]即可看明
{
unsigned long flags;
int ret = 0;

if (disc < N_TTY || disc >= NR_LDISCS)判断编号是否符合
return -EINVAL;
spin_lock_irqsave(&tty_ldisc_lock, flags);
tty_ldiscs[disc] = new_ldisc;
new_ldisc->num = disc;
new_ldisc->refcount = 0;

spin_unlock_irqrestore(&tty_ldisc_lock, flags);
return ret;
}
EXPORT_SYMBOL(tty_register_ldisc);

三、当然有注册,就有注销,只不过不常用。

/**
 * tty_unregister_ldisc-unload a line discipline
 * @disc: ldisc number
 * @new_ldisc: pointer to the ldisc object
 *
 * Remove a line discipline from the kernel providing it is not
 * currently in use.
 *
 * Locking:
 * takes tty_ldisc_lock to guard against ldisc races
 */


int tty_unregister_ldisc(int disc)
{
unsigned long flags;
int ret = 0;


if (disc < N_TTY || disc >= NR_LDISCS)
return -EINVAL;


spin_lock_irqsave(&tty_ldisc_lock, flags);
if (tty_ldiscs[disc]->refcount)
ret = -EBUSY;
else
tty_ldiscs[disc] = NULL;
spin_unlock_irqrestore(&tty_ldisc_lock, flags);
return ret;
}
EXPORT_SYMBOL(tty_unregister_ldisc);

四:和上层tty连接

每个终端设备都有个struct tty_struct结构体,可能被包含在一个更大的结构体中。

/*
 * Where all of the state associated with a tty is kept while the tty
 * is open.
 Since the termios state should be kept even if the tty
 * has been closed --- for things like the baud rate, etc --- it is
 * not stored here, but rather a pointer to the real state is stored
 * here.  Possible the winsize structure should have the same
 * treatment, but (1) the default 80x24 is usually right and (2) it's
 * most often used by a windowing system, which will set the correct
 * size each time the window is created or resized anyway.
 * - TYT, 9/14/92
 */

struct tty_operations;
struct tty_struct {
intmagic;
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;
};