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

歡迎訪問 生活随笔!

生活随笔

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

Android

s5p4418 Android 4.4.2 驱动层 HAL层 服务层 应用层 开发流程记录(一 硬件驱动层)

發布時間:2024/9/3 Android 58 豆豆
生活随笔 收集整理的這篇文章主要介紹了 s5p4418 Android 4.4.2 驱动层 HAL层 服务层 应用层 开发流程记录(一 硬件驱动层) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

歡迎轉載,務必注明出處:http://blog.csdn.net/wang_shuai_ww/article/details/44303069

本文章是記錄Android開發中驅動層、HAL層、應用層之間的關系,以及其開發方法,本文將會以實現LED的控制為例來進行記錄。

一是可以給以后自己做開發做參考,二是希望可以幫助正在學習的朋友參考。

一般的app不需要我們去關注hal和驅動,但在設計一個硬件系統時,原生的Android并未提供合適的服務,所以我們才需要去了解這個流程。由于也是剛入門,很多還不太懂,朋友們有什么疑問可以留言。


首先需要了解,Android的app想要操作硬件,是什么樣的一個流程。一般是這樣的,app應用層、服務層、硬件抽象層、底層驅動。

我是從底層到上層來進行學習和測試的。也就是:底層->硬件抽象層->服務層->app。原因是,首先需要確定底層的驅動沒有問題,而且底層驅動可以使用Linux的方法來進行測試,一步一步走到上層應用。


驅動代碼我就直接貼上來,就不去詳細解釋里面的含義了,不懂的可以參考羅升陽的《Android系統源碼情景分析》的第二章。

代碼如下:


#include <linux/kernel.h> #include <linux/module.h> #include <linux/cdev.h> #include <linux/fs.h> #include <linux/types.h> #include <linux/moduleparam.h> #include <linux/slab.h> #include <linux/ioctl.h> #include <linux/cdev.h> #include <linux/delay.h> #include <linux/io.h> #include <linux/gpio.h>#include <mach/platform.h> #include <mach/devices.h> #include <mach/soc.h> #include <mach/gpio.h> #include <linux/uaccess.h> #include <linux/pci.h>#include <linux/proc_fs.h>#define DEVICE_NAME "real_led"#define LED_DEVICE_NODE_NAME DEVICE_NAME #define LED_DEVICE_FILE_NAME DEVICE_NAME #define LED_DEVICE_PROC_NAME DEVICE_NAME #define LED_DEVICE_CLASS_NAME DEVICE_NAMEstatic int led_gpios[] = {(PAD_GPIO_C + 1), };#define LED_NUM ARRAY_SIZE(led_gpios)/*主設備和從設備號變量*/ static int led_major = 0; static int led_minor = 0; static struct class* led_class = NULL; /*訪問設置屬性方法*/ static ssize_t led_val_show(struct device* dev, struct device_attribute* attr, char* buf); static ssize_t led_val_store(struct device* dev, struct device_attribute* attr, const char* buf, size_t count); /*定義設備屬性*/ static DEVICE_ATTR(val, S_IRUGO | S_IWUSR, led_val_show, led_val_store); struct leds_dev {struct cdev dev;int led_status; };struct leds_dev *led_dev=NULL;/*打開設備方法*/ static int led_open(struct inode* inode, struct file* filp) { struct leds_dev* dev; /*將自定義設備結構體保存在文件指針的私有數據域中,以便訪問設備時拿來用*/ dev = container_of(inode->i_cdev, struct leds_dev, dev); filp->private_data = dev; return 0; } /*設備文件釋放時調用,空實現*/ static int led_release(struct inode* inode, struct file* filp) { return 0; } /*讀取設備的寄存器val的值*/ static ssize_t led_read(struct file* filp, char __user *buf, size_t count, loff_t* f_pos) { ssize_t err = 0; struct leds_dev* dev = filp->private_data; if(count < sizeof(dev->led_status)) { goto out; } /*將寄存器val的值拷貝到用戶提供的緩沖區*/ if(copy_to_user(buf, &(dev->led_status), sizeof(dev->led_status))) { err = -EFAULT; goto out; } err = sizeof(dev->led_status); out: return err; } /*寫設備的寄存器值val*/ static ssize_t led_write(struct file* filp, const char __user *buf, size_t count, loff_t* f_pos) { struct leds_dev* dev = filp->private_data; ssize_t err = 0; int i;if(count != sizeof(dev->led_status)) { goto out; } /*將用戶提供的緩沖區的值寫到設備寄存器去*/ if(copy_from_user(&(dev->led_status), buf, count)) { err = -EFAULT; goto out; } for(i=0;i<LED_NUM;i++){if((0x01&(dev->led_status>>i))==1)nxp_soc_gpio_set_out_value(led_gpios[i], 0);elsenxp_soc_gpio_set_out_value(led_gpios[i], 1);}err = sizeof(dev->led_status); out: return err; } static int led_ioctl(struct file *file, unsigned int cmd, unsigned long num) {//由于開發板只有一個LED,所以這里做個判斷,傳入的num不等于0,返回錯誤 if(num != 0) { printk("RealARM S5P4418 board only have one led lights.Please check app input parameters.\n");return -EINVAL; }nxp_soc_gpio_set_out_value(led_gpios[num], cmd); } /**************************************************************************************//*設備文件操作方法表*/ static struct file_operations led_fops = { .owner = THIS_MODULE, .open = led_open, .release = led_release, .read = led_read, .write = led_write, .unlocked_ioctl= led_ioctl, }; /**************************************************************************************/static ssize_t __led_get_val(struct leds_dev* dev, char* buf) { int val = 0; val = dev->led_status; return snprintf(buf, PAGE_SIZE, "%d\n", val); } /*把緩沖區buf的值寫到設備寄存器val中去,內部使用*/ static ssize_t __led_set_val(struct leds_dev* dev, const char* buf, size_t count) { int val = 0; int i;/*將字符串轉換成數字*/ val = simple_strtol(buf, NULL, 10); for(i=0;i<LED_NUM;i++){nxp_soc_gpio_set_out_value(led_gpios[i], val);} dev->led_status = val; return count; } /*讀取設備屬性val*/ static ssize_t led_val_show(struct device* dev, struct device_attribute* attr, char* buf) { struct leds_dev* hdev = (struct leds_dev*)dev_get_drvdata(dev); return __led_get_val(hdev, buf); } /*寫設備屬性val*/ static ssize_t led_val_store(struct device* dev, struct device_attribute* attr, const char* buf, size_t count) { struct leds_dev* hdev = (struct leds_dev*)dev_get_drvdata(dev); return __led_set_val(hdev, buf, count); } /**************************************************************************************//*讀取設備寄存器val的值,保存在page緩沖區中*/ static ssize_t led_proc_read(char* page, char** start, off_t off, int count, int* eof, void* data) { if(off > 0) { *eof = 1; return 0; } return __led_get_val(led_dev, page); } /*把緩沖區的值buff保存到設備寄存器val中去*/ static ssize_t led_proc_write(struct file* filp, const char __user *buff, unsigned long len, void* data) { int err = 0; char* page = NULL; if(len > PAGE_SIZE) { printk(KERN_ALERT"The buff is too large: %lu./n", len); return -EFAULT; } page = (char*)__get_free_page(GFP_KERNEL); if(!page) { printk(KERN_ALERT"Failed to alloc page./n"); return -ENOMEM; } /*先把用戶提供的緩沖區值拷貝到內核緩沖區中去*/ if(copy_from_user(page, buff, len)) { printk(KERN_ALERT"Failed to copy buff from user./n"); err = -EFAULT; goto out; } err = __led_set_val(led_dev, page, len); out: free_page((unsigned long)page); return err; } /*創建/proc/led文件*/ static void led_create_proc(void) { struct proc_dir_entry* entry; entry = create_proc_entry(DEVICE_NAME, 0, NULL); if(entry) { // entry->owner = THIS_MODULE; entry->read_proc = led_proc_read; entry->write_proc = led_proc_write; } } /*刪除/proc/led文件*/ static void led_remove_proc(void) { remove_proc_entry(DEVICE_NAME, NULL); } /**************************************************************************************/static int __led_setup_dev(struct leds_dev* dev) { int err; dev_t devno = MKDEV(led_major, led_minor); memset(dev, 0, sizeof(struct leds_dev)); cdev_init(&(led_dev->dev), &led_fops); dev->dev.owner = THIS_MODULE; dev->dev.ops = &led_fops; /*注冊字符設備*/ err = cdev_add(&(dev->dev),devno, 1); if(err) { return err; } return 0; } static int __init real4418_led_dev_init(void) {int ret;int i;unsigned int val;int err = -1; dev_t dev = 0; struct device* temp = NULL; for (i = 0; i < LED_NUM; i++) {ret = gpio_request(led_gpios[i], "LED");if (ret) {printk("%s: request GPIO %d for LED failed, ret = %d\n", DEVICE_NAME,led_gpios[i], ret);goto fail;}nxp_soc_gpio_set_io_func(led_gpios[i], 1); nxp_soc_gpio_set_io_dir(led_gpios[i], 1);nxp_soc_gpio_set_out_value(led_gpios[i], 0);}/*動態分配主設備和從設備號*/ err = alloc_chrdev_region(&dev, 0, 1, DEVICE_NAME); if(err < 0) { printk(KERN_ALERT"Failed to alloc char dev region./n"); goto fail; } led_major = MAJOR(dev); led_minor = MINOR(dev); /*分配led設備結構體變量*/ led_dev = kmalloc(sizeof(struct leds_dev), GFP_KERNEL); if(!led_dev) { err = -ENOMEM; printk(KERN_ALERT"Failed to alloc led_dev./n"); goto unregister; } /*初始化設備*/ err = __led_setup_dev(led_dev); if(err) { printk(KERN_ALERT"Failed to setup dev: %d./n", err); goto cleanup; } /*在/sys/class/目錄下創建設備類別目錄led*/ led_class = class_create(THIS_MODULE, LED_DEVICE_CLASS_NAME); if(IS_ERR(led_class)) { err = PTR_ERR(led_class); printk(KERN_ALERT"Failed to create led class./n"); goto destroy_cdev; } /*在/dev/目錄和/sys/class/led目錄下分別創建設備文件led*/ temp = device_create(led_class, NULL, dev, "%s", LED_DEVICE_FILE_NAME); if(IS_ERR(temp)) { err = PTR_ERR(temp); printk(KERN_ALERT"Failed to create led device."); goto destroy_class; } /*在/sys/class/led/led目錄下創建屬性文件val*/ err = device_create_file(temp, &dev_attr_val); if(err < 0) { printk(KERN_ALERT"Failed to create attribute val."); goto destroy_device; } dev_set_drvdata(temp, led_dev); led_create_proc(); printk(DEVICE_NAME"\tinitialized\n");return ret;destroy_device: device_destroy(led_class, dev); destroy_class: class_destroy(led_class); destroy_cdev: cdev_del(&(led_dev->dev)); cleanup: kfree(led_dev); unregister: unregister_chrdev_region(MKDEV(led_major, led_minor), 1); fail: for (; i >=0; i--)gpio_free(led_gpios[i]);return err; }static void __exit real4418_led_dev_exit(void) {int i;dev_t devno = MKDEV(led_major, led_minor); for (i = 0; i < LED_NUM; i++) {gpio_free(led_gpios[i]);}/*刪除/proc/led文件*/ led_remove_proc(); /*銷毀設備類別和設備*/ if(led_class) { device_destroy(led_class, MKDEV(led_major, led_minor)); class_destroy(led_class); } /*刪除字符設備和釋放設備內存*/ if(led_dev) { cdev_del(&(led_dev->dev)); kfree(led_dev); } /*釋放設備號*/ unregister_chrdev_region(devno, 1); printk(KERN_ALERT"Destroy led device./n"); }module_init(real4418_led_dev_init); module_exit(real4418_led_dev_exit);MODULE_LICENSE("GPL"); MODULE_AUTHOR("sean <wsh_sean@qq.com>");


