




版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)
文檔簡(jiǎn)介
1、Linux設(shè)備模型之終端設(shè)備(tty)驅(qū)動(dòng)架構(gòu)分析* 本文系本站原創(chuàng),歡迎轉(zhuǎn)載!轉(zhuǎn)載請(qǐng)注明出處: http:/ 這里感謝:曉剛的分析和指點(diǎn),及網(wǎng)上的所有串口資源*一 :前言終端設(shè)備在Linux系統(tǒng)中,終端是一種字符型設(shè)備,它有多種類型,通常使用tty來簡(jiǎn)稱各種類型的終端設(shè)備。tty是Teletype的縮寫,Teletype是最早出現(xiàn)的一種終端設(shè)備,很像電傳打字機(jī),是由Teletype公司生產(chǎn)的。Linux中包含如下幾類終端設(shè)備:1.串行端口終端(/dev/ttySn)串行端口終端(Serial Port Terminal)是使用計(jì)算機(jī)串行端口連接的終端設(shè)備。2.偽終端(/dev/pty/)偽終
2、端(Pseudo Terminal)是成對(duì)的邏輯終端設(shè)備3.控制臺(tái)終端(/dev/ttyn, /dev/console)二:終端設(shè)備驅(qū)動(dòng)結(jié)構(gòu)1.Tty架構(gòu)如下所示:Tty_core: Tty核心層Line discipline : 是線路規(guī)程的意思(鏈路層)。正如它的名字一樣,它表示的是這條終端”線程”的輸入與輸出規(guī)范設(shè)置.主要用來進(jìn)行輸入/輸出數(shù)據(jù)的預(yù)處理Tty_driver: Tty_driver就是終端對(duì)應(yīng)的驅(qū)動(dòng)了。它將字符轉(zhuǎn)換成終端可以理解的字串.將其傳給終端設(shè)備。tty設(shè)備發(fā)送數(shù)據(jù)的流程為:tty_core從一個(gè)用戶獲得將要發(fā)送給一個(gè)tty設(shè)備的數(shù)據(jù),tty_core將數(shù)據(jù)傳遞給Li
3、ne discipline處理,接著數(shù)據(jù)被傳遞到tty_driver,tty驅(qū)動(dòng)將數(shù)據(jù)轉(zhuǎn)換為可以發(fā)送給硬件的格式tty設(shè)備接受數(shù)據(jù)的流程為:從tty硬件接收到得數(shù)據(jù)向上交給tty_driver,進(jìn)入Line discipline處理,再進(jìn)入tty_core,在這里它被一個(gè)用戶獲取盡管大多數(shù)時(shí)候tty_core和tty_driver之間的數(shù)據(jù)傳輸會(huì)經(jīng)歷Line discipline的轉(zhuǎn)換,但是tty_core和tty_driver之間也可以直接傳輸數(shù)據(jù)2.tty主要源文件關(guān)系及數(shù)據(jù)流向:圖二:tty主要源文件關(guān)系及數(shù)據(jù)流向上圖顯示了與tty相關(guān)的主要源文件及數(shù)據(jù)流向。tty_io.c:tty_i
4、o.c定義了tty設(shè)備通用的的file_operation結(jié)構(gòu)體,并實(shí)現(xiàn)了接口函數(shù)tty_register_driver()用于注冊(cè)tty設(shè)備,它會(huì)利用fs/char_dev.c提供的接口函數(shù)注冊(cè)字符設(shè)備。tty_io.c也提供了tty_register_ldisc()接口函數(shù),用于注冊(cè)線路規(guī)程。xxx_tty.c:與具體設(shè)備對(duì)應(yīng)的tty驅(qū)動(dòng)(xxx_tty.c)將實(shí)現(xiàn)tty_driver結(jié)構(gòu)體中的成員函數(shù)。Ntty.c:ntty.c文件則實(shí)現(xiàn)了tty_disc結(jié)構(gòu)體中的成員特定tty設(shè)備的主體工作是填充tty_driver結(jié)構(gòu)體中的成員,實(shí)現(xiàn)其中的成員函數(shù),tty_driver結(jié)構(gòu)體的源碼(
5、linux/driver/char/tty_driver.h)如下:struct tty_driver int magic; /* magic number for this structure */struct cdev cdev;struct module *owner;const char *driver_name;const char *devfs_name;const char *name;int name_base; /* offset of printed name */int major; /* major device number */int minor_start; /*
6、 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 termios init_termios; /* Initial termios */int flags; /* tty driver flags */int refcount; /*
7、 for loadable tty drivers */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 termios *termios;struct termios *termios_locked;void *driver_state; /* only used for the
8、 PTY driver */* Interface routines from the upper tty layer to the tty * driver. Will be replaced with struct tty_operations. */int (*open)(struct tty_struct * tty, struct file * filp); void (*close)(struct tty_struct * tty, struct file * filp); int (*write)(struct tty_struct * tty,const unsigned ch
9、ar *buf, int count);void (*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 lon
10、g arg);void (*set_termios)(struct tty_struct *tty, struct termios * 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);void (*break_ctl)(struct t
11、ty_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 (*read_proc)(char *page, char *start, off_t off,int count, int *eof,
12、void *data);int (*write_proc)(struct file *file, const char _user *buffer,unsigned long count, void *data);int (*tiocmget)(struct tty_struct *tty, struct file *file);int (*tiocmset)(struct tty_struct *tty, struct file *file,unsigned int set, unsigned int clear);struct list_head tty_drivers;三: tty驅(qū)動(dòng)接
13、口分析1.分配tty驅(qū)動(dòng)tty driver的所有操作都包含在tty_driver中。內(nèi)核即供了一個(gè)名叫alloc_tty_driver()來分配這個(gè)tty_driver。當(dāng)然我們也可以在自己的驅(qū)動(dòng)中將它定義成一個(gè)靜態(tài)的結(jié)構(gòu)。對(duì)tty_driver進(jìn)行一些必要的初始化之后,調(diào)用tty_register_driver()將其注冊(cè).alloc_tty_driver()接口代碼(Linux/driver/char/tty_io.c)如下所示:struct tty_driver *alloc_tty_driver(int lines)struct tty_driver *driver;driver =
14、 kmalloc(sizeof(struct tty_driver), GFP_KERNEL);if (driver) memset(driver, 0, sizeof(struct tty_driver);driver->magic = TTY_DRIVER_MAGIC;driver->num = lines;/* later we'll move allocation of tables here */return driver;這個(gè)函數(shù)只有一個(gè)參數(shù)。這個(gè)參數(shù)的含義為line的個(gè)數(shù)。也即次設(shè)備號(hào)的個(gè)數(shù)。注意每個(gè)設(shè)備文件都會(huì)對(duì)應(yīng)一個(gè)line.在這個(gè)接口里為tty_driv
15、er分配內(nèi)存,然后將driver->magic與driver->num初始化之后就返回了.其中driver->magic為tty_driver這個(gè)結(jié)構(gòu)體的“幻數(shù)”,設(shè)為TTY_DRIVER_MAGIC,在這里被初始化。2.注冊(cè)tty驅(qū)動(dòng)在這里,tty_register_driver()用來注冊(cè)一個(gè)(Linux/driver/char/tty_io.c):int tty_register_driver(struct tty_driver *driver)int error;int i;dev_t dev;void *p = NULL;if (driver->flags &
16、amp; TTY_DRIVER_INSTALLED)return 0;tty_driver,源碼如下/TTY_DRIVER_DEVPTS_MEM:使用devpts進(jìn)行動(dòng)態(tài)內(nèi)存映射 if (!(driver->flags & TTY_DRIVER_DEVPTS_MEM) p = kmalloc(driver->num * 3 * sizeof(void *), GFP_KERNEL); if (!p) return -ENOMEM; memset(p, 0, driver->num * 3 * sizeof(void *); / /如果沒有指定driver->ma
17、jor,注冊(cè)字符設(shè)備號(hào) if (!driver->major) error = alloc_chrdev_region(&dev, driver->minor_start, driver->num, (char*)driver->name); if (!error) driver->major = MAJOR(dev); driver->minor_start = MINOR(dev); else dev = MKDEV(driver->major, driver->minor_start); error = register_chrde
18、v_region(dev, driver->num, (char*)driver->name); if (error < 0) kfree(p);return error;if (p) driver->ttys = (struct tty_struct *)p;driver->termios = (struct termios *)(p + driver->num);driver->termios_locked = (struct termios *)(p + driver->num * 2); else driver->ttys = NU
19、LL;driver->termios = NULL;driver->termios_locked = NULL;/注冊(cè)字符設(shè)備cdev_init(&driver->cdev, &tty_fops);driver->cdev.owner = driver->owner;error = cdev_add(&driver->cdev, dev, driver->num);if (error) cdev_del(&driver->cdev);unregister_chrdev_region(dev, driver->
20、num);driver->ttys = NULL;driver->termios = driver->termios_locked = NULL;kfree(p);return error;/指定默認(rèn)的put_charif (!driver->put_char)driver->put_char = tty_default_put_char;list_add(&driver->tty_drivers, &tty_drivers);/如果沒有指定TTY_DRIVER_DYNAMIC_DEV.即動(dòng)態(tài)設(shè)備管理if ( !(driver->fla
21、gs & TTY_DRIVER_NO_DEVFS) ) for(i = 0; i < driver->num; i+)tty_register_device(driver, i, NULL);proc_tty_register_driver(driver);return 0;注冊(cè)tty驅(qū)動(dòng)成功時(shí)返回0;參數(shù)為由alloc_tty_driver()分配的tty_driver結(jié)構(gòu)體指針。 這個(gè)函數(shù)操作比較簡(jiǎn)單。就是為tty_driver創(chuàng)建字符設(shè)備。然后將字符設(shè)備的操作集指定為tty_fops.并且將tty_driver掛載到tty_drivers鏈表中。以設(shè)備號(hào)為關(guān)鍵字找到對(duì)
22、應(yīng)的driver.四:設(shè)備文件的打開操作1.打開tty設(shè)備的操作在下面得程序里,我們會(huì)遇到tty_struct結(jié)構(gòu)體,tty_struct結(jié)構(gòu)體被tty核心用來保存當(dāng)前tty端口的狀態(tài),它的大多數(shù)成員只被tty核心使用。從注冊(cè)的過程可以看到,所有的操作都會(huì)對(duì)應(yīng)到tty_fops中。Open操作對(duì)應(yīng)的操作接口是tty_open()。代碼如下(linux/drivers/char/tty_io.c):static int tty_open(struct inode * inode, struct file * filp)struct tty_struct *tty;int noctty, retv
23、al;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 如果路徑名指向終端設(shè)備,不要把這個(gè)設(shè)備用作控制端noctty:需不需要更改當(dāng)前進(jìn)程的控制終端*/noctty = filp->f_flags & O_NOCTTY;index = -1;retval = 0;/*O_NOCTTY 如果路徑名指向終端
24、設(shè)備,不要把這個(gè)設(shè)備用作控制終端*/down(&tty_sem);/設(shè)備號(hào)(5,0) 即/dev/tty.表示當(dāng)前進(jìn)程的控制終端if (device = MKDEV(TTYAUX_MAJOR,0) if (!current->signal->tty) /如果當(dāng)前進(jìn)程的控制終端不存在,退出up(&tty_sem);return -ENXIO;/取得當(dāng)前進(jìn)程的tty_driverdriver = current->signal->tty->driver;index =current->signal->tty->index;filp-&
25、gt;f_flags |= O_NONBLOCK; /* Don't let /dev/tty block */ /* noctty = 1; */goto got_driver;#ifdef CONFIG_VT/打開的設(shè)備節(jié)點(diǎn)是否是當(dāng)前的控制終斷/dev/ttys0/(4,0)if (device = MKDEV(TTY_MAJOR,0) extern struct tty_driver *console_driver;driver = console_driver;/fg_console: 表示當(dāng)前的控制臺(tái)index = fg_console;noctty = 0;goto got
26、_driver;#endif/設(shè)備號(hào)(5,1).即/dev/console.表示外接的控制臺(tái). 通過regesit_console() if (device = MKDEV(TTYAUX_MAJOR,1) driver = console_device(&index);if (driver) /* Don't let /dev/console block */filp->f_flags |= O_NONBLOCK;noctty = 0;goto got_driver;up(&tty_sem);return -ENODEV;/index 就是文件的設(shè)備號(hào)/以文件的設(shè)
27、備號(hào)為關(guān)鍵字,到tty_drivers中搜索所注冊(cè)的driver driver = get_tty_driver(device, &index);if (!driver) up(&tty_sem);return -ENODEV;got_driver:retval = init_dev(driver, index, &tty);up(&tty_sem);if (retval)return retval;filp->private_data = tty;file_move(filp, &tty->tty_files);/*這兒我們來看一下file
28、_move函數(shù),*void file_move(struct file *file, struct list_head *list)/(linux/fs.h)* if (!list)* return;* file_list_lock();* list_move(&file->f_u.fu_list, list);* file_list_unlock();*其中調(diào)用了list_move() ;*static inline void list_move(struct list_head *list, struct list_head *head)* _list_del(list-&g
29、t;prev, list->next);* list_add(list, head);*_list_del()*在了解數(shù)據(jù)結(jié)構(gòu)的基礎(chǔ)上,_list_del()很好理解,通過* next->prev = prev;* prev->next = next;*來刪除鏈表中的一個(gè)節(jié)點(diǎn),其中prev和next是節(jié)點(diǎn)的2個(gè)指針,分別指向鏈表中的上一個(gè)*節(jié)點(diǎn)和下一個(gè)節(jié)點(diǎn)。*還調(diào)用了_list_add();*下面繼續(xù)看一下_list_add(struct list_head *new,struct list_head *prev, Struct list_head *next) *是如何實(shí)現(xiàn)
30、的* next->prev = new;* new->next = next;* new->prev = prev;* prev->next = new;*通過上面的代碼來將節(jié)點(diǎn)new加入到節(jié)點(diǎn)prev和next中間*那么file_move的作用就是將file結(jié)構(gòu)體中的一些成員拷貝到tty->tty_file中去*/*下面來看一下check_tty_count();主要是查看一下tty_file鏈表中成員數(shù)*/check_tty_count(tty, "tty_open");if (tty->driver->type = TTY_D
31、RIVER_TYPE_PTY &&tty->driver->subtype = PTY_TYPE_MASTER)noctty = 0;#ifdef TTY_DEBUG_HANGUPprintk(KERN_DEBUG "opening %s.", tty->name);#endifif (!retval) if (tty->driver->open)/*tty核心調(diào)用tty驅(qū)動(dòng)的open回調(diào)函數(shù)*/retval = tty->driver->open(tty, filp);elseretval = -ENODEV;fi
32、lp->f_flags = saved_flags;/test_bit(n,addr)用于檢測(cè)地址中數(shù)據(jù)的某一位是否為1if (!retval && test_bit(TTY_EXCLUSIVE, &tty->flags) && !capable(CAP_SYS_ADMIN) retval = -EBUSY;/Capable()檢測(cè)進(jìn)程的能力用戶違反LIDS定義的規(guī)則的時(shí)候報(bào)警if (retval) #ifdef TTY_DEBUG_HANGUPprintk(KERN_DEBUG "error %d in opening %s.&q
33、uot;, retval,tty->name);#endifrelease_dev(filp);if (retval != -ERESTARTSYS)return retval;if (signal_pending(current)return retval;/signal_pending(current)檢查當(dāng)前進(jìn)程是否有信號(hào)處理,返回不為0表示有信號(hào)需要處理,這兒如果有信號(hào)需要處理,函數(shù)返回。schedule();/選定下一個(gè)進(jìn)程并切換到它去執(zhí)行是通過schedule()函數(shù)實(shí)現(xiàn)的。/* Need to reset f_op in case a hangup happened.*/i
34、f (filp->f_op = &hung_up_tty_fops)filp->f_op = &tty_fops;goto retry_open;if (!noctty &¤t->signal->leader &&!current->signal->tty &&tty->session = 0) task_lock(current);current->signal->tty = tty;task_unlock(current);current->signal-
35、>tty_old_pgrp = 0;tty->session = current->signal->session;tty->pgrp = process_group(current);return 0;上面的過程中我們漏掉了init_dev函數(shù),下面我們繼續(xù)解析一下:static int init_dev(struct tty_driver *driver, int idx, struct tty_struct *ret_tty)struct tty_struct *tty, *o_tty;struct termios *tp, *tp_loc, *o_tp,
36、*o_tp_loc;struct termios *ltp, *ltp_loc, *o_ltp, *o_ltp_loc;int retval=0;/* check whether we're reopening an existing tty */if (driver->flags & TTY_DRIVER_DEVPTS_MEM) tty = devpts_get_tty(idx);if (tty && driver->subtype = PTY_TYPE_MASTER)tty = tty->link; else tty = driver-&g
37、t;ttysidx;if (tty) goto fast_track;/* First time open is complex, especially for PTY devices.* This code guarantees that either everything succeeds and the* TTY is ready for operation, or else the table slots are vacated* and the allocated memory released. (Except that the termios* and locked termio
38、s may be retained.)*/*try_module_get() - 如果模塊已經(jīng)插入內(nèi)核,則遞增該模塊引用計(jì)數(shù);如果該模塊還沒有插入內(nèi)核,則返回0表示出錯(cuò)。Driver->owner是指這個(gè)驅(qū)動(dòng)模塊的擁有者*/if (!try_module_get(driver->owner) retval = -ENODEV;goto end_init;/如果模塊沒有加入內(nèi)核,那么退出o_tty = NULL;tp = o_tp = NULL;ltp = o_ltp = NULL;tty = alloc_tty_struct();/分配結(jié)構(gòu)體空間if(!tty)goto fail_
39、no_mem;initialize_tty_struct(tty);/初始化結(jié)構(gòu)體中的各成員變量tty->driver = driver;tty->index = idx;tty_line_name(driver, idx, tty->name);/打印一些提示信息/*我們知道偽終端(pty)也屬于終端設(shè)備的一種* TTY_DRIVER_DEVPTS_MEM - don't use the standard arrays, instead* use dynamic memory keyed through the devpts filesystem. This* is
40、 only applicable to the pty driver.所以下面是對(duì)于偽終端的一些初始化設(shè)置?看下面的設(shè)置應(yīng)該是關(guān)于控制臺(tái)終端的初始化*/if (driver->flags & TTY_DRIVER_DEVPTS_MEM) tp_loc = &tty->termios;ltp_loc = &tty->termios_locked; else tp_loc = &driver->termiosidx;/根據(jù)索引號(hào)到數(shù)組中查找對(duì)應(yīng)的termios結(jié)構(gòu)體 ltp_loc = &driver->termios_lock
41、edidx;/如果沒有查找到對(duì)應(yīng)的termios結(jié)構(gòu)體,那么我們就手動(dòng)分配一個(gè)if (!*tp_loc) tp = (struct termios *) kmalloc(sizeof(struct termios),GFP_KERNEL);if (!tp)goto free_mem_out;*tp = driver->init_termios;/用統(tǒng)一的init_termios結(jié)構(gòu)體來初始化它if (!*ltp_loc) /同上ltp = (struct termios *) kmalloc(sizeof(struct termios),GFP_KERNEL);if (!ltp)goto
42、 free_mem_out;memset(ltp, 0, sizeof(struct termios);if (driver->type = TTY_DRIVER_TYPE_PTY) o_tty = alloc_tty_struct();if (!o_tty)goto free_mem_out;initialize_tty_struct(o_tty);/*如果是PTY,那么o_tty->driver = driver->other;查看tty_driver中對(duì)于other的定義*/o_tty->driver = driver->other;o_tty->in
43、dex = idx;tty_line_name(driver->other, idx, o_tty->name);/打印一些提示信息if (driver->flags & TTY_DRIVER_DEVPTS_MEM) o_tp_loc = &o_tty->termios;o_ltp_loc = &o_tty->termios_locked; else o_tp_loc = &driver->other->termiosidx;o_ltp_loc = &driver->other->termios_lo
44、ckedidx;if (!*o_tp_loc) /如果o_tp_loc = &o_tty->termios不存在,那么我們分配一個(gè)termios結(jié)構(gòu)體o_tp = (struct termios *)kmalloc(sizeof(struct termios), GFP_KERNEL);if (!o_tp)goto free_mem_out;*o_tp = driver->other->init_termios;if (!*o_ltp_loc) o_ltp = (struct termios *)kmalloc(sizeof(struct termios), GFP_
45、KERNEL);if (!o_ltp)goto free_mem_out;memset(o_ltp, 0, sizeof(struct termios);/* Everything allocated . set up the o_tty structure.*/if (!(driver->other->flags & TTY_DRIVER_DEVPTS_MEM) driver->other->ttysidx = o_tty;/將我們初始化的的偽終端的tty_struct結(jié)構(gòu)體添加到數(shù)組中去if (!*o_tp_loc)/如果o_tp_loc還是不存在,那么我用
46、o_tp來初始化o_tp_loc,不過為什么會(huì)不存在呢?上面已經(jīng)很系統(tǒng)的處理的一次*o_tp_loc = o_tp;if (!*o_ltp_loc)*o_ltp_loc = o_ltp;o_tty->termios = *o_tp_loc;o_tty->termios_locked = *o_ltp_loc;driver->other->refcount+;if (driver->subtype = PTY_TYPE_MASTER)o_tty->count+;/* Establish the links in both directions */tty-&g
47、t;link = o_tty;o_tty->link = tty;/* All structures have been allocated, so now we install them.* Failures after this point use release_mem to clean up, so* there's no need to null out the local pointers.*/if (!(driver->flags & TTY_DRIVER_DEVPTS_MEM) driver->ttysidx = tty;if (!*tp_lo
48、c)*tp_loc = tp;if (!*ltp_loc)*ltp_loc = ltp;tty->termios = *tp_loc;tty->termios_locked = *ltp_loc;driver->refcount+;tty->count+;/* Structures all installed . call the ldisc open routines.* If we fail here just call release_mem to clean up. No need* to decrement the use counts, as release
49、_mem doesn't care. */if (tty->ldisc.open) /如果函數(shù)指針tty_ldisc.open存在,調(diào)用之/線路規(guī)程的定義處于/linux/dirver/char/n_tty.c中retval = (tty->ldisc.open)(tty);if (retval)goto release_mem_out;if (o_tty && o_tty->ldisc.open) retval = (o_tty->ldisc.open)(o_tty);if (retval) if (tty->ldisc.close)(t
50、ty->ldisc.close)(tty);goto release_mem_out;tty_ldisc_enable(o_tty);/*static void tty_ldisc_enable(struct tty_struct *tty)set_bit(TTY_LDISC, &tty->flags);如果線路規(guī)程已經(jīng)附加上去,那么喚醒隊(duì)列wake_up(&tty_ldisc_wait);*/tty_ldisc_enable(tty);goto success;/* This fast open can be used if the tty is already
51、open. * No memory is allocated, and the only failures are from * attempting to open a closing tty or attempting multiple * opens on a pty master.*/fast_track:if (test_bit(TTY_CLOSING, &tty->flags) retval = -EIO;goto end_init;if (driver->type = TTY_DRIVER_TYPE_PTY && driver->subt
52、ype = PTY_TYPE_MASTER) /* special case for PTY masters: only one open permitted, * and the slave side open count is incremented as well. */if (tty->count) retval = -EIO;goto end_init;tty->link->count+;tty->count+;tty->driver = driver; /* N.B. why do this every time? */* FIXME */if(!te
53、st_bit(TTY_LDISC, &tty->flags)printk(KERN_ERR "init_dev but no ldiscn");success:*ret_tty = tty;/* All paths come through here to release the semaphore */ end_init:return retval;/* Release locally allocated memory . nothing placed in slots */ free_mem_out:kfree(o_tp);if (o_tty)free_t
54、ty_struct(o_tty);kfree(ltp);kfree(tp);free_tty_struct(tty);fail_no_mem:module_put(driver->owner);retval = -ENOMEM;goto end_init;/* call the tty release_mem routine to clean out this slot */ release_mem_out:printk(KERN_INFO "init_dev: ldisc open failed, ""clearing slot %dn", id
55、x);release_mem(tty, idx);goto end_init;上面關(guān)于的init_dev()的大體函數(shù)調(diào)用關(guān)系如下:Init_dev() -> initialize_tty_struct() -> tty_ldisc_assign(tty, tty_ldisc_get(N_TTY); linux/drivers/char/tty_io.c看一下tty_ldisc_assign(tty, tty_ldisc_get(N_TTY)的操作:Tty_ldisc_get():struct tty_ldisc *tty_ldisc_get(int disc)unsigned l
56、ong flags;struct tty_ldisc *ld;if (disc < N_TTY | disc >= NR_LDISCS)return NULL;spin_lock_irqsave(&tty_ldisc_lock, flags);ld = &tty_ldiscsdisc; /* Check the entry is defined */if(ld->flags & LDISC_FLAG_DEFINED)/* If the module is being unloaded we can't use it */if (!try_mod
57、ule_get(ld->owner)ld = NULL; else /* lock it */ld->refcount+;elseld = NULL;spin_unlock_irqrestore(&tty_ldisc_lock, flags);return ld;這個(gè)函數(shù)的操作為到tty_ldiscs 找到對(duì)應(yīng)項(xiàng).這個(gè)數(shù)組中的成員是調(diào)用tty_register_ldisc()將其設(shè)置進(jìn)去的.tty_ldisc_assign操作如下: static void tty_ldisc_assign(struct tty_struct *tty, struct tty_ldisc *ld) tty->ldisc = *ld; tty->ldisc.refcount = 0; 即將取出來的idisc作為tty->ldisc字段.在這段代碼中涉及到了tty_driver,tty_struct, struct tty_ldisc.這三者之間的關(guān)系用下圖表示如下:在這里,為tty_struct的ldisc是默認(rèn)指定為tty_ldiscsN_TTY.該ldisc對(duì)應(yīng)的是控制終端的線
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁(yè)內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫(kù)網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。
最新文檔
- 2025年度藝人經(jīng)紀(jì)服務(wù)合作協(xié)議
- 2025年度飲品店租賃合作合同
- 2025年度父親授權(quán)兒子代為處理債權(quán)債務(wù)合同
- 二零二五年度魚塘承包與漁業(yè)科技創(chuàng)新合作協(xié)議書
- 二零二五年度虛擬偶像經(jīng)濟(jì)合伙開店協(xié)議
- 二零二五年度新能源汽車推廣擔(dān)保借款合同
- 二零二五年度家庭財(cái)產(chǎn)分配與子女就業(yè)保障協(xié)議
- 二零二五年度特色餐飲企業(yè)員工晉升聘用合同
- 二零二五年度混凝土攪拌站租賃與綠色運(yùn)輸協(xié)議
- 2025年度蔬菜種植保險(xiǎn)服務(wù)合同
- 醫(yī)療機(jī)構(gòu)消毒記錄表清潔消毒日檢查記錄表
- 2024年北京大學(xué)強(qiáng)基計(jì)劃數(shù)學(xué)試卷試題真題(含答案詳解)
- 2024年巴西脈沖灌洗系統(tǒng)市場(chǎng)機(jī)會(huì)及渠道調(diào)研報(bào)告
- 高壓電工證考試題庫(kù)及答案(完整版)
- 測(cè)繪地理信息標(biāo)準(zhǔn)化與規(guī)范化
- 精索靜脈曲張臨床路徑表單
- 2024年山東圣翰財(cái)貿(mào)職業(yè)學(xué)院?jiǎn)握芯C合素質(zhì)考試題庫(kù)含答案(綜合卷)
- 委外催收機(jī)構(gòu)入圍項(xiàng)目投標(biāo)技術(shù)方案(技術(shù)標(biāo))
- 肝與膽病辨證課件
- (正式版)JBT 2930-2024 低壓電器產(chǎn)品型號(hào)編制方法
- 工程機(jī)械作業(yè)安全培訓(xùn)
評(píng)論
0/150
提交評(píng)論