最近这几天接触了char driver,由于自己之前没有看过LDD3,所以刚开始的时候对这种操作有很多的不理解,程序代码也不知道是什么。但是我看了好久,其实还是很容易理解的。现在我来分析下我完全靠自己理解写的一个最简单的led驱动代码,希望对大家有所帮助。
/*****************************************************************************
* addr :Changchun University of Science and Technology
*
*
* time :2012.10.26
*
*
* author:yuqingzhang
*
*
* ****************************************************************************/
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define DEVICE_NAME "myledconfigs"
#define LED_MAJOR 231
int init_module(void);
void cleanup_module(void);
/*choose GPIO*/
static unsigned long led_table [] = {
S3C2410_GPB5,
S3C2410_GPB6,
S3C2410_GPB8,
S3C2410_GPB10,
};
/*put GPIO OUT*/
static unsigned int led_cfg_table [] = {
S3C2410_GPB5_OUTP,
S3C2410_GPB6_OUTP,
S3C2410_GPB8_OUTP,
S3C2410_GPB10_OUTP,
};
static int s3c2440_led_ioctl(
struct inode *inode,
struct file *file,
unsigned int cmd,
unsigned long arg)
{
if (arg > 4)
{
return -EINVAL;
}
else
s3c2410_gpio_setpin(led_table[arg], !cmd);
}
首先是头文件,这些都是linux2.6.12内核下的一些头文件。关于S3C2440的底层文件已经有大神为我们写了,都在、include/asm/arch和arch/arm/mach-s3c2410/gpio.c两个目录下。
#define DEVICE_NAME "myledconfigs"是我们定义的drive人文件名称,他会随驱动编译过后insmod下在dev下生成myledconfigs文件。这将是我们应用程序所要用到的。
static int s3c2440_led_ioctl(
struct inode *inode,
struct file *file,
unsigned int cmd,
unsigned long arg)
这是函数很很重要的系统函数,我们应用层的程序都要通过它来执行,因为在应用层我们用open打开dev/"myledconfigs目录,open会返回一个int变量,然后我们可以通过这个函数来决定我们应用层所要执行的用到的底层。
static int __init s3c2440_led_init(void)
{
int tmp;
int i;
tmp = register_chrdev(LED_MAJOR,DEVICE_NAME, &s3c2440_leds_fops);
if (tmp
{
printk(DEVICE_NAME " can't register major number\n");
return tmp;
}
devfs_mk_cdev(MKDEV(LED_MAJOR, 0), S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP,DEVICE_NAME);
for (i = 0; i
{
s3c2410_gpio_cfgpin(led_table[i],led_cfg_table[i]);
s3c2410_gpio_setpin(led_table[i],1);
}
printk(DEVICE_NAME "initialized\n");
return 0;
}
/*this is rmmod order*/
static void __exit s3c2440_led_exit(void)
{
devfs_remove(DEVICE_NAME);
unregister_chrdev(LED_MAJOR, DEVICE_NAME);
}
module_init(s3c2440_led_init);
module_exit(s3c2440_led_exit);
MODULE_LICENSE("GPL");
这两个函数init和exit是用来动态加载的。一般驱动有两种模式被应用。一种是静态加载,一种是动态加载。静态加载时通过makefile时候通过obj,动态加载时obj -m。
应用程序如下:#include "stdio.h"
#include "unistd.h"
#include "sys/types.h"
#include "sys/ioctl.h"
#include "stdlib.h"
#include "termios.h"
#include "sys/stat.h"
#include "fcntl.h"
#include "sys/time.h"
int main(void)
{
int on=1;
int off=0;
int led;
int fd;
pid_t pid;
pid=fork();
if (pid<0)
{
printf("fork is wrong\n");
exit(1);
}
fd=open("/dev/myledconfigs",0);
if(fd<0)
{
perror("open device myledconfigs");
exit(1);
}
printf("leds test show,press ctrl+c to exit \n");
if (pid==0)
{
while(1)
{printf("This is the Child-progress\n");
ioctl(fd,on,0);
ioctl(fd,on,1);
sleep(1);
on=!on;
}
}
else
{
while(1)
{
printf("This is the parent\n");
ioctl(fd,off,2);
ioctl(fd,off,3);
sleep(1);
off=!off;
}
}
close(fd);
return 0;
}
这里是两个进程来实现换灯闪的。