任务:使用模块化编译安装驱动实现三盏LED灯的亮灭
驱动程序
#include <linux/init.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/uaccess.h>
#include <linux/io.h>#define PHY_RCC 0X50000A28
#define PHY_LED1_MODER 0x50006000
#define PHY_LED2_MODER 0x50007000
#define PHY_LED1_ODR 0x50006014
#define PHY_LED2_ODR 0x50007014unsigned int major;
char kbuf[128] = "";unsigned int *vir_rcc;
unsigned int *vir_moder1;
unsigned int *vir_odr1;unsigned int *vir_moder2;
unsigned int *vir_odr2;int mycdev_open(struct inode *inode,struct file *file)
{printk("%s:%s:%d\n",__FILE__,__func__,__LINE__);return 0;
}ssize_t mycdev_read(struct file *file,char *ubuf,size_t size,loff_t *lof)
{printk("%s:%s:%d\n",__FILE__,__func__,__LINE__);unsigned long ret;ret = copy_to_user(ubuf,kbuf,size);if(ret){printk("copy_to_user_failed\n");return -EIO;}return 0;
}ssize_t mycdev_write(struct file *file,const char *ubuf,size_t size,loff_t *lof)
{printk("%s:%s:%d\n",__FILE__,__func__,__LINE__);unsigned long ret;ret = copy_from_user(kbuf,ubuf,size);if(ret){printk("copy_from_user_failed\n");return -EIO; } if(kbuf[0] == '0'){//关闭LED1灯printk("LED1 OFF\n");(*vir_odr1) &= (~(0x1 << 10));}else if(kbuf[0] == '1'){//打开LED1灯printk("LED1 ON\n");(*vir_odr1) |= (0x1 << 10); }if(kbuf[1] == '0'){//关闭LED2灯printk("LED2 OFF\n");(*vir_odr2) &= (~(0x1 << 10));}else if(kbuf[1] == '1'){//打开LED2灯printk("LED2 ON\n");(*vir_odr2) |= (0x1 << 10); }if(kbuf[2] == '0'){//关闭LED3灯printk("LED3 OFF\n");(*vir_odr1) &= (~(0x1 << 8));}else if(kbuf[2] == '1'){//打开LED3灯printk("LED3 ON\n");(*vir_odr1) |= (0x1 << 8); }return 0;
}int mycdev_close(struct inode *inode,struct file *file)
{printk("%s:%s:%d\n",__FILE__,__func__,__LINE__);return 0;
}struct file_operations fops={.open=mycdev_open,.read=mycdev_read,.write=mycdev_write,.release=mycdev_close,};static int __init mycdev_init(void)
{major = register_chrdev(0,"mydev",&fops);if(major < 0){printk("字符设备注册失败\n");return major;}else{printk("字符设备注册成功,major=%d\n",major);}//物理地址映射到虚拟地址上vir_rcc = ioremap(PHY_RCC,4);if(vir_rcc == NULL){printk("映射失败 : %d\n",__LINE__);return -EFAULT;}//LED1/3vir_moder1 = ioremap(PHY_LED1_MODER,4);if(vir_moder1 == NULL){printk("映射失败 : %d\n",__LINE__);return -EFAULT;}vir_odr1 = ioremap(PHY_LED1_ODR,4);if(vir_odr1 == NULL){printk("映射失败 : %d\n",__LINE__);return -EFAULT;}//LED2vir_moder2 = ioremap(PHY_LED2_MODER,4);if(vir_moder2 == NULL){printk("映射失败 : %d\n",__LINE__);return -EFAULT;}vir_odr2 = ioremap(PHY_LED2_ODR,4);if(vir_odr2 == NULL){printk("映射失败 : %d\n",__LINE__);return -EFAULT;}printk("映射成功\n");//串口初始化(*vir_rcc) |= (0x3 << 4);//LED1初始化(*vir_moder1) &= (~(0x3 << 20));(*vir_moder1) |= (0x1 << 20);(*vir_odr1) &= (~(0x1 << 10));//LED2初始化(*vir_moder2) &= (~(0x3 << 20));(*vir_moder2) |= (0x1 << 20);(*vir_odr2) &= (~(0x1 << 10));//LED3初始化(*vir_moder1) &= (~(0x3 << 16));(*vir_moder1) |= (0x1 << 16);(*vir_odr1) &= (~(0x1 << 8));printk("LED初始化成功\n");return 0;
}static void __exit mycdev_exit(void)
{//取消映射iounmap(vir_rcc);iounmap(vir_moder1);iounmap(vir_odr1);iounmap(vir_moder2);iounmap(vir_odr2);unregister_chrdev(major,"mydev");
}module_init(mycdev_init);
module_exit(mycdev_exit);
MODULE_LICENSE("GPL");
应用程序
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>int main()
{int fd=open("/dev/mychrdev",O_RDWR);if(fd < 0){printf("文件打开失败\n");return -1;}else{printf("文件打开成功\n");}char buf[128]="";while(1){memset(buf,0,sizeof(buf));printf("请输入LED1/2/3的状态(1:ON/0:OFF)>>");fgets(buf,sizeof(buf),stdin);buf[strlen(buf)-1]='\0';if(buf[0]=='q'){break;}write(fd,buf,sizeof(buf));memset(buf,0,sizeof(buf));read(fd,buf,sizeof(buf));printf("buf : %s\n",buf);}close(fd);return 0;}
串口现象:
开发板现象: