日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > linux >内容正文

linux

linux 串口驱动 atmel_set_mctrl何时调用,linux uart serial使用驱动分析

發布時間:2025/3/20 linux 24 豆豆
生活随笔 收集整理的這篇文章主要介紹了 linux 串口驱动 atmel_set_mctrl何时调用,linux uart serial使用驱动分析 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

uart?tty?serial?驅動分析?內核版本3.14.23

以atmel為例:

起點:

static?int?__init?atmel_serial_init(void)

{

int?ret;

//注冊串口驅動?函數原型:int?uart_register_driver(struct?uart_driver?*drv)

ret?=?uart_register_driver(&atmel_uart);

if(ret)

return?ret;

ret?=?platform_driver_register(&atmel_serial_driver);

if(ret)

uart_unregister_driver(&atmel_uart);

return?ret;

}

struct?uart_driver??atmel_uart?=?{

.owner?=?THIS_MODULE,

.driver_name?=“atmel_serial”, ?//驅動名稱

.dev_name???=?ATMEL_DEVICENAME, ?//“ttyS”

.major ?=?SERIAL_ATMEL_MAJOR, //主設備號

.minor ?=?MINOR_START, ? //從設備號

.nr ? =?ATMEL_MAX_UART, ?//支持最多設備個數

.con ? =?ATMEL_CONSOLE_DEVICE //作為console(控制臺)的一些配置

}

ATMEL_CONSOLE_DEVICE:#define?ATMEL_CONSOLE_DEVICE?(&atmel_console)

struct?console?atmel_console?=?{

.name?=?ATMEL_DEVICENAME,

.write?=?atmel_console_write,??//通過控制臺端口發送字符

.device?=?uart_console_device,//返回tty_driver

.setup?=?atmel_console_setup,//控制臺串口設置

flags??=?CON_PRINTBUFFER,//

.index?=?-1,

.data?=?&atmel_uart,??//uart_driver

}

平臺驅動:

static?struct?platform_driver?atmel_serial_dirver?=?{

.probe?=?atmel_serial_probe,

.remove?=?atmel_serial_remove,

.suspend?=?atmel_serial_suspend,

.resume??=?atmel_serial_resume,

.driver???=?{

.name?=“atmel_usart”,

.owner–THIS_MODULE,

.of_match_table?=?of_match_ptr(atmel_serial_dt_ids),

},

}

//與驅動對應的設備發現后調用

static?int?atmel_serial_probe(struct?platform_device?*pdev)

