//头文件
#include <linux/init.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/device.h>
#include <linux/slab.h>
#include <asm/io.h>
#include <asm/uaccess.h>
#include <asm-generic/ioctl.h>
#define LED_NUM_ON _IOW('L',0x1122,int)
#define LED_NUM_OFF _IOW('L',0x3344,int)
#define LED_ALL_ON _IO('L',0x1234)
#define LED_ALL_OFF _IO('L',0x5678)
//面向对象编程----设计设备的类型
struct s5pv210_led{
unsigned int major;
struct class * cls;
struct device * dev;
int data;
};
struct s5pv210_led *led_dev;
volatile unsigned long *gpco_conf;
volatile unsigned long *gpco_data;
//实现设备操作接口
int led_open(struct inode *inode, struct file *filp)
{
printk("--------^_^ %s------------
",__FUNCTION__);
//将对应的管脚设置为输出
*gpco_conf &= ~(0xff<<12); //19--12清0
*gpco_conf |= 0x11<<12; //19---12赋值:00010001
return 0;
}
ssize_t led_write(struct file *filp, const char __user *buf, size_t size, loff_t *flags)
{
int ret;
printk("--------^_^ %s------------
",__FUNCTION__);
//应用空间数据转换为内核空间数据
ret = copy_from_user(&led_dev->data,buf,size);
if(ret != 0){
printk("copy_from_user error!
");
return -EFAULT;
}
if(led_dev->data){
//点灯
*gpco_data |= 0x3<<3;
}else{
//灭灯
*gpco_data &= ~(0x3<<3);
}
return size;
}
long led_ioctl(struct file *filp, unsigned int cmd , unsigned long args)
{
int num = args+2;
printk("--------^_^ %s------------
",__FUNCTION__);
switch(cmd){
case LED_NUM_ON: //将某个灯点亮
if(num != 3 && num != 4)
return -EINVAL;
else
*gpco_data |= 0x1 << num;
break;
case LED_NUM_OFF: //将某个灯点灭掉
if(num != 3 && num != 4)
return -EINVAL;
else
*gpco_data &= ~(0x1 << num);
break;
case LED_ALL_ON: //两个灯同时亮
*gpco_data |= 0x3<<3;
break;
case LED_ALL_OFF: //两个灯同时灭
*gpco_data &= ~(0x3<<3);
break;
default:
printk("unknow cmd!
");
}
return 0;
}
int led_close(struct inode *inode, struct file *filp)
{
printk("--------^_^ %s------------
",__FUNCTION__);
//灭灯
*gpco_data &= ~(0x3<<3);
return 0;
}
static struct file_operations fops = {
.open = led_open,
.write = led_write,
.unlocked_ioctl = led_ioctl,
.release = led_close,
};
//加载函数和卸载函数
static int __init led_init(void) //加载函数-----在驱动被加载时执行
{
int ret;
printk("--------^_^ %s------------
",__FUNCTION__);
//0,实例化设备对象
//参数1 ---- 要申请的空间的大小
//参数2 ---- 申请的空间的标识
led_dev = kzalloc(sizeof(struct s5pv210_led),GFP_KERNEL);
if(IS_ERR(led_dev)){
printk("kzalloc error!
");
ret = PTR_ERR(led_dev);
return -ENOMEM;
}
//1,申请设备号
#if 0
//静态申请主设备号
led_dev->major = 256;
ret = register_chrdev(led_dev->major,"led_drv",&fops);
if(ret < 0){
printk("register_chrdev error!
");
return -EINVAL;
}
#else
//动态申请主设备号
led_dev->major = register_chrdev(0,"led_drv",&fops);
if(led_dev->major < 0){
printk("register_chrdev error!
");
ret = -EINVAL;
goto err_kfree;
}
#endif
//2,创建设备文件-----/dev/led1
led_dev->cls = class_create(THIS_MODULE,"led_cls");
if(IS_ERR(led_dev->cls)){
printk("class_create error!
");
ret = PTR_ERR(led_dev->cls);
goto err_unregister;
}
led_dev->dev = device_create(led_dev->cls,NULL,MKDEV(led_dev->major,0),NULL,"led");
if(IS_ERR(led_dev->dev)){
printk("device_create error!
");
ret = PTR_ERR(led_dev->dev);
goto err_class;
}
//3,硬件初始化----地址映射
gpco_conf = ioremap(0xE0200060,8);
gpco_data = gpco_conf+1;
return 0;
err_class:
class_destroy(led_dev->cls);
err_unregister:
unregister_chrdev(led_dev->major,"led_drv");
err_kfree:
kfree(led_dev);
return ret;
}
static void __exit led_exit(void) //卸载函数-----在驱动被卸载时执行
{
printk("--------^_^ %s------------
",__FUNCTION__);
device_destroy(led_dev->cls,MKDEV(led_dev->major,0));
class_destroy(led_dev->cls);
unregister_chrdev(led_dev->major,"led_drv");
kfree(led_dev);
}
//声明和认证
module_init(led_init);
module_exit(led_exit);
MODULE_LICENSE("GPL");
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#define LED_NUM_ON _IOW('L',0x1122,int)
#define LED_NUM_OFF _IOW('L',0x3344,int)
#define LED_ALL_ON _IO('L',0x1234)
#define LED_ALL_OFF _IO('L',0x5678)
int main(void)
{
int fd;
fd = open("/dev/led",O_RDWR);
if(fd < 0){
perror("open");
exit(1);
}
//闪灯
while(1){
//第一个灯闪
ioctl(fd,LED_NUM_ON,1);
sleep(1);
ioctl(fd,LED_NUM_OFF,1);
sleep(1);
//第二个灯闪
ioctl(fd,LED_NUM_ON,2);
sleep(1);
ioctl(fd,LED_NUM_OFF,2);
sleep(1);
//两个灯同时闪
ioctl(fd,LED_ALL_ON);
sleep(1);
ioctl(fd,LED_ALL_OFF);
sleep(1);
}
close(fd);
return 0;
}
#指定内核源码路径
KERNEL_DIR = /home/farsight/s5pv210/kernel/linux-3.0.8
CUR_DIR = $(shell pwd)
MYAPP = test
all:
#让make进入内核源码编译,同时将当前目录中的c程序作为内核模块一起编译
make -C $(KERNEL_DIR) M=$(CUR_DIR) modules
arm-none-linux-gnueabi-gcc -o $(MYAPP) $(MYAPP).c
clean:
#删除上面编译生成的文件
make -C $(KERNEL_DIR) M=$(CUR_DIR) clean
rm -rf $(MYAPP)
install:
cp *.ko $(MYAPP) /opt/rootfs/drv_module
#指定当前目录下哪个文件作为内核模块编
obj-m = led_drv.o