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

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

驱动程序实例(一):LED设备驱动程序( platform + cdev)

發布時間:2025/4/9 编程问答 31 豆豆
生活随笔 收集整理的這篇文章主要介紹了 驱动程序实例(一):LED设备驱动程序( platform + cdev) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

結合之前對Linux內核的platform總線 ,以及對字符設備的cdev接口的分析,本文將編寫基于platform總線與cdev接口的LED設備的實例代碼并對其進行分析。

platform總線分析,詳見Linux platform驅動模型。

字符設備的cdev接口分析,詳見Linux字符設備驅動(一):cdev接口。

硬件接口:

  CPU:s5pv210;

  LED的GPIO:GPIO_J0_3 ~ GPIO_J0_5;

  LED的工作方式:低電平亮,高電平滅。

1. led_device.c

本文將設備信息寫成一個模塊的形式,需要時加載該模塊即可。

#include <linux/init.h> #include <linux/module.h> #include <linux/fs.h> #include <linux/ioport.h> #include <linux/platform_device.h>//定義并初始化LED設備的相關資源 static struct resource led_resource = {.start = 0xE0200240,.end = 0xE0200240 + 8 - 1,.flags = IORESOURCE_MEM, };//定義并初始化LED設備信息 static struct platform_device led_dev = {.name = "led", //設備名稱.id = -1, //設備數量,-1表示只有一個設備.num_resources = 1, //資源數量.resource = &led_resource, //資源指針.dev = {.release = led_release,}, };//注冊LED設備 static int __init led_device_init(void) {return platform_device_register(&led_dev); }//注銷LED設備 static void __exit led_device_exit(void) {platform_device_unregister(&led_dev); }module_init(led_device_init); module_exit(led_device_exit);MODULE_AUTHOR("Lin"); MODULE_DESCRIPTION("led device for x210"); MODULE_LICENSE("GPL");

2. led_driver.c

led_driver_init():模塊加載函數
  platform_driver_register()將驅動對象模塊注冊到平臺總線
  led_probe()探測函數,提取相應的信息
    platform_get_resource()獲取設備資源
    request_mem_region()、ioremap()虛擬內存映射
    readl()、write()初始化硬件設備
    cdev_alloc()申請cdev內存
    cdev_init()初始化cdev對象,將cdev與fops結構體綁定
    alloc_chrdev_region()申請設備號
    cdev_add()注冊LED設備對象,將cdev添加至系統字符設備鏈表中
    class_create()創建設備類
    device_create()創建設備文件