我的文件名是real4418_leds.c,把該文件放到內核目錄/drivers/leds下,并修改當前目錄下的kconfig和Makefile文件,分別如下:

kconfig添加配置選項:

config LEDS_REALARMtristate "LED Support for RealARM S5P4418"helpThis option enables support for on-chip LED drivers found on RealARMS5P4418.
Makefile添加下面的代碼:
obj-$(CONFIG_LEDS_REALARM) += real4418_leds.o 使用make ARCH=arm xconfig命令進行內核配置。如下圖所示:


編譯內核,下載到開發板啟動。


下面是測試上面代碼的方法:

需要測試三個部分,傳統設備文件接口系統、devfs文件系統接口、proc文件系統接口,這三種接口均可實現對LED的硬件操作,Android部分的hal層使用的是read和write方式。

傳統的接口系統需要寫Linux應用程序來進行測試,我這里就不再詳細寫了,可以參考《Android系統源碼情景分析》里面的寫法,就是使用open、read、write、unlocked_ioctl這些函數。下面是使用ioctl來進行測試的,read、write按照read、write的用法就行了。

/* ============================================== Name : led_test.c Author : sean Date : 16/3/2015 Description : s5p4418 led driver test ============================================== */ #include <stdio.h> #include <stdlib.h> #include <fcntl.h> #include<sys/ioctl.h> int main(int argc, char**argv) { int turn, index, fd; if(strcmp(argv[1], "on") == 0) { turn = 1; } else if(strcmp(argv[1], "off") ==0) { turn = 0; } else { printf("Usage: led_test on|off1|2|3|4\n"); exit(1); } //打開LED設備 fd = open("/dev/real_led", 0); if(fd < 0) { printf("Open Led DeviceFaild!\n"); exit(1); } printf("Open Led Device success!\n");//IO控制 ioctl(fd, turn, 1); //關閉LED設備 close(fd); return 0; }
devfs文件接口系統的測試:

啟動板子,進入到控制臺,進入到/sys/class/real_led/real_led/目錄,如果可以進入,那么說明我們led的devfs文件系統注冊成功了,反之。

使用下面所示的方法進行測試:

root@realarm:/sys/class/real_led/real_led # cat val 0 root@realarm:/sys/class/real_led/real_led # echo '1' > val root@realarm:/sys/class/real_led/real_led # cat val 1 root@realarm:/sys/class/real_led/real_led # echo '0' > val root@realarm:/sys/class/real_led/real_led # cat val 0 root@realarm:/sys/class/real_led/real_led # 當向val寫入1時,觀察LED是否被點亮了,反之。我這里測試是沒有問題的。


proc文件系統的測試:

進入到/proc目錄,首先使用ls real_led檢查是否有real_led這個文件,然后使用echo '1' > real_led和echo '0' > real_led來測試led。

如下:

root@realarm:/proc # ls real_led real_led root@realarm:/proc # echo '1' > real_led root@realarm:/proc # echo '0' > real_led root@realarm:/proc #我這里測試也是沒有問題。


這三種方式測試都沒問題了,那么驅動程序是沒有什么問題了,下一部分是硬件抽象層的說明。


總結

以上是生活随笔為你收集整理的s5p4418 Android 4.4.2 驱动层 HAL层 服务层 应用层 开发流程记录(一 硬件驱动层)的全部內容,希望文章能夠幫你解決所遇到的問題。

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

主站蜘蛛池模板: 好看的毛片 | 美女免费黄视频 | 美女搡bbb又爽又猛又黄www | 日韩在线第一 | 欧美日韩一区二区三区电影 | 手机在线看片国产 | 九月色婷婷 | 天天爽天天爽夜夜爽毛片 | 久久黄色一级视频 | 免费麻豆av | 国产精品午夜久久 | 国产激情一区二区三区四区 | 午夜激情一区二区 | 日日夜夜撸撸 | 大肉大捧一进一出好爽mba | 欧美一区二区三区电影 | 中文字幕精品视频 | 人人妻人人澡人人爽欧美一区 | 成人午夜sm精品久久久久久久 | 婷婷五月花 | 国内精品小视频 | 日韩一区二区在线播放 | 娇妻玩4p被三个男人伺候电影 | 谁有毛片网址 | 57pao成人国产永久免费视频 | 中文字幕永久在线观看 | 国产伦精品一区二区三区照片 | 国产熟妇一区二区三区四区 | 亚洲国产精品成人综合 | 在线观看h视频 | 黄色av视屏 | 天天摸天天射 | 青娱乐在线免费观看 | www.亚洲视频| 污污网站免费 | 自拍亚洲欧美 | av在线收看| 91福利网站 | 国产黄色大片 | 久久精品91 | 国产精品影院在线观看 | 欧美xxxxx少妇 | 国产精品久久影视 | 欧美午夜一区二区 | 免费a级片视频 | 久久av免费| 亚洲天堂网在线观看视频 | 色月婷婷| 色窝网 | 日韩午夜在线视频 | 国产尻逼 | aaaaa级少妇高潮大片免费看 | 熟妇人妻久久中文字幕 | 91亚洲精品久久久蜜桃网站 | 五月婷婷社区 | 最近中文字幕免费视频 | 欧美xxx在线观看 | 少妇又色又爽又高潮极品 | 久久亚洲综合国产精品99麻豆精品福利 | 91亚洲成人 | 国产精品老牛影视 | 欧美日本韩国一区二区三区 | 猛男大粗猛爽h男人味 | 国产色黄 | 校园春色综合 | 日韩欧美在线第一页 | av在线资源播放 | 日韩欧美一区二区视频 | 99热这里都是精品 | 香蕉精品在线 | 羞羞涩涩视频 | 欧美日韩国产一区 | 日韩人妻精品中文字幕 | 日本最黄网站 | 白又丰满大屁股bbbbb | 野花av| 色站av| 成人在线免费视频观看 | 九一精品在线 | 久久久经典| 国产一区精品无码 | 狂野少女电影在线观看国语版免费 | 国产黄色的视频 | 天天天干 | 欧美一区二区高清视频 | 无码精品人妻一区二区三区漫画 | 农村偷人一级超爽毛片 | 永久免费成人代码 | 免费观看视频在线观看 | 精品区在线观看 | 少妇人妻一区 | 精品国产亚洲一区二区麻豆 | 亚洲激情久久 | 国产福利在线观看视频 | 精品98| 日韩香蕉视频 | youjizz国产精品 | 激情黄色小说网站 | 97视频人人 |