A20串口驱动分析
串口驅動的整體框架實際上和顯示驅動類似
驅動程序是一個字符設備,驅動的實質內容都是在一個平臺總線設備驅動程序里
1.? 串口驅動的分析,從"drivers/tty/serial/8250/8250.c"開始
???? serial8250_init為入口函數,從這個函數一路分析下去,下面列出主要代碼
???????????? 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"這個文件中找到如下函數
?????????? 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;
?? ??? ??? ?????????????? }
?? ??? ?????????? }
?? ? ? ?? }
????????? 前四個函數是創建一個字符設備驅動程序的典型函數,后面那段if語句之所以拿出來說一下,是因為
????????? tty_register_device這個函數是用來創建設備文件的,但是這個if語句是不會執行,因為從上面的分析可?
????????? 知道這個驅動的flags里有TTY_DRIVER_DYNAMIC_DEV。那么什么時候創建了設備文件呢。實際上,上面幾個文件只是一個框架性的東西。
2.?? 接下來分析另一路主線
????? ”drivers/tty/serial/8250/8250_sunxi.c"
?????? sw_serial_init
?????? 這里注冊了一個平臺總線驅動和平臺總線設備
???????????? script_get_item(uart_para, "uart_used", &val);
???????????? 從配置文件中得到某一個串口是否可用,如果可用的話,在調用如下函數
??????????? platform_device_register
??????????? platform_driver_register
?????????? 來完成平臺總線驅動和平臺總線設備的匹配
????????? 分析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},
};
??????? 從上面兩個結構體可以看出,8個平臺總線設備匹配了1個平臺總線驅動。
?????? 那么接下來我們看看平臺總線驅動的probe函數實現了什么。
3. sw_serial_probe函數分析
??? ????????? sw_serial_get_config這個函數從配置文件中得到type和port兩個參數,type應該是管腳數目,比如基本的串口使用了tx,rx,那個type就是2,加兩個流控,type就是4,全串口type就是8.
????????? sw_serial_get_resource這個函數,從配置文件中得到管腳的定義,并從平臺設備的resources中得到,內存和中斷資源。
????????? serial8250_register_port????? serial8250_register_port定義8250.c中
????????? uart_add_one_port?? 定義在serial_core.c中
????????? tty_register_device? 定義在tty_io.c中
????????? 下面主要分析這個函數
4. struct device *tty_register_device(struct tty_driver *driver, unsigned index,
?? ??? ??? ??? ??? struct device *device)
??? {
?? ????? char name[64];
???????? 這句構造主次設備號
?? ????? 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
????????????????? 這句構造串口設備文件
?? ??? ?????????? tty_line_name(driver, index, name);
?????????? 這句用name來創建一個設備文件
?? ?????? return device_create(tty_class, device, dev, NULL, name);
?? }
???? 最終在這里創建了串口的設備文件,實際這個串口真正硬件資源相關的東西都是在這個平臺總線設備和平臺總線驅動里來管理的。
???? 最上面的那個串口字符設備驅動只是一個框架性的東西。實際和顯示驅動類似,2.6內核以后的很多驅動程序都是這種分層的方式,用平臺總線驅動程序來實現。
總結
- 上一篇: 2019年新规11月起施行!与老百姓的生
- 下一篇: Digest authenticatio