蚂蚁S9矿板PS led驱动实验-第5课 设备驱动框架下的驱动

发布时间:2026/7/31 9:29:34
蚂蚁S9矿板PS led驱动实验-第5课 设备驱动框架下的驱动
参考蚂蚁S9矿板引脚定义.csdn蚂蚁S9矿板PS led驱动实验-第1课 字符设备驱动.csdn蚂蚁S9矿板PS led驱动实验-第2课 设备树下的led驱动.csdn蚂蚁S9矿板PS led驱动实验-第3课 gpio子系统下的led驱动.csdn蚂蚁S9矿板PS led驱动实验-第4课 设备驱动分离的驱动.csdn蚂蚁S9矿板PS led驱动实验-第5课 设备驱动框架下的驱动.csdn蚂蚁S9矿板PS led驱动实验-第6课 linux自带led驱动测试.csdn设备树system-user.dtsi#include dt-bindings/gpio/gpio.h#include dt-bindings/input/input.h#include dt-bindings/media/xilinx-vip.h#include dt-bindings/phy/phy.h#include dt-bindings/interrupt-controller/irq.h/{modelz7 Board ant 789;compatiblexlnx,zynq-zc702,xlnx,zynq-7000;chosen{bootargsconsolettyPS0,115200 earlyconcdns,mmio,0xe0000000,115200n8 keep_bootcon earlyprintk root/dev/mmcblk0p2 rw rootwait;stdout-pathserial0:115200n8;};led{compatibleming,led;statusokay;default-stateon;led-gpiogpio037GPIO_ACTIVE_HIGH;};beeper{compatibleming,beeper;statusokay;default-stateoff;beeper-gpiogpio038GPIO_ACTIVE_HIGH;};key{compatibleming,key;statusokay;key-gpiogpio047GPIO_ACTIVE_LOW;interrupt-parentgpio0;interrupts47IRQ_TYPE_EDGE_BOTH;};};leddriver.c#includelinux/module.h#includelinux/of_gpio.h#includelinux/cdev.h#includelinux/uaccess.h#includelinux/platform_device.h#defineMYLED_CNT1/* 设备号个数 */#defineMYLED_NAMEmyled/* 名字 *//* LED设备结构体 */structmyled_dev{dev_tdevid;/* 设备号 */structcdevcdev;/* cdev结构体 */structclass*class;/* 类 */structdevice*device;/* 设备 */intled_gpio;/* GPIO号 */};staticstructmyled_devmyled;/* led设备 *//* * description : 打开设备 * param – inode : 传递给驱动的inode * param – filp : 设备文件file结构体有个叫做private_data的成员变量 * 一般在open的时候将private_data指向设备结构体。 * return : 0 成功;其他 失败 */staticintmyled_open(structinode*inode,structfile*filp){return0;}/* * description : 向设备写数据 * param – filp : 设备文件表示打开的文件描述符 * param – buf : 要写给设备写入的数据 * param – cnt : 要写入的数据长度 * param – offt : 相对于文件首地址的偏移 * return : 写入的字节数如果为负值表示写入失败 */staticssize_tmyled_write(structfile*filp,constchar__user*buf,size_tcnt,loff_t*offt){intret;charkern_buf[1];retcopy_from_user(kern_buf,buf,cnt);// 得到应用层传递过来的数据if(0ret){printk(KERN_ERRmyled: Failed to copy data from user buffer\r\n);return-EFAULT;}if(0kern_buf[0])gpio_set_value(myled.led_gpio,0);// 如果传递过来的数据是0则关闭ledelseif(1kern_buf[0])gpio_set_value(myled.led_gpio,1);// 如果传递过来的数据是1则点亮ledreturn0;}staticintmyled_init(structdevice_node*nd){constchar*str;intval;intret;/* 从设备树中获取GPIO */myled.led_gpioof_get_named_gpio(nd,led-gpio,0);if(!gpio_is_valid(myled.led_gpio)){printk(KERN_ERRmyled: Failed to get led-gpio\n);return-EINVAL;}/* 申请使用GPIO */retgpio_request(myled.led_gpio,PS_LED0 Gpio);if(ret){printk(KERN_ERRmyled: Failed to request led-gpio\n);returnret;}/* 确定LED初始状态 */retof_property_read_string(nd,default-state,str);if(!ret){if(!strcmp(str,on))val1;elseval0;}elseval0;/* 将GPIO设置为输出模式并设置GPIO初始电平状态 */gpio_direction_output(myled.led_gpio,val);return0;}/* LED设备操作函数 */staticstructfile_operationsmyled_fops{.ownerTHIS_MODULE,.openmyled_open,.writemyled_write,};/* * description : platform驱动的probe函数当驱动与设备 * 匹配成功以后此函数就会执行 * param – pdev : platform设备指针 * return : 0成功;其他负值,失败 */staticintmyled_probe(structplatform_device*pdev){intret;printk(KERN_INFOmyled: led driver and device has matched!\r\n);/* led初始化 */retmyled_init(pdev-dev.of_node);if(ret)returnret;/* 初始化cdev */retalloc_chrdev_region(myled.devid,0,MYLED_CNT,MYLED_NAME);if(ret)gotoout1;myled.cdev.ownerTHIS_MODULE;cdev_init(myled.cdev,myled_fops);/* 添加cdev */retcdev_add(myled.cdev,myled.devid,MYLED_CNT);if(ret)gotoout2;/* 创建类class */myled.classclass_create(THIS_MODULE,MYLED_NAME);if(IS_ERR(myled.class)){retPTR_ERR(myled.class);gotoout3;}/* 创建设备 */myled.devicedevice_create(myled.class,pdev-dev,myled.devid,NULL,MYLED_NAME);if(IS_ERR(myled.device)){retPTR_ERR(myled.device);gotoout4;}return0;out4:class_destroy(myled.class);out3:cdev_del(myled.cdev);out2:unregister_chrdev_region(myled.devid,MYLED_CNT);out1:gpio_free(myled.led_gpio);returnret;}/* * description : platform驱动模块卸载时此函数会执行 * param – dev : platform设备指针 * return : 0成功;其他负值,失败 */staticintmyled_remove(structplatform_device*dev){printk(KERN_INFOmyled: led platform driver remove!\r\n);/* 注销设备 */device_destroy(myled.class,myled.devid);/* 注销类 */class_destroy(myled.class);/* 删除cdev */cdev_del(myled.cdev);/* 注销设备号 */unregister_chrdev_region(myled.devid,MYLED_CNT);/* 删除地址映射 */gpio_free(myled.led_gpio);return0;}/* 匹配列表 */staticconststructof_device_idled_of_match[]{{.compatibleming,led},{/* Sentinel */}};/* platform驱动结构体 */staticstructplatform_drivermyled_driver{.driver{.namezynq-led,// 驱动名字用于和设备匹配.of_match_tableled_of_match,// 设备树匹配表用于和设备树中定义的设备匹配},.probemyled_probe,// probe函数.removemyled_remove,// remove函数};/* * description : 模块入口函数 * param : 无 * return : 无 */staticint__initmyled_driver_init(void){returnplatform_driver_register(myled_driver);}/* * description : 模块出口函数 * param : 无 * return : 无 */staticvoid__exitmyled_driver_exit(void){platform_driver_unregister(myled_driver);}module_init(myled_driver_init);module_exit(myled_driver_exit);MODULE_AUTHOR(DengTao 773904075qq.com);MODULE_DESCRIPTION(Led Platform Driver);MODULE_LICENSE(GPL);ledApp.c$CC-okeyApp keyApp.c#includestdio.h#includeunistd.h#includesys/types.h#includesys/stat.h#includefcntl.h#includestdlib.h#includestring.h/* * description : main主程序 * param – argc : argv数组元素个数 * param – argv : 具体参数 * return : 0 成功;其他 失败 */intmain(intargc,char*argv[]){intfd,ret;unsignedcharbuf[1];if(3!argc){printf(Usage:\n\t./ledApp /dev/myled 1 close LED\n\t./ledApp /dev/myled 0 open LED\n);return-1;}/* 打开设备 */fdopen(argv[1],O_RDWR);if(0fd){printf(file %s open failed!\r\n,argv[1]);return-1;}/* 将字符串转换为int型数据 */buf[0]atoi(argv[2]);/* 向驱动写入数据 */retwrite(fd,buf,sizeof(buf));if(0ret){printf(LED Control Failed!\r\n);close(fd);return-1;}/* 关闭设备 */close(fd);return0;}测试rootant:~# rmmod leddriverrootant:~# rmmod leddevicerootant:~# insmod leddriverrootant:~# ./ledApp /dev/myled 0rootant:~# ./ledApp /dev/myled 1