對(duì)于S5PV210 UART驅(qū)動(dòng)來說,主要關(guān)心的就是drivers/serial下的samsung.c和s5pv210.c連個(gè)文件。
由drivers/serial/Kconfig:
config SERIAL_SAMSUNG
depends on ARM && PLAT_SAMSUNG
config SERIAL_S5PV210
depends on SERIAL_SAMSUNG && (CPU_S5PV210 || CPU_S5P6442) && SERIAL_SAMSUNG_CONSOLE
可以看出模塊的依賴關(guān)系,先加載samsung.ko,然后再加載s5pv210.ko。
所以串口的初始化的簡要過程如下:
samsung.c中模塊加載函數(shù)s3c24xx_serial_modinit調(diào)用uart_register_driver(&s3c24xx_uart_drv),注冊(cè)了s3c24xx_uart_drv這個(gè)uart_driver;
s5pv210.c中模塊加載函數(shù)s5p_serial_init ----> s3c24xx_serial_init(&s5p_serial_driver, *s5p_uart_inf) ----> platform_driver_register(drv) 注冊(cè)了s5p_serial_driver這個(gè)平臺(tái)驅(qū)動(dòng),
有了平臺(tái)驅(qū)動(dòng)后,當(dāng)平臺(tái)設(shè)備與平臺(tái)驅(qū)動(dòng)match之后,調(diào)用s5p_serial_probe ----> s3c24xx_serial_probe(pdev, s5p_uart_inf[pdev->id]) ----> s3c24xx_serial_init_port初始化UART端口
> uart_add_one_port添加端口
《《《《====接下來具體分析====》》》》
一、注冊(cè)u(píng)art_driver
/* 模塊加載函數(shù)*/
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;
}
在模塊加載函數(shù)中調(diào)用serial_core.c中的uart_register_driver()注冊(cè)s3c24xx_uart_drv這個(gè)uart_driver,實(shí)際上在uart_register_driver()中包含了tty_register_driver(),代碼如下:
/**
* uart_register_driver - register a driver with the uart core layer
* @drv: low level driver structure
*
* Register a uart driver with the core driver. We in turn register
* with the tty layer, and initialise the core driver per-port state.
*
* We have a proc file in /proc/tty/driver which is named after the
* normal driver.
*
* drv->port should be NULL, and the per-port structures should be
* registered using uart_add_one_port after this call has succeeded.
*/
/*實(shí)際上是填充uart_driver結(jié)構(gòu)體*/
int uart_register_driver(struct uart_driver *drv)
{
/*聲明一個(gè)tty_driver,接下來填充其中的成員,并使uart_driver中的tty_driver指向這個(gè)結(jié)構(gòu)*/
struct tty_driver *normal;
int i, retval;
BUG_ON(drv->state);
/*
* Maybe we should be using a slab cache for this, especially if
* we have a large number of ports to handle.
*/
/*分配設(shè)備私有信息結(jié)構(gòu)體的內(nèi)存空間,并初始化為零*/
drv->state = kzalloc(sizeof(struct uart_state) * drv->nr, GFP_KERNEL);
if (!drv->state)
goto out;
normal = alloc_tty_driver(drv->nr);/*分配tty驅(qū)動(dòng)*/
if (!normal)
goto out_kfree;
drv->tty_driver = normal;/*填充uart_driver中封裝的tty_driver,使其指向分配好的tty驅(qū)動(dòng)*/
/*初始化tty_driver結(jié)構(gòu)體*/
normal->owner = drv->owner;
normal->driver_name = drv->driver_name;
normal->name = drv->dev_name;
normal->major = drv->major;
normal->minor_start = drv->minor;
normal->type = TTY_DRIVER_TYPE_SERIAL;//tty驅(qū)動(dòng)的類型
normal->subtype = SERIAL_TYPE_NORMAL;//tty驅(qū)動(dòng)的子類
normal->init_termios = tty_std_termios;//初始的termios,即初始的線路設(shè)置,用來提供一個(gè)線路設(shè)置集合
normal->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL;//控制模式
normal->init_termios.c_ispeed = normal->init_termios.c_ospeed = 9600;
normal->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
normal->driver_state = drv;//~~~~~~
tty_set_operations(normal, &uart_ops);//設(shè)置tty驅(qū)動(dòng)操作,normal->ops=&uart_ops
/*
* Initialise the UART state(s).初始化UART狀態(tài)
*/
for (i = 0; i < drv->nr; i++) {
struct uart_state *state = drv->state + i;
struct tty_port *port = &state->port;
tty_port_init(port);//tty端口初始化
port->close_delay = 500; /* .5 seconds */
port->closing_wait = 30000; /* 30 seconds */
tasklet_init(&state->tlet, uart_tasklet_action,
(unsigned long)state);//初始化tasklet,即中斷的底半部機(jī)制
}
retval = tty_register_driver(normal);//注冊(cè)tty設(shè)備
if (retval >= 0)
return retval;
put_tty_driver(normal);
out_kfree:
kfree(drv->state);
out:
return -ENOMEM;
}
二、注冊(cè)平臺(tái)驅(qū)動(dòng)
s5p_serial_init ----> s3c24xx_serial_init(&s5p_serial_driver, *s5p_uart_inf) ----> platform_driver_register(drv)
int s3c24xx_serial_init(struct platform_driver *drv,
struct s3c24xx_uart_info *info)
{
dbg('s3c24xx_serial_init(%p,%p)n', drv, info);
#ifdef CONFIG_PM
drv->suspend = s3c24xx_serial_suspend;
drv->resume = s3c24xx_serial_resume;
#endif
return platform_driver_register(drv);
}
直接調(diào)用platform_driver_register,注冊(cè)了 s5p_serial_driver這個(gè)平臺(tái)驅(qū)動(dòng)。
三、平臺(tái)驅(qū)動(dòng)的探測函數(shù)probe()
因?yàn)榘製art驅(qū)動(dòng)注冊(cè)為platform驅(qū)動(dòng),當(dāng)平臺(tái)驅(qū)動(dòng)與平臺(tái)設(shè)備進(jìn)行匹配的時(shí)候會(huì)調(diào)用平臺(tái)總線的match函數(shù),匹配成功后就會(huì)調(diào)用平臺(tái)驅(qū)動(dòng)的xxx_probe()函數(shù)來進(jìn)行一系列的初始化工作。
UART驅(qū)動(dòng)的probe()調(diào)用過程如下:
s5p_serial_probe ----> s3c24xx_serial_probe(pdev, s5p_uart_inf[pdev->id])
最終調(diào)用的是s3c24xx_serial_probe();
詳細(xì)的代碼分析如下:
/* Device driver serial port probe */
int s3c24xx_serial_probe(struct platform_device *dev,
struct s3c24xx_uart_info *info)
{
struct s3c24xx_uart_port *ourport;//s3c24xx_uart_port封裝了uart_port
int ret;
dbg('s3c24xx_serial_probe(%p, %p) %dn', dev, info, dev->id);
if (dev->id >= ARRAY_SIZE(s3c24xx_serial_ports)) {
dev_err(&dev->dev, 'unsupported device id %dn', dev->id);
return -ENODEV;
}
ourport = &s3c24xx_serial_ports[dev->id];//s3c24xx_serial_ports是s3c24xx_uart_port結(jié)構(gòu)體類型的
ourport->channelnum= dev->id;
dbg('%s: initialising port %p...n', __func__, ourport);
ret = s3c24xx_serial_init_port(ourport, info, dev);//初始化UART端口 ------->
if (ret < 0)
goto probe_err;
dbg('%s: adding portn', __func__);
uart_add_one_port(&s3c24xx_uart_drv, &ourport->port);//添加端口,配置端口,構(gòu)造與本端口對(duì)應(yīng)的設(shè)備節(jié)點(diǎn)
platform_set_drvdata(dev, &ourport->port);//將ourport->port保存成平臺(tái)總線設(shè)備的私有數(shù)據(jù)。以后再要使用它時(shí)只需調(diào)用platform_get_drvdata()就可以了
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__);
/*
注冊(cè)通知鏈,當(dāng)CPU頻率改變時(shí)調(diào)用函數(shù)s3c24xx_serial_cpufreq_transition,最終調(diào)用函數(shù)
s3c24xx_serial_set_termios設(shè)置波特率等
*/
ret = s3c24xx_serial_cpufreq_register(ourport);//動(dòng)態(tài)頻率調(diào)節(jié)初始化
if (ret < 0)
dev_err(&dev->dev, 'failed to add cpufreq notifiern');
return 0;
probe_err:
return ret;
}
其中s3c24xx_serial_init_port函數(shù)的分析如下:
/* s3c24xx_serial_init_port
*
* initialise a single serial port from the platform device given
*/
/*初始化UART端口,建立各結(jié)構(gòu)體的聯(lián)系,申請(qǐng)中斷,IO資源。復(fù)位端口*/
static int s3c24xx_serial_init_port(struct s3c24xx_uart_port *ourport,
struct s3c24xx_uart_info *info,
struct platform_device *platdev)
{
struct uart_port *port = &ourport->port;
struct s3c2410_uartcfg *cfg;
struct resource *res;
int ret;
dbg('s3c24xx_serial_init_port: port=%p, platdev=%pn', port, platdev);
if (platdev == NULL)
return -ENODEV;
//s3c24xx_init_uarts --> s5pv210_init_uarts --> s5pv210_common_init_uarts --> s3c24xx_init_uartdevs -->>platdev->dev.platform_data = cfgptr
//在該函數(shù)中將cfg掛到platdev->dev.platform_data上。
cfg = s3c24xx_dev_to_cfg(&platdev->dev);//獲取cfg
if (port->mapbase != 0)
return 0;
if (cfg->hwport > CONFIG_SERIAL_SAMSUNG_UARTS) {
printk(KERN_ERR '%s: port %d bigger than %dn', __func__,
cfg->hwport, CONFIG_SERIAL_SAMSUNG_UARTS);
return -ERANGE;
}
/* setup info for port */
port->dev = &platdev->dev;//讓端口uart_port的成員dev指向平臺(tái)設(shè)備
//ourport的結(jié)構(gòu)體類型為struct s3c24xx_uart_port不是uart_port。
//此處的info的結(jié)構(gòu)體類型為s3c24xx_uart_info在文件samsung.h 中定義,s5pv210.c中初始化。不是uart_info。
ourport->info = info;
/* copy the info in from provided structure */
ourport->port.fifosize = info->fifosize;
dbg('s3c24xx_serial_init_port: %p (hw %d)...n', port, cfg->hwport);
port->uartclk = 1;
if (cfg->uart_flags & UPF_CONS_FLOW) {
dbg('s3c24xx_serial_init_port: enabling flow controln');
port->flags |= UPF_CONS_FLOW;
}
/* sort our the physical and virtual addresses for each UART */
上一篇:ARM-Linux S5PV210 UART驅(qū)動(dòng)(5)----串口的open操作(tty_open、uart_open)
下一篇:ARM-Linux S5PV210 UART驅(qū)動(dòng)(2)---- 終端設(shè)備驅(qū)動(dòng)
推薦閱讀最新更新時(shí)間:2025-03-31 08:06





- 熱門資源推薦
- 熱門放大器推薦
設(shè)計(jì)資源 培訓(xùn) 開發(fā)板 精華推薦
- 迅為IMX6開發(fā)板Android應(yīng)用-AndroidStudio-calculator測試
- 玩轉(zhuǎn) ESP32 + Arduino (二十) SIM800L上傳數(shù)據(jù)到OneNet(新版Mqtts)
- 玩轉(zhuǎn) ESP32 + Arduino (二十一) SPIFFS文件系統(tǒng) (已棄用)
- 玩轉(zhuǎn) ESP32 + Arduino (二十二) SIM800L上傳數(shù)據(jù)到阿里IOT(溫濕度和LBS)(NTP對(duì)時(shí))
- 玩轉(zhuǎn) ESP32 + Arduino (二十三) 多文件系統(tǒng)及全局變量
- 玩轉(zhuǎn) ESP32 + Arduino (二十四) SD卡讀寫
- 玩轉(zhuǎn) ESP32 + Arduino (二十五) SSD1306庫驅(qū)動(dòng)OLED
- 玩轉(zhuǎn) ESP32 + Arduino(二十六) 按鍵控制庫 OneButton
- 玩轉(zhuǎn) ESP32 + Arduino(二十七) ESP對(duì)象
- LT3973IMS 5V、2MHz 降壓轉(zhuǎn)換器的典型應(yīng)用
- 符合 IrDA 標(biāo)準(zhǔn)的發(fā)射器/接收器
- LED7708 的典型應(yīng)用 六排最多 10 個(gè)最大電流可調(diào)的白光 LED
- TB6605FTG 三相無刷直流電機(jī)驅(qū)動(dòng)器評(píng)估板
- OP184ESZ-REEL 3V 單電源、50Hz 至 60Hz 有源陷波濾波器和假接地的典型應(yīng)用
- STEVAL-ILL077V1,具有 STNRG388A 受控電流調(diào)節(jié)和調(diào)光功能的 60W 數(shù)字 3-LED 通道評(píng)估板
- 使用 Diodes Incorporated 的 PAM2701JER 的參考設(shè)計(jì)
- DC2402A,基于 LT6237 軌到軌 SAR ADC 驅(qū)動(dòng)器放大器的演示板
- DC800A-B,LT1993CUD-4 低失真、低噪聲差分放大器/ADC 驅(qū)動(dòng)器的演示板
- 15W 返馳智能手機(jī)/平板電腦參考設(shè)計(jì)(5V/3A)
- 從實(shí)驗(yàn)室到工業(yè)場景:優(yōu)艾智合密集發(fā)布7款人形機(jī)器人
- 地表最酷人形機(jī)器人,拿下新一輪2億元融資
- 自動(dòng)駕駛警示:沒有企業(yè)能完全避免自動(dòng)駕駛在復(fù)雜環(huán)境中的失誤
- 高階就高級(jí)嗎?我們到底該如何使用智能駕駛輔助?
- 即將迎來第三代?嵐圖固態(tài)電池研發(fā)進(jìn)展曝光
- 一文了解2025年3月的固態(tài)電池大事件!
- 傳統(tǒng)鋰電、半固態(tài)、固態(tài)電池終極對(duì)決:誰將主宰新能源未來?
- 國產(chǎn)智駕迎戰(zhàn)特斯拉FSD,背后AI含量差幾何?
- 左手AI,右手機(jī)器人,半導(dǎo)體巨頭英飛凌的新故事
- 激光雷達(dá)的復(fù)仇
- 直播預(yù)約 | 汽車圈盛會(huì)!第二屆英飛凌汽車創(chuàng)新峰會(huì)(IACE)全程直播
- 雷柏、京造的無線充電鼠標(biāo)墊,等你拆開看——EEWorld邀你來玩拆解(第三期)
- #每日好讀書#說一說你看過的那些好書
- 2021 Digikey KOL系列——親手教你轉(zhuǎn)起一臺(tái)無刷電機(jī)
- 是德科技有獎(jiǎng)直播:如何使用UXR系列高端示波器
- 感謝有你,感恩龍年,EEWORLD陪你一起“鬧”龍年!
- 有獎(jiǎng)直播|瑞薩電子 RA 系列產(chǎn)品開發(fā)工具之 FSP4.0.0 新特性介紹
- Avnet&On semi 帶你看未來,3個(gè)你必須知道的行業(yè)趨勢!
- 有獎(jiǎng)直播|TI DLP® 技術(shù)在AR HUD及車內(nèi)顯示應(yīng)用的展望
- 非蘋新機(jī)加持 全球智能手機(jī)看漲 但臺(tái)灣市場仍看淡
- 單片機(jī)定時(shí)計(jì)數(shù)器、中斷和串行口的學(xué)習(xí)
- 單片機(jī)的基本結(jié)構(gòu)解析
- 基于STM32F103RB單片機(jī)的、細(xì)分度可調(diào)的步進(jìn)電機(jī)驅(qū)動(dòng)器設(shè)計(jì)
- 基于PXA270和Windows CE5.0操作系統(tǒng)上的OSD驅(qū)動(dòng)的設(shè)計(jì)和實(shí)現(xiàn)
- 數(shù)字化打開充電服務(wù)想象空間
- 廣東電網(wǎng):專利申請(qǐng)“爆長” 科技支撐增強(qiáng)
- 南方電網(wǎng)計(jì)劃在未來4年投資251億元投建充電設(shè)施
- 華東能源監(jiān)管局聽取2020年華東電網(wǎng)運(yùn)行方式匯報(bào)
- 國家電網(wǎng)在綜合能源服務(wù)領(lǐng)域的“野心”