现在的位置: 首页 > 综合 > 正文

全亮全灭点亮mini2440的设备驱动

2013年04月20日 ⁄ 综合 ⁄ 共 2495字 ⁄ 字号 评论关闭

首先,求助一下。今天忙了一下午,就为了找到一个可以和国嵌内核匹配的u-boot,但是还是没有找到。网上的大神们谁有国嵌的mini2440的u-boot可以传给我一个,感激不尽。

由于没有u-boot,内核模块编译出来了也不能在板子上运行,所以很多代码没有亲测。

 

首先说编译内核模块,编译内核模块的Makefile如下:

ifneq ($(KERNELRELEASE),)

obj-m := mini2440_leds.o

else
	
KDIR := /home/guoqian/4-3-1/linux-2.6.29
all:
	make -C $(KDIR) M=$(PWD) modules ARCH=arm CROSS_COMPILE=arm-linux-
clean:
	rm -f *.ko *.o *.mod.o *.mod.c *.symvers  modul*

endif

KDIR := /home/guoqian/4-3-1/linux-2.6.29   这个路径是要找到自己板载内核的路径,同时要注意这个路径下的内核是已经被编译过的,最好直接一次编译成zImage。要不然会出现各类的问题,不过还好前人走的路很多,随手百度问题也就解决了。

但是今天又开始面临了第二个困扰。上图。

这就是今天面临的情况。驱动程序中调用的IO函数一会再列出来,但是这两个驱动函数初步可以看出是在内核中实现的。出现的错误是寄存器的定义问题。所以要想把程序走通,必须使用国嵌移植的内核。所以弄到了国嵌的u-boot以后估计就可以开始测试代码了。

下面开始分析点亮和熄灭四个二极管的驱动程序。

1.dev_init

static int __init dev_init(void)
{
	int ret;

	int i;
	
	for (i = 0; i < 4; i++) {
		s3c2410_gpio_cfgpin(led_table[i], led_cfg_table[i]);
		//设置IO口的模式,定义为输出。
		s3c2410_gpio_setpin(led_table[i], 0);
		//定义引脚全部为低电平,在结束后,四个 LED 应该是全部都是发光。
	}
	
  /*注册混杂设备*/
	ret = misc_register(&misc);

	printk (DEVICE_NAME"\tinitialized\n");

	return ret;
}

注意:混杂设备注册是在dev_init函数中完成的。

2.在dev_init函数中完成了混杂设备的注册,下面列出混杂设备的属性定义。

static struct miscdevice misc = {
	.minor = MISC_DYNAMIC_MINOR,    //这个宏(内核中)定义的混杂设备的此设备号,
	                                //由内核动态的进行分配的。
	.name = DEVICE_NAME,            //定义了设备的名字--可以随意定义。
	.fops = &dev_fops,              //混杂设备的实质是字符设备,字符设备都有file_operations。
};

3.file_operations

static struct file_operations dev_fops = {
	.owner	=	THIS_MODULE,
	.ioctl	=	sbc2440_leds_ioctl,
	//驱动程序不一定要实现open和release,但是内核会自动实现这两个设备方法。
};

注意:最后一句备注。现在接触的程序太少了,没能真正的理解。

4.s3c2440_leds_ioctl函数。

static int s3c2440_leds_ioctl(
	struct inode *inode, 
	struct file *file, 
	unsigned int cmd, 
	unsigned long arg)
/*传递进来的是整形的参数arg,所以没有进行对参数的检测,只有传进来是指针的时候才进行检测。*/
{
	switch(cmd) {
	case 0:
	case 1:
		if (arg > 4) {
			return -EINVAL;
		}
		s3c2410_gpio_setpin(led_table[arg], !cmd);
		//根据命令传进来的参数来直接设置灯的亮和灭----arg。
		return 0;
	default:
		return -EINVAL;
	}
}

注意:命令的实质是一个三十二位的无符号长整形数,定义命令是要让命令具有更高的可读性,使命令执行的时候更加安全。
5.最后送上两个数组

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

 //LED 对应端口将要输出的状态列表
static unsigned int led_cfg_table [] = {
	S3C2410_GPB5_OUTP,
	S3C2410_GPB6_OUTP,
	S3C2410_GPB7_OUTP,
	S3C2410_GPB8_OUTP,
};

在网上找到了这两个数组参数具体实现的代码了,就不贴了,因为自己看不懂,所以就这样先。

6.直接粘上测试部分的应用程序

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/ioctl.h>

int main(int argc, char **argv)
{
	int on;
	int led_no;
	int fd;
	/*argv[1]本身是一个字符串,把这个字符串通过%d传递给led_no
	  on < 0 || on > 1 设定on的有效值只能取0或1。
	  led_no < 0 || led_no > 3  设定led_no的有效值。
	*/
	if (argc != 3 || sscanf(argv[1], "%d", &led_no) != 1 || sscanf(argv[2],"%d", &on) != 1 ||
	    on < 0 || on > 1 || led_no < 0 || led_no > 3) {
		fprintf(stderr, "Usage: leds led_no 0|1\n");
		exit(1);
	}
	fd = open("/dev/leds", 0);
	if (fd < 0) {
		perror("open device leds");
		exit(1);
	}
	ioctl(fd, on, led_no);
	close(fd);
	return 0;
}

 

抱歉!评论已关闭.