日本搞逼视频_黄色一级片免费在线观看_色99久久_性明星video另类hd_欧美77_综合在线视频

國內(nèi)最全IT社區(qū)平臺 聯(lián)系我們 | 收藏本站
阿里云優(yōu)惠2
您當(dāng)前位置:首頁 > php開源 > 綜合技術(shù) > E:安桌層及文件系統(tǒng)層的PRINTf輸出原理

E:安桌層及文件系統(tǒng)層的PRINTf輸出原理

來源:程序員人生   發(fā)布時間:2016-10-12 09:35:12 閱讀次數(shù):2971次

/device/console操控臺原理分析,通過調(diào)用此操控臺來輸出信息,同時這兒觸及到/device/console調(diào)用TTY,然后TTY調(diào)用低層串口的分析 安桌LOG輸出原理)

LINUX內(nèi)核源碼版本:linux⑶.0.86  

 

/dev/console即控制臺,是與操作系統(tǒng)交互的裝備,系統(tǒng)將1些調(diào)試信息直接輸出到控制臺上,是TTY裝備的1個子集

 

Tty:teltypewriters  Teletypes簡稱電傳打印機:終端是1種字符型裝備,它有多種類型,通常使用tty來簡稱各種類型的終端裝備ConsoleTTY裝備的1種。Console調(diào)用到最低層就是TTY裝備驅(qū)動。

TTY CONSOLE UART關(guān)系圖(由我的平臺有4路串口,要分析到USER空間/dev/console最后是通過那1路口輸出的,注意和內(nèi)核空間的printkconsole操控臺輸出端口是不是1致,分析原理。由前面幾節(jié)分析可知printk輸出是由uboot傳入的參數(shù)來肯定那1路串口輸出的的。Console=ttySAC0,115200n80)

分析代碼前根據(jù)網(wǎng)絡(luò)資料得出的1張圖:

 

自己分析代碼后得到的圖:

 

 

紅色部份是分析了所有代碼后得出的結(jié)論:

下面進程很雜亂,到現(xiàn)在還是沒有分析清楚,只能是明白了個大概,由于結(jié)構(gòu)體太多,沒交繁復(fù)雜。現(xiàn)在還是亂。只能再次分析1下流程(只針對/dev/console的寫進程。我們要知道用戶空間的console是支持輸入輸出的。Kernel空音的console只支持輸出信息。這是很重要的區(qū)分。)。

