Android模拟器学framework和driver之传感器篇1(linux sensor driver)
對于android模擬器開發環境的搭建這里我就不多說了,網上google下一大堆,還有就是android 模擬器的kernel使用的是goldfish的kernel,可以使用git得到源碼,然后就可以編譯了,大家還是可以參考羅老師的博客。。。
?
在這里我準備編寫一個溫度傳感器的虛擬driver,之前寫過g-sensor和light sensor,所以不想寫了,換個新鮮的,其實驅動架構都是一樣的,OK 分化不多說,下面就介紹一下這個驅動。
?
在這里,我比較偷懶的使用了linux的一個iio子系統,這是一個不成熟的子系統,所以被放到源碼陌路下面的/drvers/staging中,對于這個子系統,我也只是粗略的看過它的驅動模型,好吧 ^0^,不過個人覺得這個子系統還是蠻簡單使用的,而卻里面的api不是很多,相信大家隨便分析下就能搞懂了。
?
OK,首先是頭文件
/common/drivers/staging/iio/temperature/android-temperature.h
?
[cpp]?view plaincopy- #include?<linux/module.h>??
- #include?<linux/platform_device.h>??
- #include?<linux/slab.h>??
- #include?<linux/input-polldev.h>??
- #include?"../iio.h"??
- ??
- #define?POLL_INTERVAL???2000????//set?poll?time??
- ??
- struct?temperature_drvdata?{??
- ????struct?iio_dev?*indio_dev;??
- ????struct?input_polled_dev?*poll_input;??
- ????//....reserved??
- };??
相信大家看到了這個頭文件就差不多知道驅動是怎么寫的了吧,我選用的是platform device driver,driver layer向user space傳送數據時通過input sybsystem傳送的,這也是android sensor驅動比較主流的做法,還有一些做法是直接往自己創建的sysfs中寫數據,這也是一中比較簡單的做法,事件的觸控方式我選用的是poll方式,因為這里我寫的驅動是一個虛擬的設備,一般出發方式會選用中斷觸發,而我這個驅動選擇每隔一段時間往user space上報數據,時間間隔就是這里的POLL_INTERVAL這個宏設定的。
說了這么多都沒有看到驅動的代碼真不好意思,下面來分析下驅動的代碼。
/common/drivers/staging/iio/temperature/android-temperature.c
首先是init和exit函數:
?
[html]?view plaincopy- <span?style="color:#cc33cc;"><strong>static?int?__init?temperature_init(void)??
- {??
- ????printk(KERN_INFO?"temperature?init...\n");??
- ????return?platform_driver_register(&temperature_device_driver);??
- }??
- ??
- static?void?__exit?temperature_exit(void)??
- {??
- ????platform_driver_unregister(&temperature_device_driver);??
- }??
- ??
- module_init(temperature_init);??
- module_exit(temperature_exit);</strong></span>??
- 這也沒啥好說的,大家愿意的話可以再后面在添上這個driver?module的作者和出處,傳揚千里,哈哈,我就不了,本人比較謙虛。??
這邊最主要的應該就是temperature_device_driver這個變量這是一個platform_driver結構體,在驅動注冊的時候必須把這個結構體傳進去,我們的platform設備模型就是通過這個結構體找到相應的device,然后把driver和device綁定在一起,這邊涉及到linux 設備驅動模型,這邊我也不做詳細的分析了,想要了解的話可以自己學習,個人覺得如果是做linux驅動的話了解linux 設備驅動模型是很重要的,這可以讓我們站在一個比較高的層次上去寫代碼。
?
OK,不扯了看下這個結構體:
?
[cpp]?view plaincopy- <span?style="background-color:?rgb(255,?255,?255);"><span?style="color:#cc33cc;">static?struct?platform_driver?temperature_device_driver?=?{??
- ????.probe??????=???temperature_probe,??
- //??.remove?????=???__devexit_p(temperature_remove),??
- ????.driver?????=?{??
- ????????.name?=?"android-temperature",??
- ????????.owner=?THIS_MODULE,??
- ????},??
- };</span></span>??
這邊就是定義了probe和remove,真實的設備的話還有會suspend,resume,early_suspend,late_resume等回調函數,在適當的時間會回調到這些函數(犀利的讀者可能看到了這邊remove我沒有去實現,哈哈,我比較懶,不過大家要有一個良好的習慣,不要學我)。但是在這邊注冊了platform的驅動,是去找哪的platform設備呢?當然是我們自己要去實現啦,通常device端我們都會在板級的文件中去定義,我們這里是:
?
/common/arch/arm/mach-goldfish/board-goldfish.c
?
[cpp]?view plaincopy- <strong><span?style="color:#cc33cc;">struct?platform_device?android_temperature_device?=?{??
- ????.name="android-temperature",??
- ????.id=-1,??
- };??
- </span></strong>??
- static?void?__init?goldfish_init(void)??
- {??
- ????platform_device_register(&goldfish_pdev_bus_device);??
- <span?style="color:#cc33cc;"><strong>???platform_device_register(&android_temperature_device);</strong></span>??
- }??
大家注意。這邊的name和driver中platform_driver中name用該一樣,不然他們怎么可以綁定在一起呢,不然他們怎么會找到對方呢,有緣千里來相會嘛,對不?
?
OK,當我們的driver找到了device的時候會執行probe回調函數,也就是這里的temperature_probe函數,好,我們來看一下這個probe函數:
?
[cpp]?view plaincopy- <strong><span?style="color:#cc33cc;">static?int?temperature_probe(struct?platform_device?*pdev)??
- {??
- ????struct?temperature_drvdata?*ddata;??
- ????struct?input_dev?*idev;??
- ????int?err=0;??
- ????printk(KERN_INFO?"%s\n",__FUNCTION__);??
- ????ddata=kzalloc(sizeof(struct?temperature_drvdata),GFP_KERNEL);??
- ????if(!ddata)?{??
- ????????printk(KERN_INFO?"failed?to?allocate?memory...\n");??
- ????????err=-ENOMEM;??
- ????????goto?exit;??
- ????}??
- ????//----for?iio?device??
- ????ddata->indio_dev=iio_allocate_device();??
- ????if(!ddata->indio_dev){??
- ????????printk(KERN_INFO?"error?to?allocate?iio?device?memory....\n");??
- ????????goto?exit_iio_alloc;??
- ????}??
- ????ddata->indio_dev->attrs?=?&temperature_attr_group;??
- ????ddata->indio_dev->dev.parent?=?&pdev->dev;??
- ????ddata->indio_dev->dev_data?=?(void?*)(ddata);??
- ????ddata->indio_dev->driver_module?=?THIS_MODULE;??
- ????ddata->indio_dev->modes?=?INDIO_DIRECT_MODE;??
- ????err?=?iio_device_register(ddata->indio_dev);??
- ????if(err){??
- ????????printk(KERN_INFO?"iio?device?register?failed....\n");??
- ????????goto?exit_iio_reg;??
- ????}??
- ????//-----for?input?device??
- ????ddata->poll_input=input_allocate_polled_device();??
- ????if(!(ddata->poll_input)){??
- ????????err=-ENOMEM;??
- ????????printk(KERN_INFO?"input?poll?allocate?failed...\n");??
- ????????goto?exit_iio_reg;??
- ????}??
- ????ddata->poll_input->poll=temperature_dev_poll;??
- ????ddata->poll_input->poll_interval?=?POLL_INTERVAL;??
- ????idev=ddata->poll_input->input;??
- ????idev->name?=?"Android?Temperature?Sensor";??
- ????idev->phys?=?"temperature-sensor/input0";??
- ????idev->dev.parent=&pdev->dev;??
- ????idev->id.bustype=BUS_HOST;??
- ????idev->id.vendor=0x1234;??
- ????idev->id.product=0x0123;??
- ????idev->id.version=0x0012;??
- ????__set_bit(EV_ABS,idev->evbit);??
- ????__set_bit(ABS_PRESSURE,idev->absbit);??
- ????__set_bit(EV_SYN,idev->evbit);??
- ????input_set_abs_params(idev,ABS_PRESSURE,0,65535,0,0);??
- ????err=input_register_polled_device(ddata->poll_input);??
- ????if(err){??
- ????????printk(KERN_INFO?"input?register?poll?device?failed....\n");??
- ????????goto?err_reg_poll;??
- ????}??
- ????platform_set_drvdata(pdev,ddata);??
- ????return?0;??
- err_reg_poll:??
- ????input_free_polled_device(ddata->poll_input);??
- exit_iio_reg:??
- ????iio_free_device(ddata->indio_dev);??
- exit_iio_alloc:??
- ????kfree(ddata);??
- exit:??
- ????return?err;??
- }</span></strong>??
這邊做的都是一些初始化的事情,我們這邊首先給我們的機構體分配內存,然后給iio device分配空間,然后注冊iio device,然后注冊input_polled_device這里可以參考input)poll的源碼,主要就是內嵌了一個工作隊列來poll數據,這里不多說讀者可以自行去分析。
?
這里最重要的有2點我提一下,首先就是我們poll數據的回調函數被掛在ddata->poll_input->poll=temperature_dev_poll;參考源碼這個回調函數是什么時候被執行的呢,其實input_polled_dev還有幾個回調函數,其中有一個open和close函數,當user space去open input下面的這個event的時候poll回調函數就會一直執行,時間間隔為我們定義的interval這個參數。還有一點就是iio 設備驅動上面掛的文件系統就是ddata->indio_dev->attrs = &temperature_attr_group;用法很簡單吧,這邊我只是注冊了一個name的文件節點,user space可以去讀寫這個節點,一般我們寫驅動的時候可以用這個文件節點來開關我們的設備。
OK,接下來就是一些事件的處理,看如下代碼:
?
[cpp]?view plaincopy- <span?style="color:#cc33cc;"><strong>#include?"android-temperature.h"??
- ??
- ??
- static?ssize_t?temperature_show_name(struct?device?*dev,??
- ????struct?device_attribute?*attr,?char?*buf)??
- {?????
- ????return?sprintf(buf,?"%s\n",?"android-temperature?sensor");??
- }??
- ??
- static?IIO_DEVICE_ATTR(name,?S_IRUGO,?temperature_show_name,?NULL,0);??
- ??
- static?struct?attribute?*temperature_attributes[]?=?{??
- ????&iio_dev_attr_name.dev_attr.attr,??
- ????NULL??
- };??
- ??
- static?const?struct?attribute_group?temperature_attr_group?=?{??
- ????.attrs?=?temperature_attributes,??
- };??
- ??
- static?int?tempValue;??
- static?void?temperature_dev_poll(struct?input_polled_dev?*dev)??
- {??
- ????printk(KERN_INFO?"Current?Temperature:?%d\n",tempValue);??
- ????if((tempValue++)==100)??
- ????????tempValue=0;??
- ????input_event(dev->input,EV_ABS,ABS_PRESSURE,tempValue);??
- ????input_sync(dev->input);??
- }</strong></span>??
這里我們上報的數據就是這個tempValue,會每隔一段時間自增1,直到100再回到0,。
?
OK,驅動介紹完,接下來就可以把驅動編譯進goldfish里面,然后運行模擬器,使用adb進入:
?
[html]?view plaincopy- <strong><span?style="color:#cc33cc;">root@jay:/home/jay/android/common#?adb?shell??
- #?cd?sys/bus/iio/devices/??
- #?ls??
- device0??
- device1??
- device2??
- #?cd?device2??
- #?ls??
- uevent??
- subsystem??
- power??
- name??
- #?cat?name??
- android-temperature?sensor??
- #?</span></strong>??
大家可以看到我這邊cat出name就是自己寫進去的那個名字,初步測試驅動ok接下來下一篇中給大家介紹下編譯生成一個tool來測試驅動功能。
轉載于:https://www.cnblogs.com/zhangjie-ai-liujun/archive/2012/03/31/2426695.html
總結
以上是生活随笔為你收集整理的Android模拟器学framework和driver之传感器篇1(linux sensor driver)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 苦海无涯下一句是什么啊?
- 下一篇: 总结是学习最好的方式(转)