{

sturct?atmel_uart_port?*port;

//獲取設備樹參數

struct?device_node?*np??=?pdev->dev.of_node;

//獲取平臺設備參數

struct?atmel_uart_data?*pdata?=?dev_get_platdata(&pdev->dev);

void?*data;

int?ret?=?-ENODEV;

//以下主要是為了獲取設備號?是第幾個串口設備

//當設備樹參數存在時,?使用設備樹的參數?否則使用平臺設備的參數

if(np)

ret?=?of_alias_get_id(np,“serial”);

else

if(pdata)

ret?=?pdata->num;

if(ret?

ret?=?find_first_zero_bit(atmel_ports_in_use,?ATMEL_MAX_UART);

if(ret?>=?ATMEL_MAX_UART) {

ret?=?-ENODEV;

goto?err;

}

if(test_and_set_bit(ret,?atmel_ports_in_use))?{

ret?=?-EBUSY;

goto?err;

}

//對應的串口結構?取出?賦值。

port?=?&atmel_ports[ret];

port->backup_imr?=?0;

port->uart.line??=?ret;?//設備號

//初始化使用的串口結構體的數據

ret?=?atmel_init_port(port,pdev);

if(ret)

goto?err;

if(!atmel_usr_pdc_rx(&port->uart))?{

ret?=?-ENOMEM;

//申請接收緩沖區

data=kmalloc(sizeof(struct?atmel_uart_char)?*?ATMEL_SERIAL_RINGSIZE,??GFP_KERNEL);

if(!data)

goto?err_alloc_ring;

port->rx_ring.buf?=?data;

}

//將前面注冊串口設備的驅動和串口的設備聯系到一起

//此函數的原型:int?uart_add_one_port(struct?uart_driver?*drv,?struct?uart_port?*uport)

ret?=?uart_add_one_port(&atmel_uart,?&port->uart);

if(ret)

goto?err_add_port;

if(atmel_is_cosole_port(&port->uart)??&&?ATMEL_CONSOLE_DEVICE->flags?&?CON_ENABLE) {

clk_disable_unprepare(port->clk);

}

//使能設備可喚醒??

device_init_wakeup(&pdev->dev,1);

//將使用的串口結構體當做設備的私有數據?進行傳遞。

platform_set_drvdata(pdev,?port);

//初始化一些串口結構體的狀態數據

atmel_get_ip_name(&port->uart);

//出錯處理

err_add_port:

kfree(port->rx_ring.buf);

port->rx_ring.buf?=?NULL;

err_alloc_ring:

if(!atmel_is_console_port(&port->uart))?{

clk_put(port->clk);

port->clk?=?NULL;

}

err:

return?ret;

}

//串口設備卸載

static?int?atmel_serial_remove(struct?platform_device?*pdev)

{

struct?uart_port?*port?=?platform_get_drvdata(pdev);

struct?atmel_uart_port??*atmel_port?=?to_atmel_uart_port(port);

tasklet_kill(&atmel_port->tasklet);

//關閉可喚醒狀態

device_init_wakeup(&pdev->dev,?0);

ret?=?uart_remove_one_port(&atmel_uart,??port);

kfree(atmel_port->rx_ring.buf);

clear_bit(port->line,?atmel_ports_in_use);

clk_put(atmel_port->clk);

return?ret;

}

//填充串口設備的結構struct?uart_port

static?int?atmel_init_port(struct?atmel_uart_port?*atmel_port,?strcut?platform_device?*pdev)

{

int?ret;

struct?uart_port?*port?=?&atmel_port->uart;

struct?atmel_uart_data?*pdata?=?dev_get_platdata(&pdev->dev);

if(!atmel_init_property(atmel_port,?pdev))//第一次初始化,函數始終返回為0即?下面的函數一定會被執行

atmel_set_ops(port);//將串口接收和發送的初始化,執行,釋放的操作賦值

//485的一些初始操作

atmel_init_rs485(atmel_port,?pdev);

port->iotype?=?UPIO_MEM;

port->flags???=?UPF_BOOT_AUTOCONF;

port->ops????=?&atmel_pops;//操作函數結構?const?struct?uart_ops?*ops;

port->fifosize?=??1;//fifo?大小??

port->dev?=?&pdev->dev;

port->mapbase?=?pdev->resource[0].start;

port->irq =?pdev->resource[1].start;

//task初始化

tasklet_int(&atmel_port->tasklet,?atmel_tasklet_func,?(unsigned?long)port);

//環形緩沖區初始化

memset(&atmel_port->rx_ring,?0,?sizeof(atmel_port->rx_ring));

//時鐘的配置

if(!atmel_port->clk){

atmel_port->clk?=?clk_get(&pdev->dev,“usart”);

if(IS_ERR(atmel_port->clk))?{

ret?=?PTR_ERR(atmel_port->clk);

atmel_port->clk?=?NULL;

return?ret;

}

ret?=?clk_prepare_enable(atmel_port->clk)

if(ret){

clk_put(atmel_port->clk);

atmel_port->clk?=?NULL;

return?ret;

}

port->uartclk?=?clk_get_rate(atmel_port->clk);

clk_disable_unprepare(atmel_port->clk);?//只有當使用時才打開串口時鐘

}

if(atmel_port->rs485.flags?&?SER_RS485_ENABLE)

atmel_port->tx_done_mask?=?ATMEL_US_TXEMPTY;

else?if(atmel_use_pdc_tx(port)){

port->fifosize?=?PDC_BUFFER_SIZE;

atmel_port->tx_done_mask?=?ATMEL_US_ENDTX?|?ATMEL_US_TXBUFE;

}else{

atmel_port->tx_done_mask?=?ATMEL_US_TXRDY;

}

}

//串口的操作函數??此函數的介紹可以查看內核目錄下Documentation/serial/driver文檔

static?struct?uart_ops?atmel_pops?=?{

.tx_empty??=?atmel_tx_empty,//發送為空?狀態

.set_mctrl??=?atmel_set_mctrl,//model控制

.get_mctrl??=?atmel_get_mctrl,

.stop_tx =?atmel_stop_tx,??//停止發送

.start_tx ?=?atmel_start_tx,//開始發送數據

.stop_rx ?=?atmel_stop_rx,//停止接收數據

.enable_ms???=?atmel_enable_ms,//使能model控制中斷

.break_ctl =?atmel_break_ctl,?//?start?break?or?stop?break

.startup ?=?atmel_startup,//打開串口?配置串口??將在打開串口時被執行

.shutdown =?atmel_shutdown,//關閉串口?釋放資源的操作

.flush_buffer =?atmel_flush_buffer

.set_termios =?atmel_set_termiso,?,//設置串口?波特率等

.set_ldisc ?=?atmel_set_ldisc,

.type ?=?atmel_type,//返回port的名稱

.release_port =?atmel_release_port,//釋放串口的address?iounmap映射的資源

.request_port =?atmel_request_port,//申請串口address?ioremap

.config_port =?atmel_config_port,

.verify_port =?atmel_verify_port,//檢查串口的配置

.pm ? =?atmel_serial_pm,//串口時鐘管理?關閉或打開

.ioctl ? =?atmel_ioctl,//ioctl?接口

.poll_get_char =?atmel_poll_get_char,

.poll_put_char=?atmel_poll_put_char,

}

//串口打開設置參數解析

static?int?atmel_startup(struct?uart_port?*port)

{

struct?platform_device?*pdev?=?to_platform_device(port->dev);

struct?atmel_uart_port?*atmel_port?=?to_atmel_uart_port(port);

struct?tty_struct?*tty?=?port->state->port.tty;

int?retval;

//屏蔽所有的中斷

UART_PUT_IDR(port,?-1);

//申請中斷處理函數

retval?=?request_irq(port->irq,??atmel_interrupt,??IRQF_SHARED,?tty??tty->name:”atmel_serial”,?port);

if(retval){

printk(“atmel_serial:atmel_startup–can’t?get?irq\n”);

return?retval;

}

//串口使用狀態的初始化

atmel_init_property(atmel_port,?pdev);

//調用串口接收和發送數據之前的準備工作

//有三種方式:?普通,PDC,DMA三種方式發送和接收數據

if(atmel_port->prepare_rx){

retval?=?atmel_port->prepare_rx(port);

if(retval?

atmel_set_ops(port);

}

if(atmel_port->prepare_tx){

retval?=?atmel_port->prepare_tx(port);

if(retval<0)

atmel_set_ops(port);

}

//調用打開時的鉤子函數

if(atmel_open_hook){

retval?=?atmel_open_hook(port);

if(retval){

free_irq(port->irq,?port);

return?retval;

}

}

//中斷寄存器這時的狀態?保存

atmel_port->irq_status_prev?=?UART_GET_CSR(port);

atmel_port->irq_status?=?atmel_port->irq_status_prev;

//使能串口

UART_PUT_CR(port,?ATMEL_US_RSTSTA?|?ATMEL_US_RSTRX);

UART_PUT_CR(port,?ATMEL_US_TXEN|?ATMEL_US_RXEN);

//設置定時器?此定時函數?完成兩件事:1:tasklet_schedule??2:?mod_timer

setup_timer(&atmel_port->uart_timer,?atmel_uart_timer_callback,?(unsigned?long)port);

if(atmel_usr_pdc_rx(port))?{

//如果不是usart同步和異步的區別?下面其他接收方式同理

if(!atmel_port->is_usart){

//設置超時時間

mod_timer(&atmel_port->uart_timer,?jiffies?+?uart_poll_timeout(prot));

}else{

//如果是usart可以直接設定超時值給寄存器,讓硬件判斷

UART_PUT_RTOR(port,?PDC_RX_TIMEOUT);

UART_PUT_CR(port,?ATMEL_US_STTTO);

//使能超時和接收中斷

UART_PUT_IER(port,?ATMEL_US_ENDRX?|?ATMEL_US_TIMEOUT);

}

UART_PUT_PTCR(port,?ATMEL_PDC_RXTEN);

}else?if(atmel_use_dma_rx(port)){

if(!(atmel_port->is_usart))?{

mod_timer(&atmel_port->uart_timer,?jiffies?+?uart_poll_timeout(port));

}else{

//如果是usart可以直接設定超時值給寄存器,讓硬件判斷

UART_PUT_RTOR(port,?PDC_RX_TIMEOUT);

UART_PUT_CR(port,?ATMEL_US_STTTO);

//使能超時中斷

UART_PUT_IER(port,ATMEL_US_TIMEOUT);

}

}else{

//使能接收中斷

UART_PUT_IER(port,?ATMEL_US_RXRDY);

}

return?0;

}

總結

以上是生活随笔為你收集整理的linux 串口驱动 atmel_set_mctrl何时调用,linux uart serial使用驱动分析的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

主站蜘蛛池模板: 欧美三级午夜理伦三级中视频 | 国产亚洲不卡 | 女生和男生一起插插插 | 污污视频网站在线免费观看 | 四虎成人精品在永久免费 | 亚洲欧美自拍另类 | 久久久久久久香蕉 | 麻豆tube| 欧美精品久久久久久 | 狠狠91 | 亚洲精品午夜 | 国产在线免费 | 一本色道久久综合狠狠躁 | 九色综合网 | 综合久久久久久 | 天堂在线精品 | 日韩一级片中文字幕 | caoporen在线 | 亚洲人体一区 | 天天拍天天操 | 自拍亚洲国产 | 在线观看黄网 | 天堂福利在线 | 国产乱人对白 | 精品久久在线观看 | a中文在线 | av成人免费在线观看 | a级一级片| 成人性生交大片免费卡看 | 免费黄色小网站 | 中文字幕3| 久久艹在线观看 | 麻豆视频二区 | 影音先锋啪啪 | 亚洲日本中文字幕 | 精品九九在线 | 欧美激情xxxxx| 日产精品久久久久 | 中国大陆一级片 | 97国产在线播放 | 自拍偷拍欧美日韩 | 五月综合激情网 | 亚洲色图36p| 国产精品福利小视频 | 色噜av| 国产在线激情 | 青春草在线视频免费观看 | 精品国产九九 | 久久久久国产 | 国产一区第一页 | 不卡视频一区 | 欧美久久久久久又粗又大 | 日韩欧美在线观看一区 | 51吃瓜网今日吃瓜 | 精品国产一区二区在线观看 | 日本va欧美va欧美va精品 | 久久精品一日日躁夜夜躁 | jizzjizz免费| 777精品伊人久久久久大香线蕉 | 国产主播福利在线 | 午夜家庭影院 | 在线观看波多野结衣 | 麻豆精品国产传媒av绿帽社 | 欧美日韩3p | 九七影院在线观看免费观看电视 | 岛国片在线免费观看 | av免费天堂 | 538精品在线视频 | 久草成人 | 好爽又高潮了毛片 | 日韩最新在线 | 色婷婷久久五月综合成人 | 91蝌蚪网| 青青国产 | 老司机精品在线 | 香蕉在线播放 | 人妻洗澡被强公日日澡 | 婷婷丁香花五月天 | 快灬快灬一下爽69 | 久久大综合 | 欧美日韩一区二区三区四区五区六区 | 99国产在线观看 | 国产情侣激情 | 国产成人在线免费观看 | 伊人天天 | 野花视频在线免费观看 | 日色视频 | 亚洲国产日韩一区无码精品久久久 | 久久久久久久久久久99 | 神马久久春色 | 亚洲av成人精品一区二区三区 | 国产免费av网站 | 韩国精品在线 | 久久午夜片 | 99久久精品一区二区 | 91激情视频在线观看 | 青娱乐在线视频免费观看 | a天堂在线观看视频 | 午夜精品久久久久久久无码 |