/dev/console

  1. 裝備打開。得到tty_struct結(jié)構(gòu)體,并且賦值在file中1個private_data中。同時由于

    struct tty_driver *console_driver = console_device(&index);得來是由uboot傳入的參數(shù)來決定的。因此這兒/dev/console輸出0串口來決定。由其它節(jié)部份的參數(shù)解析部份得知。

    struct tty_driver *console_driver = console_device(&index)->console_drivers(內(nèi)核層register_console注冊函數(shù)時1個指針鏈表)->driver = c->device(c, index);

  2. 寫操作//把數(shù)據(jù)寫入file文件中的private_data指向的tty_struct中的1xmit變量(這兒有好層轉(zhuǎn)換),同時打開中斷。產(chǎn)生中斷條件。

    Write->[ld->ops->write=n_tty_write]->[tty->ops=driver->ops]=[tty_operations uart_ops]=[.write= uart_write,]

     

    3.中斷發(fā)送://中斷的注冊是在open函數(shù)中履行的。這兒自動過來履行的。

    ret = request_irq(ourport->rx_irq, s3c24xx_serial_rx_chars, 0,

      s3c24xx_serial_portname(port), ourport);---->

    s3c24xx_serial_tx_chars->wr_regb(port, S3C2410_UTXH, xmit->buf[xmit->tail]);發(fā)送數(shù)據(jù)

     

    //下面是上面結(jié)論分析進程。

     

    /dev/console字符裝備注冊流程分析:

    #define fs_initcall(fn)__define_initcall("5",fn,5)

    chr_dev_init->tty_init->MKDEV(TTYAUX_MAJOR, 1)->console_fops操作函數(shù)

    static const struct file_operationsconsole_fops = {

    .llseek= no_llseek,

    .read= tty_read,

    .write= redirected_tty_write,

    .poll= tty_poll,

    .unlocked_ioctl= tty_ioctl,

    .compat_ioctl= tty_compat_ioctl,

    .open= tty_open,

    .release= tty_release,

    .fasync= tty_fasync,

    };

    完成了對裝備的注冊,然后是打開裝備和讀寫裝備了,這個部份應(yīng)當(dāng)是用戶空間來完成的。我們不去看相干代碼,只從通用的打開讀寫通用操作方法來作分析。Open write read這3個函數(shù)由用戶空間來調(diào)用。當(dāng)用戶空間調(diào)打開讀寫函數(shù)時會調(diào)用上面注冊的驅(qū)動的操作函數(shù)對應(yīng)的函數(shù)。所以接下來分析Open write read

    Open:tty_open

    struct tty_driver *console_driver = console_device(&index)->console_drivers(內(nèi)核層register_console注冊函數(shù)時1個指針鏈表)->driver = c->device(c, index);

    retval = tty_alloc_file(filp);

    struct tty_driver *console_driver = console_device(&index);

  • tty = tty_init_dev(driver, index, 0);//這個函數(shù)里去構(gòu)建LDISC結(jié)構(gòu)體了,叫做線規(guī)程/線路規(guī)程line discipline

     

    /*

    //ldisc構(gòu)建進程:

    tty_init_dev(driver, index, 0);//tty_driver  0  0

    initialize_tty_struct(tty, driver, idx);//tty_struct tty_driver 0

    tty_ldisc_init(tty);

    Ld->ops=tty_ldiscs[disc]=tty_ldiscs[0]

    /*

     

    ty_ldiscs怎樣得來的是關(guān)鍵:

    start_kernel->console_init()->/* Setup the default TTY line discipline. */

    tty_ldisc_begin();->/* Setup the default TTY line discipline. */

    (void) tty_register_ldisc(N_TTY, &tty_ldisc_N_TTY);->->

    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

    };

    tty_ldiscs[disc] = new_ldisc;

    tty_ldiscs[0] = tty_ldisc_N_TTY ;等于上面TTY裝備

    通過上面分析可知

    Ld->ops=tty_ldiscs[disc]=tty_ldiscs[0]=tty_ldisc_N_TTY

     

     

    */

    tty->ldisc = ld;

    tty_add_file(tty, filp);

    struct tty_file_private *priv = file->private_dat=tty_struct;因此通過file文件中的private_data來操作tty_sruct。這個結(jié)構(gòu)體時里面包括tty_driver tty->ldisc多個變量。

     

     

    */

    tty_add_file(tty, filp);

    上面代碼完成通過文件的struct tty_file_private *priv = file->private_data變量來保存tty_struct(同時TTY結(jié)構(gòu)體包括tty_drivers)驅(qū)動變量。

     

    我們代碼的console_drivers以下:

    static struct console s3c24xx_serial_console = {

    .name= S3C24XX_SERIAL_NAME,

    .device=uart_console_device,

    .flags= CON_PRINTBUFFER,

    .index= ⑴,

    .write= s3c24xx_serial_console_write,

    .setup= s3c24xx_serial_console_setup,

    .data= &s3c24xx_uart_drv,

    };

    struct tty_driver *uart_console_device(struct console *co, int *index)

    {

    struct uart_driver *p = co->data;

    *index = co->index;//0通過UBOOT傳入?yún)?shù)等到0

    returnp->tty_driver;

    }

    static struct uart_driver s3c24xx_uart_drv = {

    .owner= THIS_MODULE,

    .driver_name= "s3c2410_serial",

    .nr= CONFIG_SERIAL_SAMSUNG_UARTS,

    #ifdef CONFIG_SERIAL_SAMSUNG_CONSOLE_SWITCH

    .cons= NULL,

    #else

    .cons= S3C24XX_SERIAL_CONSOLE,

    #endif

    .dev_name= S3C24XX_SERIAL_NAME,

    .major= S3C24XX_SERIAL_MAJOR,

    .minor= S3C24XX_SERIAL_MINOR,

    };

    p->tty_drivers3c24xx_uart_drv結(jié)構(gòu)體的成員,但在上面數(shù)組的初始化中并沒有初始化此值,因此可以肯定是在在其它地方初始化的tty_driver的。

    下面來分析tty_driver的初始化流程:

    s3c24xx_serial_modinit->uart_register_driver(&s3c24xx_uart_drv)->:

    struct tty_driver *normal;

    drv->tty_driver = normal;

    tty_set_operations(normal, &uart_ops); //driver->ops = op;

    /*

    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

    .proc_fops= &uart_proc_fops,

    #endif

    .tiocmget= uart_tiocmget,

    .tiocmset= uart_tiocmset,

    .get_icount= uart_get_icount,

    #ifdef CONFIG_CONSOLE_POLL

    .poll_init= uart_poll_init,

    .poll_get_char= uart_poll_get_char,

    .poll_put_char= uart_poll_put_char,

    #endif

    };

    tty->ops = driver->ops;

    struct tty_driver *driver;

    struct tty_driver *console_driver = console_device(&index);

    tty->ops=driver->ops->console_drivers->driver = c->device(c, index)->

     tty_operations uart_ops=tty_operations uart_ops;--->tty->ops=driver->ops=tty_operations uart_ops

     

    */

    通過上面代碼分析可知:用操作/dev/console寫函數(shù)時

    .write= redirected_tty_write,

    static ssize_t tty_write(struct file *file, const char __user *buf,

    size_t count, loff_t *ppos)

    struct tty_struct *tty = file_tty(file);//包括tty_driver結(jié)構(gòu)體。

    ld = tty_ldisc_ref_wait(tty);

    ld->ops->write//////因此找到這個函數(shù)才是我們的根本,看是如何實現(xiàn)的。????????????????

    通過前面分析知:

    Ld->ops=tty_ldiscs[disc]=tty_ldiscs[0]=tty_ldisc_N_TTY

    因此ld->ops->write=n_tty_write//tty_ldisc_N_TTY中的函數(shù)完成線程規(guī)程檢查

    最后還是調(diào)用tty->ops->write(tty, b, nr);來輸出數(shù)據(jù)。規(guī)則檢查部份不能把數(shù)據(jù)輸出的串口

    綜上:對/dev/console裝備的寫函數(shù)的履行流程以下:

    Write->[ld->ops->write=n_tty_write]->[tty->ops=driver->ops]=[tty_operations uart_ops]=[.write= uart_write,]

    static int uart_write(struct tty_struct *tty,

    const unsigned char *buf, int count)

    __uart_start(tty);

    port->ops->start_tx(port);//ops= s3c24xx_serial_ops;

    static struct uart_ops s3c24xx_serial_ops = {

    .pm= s3c24xx_serial_pm,

    .tx_empty= s3c24xx_serial_tx_empty,

    .get_mctrl= s3c24xx_serial_get_mctrl,

    .set_mctrl= s3c24xx_serial_set_mctrl,

    .stop_tx= s3c24xx_serial_stop_tx,

    .start_tx= s3c24xx_serial_start_tx,

    .stop_rx= s3c24xx_serial_stop_rx,

    .enable_ms= s3c24xx_serial_enable_ms,

    .break_ctl= s3c24xx_serial_break_ctl,

    .startup= s3c24xx_serial_startup,

    .shutdown= s3c24xx_serial_shutdown,

    .set_termios= s3c24xx_serial_set_termios,

    .type= s3c24xx_serial_type,

    .release_port= s3c24xx_serial_release_port,

    .request_port= s3c24xx_serial_request_port,

    .config_port= s3c24xx_serial_config_port,

    .verify_port= s3c24xx_serial_verify_port,

    .wake_peer= s3c24xx_serial_wake_peer,

    };

    s3c24xx_serial_start_tx//這個函數(shù)是打開中斷  我們/dev/console應(yīng)當(dāng)是通過中斷來把數(shù)據(jù)發(fā)送出去的。數(shù)據(jù)存在struct circ_buf xmit結(jié)構(gòu)體中。這個函數(shù)只是把數(shù)據(jù)緩存在變量中和打開串口,發(fā)送數(shù)據(jù)是在中斷中進行的。tty->ops->open(tty, filp);====s3c24xx_serial_startup打開中斷ret = request_irq(ourport->rx_irq, s3c24xx_serial_rx_chars, 0,

      s3c24xx_serial_portname(port), ourport);注冊串口發(fā)送函數(shù)。

    static irqreturn_t

    static irqreturn_t s3c24xx_serial_tx_chars(int irq, void *id)

    struct s3c24xx_uart_port *ourport = id;

    struct circ_buf *xmit = &port->state->xmit;//這個是在s3c24xx_serial_start_tx中去指定的。

    /*

    ret = request_irq(ourport->rx_irq, s3c24xx_serial_rx_chars, 0,

      s3c24xx_serial_portname(port), ourport);*/

    上面中斷函數(shù)的id/dev/consoletty_drvier是同1個變量。所以在觸發(fā)中斷發(fā)送時能正確的發(fā)送數(shù)據(jù)。wr_regb(port, S3C2410_UTXH, xmit->buf[xmit->tail]);

     

     

     

     

    /dev/tty字符裝備注冊流程分析:

    #define fs_initcall(fn)__define_initcall("5",fn,5)

    chr_dev_init->tty_init->MKDEV(TTYAUX_MAJOR, 0)->tty_fops

    上面只是注冊了1個tty裝備。Tty實際上是1多個的。最后是tty_register_driver-for (i = 0; i < driver->num; i++) {

    d = tty_register_device(driver, i, NULL);-device_create(tty_class, device, dev, NULL, name);

    上面完成多個裝備的注冊tty裝備的注冊,這兒主要是串串的。所有的tty1字符輸輸入輸出裝備都可以用tty_register_driver來注冊。可以注冊多個。上面/dev/console只是利用了其中的1類來解決問題。Tty裝備是可以單獨來解決問題的。用tty_register_driver注冊。但我們分析的串口部份是用的tty_init來注冊裝備。然后通過打開函數(shù)來與tty_structtty_drvier關(guān)聯(lián)解決問題。大致分析了代碼發(fā)/dev/conosle/  /dev/tty邏輯差不多。細(xì)節(jié)就不去分析了。可以明確的是對這兩個裝備的輸入輸出都是由uboot傳入?yún)?shù)來決是那1個口的。前1個用于系統(tǒng)信息調(diào)試 ,后1個應(yīng)當(dāng)是作其它功能。對這裝備當(dāng)作1般裝備來理解。只是加入很多中間層,所以分析起來比較麻煩。暫不去細(xì)究。分析了好幾天還是亂。不是清晰的邏輯。

     

    static const struct file_operations tty_fops = {

    .llseek= no_llseek,

    .read= tty_read,

    .write= tty_write,

    .poll= tty_poll,

    .unlocked_ioctl 生活不易,碼農(nóng)辛苦
    如果您覺得本網(wǎng)站對您的學(xué)習(xí)有所幫助,可以手機掃描二維碼進行捐贈
    程序員人生

------分隔線----------------------------
分享到:
------分隔線----------------------------
為碼而活
積分:4237
15粉絲
7關(guān)注
欄目熱點
關(guān)閉
程序員人生
主站蜘蛛池模板: 国产精品久久久久婷婷二区次 | 欧美日韩一二三区 | 日本精品中文字幕 | 在线免费国产 | 亚洲欧美综合精品久久成人 | 经典一区二区 | 国产亚洲精品久久久 | 欧美成人午夜免费视在线看片 | 亚洲日韩中文字幕一区 | av看片| 麻豆国产一区二区三区四区 | 久久免费视频网 | 一区二区三区四区在线视频 | 亚洲福利在线观看 | 国产精品一区一区三区 | 色自拍 | 久久久国产一区 | 欧美视频一区二区 | 影视在线免费观看 | 好叼妞| 欧美一级做a爰片久久高潮 亚洲一级一级 | 欧美在线一区二区三区四区 | 天堂成人国产精品一区 | 国产日韩欧美一区二区 | 在线播放a | 色综合av在线 | 国产高清不卡av | 国产一区二区三区久久久久久久久 | 精品国产乱码久久久久久丨区2区 | 欧洲女同video hd| 欧美成人精品网站 | 国产日韩精品视频 | 亚洲成人一区在线观看 | 亚洲电影一区 | 午夜性刺激免费看视频 | 精品视频在线免费观看 | 欧美成人免费一级人片100 | 午夜激情视频在线观看 | 亚洲乱码国产乱码精品精 | 日韩在线播放视频 | 99色网站 |