Linux驱动程序学习笔记(3)——点亮LED
来源:互联网 发布:2016数控编程工资待遇 编辑:程序博客网 时间:2024/04/29 19:26
一,难点
1,ioremap 和 iounmap
要操作硬件,首先要操作相关IO寄存器,知道寄存器的物理地址后,要经过Io映射到虚拟地址里才可以使用,所以要用到ioremap 和 iounmap两个函数。
(1)void __iomem * ioremap (unsigned long phys_addr, unsigned long size),
第一个参数为物理地址,第二个参数为要映射的空间的大小,返回值为映射到的虚拟地址的指针,还要转换成相应的类型指针,如:
pGpbcon = (volatile unsigned long *)ioremap(0x56000010,16);
(2)void iounmap(void *addr),
释放映射关系,参数为申请映射的虚拟地址,如
iounmap(pGpbcon);
2,用户空间传递数据到内核空间
copy_from_user(&val,userbufer,count);//如果失败,返回有多少个Bytes未完成copy
第一个参数为内核空间变量的地址,第二个参数为用户空间,第三个参数为传递内容的大小。第二第三两个参数是file_operations指定的write函数的相应的2个参数
注意返回值是有多少个Bytes未完成copy,用法:
static int led_write(struct file * file, const char __user * userbuf,
size_t count, loff_t * off)
{
int val;
copy_from_user(&val, userbuf, count);//注意不要写成val = copy_from_user(&val, userbuf, count);
/*..............*/
return 0;
}
3,有关次设备号
一个设备文件拥有主设备号和次设备号,驱动程序只对应主设备号,次设备号给用户自定义使用,可以创建几个主设备号相同而次设备号不同的设备文件(应用程序打开的是设备文件),他们都对应相同的驱动程序,然后根据次设备号不同在驱动程序里执行不同的操作。
(1)创建几个主设备号相同而次设备号不同的设备文件的方法:
static struct class *led_class;
static struct class_device *led_class_device[4];
在模块初始化函数里:
led_class = class_create(THIS_MODULE, "ledClass");
for(i=0;i<4;i++)
{
led_class_device[i] = class_device_create(led_class,NULL,MKDEV(major,i),NULL,"led%d",i);
}
记得在模块退出函数里:
led_class = class_create(THIS_MODULE, "ledClass");
for(i=0;i<4;i++)
{
led_class_device[i] = class_device_create(led_class,NULL,MKDEV(major,i),NULL,"led%d",i);
}
(2)从打开的设备文件里获取次设备号方法
int minor=MINOR(inode->i_rdev);//在open函数里知道inode可以使用这个方法
int minor=MINOR(file->f_dentry->d_inode->r_dev);//在write、read等函数里知道file,可以用这个方法
二,方法
要操作LED只要初始化时候进行ioremap获得GPBCON和GPBDAT寄存器的地址,然后和裸机一样对寄存器进行相关操作即可,在函数退出函数时候要用iounmap解除映射。还有就是write和read等函数的使用
三,代码
1,驱动代码
#include <linux/module.h>#include <linux/kernel.h>#include <linux/fs.h>#include <linux/init.h>#include <linux/delay.h>#include <asm/uaccess.h>#include <asm/irq.h>#include <asm/io.h>#include <asm/arch/regs-gpio.h>#include <asm/hardware.h>#define GPBCONADDR 0x56000010static struct class *led_class;static struct class_device *led_class_device[4];volatile unsigned long *pGpbcon;volatile unsigned long *pGpbdat;int major;int minor;static int led_open(struct inode *inode, struct file *file){printk("Hello, Driver of led\n");minor=MINOR(inode->i_rdev);*pGpbcon &= ~(3<<(minor+5)*2);*pGpbcon |= (1<<(minor+5)*2);return 0;}static int led_write(struct file * file, const char __user * userbuf, size_t count, loff_t * off){int val;printk("Write led Done!\n");MINOR(file->f_dentry->d_inode->r_dev);copy_from_user(&val, userbuf, count);if(val==1){printk("led on!!!\n");printk("minor:%d\n",minor);*pGpbdat &= ~(1<<(minor+5));}else{*pGpbdat |= (1<<(minor+5));}return 0;}static struct file_operations led_ops ={.owner = THIS_MODULE,.open = led_open,.write = led_write};static int led_init(void){int i=0;major = register_chrdev(0,"leddriver",&led_ops);led_class = class_create(THIS_MODULE, "ledClass");for(i=0;i<4;i++){led_class_device[i] = class_device_create(led_class,NULL,MKDEV(major,i),NULL,"led%d",i);}pGpbcon = (volatile unsigned long *)ioremap(GPBCONADDR,16);pGpbdat = pGpbcon + 1;return 0;}static void led_exit(void){int i=0;iounmap(pGpbcon);unregister_chrdev(major,"leddriver");for(i=0;i<4;i++){class_device_unregister(led_class_device[i]);}class_destroy(led_class);}module_init(led_init);module_exit(led_exit);MODULE_LICENSE("GPL");
2,测试代码
#include <sys/types.h>#include <sys/stat.h>#include <fcntl.h>#include <stdio.h>int main(int argc, char **argv){int fid;int val;if(argc !=3 ){printf("input error\n");return -1;}if(strcmp(argv[2],"on")==0)val = 1;elseval = 0;char filename[40] = "/dev/";strcat(filename,argv[1]);fid = open(filename,O_RDWR);if(fid < 0){printf("%s Open error!\n",argv[1]);return -1;}write(fid,&val,4);close(fid);return 0;}
输入./ledTest led1 on 点亮第一站led,./ledTest led1 off 熄灭第一盏led
./ledTest led2 on 点亮第2站led,./ledTest led2 off 熄灭第2盏led 以此类推
- Linux驱动程序学习笔记(3)——点亮LED
- 嵌入式Linux学习笔记(5)——点亮mini2440 LED
- bb_black_学习笔记——(3)点亮LED之shell命令
- CC2530学习笔记のGPIO配置——点亮LED
- stm32学习笔记(一)点亮LED
- arm驱动程序——点亮led(韦东山的视频总结及针对linux-2.6.30)
- Linux驱动学习——使用汇编语言点亮一个LED
- 嵌入式Linux裸机开发(一)——点亮Led
- arm驱动程序——点亮led-利用次设备号(韦东山的视频总结及针对linux-2.6.30)
- uboot学习笔记(1.2点亮LED灯)
- STM32学习笔记——控制GPIO输出点亮LED灯(直接操作存储器)
- STM32学习笔记1——点亮第一盏LED灯
- [转载]STM32学习笔记——控制GPIO输出点亮LED灯(直接操作存储器)
- ble学习笔记二-----------------点亮led
- STM32学习笔记1-点亮LED
- STM32学习笔记之点亮LED灯
- CC3220学习笔记---点亮LED寄存器版
- CC3220学习笔记---点亮LED PinMux版
- java的布局-1
- 二叉树的基础问题
- win8的一些简单基本的操作
- win8系统的操作
- VS2008编译的程序在某些机器上运行提示“由于应用程序配置不正确,应用程序未能启动”的问题
- Linux驱动程序学习笔记(3)——点亮LED
- win8系统简介
- 从页面插入信息到数据库(简单实例)
- MYSQL中删除重复记录的方法
- java的布局-2
- #pragma
- 成为高效程序员的搜索技巧
- UVa 839 - Not so Mobile
- 想成为嵌入式程序员应知道的10个基本问题