普通字符设备LED驱动程序(IO映射内存实现)

 驱动程序:

 

#include <linux/module.h> //内核模块头文件
#include <linux/moduleparam.h>  //内核模块参数头文件
#include <linux/kernel.h>  //printk头文件

#include<asm/io.h>//ioremap需要
//包含有可装载模块需要的大量符合和函数的定义;
#include <linux/init.h>
//指定初始化和清除函数;

//struct file_operactions 相关头文件
#include <linux/fs.h>
#include <asm/uaccess.h>

//struct cdev 相关头文件
#include <linux/types.h>
#include <linux/cdev.h>

//定义设备名称
#define DEVICE_NAME "led2"

//定义主次设备号
static unsigned int LedMajor=0;
static unsigned int LedMinor=0;

/* 注册字符设备 */
static struct cdev *led_cdev;
static dev_t dev;  //设备号

volatile unsigned int long *gpb_con = NULL;  
volatile unsigned int long *gpb_data = NULL;  


static int led_ioctl(struct inode *inode, struct file *file,  
                    unsigned int cmd, unsigned long arg)  
{  
   
         if((cmd>1) | (cmd<0) | (arg>3) | (arg<0))  
                   return -EINVAL;  
                    
         switch(cmd)  
         {  
                   case 0:  
                            *gpb_data&= ~(1<<(arg+5));  //0
                            break;  
                   case 1:  
                            *gpb_data|= (1<<(arg+5));  //1
                            break;  
                             
                   default:  
                            return -EINVAL;  
                             
         }  
          
         return 0;  
}  


static int led_open(struct inode *inode, struct file *file)
{
	printk("led_open\n");
	
	//映射I/O内存  
	gpb_con = (volatile unsigned long *)ioremap(0x56000010,16); //0x56000010为GPIOB控制寄存器的物理地址  
	gpb_data = gpb_con+1;  //这里+1是加了4个字节,因为指针+1是以指针的长度为单位的(unsigned long *)

	/* 配置GPB5,6,7,8为输出 */
	*gpb_con |= (1<<(5*2)) | (1<<(6*2)) | (1<<(7*2)) | (1<<(8*2));
	/* 初始化为灭 */
	*gpb_data |=(1<<5) | (1<<6) | (1<<7) | (1<<8); 

	printk("leaving led_open\n");
	return 0;

}

static int led_release(struct inode *inode,struct file *file)
{

        printk("close major=%d, minor=%d\n", imajor(inode), iminor(inode));
	return 0;
}

static struct file_operations chardev_fops={
	.owner = THIS_MODULE,
	.open = led_open,
	.release = led_release,
	.ioctl = led_ioctl,
};


static int __init dev_init(void)
{
	int result;
/*分配设备编号*/
	if(LedMajor)
	{
		dev=MKDEV(LedMajor,LedMinor);//创建设备编号
		result=register_chrdev_region(dev,1,DEVICE_NAME);
	} 
	else 
	{
		result=alloc_chrdev_region(&dev,LedMinor,1,DEVICE_NAME);
		LedMajor=MAJOR(dev);
	}
	if(result<0)
	{
		printk(KERN_WARNING"LED: cannot get major %d \n",LedMajor);
		return result;
	}
/* 注册字符设备 */
	led_cdev=cdev_alloc();//为struct cdev 分配空间

	cdev_init(led_cdev,&chardev_fops);//初始化struct cdev
	
	led_cdev->owner=THIS_MODULE;
	
	result=cdev_add(led_cdev,dev,1);
	
	if(result)
		printk("<1>Error %d while register led device!\n",result);
		
	printk("initialzed.\n");

	return 0;
}

static void __exit dev_exit(void)
{
	unregister_chrdev_region(MKDEV(LedMajor,LedMinor),1);
	cdev_del(led_cdev);
}

module_init(dev_init);
module_exit(dev_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Bai");


这段代码把GPB寄存器的物理地址映射到内存上,再进行操作。

注册一个独立的cdev设备的基本过程如下:

1、为struct cdev 分配空间
struct cdev *my_cdev = cdev_alloc();

2、初始化struct cdev ,主要是对 file_operations成员赋值,

void cdev_init(struct cdev *cdev, const struct  file_operations *fops)

3、初始化cdev.owner 指针,实现模块管理时的指针引用

cdev.owner = THIS_MODULE;

4、cdev设置完成后,向内核字符设备数组添加新的struct cdev的信息(在执行这步之前必须确定你对struct cdev的以上设置已经完成)

int cdev_add(struct cdev *dev, dev_t devno, unsigned count)

dev 是 cdev 结构, devno是这个设备响应的第一个设备号, count 是应当关联到设备的设备号的数目.

5、从系统中移除一个字符设备:
void cdev_del(struct cdev *dev)

 

使用:

1)用Makefile编译成ko文件放到开发板上

2)arm-linux-gcc led2_test.c -o led2_test 编译后放到开发板上

3)insmod mini2440_led2.ko加载模块

4)用cat /proc/devices 看看设备号   led2是253

5)再mknod /dev/led2 c 253 0

4)./led2_test 0 1 再./led2_test 1 1测试

5)rmmod mini2440_led2卸载

 

 

 

自动创建设备文件:

加上

#include <linux/device.h> /* device_create()*/
static struct class *led_class;// 
	/*自动创建设备文件*/
	led_class = class_create(THIS_MODULE,"led_dev"); /*在sys下创建类目录/sys/class/led_dev*/
	
	device_create(led_class, NULL, MKDEV(LedMajor,0), NULL, "led2"); //自动创建设备文件led2

 

ok


 

 

  • 0
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值