在线看毛片网站电影-亚洲国产欧美日韩精品一区二区三区,国产欧美乱夫不卡无乱码,国产精品欧美久久久天天影视,精品一区二区三区视频在线观看,亚洲国产精品人成乱码天天看,日韩久久久一区,91精品国产91免费

<menu id="6qfwx"><li id="6qfwx"></li></menu>
    1. <menu id="6qfwx"><dl id="6qfwx"></dl></menu>

      <label id="6qfwx"><ol id="6qfwx"></ol></label><menu id="6qfwx"></menu><object id="6qfwx"><strike id="6qfwx"><noscript id="6qfwx"></noscript></strike></object>
        1. <center id="6qfwx"><dl id="6qfwx"></dl></center>

            新聞中心

            EEPW首頁(yè) > 嵌入式系統(tǒng) > 設(shè)計(jì)應(yīng)用 > Linux下的串口總線驅(qū)動(dòng)(一)

            Linux下的串口總線驅(qū)動(dòng)(一)

            作者: 時(shí)間:2016-11-22 來源:網(wǎng)絡(luò) 收藏
            一.系統(tǒng)理論

            PC機(jī)南橋的LPC總線(Low Pin Count并行總線,代替以前的ISA總線)上掛接了一個(gè)超級(jí)I/O模塊,而UART是這個(gè)超級(jí)模塊芯片組的一部分,這個(gè)UART通過RS232線程轉(zhuǎn)換與串行端口相連。與RS232不同,RS485并不是標(biāo)準(zhǔn)的PC接口,但在嵌入式領(lǐng)域,會(huì)為了可靠通信而使用RS485,RS485使用差分信號(hào),因此其傳輸距離可以達(dá)到數(shù)百米,而RS232傳輸距離僅數(shù)幾米,在處理器一端,RS485接口是半雙工的UART操作。

            本文引用地址:http://www.biyoush.com/article/201611/319918.htm

            Linux包含如下幾種終端設(shè)備:串行端口終端(/dev/ttySn)、偽終端(/dev/pty)、控制終端(/dev/tty)、控制臺(tái)終端(/dev/ttyn,/dev/conslole)。串行端口終端使用的設(shè)備名為/dev/ttyS0,/dev/ttyS1等,對(duì)應(yīng)的設(shè)備號(hào)為(4,0),(4,1)。通過查看/proc/tty/drivers文件可以知道什么類型的tty設(shè)備存在以及什么驅(qū)動(dòng)被加載到內(nèi)核,這個(gè)文件包括一個(gè)當(dāng)前存在的不同tty驅(qū)動(dòng)的列表,包括驅(qū)動(dòng)名,缺省的節(jié)點(diǎn)名,驅(qū)動(dòng)的主編號(hào),驅(qū)動(dòng)的次編號(hào)范圍,以及tty驅(qū)動(dòng)的類型。

            I/O系統(tǒng)調(diào)用是從帶有線路規(guī)程的TTY I/O核心開始,然后通過TTY層,最后到達(dá)UART驅(qū)動(dòng)層。主要涉及串口內(nèi)核配置、UART層內(nèi)核代碼、TTY層內(nèi)核代碼、線路規(guī)程內(nèi)核代碼、串口測(cè)試代碼五個(gè)部分。

            二.串口內(nèi)核配置

            對(duì)于Mini2440串口驅(qū)動(dòng),我想從配置開始講起。在內(nèi)核中Kconfig必須完成一層層調(diào)用,如果沒有在上一個(gè)Kconfig中調(diào)用該層Kconfig,那么該層Kconfig中的內(nèi)容不會(huì)在此出現(xiàn)。這種情況下,只有當(dāng)該層的Kconfig被其他層調(diào)用,該層Kconfig中的內(nèi)容才會(huì)被顯示。所以我們找找drivers/serial/Kconfig在哪里被調(diào)用的呢?

            在/drivers/char/kconfig中可以看到一行代碼source "drivers/serial/Kconfig",那我們就到drivers/serial/Kconfig下看看

            Samsung SoC serial support對(duì)應(yīng)于samsung.o serial_core.o

            config SERIAL_SAMSUNG

            tristate "Samsung SoC serial support"

            depends on ARM && PLAT_S3C

            select SERIAL_CORE

            Support for console on Samsung SoC serial port對(duì)應(yīng)于控制臺(tái)驅(qū)動(dòng)

            Samsung S3C2440/S3C2442 Serial port support對(duì)應(yīng)于s3c2440.o

            在/drivers/char/Makefile中可以看到

            obj-y += mem.o random.o tty_io.o n_tty.o tty_ioctl.o tty_ldisc.o tty_buffer.o tty_port.o

            我們知道tty_io.o n_tty.o tty_ioctl.o tty_ldisc.o tty_buffer.o tty_port.o已編入內(nèi)核

            自此,我們知道關(guān)于串口驅(qū)動(dòng),我們內(nèi)核中被編譯了s3c2440.o samsung.o serial_core.o tty_io.o n_tty.o tty_ioctl.o tty_ldisc.o tty_buffer.o tty_port.o

            我們對(duì)此進(jìn)行分類,屬于UART層的是s3c2440.o samsung.o;屬于TTY層的是serial_core.o;屬于線路規(guī)程的是tty_io.o n_tty.o tty_ioctl.o tty_ldisc.o tty_buffer.o tty_port.o 。

            好了,對(duì)于串口的地圖我們已經(jīng)分析好了,那我們就按照UART層,TTY層,線路規(guī)程一個(gè)個(gè)的逛逛吧。

            三.UART層內(nèi)核代碼

            我們先看看samsung.o的init代碼吧,這里面完成了uart_driver的注冊(cè)

            static int __init s3c24xx_serial_modinit(void)

            {

            int ret;

            ret = uart_register_driver(&s3c24xx_uart_drv); //注冊(cè)u(píng)art_driver

            if (ret < 0) {

            printk(KERN_ERR "failed to register UART drivern");

            return -1;

            }

            return 0;

            }

            static struct uart_driver s3c24xx_uart_drv = {

            .owner = THIS_MODULE,

            .dev_name = "s3c2410_serial", //設(shè)備名

            .nr = CONFIG_SERIAL_SAMSUNG_UARTS, //UART端口個(gè)數(shù)

            .cons = S3C24XX_SERIAL_CONSOLE, //指向控制臺(tái)結(jié)構(gòu)

            .driver_name = S3C24XX_SERIAL_NAME, //驅(qū)動(dòng)的名字

            .major = S3C24XX_SERIAL_MAJOR, //串口主設(shè)備號(hào)

            .minor = S3C24XX_SERIAL_MINOR, //串口次設(shè)備號(hào)

            };

            我們關(guān)注下上面這個(gè)結(jié)構(gòu)體中一個(gè)成員S3C24XX_SERIAL_CONSOLE

            #define S3C24XX_SERIAL_CONSOLE &s3c24xx_serial_console

            static struct console s3c24xx_serial_console = {

            .name = S3C24XX_SERIAL_NAME,

            .device = uart_console_device,

            .flags = CON_PRINTBUFFER,

            .index = -1,

            .write = s3c24xx_serial_console_write,

            .setup = s3c24xx_serial_console_setup

            };

            上面是控制臺(tái)的結(jié)構(gòu)體成員。

            對(duì)于UART驅(qū)動(dòng),我們除了需要注冊(cè)u(píng)art_driver外,還需要注冊(cè)端口,我們看看s3c2440.o。

            這個(gè)文件里面注冊(cè)了一個(gè)平臺(tái)設(shè)備,其中平臺(tái)設(shè)備的探測(cè)函數(shù)最終調(diào)用了samsung.o中的s3c24xx_serial_probe函數(shù)。

            int s3c24xx_serial_probe(struct platform_device *dev,

            struct s3c24xx_uart_info *info)

            {

            struct s3c24xx_uart_port *ourport;

            int ret;

            dbg("s3c24xx_serial_probe(%p, %p) %dn", dev, info, probe_index);

            ourport = &s3c24xx_serial_ports[probe_index]; //選擇s3c24xx_uart_port

            probe_index++; //索引號(hào)自增

            dbg("%s: initialising port %p...n", __func__, ourport);

            ret = s3c24xx_serial_init_port(ourport, info, dev); //初始化串口

            if (ret < 0)

            goto probe_err;

            dbg("%s: adding portn", __func__);

            uart_add_one_port(&s3c24xx_uart_drv, &ourport->port); //向內(nèi)核注冊(cè)端口

            platform_set_drvdata(dev, &ourport->port); //設(shè)置私有數(shù)據(jù)

            ret = device_create_file(&dev->dev, &dev_attr_clock_source); //添加設(shè)備屬性

            if (ret < 0)

            printk(KERN_ERR "%s: failed to add clksrc attr.n", __func__);

            ret = s3c24xx_serial_cpufreq_register(ourport); //注冊(cè)CPU頻率

            if (ret < 0)

            dev_err(&dev->dev, "failed to add cpufreq notifiern");

            return 0;

            probe_err:

            return ret;

            }

            通過上面的函數(shù),我們發(fā)現(xiàn)在UART層,我們調(diào)用了uart_add_one_port函數(shù)完成端口的添加,我們來看看添加了什么端口呢?

            static struct s3c24xx_uart_port s3c24xx_serial_ports[CONFIG_SERIAL_SAMSUNG_UARTS] = {

            [0] = {

            .port = {

            .lock = __SPIN_LOCK_UNLOCKED(s3c24xx_serial_ports[0].port.lock),

            .iotype = UPIO_MEM,

            .irq = IRQ_S3CUART_RX0,

            .uartclk = 0,

            .fifosize = 16,

            .ops = &s3c24xx_serial_ops, //對(duì)UART操作的函數(shù)

            .flags = UPF_BOOT_AUTOCONF,

            .line = 0,

            }

            },

            [1] = {

            .port = {

            .lock = __SPIN_LOCK_UNLOCKED(s3c24xx_serial_ports[1].port.lock),

            .iotype = UPIO_MEM,

            .irq = IRQ_S3CUART_RX1,

            .uartclk = 0,

            .fifosize = 16,

            .ops = &s3c24xx_serial_ops, //對(duì)UART操作的函數(shù)

            .flags = UPF_BOOT_AUTOCONF,

            .line = 1,

            }

            },

            #if CONFIG_SERIAL_SAMSUNG_UARTS > 2

            [2] = {

            .port = {

            .lock = __SPIN_LOCK_UNLOCKED(s3c24xx_serial_ports[2].port.lock),

            .iotype = UPIO_MEM,

            .irq = IRQ_S3CUART_RX2,

            .uartclk = 0,

            .fifosize = 16,

            .ops = &s3c24xx_serial_ops, //對(duì)UART操作的函數(shù)

            .flags = UPF_BOOT_AUTOCONF,

            .line = 2,

            }

            },

            #endif

            #if CONFIG_SERIAL_SAMSUNG_UARTS > 3

            [3] = {

            .port = {

            .lock = __SPIN_LOCK_UNLOCKED(s3c24xx_serial_ports[3].port.lock),

            .iotype = UPIO_MEM,

            .irq = IRQ_S3CUART_RX3,

            .uartclk = 0,

            .fifosize = 16,

            .ops = &s3c24xx_serial_ops, //對(duì)UART操作的函數(shù)

            .flags = UPF_BOOT_AUTOCONF,

            .line = 3,

            }

            }

            #endif

            };

            在端口的定義中,我們知道s3c24xx_uart_port中定義了一個(gè)uart_port結(jié)構(gòu)體,繼續(xù)跟蹤對(duì)UART的操作函數(shù)

            static struct uart_ops s3c24xx_serial_ops = {

            .pm = s3c24xx_serial_pm,

            .tx_empty = s3c24xx_serial_tx_empty, //發(fā)送是否忙

            .get_mctrl = s3c24xx_serial_get_mctrl,

            .set_mctrl = s3c24xx_serial_set_mctrl,

            .stop_tx = s3c24xx_serial_stop_tx,

            .start_tx = s3c24xx_serial_start_tx, //類似于write

            .stop_rx = s3c24xx_serial_stop_rx,

            .enable_ms = s3c24xx_serial_enable_ms,

            .break_ctl = s3c24xx_serial_break_ctl,

            .startup = s3c24xx_serial_startup, //類似于open

            .shutdown = s3c24xx_serial_shutdown, //類似于close

            .set_termios = s3c24xx_serial_set_termios, //設(shè)置線路規(guī)程

            .type = s3c24xx_serial_type,

            .release_port = s3c24xx_serial_release_port, //釋放端口資源

            .request_port = s3c24xx_serial_request_port, //申請(qǐng)端口資源

            .config_port = s3c24xx_serial_config_port, //配置端口

            .verify_port = s3c24xx_serial_verify_port,

            };

            對(duì)于上述uart_ops函數(shù),我們需要自己去實(shí)現(xiàn)uart層的具體操作。

            我們?cè)赨ART層主要涉及uart_driver,uart_port,uart_ops三個(gè)結(jié)構(gòu)體,并調(diào)用tty層的uart_register_driver和uart_add_one_port完成驅(qū)動(dòng)和端口的注冊(cè),UART層具體操作函數(shù)需要用戶自己設(shè)計(jì)。

            好了,總結(jié)下UART驅(qū)動(dòng)層需要完成的任務(wù):

            其一,定義uart_driver、uart_ops、uart_port等結(jié)構(gòu)體的實(shí)例并在適當(dāng)?shù)牡胤礁鶕?jù)具體硬件和驅(qū)動(dòng)的情況初始化它們,當(dāng)然具體設(shè)備XXX的驅(qū)動(dòng)可以將這些結(jié)構(gòu)套在新定義的XXX_uart_driver、XXX_uart_ops、XXX_uart_port之內(nèi)。

            其二,在模塊初始化時(shí)調(diào)用uart_register_driver()和uart_add_one_port()以注冊(cè)UART驅(qū)動(dòng)并添加端口,在模塊卸載時(shí)調(diào)用uart_unregister_driver()和uart_remove_one_port()以注銷UART驅(qū)動(dòng)并移除端口。

            其三,根據(jù)具體硬件的datasheet實(shí)現(xiàn)uart_ops中的成員函數(shù),這些函數(shù)的實(shí)現(xiàn)成為UART驅(qū)動(dòng)的主體工作。



            關(guān)鍵詞: Linux串口總線驅(qū)

            評(píng)論


            技術(shù)專區(qū)

            關(guān)閉