A20串口驱动分析
串口驅(qū)動的整體框架實際上和顯示驅(qū)動類似
驅(qū)動程序是一個字符設備,驅(qū)動的實質(zhì)內(nèi)容都是在一個平臺總線設備驅(qū)動程序里
1.? 串口驅(qū)動的分析,從"drivers/tty/serial/8250/8250.c"開始
???? serial8250_init為入口函數(shù),從這個函數(shù)一路分析下去,下面列出主要代碼
???????????? serial8250_reg.nr = UART_NR;????????? UART_NR為8,查看datasheet可知A20支持8個uart
?? ????????? ret = uart_register_driver(&serial8250_reg);
???? uart_register_driver在”drivers/tty/serial/serial_core.c“中可以找到
???????????? normal->type? = TTY_DRIVER_TYPE_SERIAL;?
???????????? normal->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
???????????? tty_register_driver
??? tty_register_driver 在"drivers/tty/tty_io.c"這個文件中找到如下函數(shù)
?????????? alloc_chrdev_region
?????????? register_chrdev_region
?????????? cdev_init
??????????? cdev_add
?????????? if (!(driver->flags & TTY_DRIVER_DYNAMIC_DEV)) {
?? ??? ?????????? for (i = 0; i < driver->num; i++) {
?? ??? ??? ?????????????? d = tty_register_device(driver, i, NULL);
?? ??? ??? ?????????????? if (IS_ERR(d)) {
?? ??? ??? ??? ??????????????? error = PTR_ERR(d);
?? ??? ??? ??? ? ? ? ? ? ? ?? goto err;
?? ??? ??? ?????????????? }
?? ??? ?????????? }
?? ? ? ?? }
????????? 前四個函數(shù)是創(chuàng)建一個字符設備驅(qū)動程序的典型函數(shù),后面那段if語句之所以拿出來說一下,是因為
????????? tty_register_device這個函數(shù)是用來創(chuàng)建設備文件的,但是這個if語句是不會執(zhí)行,因為從上面的分析可?
????????? 知道這個驅(qū)動的flags里有TTY_DRIVER_DYNAMIC_DEV。那么什么時候創(chuàng)建了設備文件呢。實際上,上面幾個文件只是一個框架性的東西。
2.?? 接下來分析另一路主線
????? ”drivers/tty/serial/8250/8250_sunxi.c"
?????? sw_serial_init
?????? 這里注冊了一個平臺總線驅(qū)動和平臺總線設備
???????????? script_get_item(uart_para, "uart_used", &val);
???????????? 從配置文件中得到某一個串口是否可用,如果可用的話,在調(diào)用如下函數(shù)
??????????? platform_device_register
??????????? platform_driver_register
?????????? 來完成平臺總線驅(qū)動和平臺總線設備的匹配
????????? 分析device和driver 如下
????????? static struct platform_driver sw_serial_driver = {
?????????????????? .probe????? = sw_serial_probe,
?????????????????? .remove???? = sw_serial_remove,
?? ? ? ? ? ? ? ? ? .suspend??? = sw_serial_suspend,
?????????????????? .resume???? = sw_serial_resume,
?? ? ? ? ? ? ? ? ? .driver???? = {
??????????????????????????? .name?? = "sunxi-uart",
??????????????????????????? .owner? = THIS_MODULE,
?????????????????? },
????????? };
??????? struct platform_device sw_uart_dev[] = {
??? [0] = {.name = "sunxi-uart", .id = 0, .num_resources = ARRAY_SIZE(sw_uart_res[0]), .resource = &sw_uart_res[0][0], .dev.release = sunxi_serial_release},
??? [1] = {.name = "sunxi-uart", .id = 1, .num_resources = ARRAY_SIZE(sw_uart_res[1]), .resource = &sw_uart_res[1][0], .dev.release = sunxi_serial_release},
??? [2] = {.name = "sunxi-uart", .id = 2, .num_resources = ARRAY_SIZE(sw_uart_res[2]), .resource = &sw_uart_res[2][0], .dev.release = sunxi_serial_release},
??? [3] = {.name = "sunxi-uart", .id = 3, .num_resources = ARRAY_SIZE(sw_uart_res[3]), .resource = &sw_uart_res[3][0], .dev.release = sunxi_serial_release},
??? [4] = {.name = "sunxi-uart", .id = 4, .num_resources = ARRAY_SIZE(sw_uart_res[4]), .resource = &sw_uart_res[4][0], .dev.release = sunxi_serial_release},
??? [5] = {.name = "sunxi-uart", .id = 5, .num_resources = ARRAY_SIZE(sw_uart_res[5]), .resource = &sw_uart_res[5][0], .dev.release = sunxi_serial_release},
??? [6] = {.name = "sunxi-uart", .id = 6, .num_resources = ARRAY_SIZE(sw_uart_res[6]), .resource = &sw_uart_res[6][0], .dev.release = sunxi_serial_release},
??? [7] = {.name = "sunxi-uart", .id = 7, .num_resources = ARRAY_SIZE(sw_uart_res[7]), .resource = &sw_uart_res[7][0], .dev.release = sunxi_serial_release},
};
??????? 從上面兩個結(jié)構(gòu)體可以看出,8個平臺總線設備匹配了1個平臺總線驅(qū)動。
?????? 那么接下來我們看看平臺總線驅(qū)動的probe函數(shù)實現(xiàn)了什么。
3. sw_serial_probe函數(shù)分析
??? ????????? sw_serial_get_config這個函數(shù)從配置文件中得到type和port兩個參數(shù),type應該是管腳數(shù)目,比如基本的串口使用了tx,rx,那個type就是2,加兩個流控,type就是4,全串口type就是8.
????????? sw_serial_get_resource這個函數(shù),從配置文件中得到管腳的定義,并從平臺設備的resources中得到,內(nèi)存和中斷資源。
????????? serial8250_register_port????? serial8250_register_port定義8250.c中
????????? uart_add_one_port?? 定義在serial_core.c中
????????? tty_register_device? 定義在tty_io.c中
????????? 下面主要分析這個函數(shù)
4. struct device *tty_register_device(struct tty_driver *driver, unsigned index,
?? ??? ??? ??? ??? struct device *device)
??? {
?? ????? char name[64];
???????? 這句構(gòu)造主次設備號
?? ????? dev_t dev = MKDEV(driver->major, driver->minor_start) + index;
????????
?? ?????? if (index >= driver->num) {
?? ??? ???????? printk(KERN_ERR "Attempt to register invalid tty line number "
?? ??? ??????????????? " (%d).\n", index);
?? ??? ????????? return ERR_PTR(-EINVAL);
?? ????? }
?? ????? if (driver->type == TTY_DRIVER_TYPE_PTY)
?? ??? ?????????? pty_line_name(driver, index, name);
?? ? ? ? else
????????????????? 這句構(gòu)造串口設備文件
?? ??? ?????????? tty_line_name(driver, index, name);
?????????? 這句用name來創(chuàng)建一個設備文件
?? ?????? return device_create(tty_class, device, dev, NULL, name);
?? }
???? 最終在這里創(chuàng)建了串口的設備文件,實際這個串口真正硬件資源相關的東西都是在這個平臺總線設備和平臺總線驅(qū)動里來管理的。
???? 最上面的那個串口字符設備驅(qū)動只是一個框架性的東西。實際和顯示驅(qū)動類似,2.6內(nèi)核以后的很多驅(qū)動程序都是這種分層的方式,用平臺總線驅(qū)動程序來實現(xiàn)。
總結(jié)
- 上一篇: 2019年新规11月起施行!与老百姓的生
- 下一篇: 小米首款徕卡旗舰7月发!雷军晒刚入手的徕