#include <linux/init.h> #include <linux/module.h> #include <linux/fs.h> #include <linux/ioport.h> #include <linux/platform_device.h> #include <linux/slab.h> #include <asm/io.h> #include <linux/leds.h> #include <asm/uaccess.h> #include <linux/cdev.h> #include <linux/kdev_t.h> #include <linux/ioctl.h>#define LED_IOC_MAGIC 'l'   //ioctl幻數 #define LED_IOC_MAXNR 2   //ioctl最大命令序數 #define LED_ON _IO(LED_IOC_MAGIC, 0) //ioctl自定義命令 #define LED_OFF _IO(LED_IOC_MAGIC, 1)#define DEVNAME "led" //設備名稱static int led_major = 0; //主設備號 static int led_minor = 0; //次設備號 const int led_count = 1; //次設備數量//GPIO寄存器變量定義 typedef struct GPJ0REG {volatile unsigned int gpj0con;volatile unsigned int gpj0dat; }gpj0_reg_t;static gpj0_reg_t *pGPIOREG = NULL;static dev_t led_devnum; //設備號 static struct cdev *led_cdev = NULL; //設備對象static struct class *led_cls = NULL; //設備類 static struct device *led_dev = NULL; //設備//LED設備的ioctl函數實現 static int led_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg) {int reg_value = 0;//檢測命令的有效性if (_IOC_TYPE(cmd) != LED_IOC_MAGIC) return -EINVAL;if (_IOC_NR(cmd) > LED_IOC_MAXNR) return -EINVAL;//根據命令,執行相應的硬件操作switch(cmd) {case LED_ON:reg_value = readl(&pGPIOREG->gpj0dat); reg_value &= ~((1 << 3) | (1 << 4) | (1 << 5));writel(&pGPIOREG->gpj0dat, reg_value);break;case LED_OFF:reg_value = readl(&pGPIOREG->gpj0dat); reg_value |= (1 << 3) | (1 << 4) | (1 << 5);writel(&pGPIOREG->gpj0dat, reg_value);break;default: return -EINVAL;}return 0; }static int led_open(struct inode *inode, struct file *filp) {return 0; }static int led_release(struct inode *inode, struct file *filp) {return 0; }//LED設備的write函數實現 static ssize_t led_write(struct file *file, const char __user *user_buf, size_t count, loff_t *ppos) {char kbuf[20] = {0};int reg_value = 0;memset(kbuf, 0, sizeof(kbuf));if (copy_from_user(kbuf, user_buf, count)){return -EFAULT;}if (kbuf[0] == '0'){reg_value = readl(&(pGPIOREG->gpj0dat)); reg_value |= (1 << 3) | (1 << 4) | (1 << 5);writel(reg_value, &(pGPIOREG->gpj0dat));}else{reg_value = readl(&(pGPIOREG->gpj0dat)); reg_value &= ~((1 << 3) | (1 << 4) | (1 << 5));writel(reg_value, &(pGPIOREG->gpj0dat));}return 1; }//定義并初始化LED設備的操作集 static const struct file_operations led_ops = {.owner = THIS_MODULE,.open = led_open,.write = led_write,.ioctl = led_ioctl,.release = led_release, };//LED設備的probe函數實現 static int led_probe(struct platform_device *pdev) {struct resource *res_led = NULL;int ret = -1;int reg_value = 0;int i = 0;/****************************申請資源*******************************///獲取資源res_led = platform_get_resource(pdev, IORESOURCE_MEM, 0);if (!res_led) {return -ENOMEM;}//動態內存映射if (!request_mem_region(res_led->start, resource_size(res_led), "GPIOJ0")){return -EBUSY;}pGPIOREG = ioremap(res_led->start, resource_size(res_led));if (pGPIOREG == NULL) {ret = -ENOENT;goto ERR_STEP;}/****************************初始化資源*******************************///設置GPIO為輸出模式reg_value = readl(&(pGPIOREG->gpj0con)); reg_value |= (1 << (3*4)) | (1 << (4*4)) | (1 << (5*4));writel(reg_value, &(pGPIOREG->gpj0con));/***************************創建接口(cdev)***************************///申請cdev內存led_cdev = cdev_alloc();if (led_cdev == NULL){ret = -ENOMEM;goto ERR_STEP1;}//初始化led_cdev(將led_cdev于led_ops關聯)cdev_init(led_cdev, &led_ops);//申請設備號ret = alloc_chrdev_region(&led_devnum, led_minor, led_count, DEVNAME);if (ret < 0){goto ERR_STEP1;}//注冊LED設備對象(將cdev添加至系統字符設備鏈表中)ret = cdev_add(led_cdev, led_devnum, led_count);if (ret < 0){goto ERR_STEP2;}//創建設備類led_cls = class_create(THIS_MODULE, DEVNAME);if (IS_ERR(led_cls)) {ret = PTR_ERR(led_cls);goto ERR_STEP3;}//在設備類下創建設備文件led_major = MAJOR(led_devnum);for(i = led_minor; i < (led_count + led_minor); i++){led_dev = device_create(led_cls, NULL, MKDEV(led_major, i), NULL, "%s%d", DEVNAME, i);if(IS_ERR(led_dev)){ret = PTR_ERR(led_dev);goto ERR_STEP4;}}return 0;/*******************************倒映式錯誤處理*******************************/ ERR_STEP4:for(--i; i >= led_minor; i--){device_destroy(led_cls, MKDEV(led_major, i));}class_destroy(led_cls);ERR_STEP3:cdev_del(led_cdev);ERR_STEP2:unregister_chrdev_region(led_devnum, led_count);ERR_STEP1:iounmap(pGPIOREG); ERR_STEP:release_mem_region(res_led->start, resource_size(res_led));return ret; }int led_remove(struct platform_device *pdev) {int i = 0;//刪除設備文件for(i = led_minor; i < (led_count + led_minor); i++){device_destroy(led_cls, MKDEV(led_major, i));}//刪除設備類 class_destroy(led_cls);//刪除設備對象 cdev_del(led_cdev);//注銷設備號 unregister_chrdev_region(led_devnum, led_count);//釋放內存 iounmap(pGPIOREG);return 0; }//定義并初始化LED驅動信息 static struct platform_driver led_drv = {.driver = {.name = "led",.owner = THIS_MODULE,},.probe = led_probe,.remove = led_remove, };//注冊LED驅動 static int __init led_driver_init(void) {return platform_driver_register(&led_drv); }//注銷LED驅動 static void __exit led_driver_exit(void) {platform_driver_unregister(&led_drv); }module_init(led_driver_init); module_exit(led_driver_exit);MODULE_AUTHOR("Lin"); MODULE_DESCRIPTION("led driver for x210"); MODULE_LICENSE("GPL");

3. 測試所用應用程序

運行應用程序之前,需確保上述兩個模塊(device、driver)被裝載。運行結果表明LED設備能被應用程序操作。

#include <stdio.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <unistd.h> #include <string.h> #include <sys/ioctl.h>#define FILE_NAME "/dev/led0"#define LED_ON _IO(LED_IOC_MAGIC, 0) #define LED_OFF _IO(LED_IOC_MAGIC, 1)char WriteBuf[30]; char ReadBuf[30]; char ScanBuf[30];int main(void) {int fd = -1;int i = 0;//打開設備文件if ((fd = open(FILE_NAME, O_RDWR)) < 0){printf("%s open error\n", FILE_NAME);return -1;}while (1){memset(ScanBuf, 0, sizeof(ScanBuf));printf("please input data for LED\n");if (scanf("%s", ScanBuf)){//打開LED設備if (!strcmp(ScanBuf, "on")){write(fd, "1", 1);}//關閉LED設備else if (!strcmp(ScanBuf, "off")){write(fd, "0", 1);}//閃爍LED設備else if (!strcmp(ScanBuf, "flash")){for (i=5; i>0; i--){ioctl(fd, LED_ON);sleep(1);ioctl(fd, LED_OFF);sleep(1);}}
else {break;}}}close(fd);return 0; }

?

轉載于:https://www.cnblogs.com/linfeng-learning/p/9376804.html

總結

以上是生活随笔為你收集整理的驱动程序实例(一):LED设备驱动程序( platform + cdev)的全部內容,希望文章能夠幫你解決所遇到的問題。

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