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

歡迎訪問 生活随笔!

生活随笔

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

linux

Linux驱动修炼之道-SPI驱动框架源码分析(中)

發(fā)布時間:2024/9/5 linux 42 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Linux驱动修炼之道-SPI驱动框架源码分析(中) 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

來自:http://blog.csdn.NET/woshixingaaa/article/details/6574220

這篇來分析spi子系統(tǒng)的建立過程。
嵌入式微處理器訪問SPI設(shè)備有兩種方式:使用GPIO模擬SPI接口的工作時序或者使用SPI控制器。使用GPIO模擬SPI接口的工作時序是非常容易實現(xiàn)的,但是會導(dǎo)致大量的時間耗費在模擬SPI接口的時序上,訪問效率比較低,容易成為系統(tǒng)瓶頸。這里主要分析使用SPI控制器的情況。

這個是由sys文件系統(tǒng)導(dǎo)出的spi子系統(tǒng)在內(nèi)核中的視圖了。
首先了解一下Linux內(nèi)核中的幾個文件:spi.c也就是spi子系統(tǒng)的核心了,spi_s3c24xx.c是s3c24xx系列芯片的SPI controller驅(qū)動,它向更上層的SPI核心層(spi.c)提供接口用來控制芯片的SPI controller,是一個被其他驅(qū)動使用的驅(qū)動。而spidev.c是在核心層基礎(chǔ)之上將SPI controller模擬成一個字符型的驅(qū)動,向文件系統(tǒng)提供標準的文件系統(tǒng)接口,用來操作對應(yīng)的SPI controller。
下面我們來看看spi子系統(tǒng)是怎么注冊進內(nèi)核的:

view plain
  • static?int?__init?spi_init(void)??
  • {??
  • ????int?status;??
  • ????buf?=?kmalloc(SPI_BUFSIZ,?GFP_KERNEL);??
  • ????if?(!buf)?{??
  • ????????status?=?-ENOMEM;??
  • ????????goto?err0;??
  • ????}??
  • ????status?=?bus_register(&spi_bus_type);??
  • ????if?(status?<?0)??
  • ????????goto?err1;??
  • ????status?=?class_register(&spi_master_class);??
  • ????if?(status?<?0)??
  • ????????goto?err2;??
  • ????return?0;??
  • err2:??
  • ????bus_unregister(&spi_bus_type);??
  • err1:??
  • ????kfree(buf);??
  • ????buf?=?NULL;??
  • err0:??
  • ????return?status;??
  • }??
  • postcore_initcall(spi_init);??
  • 這里注冊了一個spi_bus_type,也就是一個spi總線,和一個spi_master的class。分別對應(yīng)上圖中sys/bus/下的spi目錄和sys/class/下的spi_master目錄。

    下面來分析SPI controller驅(qū)動的注冊與初始化過程,首先執(zhí)行的是s3c24xx_spi_init。

    view plain
  • static?int?__init?s3c24xx_spi_init(void)??
  • {??
  • ????????return?platform_driver_probe(&s3c24xx_spi_driver,?s3c24xx_spi_probe);??
  • }??
  • platform_driver_probe中完成了s3c24xx_spi_driver這個平臺驅(qū)動的注冊,相應(yīng)的平臺設(shè)備在devs.c中定義,在smdk2440_devices中添加&s3c_device_spi0,&s3c_device_spi1,這就生成了圖中所示的s3c24xx-spi.0與s3c24xx-spi.1,當然了這圖是在網(wǎng)上找的,不是我畫的,所以是6410的。這里s3c24xx-spi.0表示s3c2440的spi controller的0號接口,s3c24xx-spi.1表示s3c2440的spi controller的1號接口。注冊了s3c24xx_spi_driver后,賦值了平臺驅(qū)動的probe函數(shù)為s3c24xx_spi_probe。所以當match成功后,調(diào)用s3c24xx_spi_probe,這里看其實現(xiàn):

    view plain
  • <span?style="font-size:18px;">static?int?__init?s3c24xx_spi_probe(struct?platform_device?*pdev)??
  • {??
  • ????struct?s3c2410_spi_info?*pdata;??
  • ????struct?s3c24xx_spi?*hw;??
  • ????struct?spi_master?*master;??
  • ????struct?resource?*res;??
  • ????int?err?=?0;??
  • ????/*分配struct?spi_master+struct?s3c24xx_spi大小的數(shù)據(jù),把s3c24xx_spi設(shè)為spi_master的私有數(shù)據(jù)*/??
  • ????master?=?spi_alloc_master(&pdev->dev,?sizeof(struct?s3c24xx_spi));??
  • ????if?(master?==?NULL)?{??
  • ????????dev_err(&pdev->dev,?"No?memory?for?spi_master\n");??
  • ????????err?=?-ENOMEM;??
  • ????????goto?err_nomem;??
  • ????}??
  • ????/*從master中獲得s3c24xx_spi*/??
  • ????hw?=?spi_master_get_devdata(master);??
  • ????memset(hw,?0,?sizeof(struct?s3c24xx_spi));??
  • ??
  • ??
  • ????hw->master?=?spi_master_get(master);??
  • ????/*驅(qū)動移植的時候需要實現(xiàn)的重要結(jié)構(gòu),初始化為&s3c2410_spi0_platdata*/??
  • ????hw->pdata?=?pdata?=?pdev->dev.platform_data;??
  • ????hw->dev?=?&pdev->dev;??
  • ??
  • ??
  • ????if?(pdata?==?NULL)?{??
  • ????????dev_err(&pdev->dev,?"No?platform?data?supplied\n");??
  • ????????err?=?-ENOENT;??
  • ????????goto?err_no_pdata;??
  • ????}??
  • ????/*設(shè)置平臺的私有數(shù)據(jù)為s3c24xx_spi*/??
  • ????platform_set_drvdata(pdev,?hw);??
  • ????init_completion(&hw->done);??
  • ??
  • ??
  • ????/*?setup?the?master?state.?*/??
  • ????/*該總線上的設(shè)備數(shù)*/??
  • ????master->num_chipselect?=?hw->pdata->num_cs;??
  • ????/*總線號*/????
  • ????master->bus_num?=?pdata->bus_num;??
  • ??
  • ??
  • ????/*?setup?the?state?for?the?bitbang?driver?*/??
  • ????/*spi_bitbang專門負責數(shù)據(jù)的傳輸*/??
  • ????hw->bitbang.master?????????=?hw->master;??
  • ????hw->bitbang.setup_transfer?=?s3c24xx_spi_setupxfer;??
  • ????hw->bitbang.chipselect?????=?s3c24xx_spi_chipsel;??
  • ????hw->bitbang.txrx_bufs??????=?s3c24xx_spi_txrx;??
  • ????hw->bitbang.master->setup??=?s3c24xx_spi_setup;??
  • ??
  • ??
  • ????dev_dbg(hw->dev,?"bitbang?at?%p\n",?&hw->bitbang);??
  • ???????
  • ????。。。。。。。。。。。。。。。。。。。。。。。。??
  • ??????
  • ????/*初始化設(shè)置寄存器,包括對SPIMOSI,SPIMISO,SPICLK引腳的設(shè)置*/??
  • ????s3c24xx_spi_initialsetup(hw);??
  • ??
  • ??
  • ????/*?register?our?spi?controller?*/??
  • ??
  • ??
  • ????err?=?spi_bitbang_start(&hw->bitbang);??
  • ????????。。。。。。。。。。。。。。。。。。。。。??
  • }??
  • spi?controller的register在spi_bitbang_start函數(shù)中實現(xiàn):??
  • int?spi_bitbang_start(struct?spi_bitbang?*bitbang)??
  • {??
  • ????int?status;??
  • ??
  • ??
  • ????if?(!bitbang->master?||?!bitbang->chipselect)??
  • ????????return?-EINVAL;??
  • ????/*動態(tài)創(chuàng)建一個work_struct結(jié)構(gòu),它的處理函數(shù)是bitbang_work*/??
  • ????INIT_WORK(&bitbang->work,?bitbang_work);??
  • ????spin_lock_init(&bitbang->lock);??
  • ????INIT_LIST_HEAD(&bitbang->queue);??
  • ????/*spi的數(shù)據(jù)傳輸就是用這個方法*/??
  • ????if?(!bitbang->master->transfer)??
  • ????????bitbang->master->transfer?=?spi_bitbang_transfer;??
  • ????if?(!bitbang->txrx_bufs)?{??
  • ????????bitbang->use_dma?=?0;??
  • ????????/*spi_s3c24xx.c中有spi_bitbang_bufs方法,在bitbang_work中被調(diào)用*/??
  • ????????bitbang->txrx_bufs?=?spi_bitbang_bufs;??
  • ????????if?(!bitbang->master->setup)?{??
  • ????????????if?(!bitbang->setup_transfer)??
  • ????????????????bitbang->setup_transfer?=??
  • ?????????????????????spi_bitbang_setup_transfer;??
  • ????????????/*在spi_s3c24xx.c中有setup的處理方法,在spi_new_device中被調(diào)用*/??
  • ????????????bitbang->master->setup?=?spi_bitbang_setup;??
  • ????????????bitbang->master->cleanup?=?spi_bitbang_cleanup;??
  • ????????}??
  • ????}?else?if?(!bitbang->master->setup)??
  • ????????return?-EINVAL;??
  • ??
  • ??
  • ????/*?this?task?is?the?only?thing?to?touch?the?SPI?bits?*/??
  • ????bitbang->busy?=?0;??
  • ????/調(diào)用create_singlethread_workqueue創(chuàng)建單個工作線程/??
  • ????bitbang->workqueue?=?create_singlethread_workqueue(??
  • ????????????dev_name(bitbang->master->dev.parent));??
  • ????if?(bitbang->workqueue?==?NULL)?{??
  • ????????status?=?-EBUSY;??
  • ????????goto?err1;??
  • ????}??
  • ????status?=?spi_register_master(bitbang->master);??
  • ????if?(status?<?0)??
  • ????????goto?err2;??
  • ????return?status;??
  • err2:??
  • ????destroy_workqueue(bitbang->workqueue);??
  • err1:??
  • ????return?status;??
  • }</span>??
  • 然后看這里是怎樣注冊spi主機控制器驅(qū)動的:

    view plain
  • int?spi_register_master(struct?spi_master?*master)??
  • {??
  • ????。。。。。。。。。。。。。。。。??
  • ????/*將spi添加到內(nèi)核,這也是sys/class/Spi_master下產(chǎn)生Spi0,Spi1的原因*/??
  • ????dev_set_name(&master->dev,?"spi%u",?master->bus_num);??
  • ????status?=?device_add(&master->dev);??
  • ????scan_boardinfo(master);??
  • }??
  • 這里跟蹤scan_boardinfo函數(shù):

    view plain
  • static?void?scan_boardinfo(struct?spi_master?*master)??
  • {??
  • ????struct?boardinfo????*bi;??
  • mutex_lock(&board_lock);??
  • ????/*遍歷所有掛在board_list上的struct?boardinfo*/??
  • ????list_for_each_entry(bi,?&board_list,?list)?{??
  • ????????struct?spi_board_info???*chip?=?bi->board_info;??
  • ????????unsigned????n;??
  • ????????/*遍歷每個boardinfo管理的spi_board_info,如果設(shè)備的總線號與控制器的總線好相等,則創(chuàng)建新設(shè)備*/??
  • ????????for?(n?=?bi->n_board_info;?n?>?0;?n--,?chip++)?{??
  • ????????????if?(chip->bus_num?!=?master->bus_num)??
  • ????????????????continue;??
  • ????????????(void)?spi_new_device(master,?chip);??
  • ????????}??
  • ????}??
  • ????mutex_unlock(&board_lock);??
  • }??
  • 在移植的時候我們會在mach-smdk2440.c中的smdk2440_machine_init中添加spi_register_board_info

    這個函數(shù)完成了將spi_board_info交由boardinfo管理,并把boardinfo掛載到board_list鏈表上。也就是說在系統(tǒng)初始化的時候?qū)pi_device交由到掛在board_list上的boardinfo管理,在spi controller的driver注冊的時候不但注冊這個主機控制器的驅(qū)動,還要遍歷這個主機控制器的總線上的spi_device,將總線上的spi_device全部注冊進內(nèi)核。當注冊進內(nèi)核并且spi_driver已經(jīng)注冊的時候,如果總線match成功,則會調(diào)用spi_driver的probe函數(shù),這個將在后邊進行分析。

    view plain
  • <span?style="font-size:18px;">int?__init??
  • spi_register_board_info(struct?spi_board_info?const?*info,?unsigned?n)??
  • {??
  • ????struct?boardinfo????*bi;??
  • ??
  • ??
  • ????bi?=?kmalloc(sizeof(*bi)?+?n?*?sizeof?*info,?GFP_KERNEL);??
  • ????if?(!bi)??
  • ????????return?-ENOMEM;??
  • ????bi->n_board_info?=?n;??
  • ????memcpy(bi->board_info,?info,?n?*?sizeof?*info);??
  • ??
  • ??
  • ????mutex_lock(&board_lock);??
  • ????list_add_tail(&bi->list,?&board_list);??
  • ????mutex_unlock(&board_lock);??
  • ????return?0;??
  • }</span>??
  • 看一下創(chuàng)建新設(shè)備的函數(shù):
    view plain
  • <span?style="font-size:18px;">struct?spi_device?*spi_new_device(struct?spi_master?*master,??
  • ??????????????????struct?spi_board_info?*chip)??
  • {??
  • ????struct?spi_device???*proxy;??
  • ????int?????????status;??
  • ????proxy?=?spi_alloc_device(master);??
  • ????if?(!proxy)??
  • ????????return?NULL;??
  • ??
  • ??
  • ????WARN_ON(strlen(chip->modalias)?>=?sizeof(proxy->modalias));??
  • ????/*初始化spi_device的各個字段*/??
  • ????proxy->chip_select?=?chip->chip_select;??
  • ????proxy->max_speed_hz?=?chip->max_speed_hz;??
  • ????proxy->mode?=?chip->mode;??
  • ????proxy->irq?=?chip->irq;??
  • ????/*這里獲得了spi_device的名字,這個modalias也是在我們移植時在mach-smdk2440.c中的s3c2410_spi0_board中設(shè)定的*/??
  • ????strlcpy(proxy->modalias,?chip->modalias,?sizeof(proxy->modalias));??
  • ????proxy->dev.platform_data?=?(void?*)?chip->platform_data;??
  • ????proxy->controller_data?=?chip->controller_data;??
  • ????proxy->controller_state?=?NULL;??
  • ????/*主要完成將spi_device添加到內(nèi)核*/??
  • ????status?=?spi_add_device(proxy);??
  • ????if?(status?<?0)?{??
  • ????????spi_dev_put(proxy);??
  • ????????return?NULL;??
  • ????}??
  • ??
  • ??
  • ????return?proxy;??
  • }</span>??
  • 下面來看分配spi_alloc_device的函數(shù),主要完成了分配spi_device,并初始化spi->dev的一些字段。
    view plain
  • struct?spi_device?*spi_alloc_device(struct?spi_master?*master)??
  • {??
  • ????struct?spi_device???*spi;??
  • ????struct?device???????*dev?=?master->dev.parent;??
  • ????if?(!spi_master_get(master))??
  • ????????return?NULL;??
  • ????spi?=?kzalloc(sizeof?*spi,?GFP_KERNEL);??
  • ????if?(!spi)?{??
  • ????????dev_err(dev,?"cannot?alloc?spi_device\n");??
  • ????????spi_master_put(master);??
  • ????????return?NULL;??
  • ????}??
  • ????spi->master?=?master;??
  • ????spi->dev.parent?=?dev;??
  • ????/*設(shè)置總線是spi_bus_type,下面會講到spi_device與spi_driver是怎樣match上的*/??
  • ????spi->dev.bus?=?&spi_bus_type;??
  • ????spi->dev.release?=?spidev_release;??
  • ????device_initialize(&spi->dev);??
  • ????return?spi;??
  • }??
  • 下面來看分配的這個spi_device是怎樣注冊進內(nèi)核的:
    view plain
  • int?spi_add_device(struct?spi_device?*spi)??
  • {??
  • ????static?DEFINE_MUTEX(spi_add_lock);??
  • ????struct?device?*dev?=?spi->master->dev.parent;??
  • ????int?status;??
  • ????/*spi_device的片選號不能大于spi控制器的片選數(shù)*/??
  • ????if?(spi->chip_select?>=?spi->master->num_chipselect)?{??
  • ????????dev_err(dev,?"cs%d?>=?max?%d\n",??
  • ????????????spi->chip_select,??
  • ????????????spi->master->num_chipselect);??
  • ????????return?-EINVAL;??
  • ????}??
  • ????/*這里設(shè)置是spi_device在Linux設(shè)備驅(qū)動模型中的name,也就是圖中的spi0.0,而在/dev/下設(shè)備節(jié)點的名字是proxy->modalias中的名字*/??
  • ????dev_set_name(&spi->dev,?"%s.%u",?dev_name(&spi->master->dev),??
  • ????????????spi->chip_select);??
  • ????mutex_lock(&spi_add_lock);??
  • ????/*如果總線上掛的設(shè)備已經(jīng)有這個名字,則設(shè)置狀態(tài)忙碌,并退出*/??
  • ????if?(bus_find_device_by_name(&spi_bus_type,?NULL,?dev_name(&spi->dev))??
  • ????????????!=?NULL)?{??
  • ????????dev_err(dev,?"chipselect?%d?already?in?use\n",??
  • ????????????????spi->chip_select);??
  • ????????status?=?-EBUSY;??
  • ????????goto?done;??
  • ????}??
  • ????/對spi_device的時鐘等進行設(shè)置/??
  • ????status?=?spi->master->setup(spi);??
  • ????if?(status?<?0)?{??
  • ????????dev_err(dev,?"can't?%s?%s,?status?%d\n",??
  • ????????????????"setup",?dev_name(&spi->dev),?status);??
  • ????????goto?done;??
  • ????}??
  • ????/*添加到內(nèi)核*/??
  • ????status?=?device_add(&spi->dev);??
  • ????if?(status?<?0)??
  • ????????dev_err(dev,?"can't?%s?%s,?status?%d\n",??
  • ????????????????"add",?dev_name(&spi->dev),?status);??
  • ????else??
  • ????????dev_dbg(dev,?"registered?child?%s\n",?dev_name(&spi->dev));??
  • ??
  • ??
  • done:??
  • ????mutex_unlock(&spi_add_lock);??
  • ????return?status;??
  • }??
  • ??
  • ??
  • static?int?s3c24xx_spi_setup(struct?spi_device?*spi)??
  • {??
  • ????。。。。。。。。。。。。。。??
  • ????ret?=?s3c24xx_spi_setupxfer(spi,?NULL);??
  • ????。。。。。。。。。。。。。。??
  • }??
  • ??
  • ??
  • static?int?s3c24xx_spi_setupxfer(struct?spi_device?*spi,??
  • ?????????????????struct?spi_transfer?*t)??
  • {??
  • ????struct?s3c24xx_spi?*hw?=?to_hw(spi);??
  • ????unsigned?int?bpw;??
  • ????unsigned?int?hz;??
  • ????unsigned?int?div;??
  • ????/*設(shè)置了每字長的位數(shù),發(fā)送速度*/??
  • ????bpw?=?t???t->bits_per_word?:?spi->bits_per_word;??
  • ????hz??=?t???t->speed_hz?:?spi->max_speed_hz;??
  • ??
  • ??
  • ????if?(bpw?!=?8)?{??
  • ????????dev_err(&spi->dev,?"invalid?bits-per-word?(%d)\n",?bpw);??
  • ????????return?-EINVAL;??
  • ????}??
  • ????/*色黃志分頻值*/??
  • ????div?=?clk_get_rate(hw->clk)?/?hz;??
  • ??
  • ??
  • ????/*?is?clk?=?pclk?/?(2?*?(pre+1)),?or?is?it?
  • ?????*????clk?=?(pclk?*?2)?/?(?pre?+?1)?*/??
  • ??
  • ??
  • ????div?/=?2;??
  • ??
  • ??
  • ????if?(div?>?0)??
  • ????????div?-=?1;??
  • ??
  • ??
  • ????if?(div?>?255)??
  • ????????div?=?255;??
  • ??
  • ??
  • ????dev_dbg(&spi->dev,?"setting?pre-scaler?to?%d?(hz?%d)\n",?div,?hz);??
  • ????writeb(div,?hw->regs?+?S3C2410_SPPRE);??
  • ??
  • ??
  • ????spin_lock(&hw->bitbang.lock);??
  • ????if?(!hw->bitbang.busy)?{??
  • ????????hw->bitbang.chipselect(spi,?BITBANG_CS_INACTIVE);??
  • ????????/*?need?to?ndelay?for?0.5?clocktick???*/??
  • ????}??
  • ????spin_unlock(&hw->bitbang.lock);??
  • ??
  • ??
  • ????return?0;??
  • }??
  • 下面來看這個spi_driver是怎樣注冊的,又是與spi_device怎樣match上的。
    在spidev.c中:
    view plain
  • static?int?__init?spidev_init(void)??
  • {??
  • ????int?status;??
  • ????BUILD_BUG_ON(N_SPI_MINORS?>?256);??
  • ????status?=?register_chrdev(SPIDEV_MAJOR,?"spi",?&spidev_fops);??
  • ????if?(status?<?0)??
  • ????????return?status;??
  • ????spidev_class?=?class_create(THIS_MODULE,?"spidev");??
  • ????if?(IS_ERR(spidev_class))?{??
  • ????????unregister_chrdev(SPIDEV_MAJOR,?spidev_spi.driver.name);??
  • ????????return?PTR_ERR(spidev_class);??
  • ????}??
  • ????status?=?spi_register_driver(&spidev_spi);??
  • ????if?(status?<?0)?{??
  • ????????class_destroy(spidev_class);??
  • ????????unregister_chrdev(SPIDEV_MAJOR,?spidev_spi.driver.name);??
  • ????}??
  • ????return?status;??
  • }??
  • 注冊了名為”spi”的字符驅(qū)動,然后注冊了spidev_spi驅(qū)動,這個就是圖中sys/Bus/Spi/Drivers/下的spidev。
    view plain
  • static?struct?spi_driver?spidev_spi?=?{??
  • ????.driver?=?{??
  • ????????.name?=?????"spidev",??
  • ????????.owner?=????THIS_MODULE,??
  • ????},??
  • ????.probe?=????spidev_probe,??
  • ????.remove?=???__devexit_p(spidev_remove),??
  • };??
  • view plain
  • static?struct?spi_driver?spidev_spi?=?{??
  • ????.driver?=?{??
  • ????????.name?=?????"spidev",??
  • ????????.owner?=????THIS_MODULE,??
  • ????},??
  • ????.probe?=????spidev_probe,??
  • ????.remove?=???__devexit_p(spidev_remove),??
  • };??
  • 這里來看__driver_attach這個函數(shù),其中分別調(diào)用了driver_match_device,driver_probe_device函數(shù)。如果匹配成果調(diào)用probe函數(shù),否則返回。
    view plain
  • static?int?__driver_attach(struct?device?*dev,?void?*data)????
  • {????
  • ????struct?device_driver?*drv?=?data;????
  • ????if?(!driver_match_device(drv,?dev))????
  • ????????return?0;????
  • ????
  • ????if?(dev->parent)?/*?Needed?for?USB?*/????
  • ????????down(&dev->parent->sem);????
  • ????down(&dev->sem);????
  • ????if?(!dev->driver)????
  • ????????driver_probe_device(drv,?dev);????
  • ????up(&dev->sem);????
  • ????if?(dev->parent)????
  • ????????up(&dev->parent->sem);????
  • ????
  • ????return?0;????
  • }????
  • 匹配的時候調(diào)用的bus的match函數(shù)。
    view plain
  • struct?bus_type?spi_bus_type?=?{??
  • ???????.name?????????????=?"spi",??
  • ???????.dev_attrs???????=?spi_dev_attrs,??
  • ???????.match???????????=?spi_match_device,??
  • ???????.uevent???????????=?spi_uevent,??
  • ???????.suspend??=?spi_suspend,??
  • ???????.resume??????????=?spi_resume,??
  • };??
  • static?int?spi_match_device(struct?device?*dev,?struct?device_driver?*drv)??
  • {??
  • ????const?struct?spi_device?*spi?=?to_spi_device(dev);??
  • ??
  • ??
  • ????return?strcmp(spi->modalias,?drv->name)?==?0;??
  • }??
  • 可以看到這里根據(jù)驅(qū)動和設(shè)備的名字進行匹配,匹配成功后調(diào)用驅(qū)動的probe函數(shù)。
    view plain
  • static?int?spi_drv_probe(struct?device?*dev)??
  • {??
  • ????const?struct?spi_driver?????*sdrv?=?to_spi_driver(dev->driver);??
  • ??
  • ??
  • ????return?sdrv->probe(to_spi_device(dev));??
  • }??
  • 可以看大調(diào)用了具體的probe函數(shù),這里實現(xiàn)了把spidev添加到device_list,這樣這個虛擬的字符驅(qū)動就注冊并初始化完畢。
    view plain
  • static?int?spidev_remove(struct?spi_device?*spi)??
  • {??
  • ????struct?spidev_data??*spidev?=?spi_get_drvdata(spi);??
  • ??
  • ??
  • ????/*?make?sure?ops?on?existing?fds?can?abort?cleanly?*/??
  • ????spin_lock_irq(&spidev->spi_lock);??
  • ????spidev->spi?=?NULL;??
  • ????spi_set_drvdata(spi,?NULL);??
  • ????spin_unlock_irq(&spidev->spi_lock);??
  • ??
  • ??
  • ????/*?prevent?new?opens?*/??
  • ????mutex_lock(&device_list_lock);??
  • ????list_del(&spidev->device_entry);??
  • ????device_destroy(spidev_class,?spidev->devt);??
  • ????clear_bit(MINOR(spidev->devt),?minors);??
  • ????if?(spidev->users?==?0)??
  • ????????kfree(spidev);??
  • ????mutex_unlock(&device_list_lock);??
  • ??
  • ??
  • ????return?0;??
  • }??
  • 在spidev的注冊函數(shù)中注冊了文件操作集合file_operations,為用戶空間提供了操作SPI controller的接口。
    view plain
  • static?struct?file_operations?spidev_fops?=?{??
  • ????.owner?=????THIS_MODULE,??
  • ????/*?REVISIT?switch?to?aio?primitives,?so?that?userspace?
  • ?????*?gets?more?complete?API?coverage.??It'll?simplify?things?
  • ?????*?too,?except?for?the?locking.?
  • ?????*/??
  • ????.write?=????spidev_write,??
  • ????.read?=?????spidev_read,??
  • ????.unlocked_ioctl?=?spidev_ioctl,??
  • ????.open?=?????spidev_open,??
  • ????.release?=??spidev_release,??
  • };??
  • 到此為止spi子系統(tǒng)與spi_master,spi_device,spi_driver這個Linux設(shè)備驅(qū)動模型已經(jīng)建立完了。

    總結(jié)

    以上是生活随笔為你收集整理的Linux驱动修炼之道-SPI驱动框架源码分析(中)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。