下面具体说一段代码 (原创禁止转载) 驱动源码 //******************************************************************************** #include <linux/module.h> #include <linux/kernel.h> #include <linux/fs.h> #include <linux/errno.h> #include <linux/types.h> #include <linux/cdev.h> #include <linux/wait.h> #include <mach/regs-gpio.h> //gpio 寄存器的内核初始宏定义 #include <mach/regs-gpioj.h> //gpio 寄存器的内核扩展宏定义 #include <asm/uaccess.h> #include <asm/io.h> // __raw_writel __raw_readl 函数,用来操作地址数据 //懂得硬件的老大们,这里应该知道是要用些linux内核内部函数了 //很多老大们省略了这些.h,不知道是为了节省,还是就不想让人知道在哪里找到函数原型 //至少很多老大们的书,为了节省纸去掉了 #define LED_CFG __raw_writel((__raw_readl(S3C2440_GPJCON) |(0xffff))&(0x5555),S3C2440_GPJCON) //这个是2440的gpio的一个初始配置,具体的原理图上有 //为了配置所有gpio口为输出 //先取回16bits配置地址数据,再或(1111111111111111)与(101010101010101) //再写回16bits配置地址数据 //gpio 16bits地址数据为输出数据 #define WRITE_H(abc) __raw_writel(abc,S3C2440_GPJDAT) //给gpio 输出16bits数据 MODULE_LICENSE("GPL"); //你自己的license GPL 的尊守 #define major 235 //code 的节点号 static unsigned int code[]={0x11,0xd7,0x23,0x83,0xc5,0x89, 0x09,0xd3,0x01,0x81}; //以下是 //0x11 =0001 0001 这个是数码管显示0 第0 bits 4 bits 是高电屏led是灭的, 其它的都是底电屏亮 //0xd7 =1101 0111 这个是数码管显示1 //0x23 =0010 0011 这个是数码管显示2 //0x83 =1000 0011 这个是数码管显示3 //0xc5 =1100 0101 这个是数码管显示4 //0x89 =1000 1001 这个是数码管显示5 //0x09 =0000 1001 这个是数码管显示6 //0xd3 =1101 0011 这个是数码管显示7 //0x01 =0000 0001 这个是数码管显示8 //0x81 =1000 0001 这个是数码管显示9
unsigned int olddat; //用来保存原来的dat int led_open(struct inode *inode,struct file *filp) { //一个空结构 return 0; } int led_ioctl(struct inode *inode,struct file *filp, unsigned int cmd,unsigned long arg) { //cmd 为在数码管要显示的数0-9 if((cmd>=0)&&(cmd<=9)) { WRITE_H(__raw_readl(S3C2440_GPJDAT)|0xFF); //关闭所有数码管显示 //0xFF 1111 1111 WRITE_H(__raw_readl(S3C2440_GPJDAT)&code[cmd]); //将数码管数据写回,点亮数码管 return 0; } if(cmd==10) { //如果cmd 为10 就将数码管关闭 WRITE_H(__raw_readl(S3C2440_GPJDAT)|0xFF); //关闭所有数码管显示 //0xFF 1111 1111 return 0; } if(cmd==11) { //cmd=11 是为了测试. WRITE_H(__raw_readl(S3C2440_GPJDAT)|0xFF); WRITE_H(__raw_readl(S3C2440_GPJDAT)&0xFE); //0xFE 1111 1110 return 0; } printk("ioctl error\nCommand 0-9"); return -EFAULT; }
struct file_operations led_fops={ .owner = THIS_MODULE, .ioctl=led_ioctl, //生明ioctl起动led_ioctl函数 .open=led_open, //生明ioctl起动led_open函数 };
struct led_dev_g { struct cdev devno; } led_dev; //全局的节点结构体 void led_cleanup_module(void) { dev_t devno=MKDEV(major,0); //创建节点号与内核关联 WRITE_H(__raw_readl(S3C2440_GPJDAT)|0xFF); //关闭所有数码管显示 WRITE_H(olddat); //还原写回老的数据 unregister_chrdev_region(devno,1); //撤销注册节点 printk("Stop Led ...\n"); } int led_init_module(void) { int result; dev_t dev=0; printk("Start Led Mem......\n"); olddat=__raw_readl(S3C2440_GPJDAT); //保存原始数据 LED_CFG; //设置为GPIO输出格式 WRITE_H(__raw_readl(S3C2440_GPJDAT)|0xFF); //关闭所有数码管显示 dev=MKDEV(major,0); //创建节点号与内核关联 result=register_chrdev_region(dev,1,"qvb_led"); //内核声明节点号 if(result<0) { printk("can't major\n"); return result; } cdev_init(&led_dev.devno,&led_fops); //节点的初始化 led_dev.devno.owner=THIS_MODULE; led_dev.devno.ops=&led_fops; //节点文件指向 led_fops result=cdev_add(&led_dev.devno,dev,1); //led_fops 联系 dev if(result) { printk("Error not add"); led_cleanup_module(); return result; } return 0; }
module_init(led_init_module); module_exit(led_cleanup_module); //************************************************************************* 应用程序使用该驱动 使用命令 insmod dataled.ko mknod /dev/qvbled c 235 0 以下是应用程序 //************************************************************************* #include <stdio.h> #include <fcntl.h> //文件描述控制函数库 int main(int argc,char *argv[]) { int fd; int retval; int cmd; fd=open("/dev/qvbled",O_RDWR); if(fd==-1) { perror("/dev/qvbled error"); exit(-1); } if(argc<2) { printf("\nPlease: cmd 0-9 \n"); printf(" Led on\n"); printf("\nPlease: cmd off \n"); printf(" Led off\n"); exit(-1); } cmd=atoi(argv[1]); if(cmd==11) { retval=ioctl(fd,cmd,0); } if((cmd>=0)&&(cmd<=9)) { retval=ioctl(fd,cmd,0); } if(!strcmp(argv[1],"off")) { retval=ioctl(fd,10,0); } close(fd); return 0; } //*************************************************************************** |
|
|
|
|