Tty driver Architecture Analysis for Linux device models

Source: Internet
Author: User

---------------------------------------- This article is the original site, welcome to reprint! Reprinted please indicate the source: http://ericxiao.cublog.cn/http://blog.chinaunix.net/uid-20543183-id-1930820.html
------------------------------------------ 1: The forward tty name is derived from the abbreviation of byte by telex. Linux represents various terminals. Terminals usually correspond to hardware. For example, it corresponds to the keyboard and mouse of the input device. The control terminal and serial port terminal of the output device display also have the Pty driver corresponding to the non-device. Among so many terminal models, how does Linux model them in a unified manner? This is the question we will discuss today. ii. tty driver overview tty architecture is as follows: As shown in, the user space interacts with tty_core through device files. tty_core selects to interact with line discipline and tty_driver based on the type of space operation. for example, the ioctl command of the hardware is directly sent to tty_driver for processing. The read and write operations will be handed over to the line discipline for processing. Line discipline is the meaning of the line procedure. Like its name, it indicates the input and output specification settings of the "Thread" of the terminal. It is mainly used for preprocessing of input/output data. After processing. The data will be handed over to tty_drivertty_driver, which is the driver corresponding to the terminal. It converts characters into strings that can be understood by the terminal and transmits them to the terminal device. It is worth noting that this architecture does not provide read operations for tty_dritherefore. That is to say, neither tty_core nor line discipline can directly read terminal information from tty_driver. This is because the hardware of the tty_driver pair is not necessarily the common load of the input and output data. For example, the output device of a control terminal is a display. The input device is a keyboard. Based on this principle. In line
The discipline has an input cache. And provides an interface function called receive_buf. The corresponding terminal device only needs to call the receiver_buf function of line discipine to write data to the input cache. If a device is both an input device and an output device. Call receive_buf () to write data to the Interrupt Processing of the device. 3. For the TTY Driver Interface analysis, see ldd3. Here, we only perform an analysis on its interface implementation. All operations of tty driver are included in tty_driver. The kernel provides alloc_tty_driver () to allocate the tty_driver. Of course, we can also define it as a static structure in our own driver. Call tty_register_driver () to register tty_driver after necessary initialization. the code of the alloc_tty_driver () interface is as follows: struct tty_driver * alloc_tty_driver (INT lines) {struct tty_driver * driver; driver = kzarloc (sizeof (struct tty_driver), gfp_kernel) {driver-> magic = tty_driver_magic; driver-> num = lines;/* later we'll move allocation of tables here */} return driver;} This function has only one parameter. This parameter indicates the number of lines. That is, the number of device numbers. Note that each device file corresponds to a line. in this interface, allocate memory for tty_driver, and then choose driver> mage. driver-> num is returned after initialization. tty_register_driver () is used to register a tty_driver. The Code is as follows: int tty_register_driver (struct tty_driver * driver) {int error; int I; dev_t dev; void ** P = NULL; // tty_driver_installed: if (Driver-> flags & tty_driver_installed) return 0; // tty_driver_devpts_mem: Use devpts for dynamic memory ing if (! (Driver-> flags & tty_driver_devpts_mem) & driver-> num) {P = kzarloc (Driver-> num * 3 * sizeof (void *), gfp_kernel); If (! P) Return-enomem;} // register the character device number // If driver-> major if (! 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) {driver-> TTYs = (struct tty_struct **) P; driver-> termios = (struct ktermios **) (p + driver-> num ); driver-> termios_locked = (struct ktermios **) (p + driv Er-> num * 2);} else {driver-> TTYs = NULL; driver-> termios = NULL; driver-> termios_locked = NULL ;} // register the character device 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 = driver-> termios_locked = NULL; kfree (p); Return Error;} // specify the default put_ch Ar if (! Driver-> put_char) driver-> put_char = cursor; mutex_lock (& tty_mutex); list_add (& driver-> tty_drivers, & tty_drivers); mutex_unlock (& tty_mutex ); // If tty_driver_dynamic_dev. that is, dynamic device management if (! (Driver-> flags & tty_driver_dynamic_dev) {for (I = 0; I <driver-> num; I ++) tty_register_device (driver, I, null );} proc_tty_register_driver (driver); Return 0;} this function is relatively simple to operate. Creates a character device for tty_driver. Then, specify the operation set of the character device as tty_fops and mount the tty_driver to the tty_drivers linked list. In fact, the function of this linked list is similar to the input_dev [] array in the input subsystem we analyzed previously. Find the corresponding driver with the device number as the keyword. If tty_driver_dynamic_dev. A class device will also be created in sysfs. this is mainly for udev to manage devices. the above operations are shown in a flowchart as follows: 4. Operations on device files are the focus of this section. Its main operation is to map the operations to ldsic or tty_driver. 4.1: the operations on the tty device can be seen from the registration process, and all the operations will correspond to tty_fops. The operation interface corresponding to the open operation is tty_open (). The Code is as follows: static int tty_open (struct inode * inode, struct file * filp) {struct tty_struct * tty; int noctty, retval; struct tty_driver * driver; int index; dev_t device = inode-> I _rdev; unsigned short saved_flags = filp-> f_flags; nonseekable_open (inode, filp); retry_open: // o_noctty if the path name points to the terminal device, do not use this device as the control terminal // noctty: you do not need to change the control terminal noctty = filp-> f_flags & o_noctty; Index =-1; retval = 0; mutex_lock (& tty _ Mutex); // The device number (5, 0), that is,/dev/tty. indicates the control terminal of the current process if (device = mkdev (ttyaux_major, 0) {tty = get_current_tty (); // if the control terminal of the current process does not exist, exit if (! TTY) {mutex_unlock (& tty_mutex); Return-enxio;} // get the tty_driver driver of the current process = tty-> driver; Index = tty-> index; filp-> f_flags | = o_nonblock;/* Don't let/dev/tty block * // * noctty = 1; */goto got_driver ;} # ifdef config_vt // device number ). that is,/dev/tty0: indicates the current console if (device = mkdev (tty_major, 0) {extern struct tty_driver * console_driver; driver = console_driver; // fg_console: indicates the current console Index = fg_console; Noctty = 1; goto got_driver;} # endif // device number (5, 1 ). that is,/dev/console. indicates the external console. use regesit_console () if (device = mkdev (ttyaux_major, 1) {driver = lele_device (& Index); If (driver) {/* Don't let/dev/console block */filp-> f_flags | = o_nonblock; noctty = 1; goto got_driver;} mutex_unlock (& tty_mutex ); return-enodev;} // search for the registered driver = get_tty_driver (device, & Index) in tty_drivers with the keyword "device ); If (! Driver) {mutex_unlock (& tty_mutex); Return-enodev;} got_driver: // index indicates its next device number retval = init_dev (driver, index, & TTY ); mutex_unlock (& tty_mutex); If (retval) return retval; filp-> private_data = tty; file_move (filp, & tty-> tty_files); check_tty_count (TTY, "tty_open "); if (tty-> driver-> type = tty_driver_type_pty & tty-> driver-> subtype = pty_type_master) noctty = 1; # ifdef tty_debug_hangup printk (Ke Rn_debug "Opening % s...", tty-> name); # endif if (! Retval) {If (tty-> driver-> open) retval = tty-> driver-> open (TTY, filp); else retval =-enodev ;} filp-> f_flags = saved_flags; If (! Retval & test_bit (tty_exclusive, & tty-> flags )&&! Capable (cap_sys_admin) retval =-ebusy; If (retval) {# ifdef tty_debug_hangup printk (kern_debug "error % d in opening % s... ", retval, tty-> name); # endif release_dev (filp); If (retval! =-Erestartsys) return retval; If (signal_pending (current) return retval; schedule ();/** need to reset f_op in case a hangup happened. */If (filp-> f_op = & hung_up_tty_fops) filp-> f_op = & tty_fops; goto retry_open;} mutex_lock (& tty_mutex ); spin_lock_irq (& Current-> sighand-> siglock); // set the terminal of the current process if (! Noctty & Current-> signal-> leader &&! Current-> signal-> tty & tty-> session = NULL) _ proc_set_tty (current, TTY); spin_unlock_irq (& Current-> sighand-> siglock ); mutex_unlock (& tty_mutex); tty_audit_opening (); Return 0 ;}note that there is an easy-to-ignore operation here: init_dev (). Init_dev ()-à initialize_tty_struct () à pretty (TTY, tty_ldisc_get (n_tty); take a look at the operations of compile (TTY, tty_ldisc_get (n_tty): tty_ldisc_get (): struct tty_ldisc * struct (INT disc) {unsigned long flags; struct tty_ldisc * LD; If (disc <n_tty | disc> = nr_ldiscs) return NULL; spin_lock_irqsave (& signature, flags); LD = & tty_ldiscs [Disc];/* check the entry is defined */If (LD-> flags & Ldisc_flag_defined) {/* If the module is being unloaded we can't use it */If (! Try_module_get (LD-> owner) LD = NULL; else/* Lock it */LD-> refcount ++;} else LD = NULL; spin_unlock_irqrestore (& tty_ldisc_lock, flags ); return LD;} the operation of this function is to locate the corresponding item in tty_ldiscs. the members in this array call tty_register_ldisc () to set it. the tty_ldisc_assign operation is as follows: static void tty_ldisc_assign (struct tty_struct * tty, struct tty_ldisc * LD) {tty-> ldisc = * LD; tty-> ldisc. refcount = 0;} The retrieved idisc is used as the tty-> ldisc field. in this Code, tty_dri is involved. Ver, tty_struct, struct tty_ldisc. the relationship between the three is represented as follows: Here, ldisc for tty_struct is specified as tty_ldiscs [n_tty] by default. this ldisc corresponds to the line specification of the control terminal. You can use IOCTL with tiocsetd to call the ioctl in the space. the above open is shown in a flowchart as follows: 4.2: The write operation of the device file corresponding to tty_fops-> write is tty_write (). code: static ssize_t tty_write (struct file * file, const char _ User * Buf, size_t count, loff_t * PPOs) {struct tty_struct * tty; struct inode * inode = file-> f_path.dentry-> d_inode; ssize_t ret; struct tty_ldisc * LD; tty = (struct tty_struct *) file-> private_data; If (TTY, inode, "Tty_write") Return-EIO; If (! Tty |! Tty-> driver-> write | (test_bit (tty_io_error, & tty-> flags) Return-EIO; LD = tty_ldisc_ref_wait (TTY); If (! LD-> write) ret =-EIO; else ret = do_tty_write (LD-> write, tty, file, Buf, count); tty_ldisc_deref (LD); return ret ;} during the open process, tty_struc

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.