第一篇 字符设备驱动程序之LED流水灯驱动

本文分享了作者第二次编写字符设备驱动程序的经验,详细介绍了基于友善之臂micro2440平台和Linux内核2.6.29.4的驱动程序实现过程,并记录了在编译及模块加载过程中遇到的问题及其解决方案。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

    第二次写字符设备驱动程序,对字符设备驱动有了进一步的了解。程序的思考参考于:http://bbs.witech.com.cn/forum.php?mod=viewthread&tid=6408&extra=page%3D1

    基于友善之臂micro2440,linux内核版本为2.6.29.4。

    首先给出源代码(lightwater.c):


#include<linux/module.h>
#include<linux/init.h>
#include<linux/fs.h>
#include<linux/module.h>
#include<linux/kernel.h>
#include<linux/version.h>
#include<linux/errno.h>
#include<linux/cdev.h>
#include<linux/moduleparam.h>
#include<linux/ioctl.h>
 
/*GPIO端口的映射口,在arch/arm/mach-s3c2410/include/mach/regs-gpio.h下定义*/
#include<mach/regs-gpio.h>
/*声明对GPIO接口进行操作的外部接口函数,extern声明,函数原型在linux/arch/arm/plat-s3c24xx/下*/
#include<mach/hardware.h>

#include"lightwater.h"

static int major_dev = LIGHT_MAJOR;

module_param(major_dev ,int,S_IRUGO);

dev_t light_dev = MKDEV(LIGHT_MAJOR,0);
int ret=0;

struct cdev cdev;

unsigned long s3c2410_led_table[]={
	S3C2410_GPB5,
	S3C2410_GPB6,
	S3C2410_GPB7,
	S3C2410_GPB8
	};


int light_ioctl(struct inode *inode,struct file *file,unsigned int cmd,unsigned long arg){
	switch(cmd){
	case 0:	s3c2410_gpio_setpin(s3c2410_led_table[0],0);
		s3c2410_gpio_setpin(s3c2410_led_table[1],1);
		s3c2410_gpio_setpin(s3c2410_led_table[2],1);
		s3c2410_gpio_setpin(s3c2410_led_table[3],1);
		break;

	case 1:	s3c2410_gpio_setpin(s3c2410_led_table[0],1);
		s3c2410_gpio_setpin(s3c2410_led_table[1],0);
		s3c2410_gpio_setpin(s3c2410_led_table[2],1);
		s3c2410_gpio_setpin(s3c2410_led_table[3],1);
		break;

	case 2:	s3c2410_gpio_setpin(s3c2410_led_table[0],1);
		s3c2410_gpio_setpin(s3c2410_led_table[1],1);
		s3c2410_gpio_setpin(s3c2410_led_table[2],0);
		s3c2410_gpio_setpin(s3c2410_led_table[3],1);
		break;
	
	case 3:	s3c2410_gpio_setpin(s3c2410_led_table[0],1);
		s3c2410_gpio_setpin(s3c2410_led_table[1],1);
		s3c2410_gpio_setpin(s3c2410_led_table[2],1);
		s3c2410_gpio_setpin(s3c2410_led_table[3],0);
		break;
	default:break;
	}
	
	return 0;
}

struct file_operations light_ops={
         .owner = THIS_MODULE,
         .ioctl = light_ioctl,
         };
static int __init lightwater_init(void){
	unsigned int i;
	if(major_dev)
		/*静态注册函数的第二个参数是注册设备的个数,最开始不小心设为0了,所以若采用静态注册,成功运行模块后不会在/proc/devices中生成相应设备号和设备名。*/		
		ret = register_chrdev_region(light_dev,1,DEV_NAME);
	else
		ret = alloc_chrdev_region(&light_dev,0,1,DEV_NAME);
 	/*return -1的返回值以及下面的返回值都很重要,最开始大括号忘写了,后面载入模块的时候一直出现 "operation not permitted".这里的返回值,对载入模块之后的错误判断很重要*/
		if(ret<0){
		printk("Char device register failed\n ");	
		return -1;
		}
	/*加入字符设置,包括初始化字符设备和添加字符设备*/
	cdev_init(&cdev,&light_ops);
	cdev.owner = THIS_MODULE;
	cdev.ops = &light_ops;
	ret = cdev_add(&cdev,light_dev,1);
	
	if(ret<0){
		printk("cdev adding goes wrong!\n");
		return -1;
		}
	printk("cdev is added\n");
	
	/*初始化led灯,s3c2410_gpio_cfgpin的第二个参数设定端口功能,很多网上的例子是通过数组来对应设定每个io口的功能,这里因为是都作为输出,所以直接写一个s3c2410_GPIO_OUTPUT即可*/
 	for(i=0;i<4;i++){
		s3c2410_gpio_cfgpin(s3c2410_led_table[i],S3C2410_GPIO_OUTPUT);
		s3c2410_gpio_setpin(s3c2410_led_table[i],1);
	}
	printk("led driver installed!\n");
	return ret;
}

static void __exit lightwater_exit(void){
	unregister_chrdev_region(light_dev,1);
	cdev_del(&cdev);
}

module_init(lightwater_init);
module_exit(lightwater_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("FriendlyARM Inc.");

 

头文件(lightwater.h)中已对字符名和主设备号进行简单的定义

 

在编译及插入内核模块过程中出现几个问题:

1,找不到reg-gpio.h文件,但在相应的文件夹内确实可以找到该文件,却可以找到hardware.h文件,这两个文件都存在于同样的文件夹中。修改源代码的.config文件后再编译就可以找到了。

2,将编译后的内核模块传送到开发板去运行时,出现truncated的错误,表示文件传输过程中被截断了,再传一次就可以了

3,插入模块时出现“operation not permitted”的错误,但操作权限都使用root权限。原因解释已经在源代码中说过,返回值会解释插入模块时出现的错误。

4,编写程序时,应注意函数原型,如果函数原型有返回值,则写的程序代码也必须有返回值。

5,在开发板中使用insmod *.ko 插入模块后,用rmmod时出现“no such file or directory”的错误,修改 /lib/modules/下的文件夹的名称,我是将2.6.29-FriendlyARM修改成2.6.29.4-FriendlyARM。然后rmmod就会出现module '*' not found,但用lsmod时却没有了插入的模块,表示模块已经卸载了。但是为什么会出现not found的错误呢?按网上说的方法,将编写的模块拷入/lib/modules/2.6.29.4-FriendlyARM中则可以成功卸载并且没有提示错误。why?怎么解决?

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值