Linux tty driver

Source: Internet
Author: User

Tty architecture is divided into three layers:
Level 1:
Tty_core
The top-layer architecture of all tty drivers provides a unified interface to the application. The read/write calls at the application layer will first arrive here. This layer is implemented by the kernel and the code is mainly distributed in
The n_tty.c and tty_io.c files in the drivers/Char directory
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,
};
The tty_register_driver function is called when a tty driver is registered.
Int tty_register_driver (struct tty_driver * driver)
{
...
Cdev_init (& driver-> cdev, & tty_fops );
...
}
Static ssize_t tty_read (struct file * file, char _ User * Buf, size_t count,
Loff_t * PPOs)
{
...
LD = tty_ldisc_ref_wait (TTY );
If (LD-> OPS-> Read)
I = (LD-> OPS-> Read) (TTY, file, Buf, count );
// Call the READ function of the ldisc layer (line procedure)
Else
I =-EIO;
Tty_ldisc_deref (LD );
...
}
Static ssize_t tty_write (struct file * file, const char _ User * Buf,
Size_t count, loff_t * PPOs)
{
...
LD = tty_ldisc_ref_wait (TTY );
If (! LD-> OPS-> write)
Ret =-EIO;
Else
Ret = do_tty_write (LD-> OPS-> write, tty, file, Buf, count );
Tty_ldisc_deref (LD );
Return ret;
}
Static inline ssize_t do_tty_write (
Ssize_t (* write) (struct tty_struct *, struct file *, const unsigned char *, size_t ),
Struct tty_struct * tty,
Struct file * file,
Const char _ User * Buf,
Size_t count)
{
...
For (;;){
Size_t size = count;
If (size> chunk)
Size = chunk;
Ret =-efault;
If (copy_from_user (tty-> write_buf, Buf, size ))
Break;
Ret = write (TTY, file, tty-> write_buf, size );
// Call the write function at the ldisc Layer
If (Ret <= 0)
Break;
...
}
Layer 2: line procedure
Different tty devices have different line procedures. This layer is also implemented by the kernel. The main code is in the drivers/Char. tty_ldisc.c file.
From the tty_read/tty_write function, we can see that they finally called the read/write function of the line procedure.
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
};
Static ssize_t n_tty_write (struct tty_struct * tty, struct file * file,
Const unsigned char * Buf, size_t nr)
{
...
Add_wait_queue (& tty-> write_wait, & wait); // put the current process in the waiting queue
While (1 ){
Set_current_state (task_interruptible );
If (signal_pending (current )){
Retval =-erestartsys;
Break;
}
// The reason for continued execution may be that the signal is interrupted, rather than the condition is met.
// We will continue only when the conditions are met. Otherwise, we will return directly!
If (tty_hung_up_p (File) | (tty-> link &&! Tty-> link-> count )){
Retval =-EIO;
Break;
}
If (o_opost (TTY )&&! (Test_bit (tty_hw_cook_out, & tty-> flags ))){
While (NR> 0 ){
Ssize_t num = process_output_block (TTY, B, NR );
If (Num <0 ){
If (num =-eagain)
Break;
Retval = num;
Goto break_out;
}
B + = num;
NR-= num;
If (Nr = 0)
Break;
C = * B;
If (process_output (C, TTY) <0)
Break;
B ++; NR --;
}
If (tty-> OPS-> flush_chars)
Tty-> OPS-> flush_chars (TTY );
} Else {
While (NR> 0 ){
C = tty-> OPS-> write (TTY, B, NR );
// Call the write function in the specific driver
If (C <0 ){
Retval = C;
Goto break_out;
}
If (! C)
Break;
B + = C;
NR-= C;
}
}
If (! NR)
Break;
// Write all and return
If (file-> f_flags & o_nonblock ){
Retval =-eagain;
Break;
}
/*
If it is opened in a non-blocking manner, it is returned directly. Otherwise, let out the CPU and wait until the conditions are met before execution.
*/

Schedule (); // execute here, the current process will actually let out the CPU !!!
}
Break_out:
_ Set_current_state (task_running );
Remove_wait_queue (& tty-> write_wait, & wait );
...
}

Blocking is implemented in the ldisc layer, that is, the line rules. For the sake of cost and operability, we will no longer implement the write/read function of the blocking type.

The above code contains a sentence:
C = tty-> OPS-> write (TTY, B, NR );
This Code calls the OPS-> write function of the tty_struct structure. But what is the relationship between OPS-> write in the tty_struct structure and the write function defined in the specific driver?
Tty_open-> tty_init_dev-> initialize_tty_struct
Driver/Char/tty_io.c
Void initialize_tty_struct (struct tty_struct * tty,
Struct tty_driver * driver, int idx)
{
...
Tty-> Ops = driver-> OPS;
...
}
It can be seen that when the tty device is turned on, the ops pointer of the driver is assigned to the OPs of the tty_struct struct of the tty device.
In this way, tty-> OPS-> write () actually calls the specific driver's write function. For example, if it is a serial driver, it will call the write function of the serial driver!
The n_tty_read operation is complicated and is not discussed for the moment. However, it will eventually call the specific tty-driven READ function.

Layer 3:
The specific tty driver is implemented by us.
For example, the following is a piece of code from serial_core.c, which describes the serial port driver:
Static const struct tty_operations uart_ops = {
. Open = uart_open,
. Close = uart_close,
. Write = uart_write,
. Put_char = uart_put_char,
. Flush_chars = uart_flush_chars,
. Write_room = uart_write_room,
. Chars_in_buffer = uart_chars_in_buffer,
. Flush_buffer = uart_flush_buffer,
. IOCTL = uart_ioctl,
. Throttle = uart_throttle,
. Unthrottle = uart_unthrottle,
. Send_xchar = uart_send_xchar,
. Set_termios = uart_set_termios,
. Set_ldisc = uart_set_ldisc,
. Stop = uart_stop,
. Start = uart_start,
. Hangup = uart_hangup,
. Break_ctl = uart_break_ctl,
. Wait_until_sent = uart_wait_until_sent,
# Ifdef config_proc_fs
. Read_proc = uart_read_proc,
# Endif
. Tiocmget = uart_tiocmget,
. Tiocmset = uart_tiocmset,
# Ifdef config_console_poll
. Poll_init = uart_poll_init,
. Poll_get_char = uart_poll_get_char,
. Poll_put_char = uart_poll_put_char,
# Endif
};
Int uart_register_driver (struct uart_driver * DRV)
{
Struct tty_driver * normal = NULL;
DRV-> tty_driver = normal;

Normal-> owner = DRV-> owner;
Normal-> driver_name = DRV-> driver_name;
Normal-> name = DRV-> dev_name;
Normal-> major = DRV-> Major;
Normal-> minor_start = DRV-> minor;
Normal-> type = tty_driver_type_serial;
Normal-> subtype = serial_type_normal;
Normal-> init_termios = tty_std_termios;
Normal-> init_termios.c_cflag = b9600 | cs8 | cread | hupcl | clocal;
Normal-> init_termios.c_ispeed = normal-> init_termios.c_ospeed= 9600;
Normal-> flags = tty_driver_real_raw | tty_driver_dynamic_dev;
Normal-> driver_state = DRV;
Tty_set_operations (normal, & uart_ops );//##
...
}
We mainly implement the functions of this layer. The first two layers are implemented in the kernel, and we only need to apply them. When we write this driver in tty driver format and implement several necessary functions, this driver can run successfully.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.