Linux驱动程序学习笔记(3)——点亮LED

一,难点

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 0x56000010

static 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;
	else
		val = 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 以此类推

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值