//Makefile
#内核路径
KERNEL_DIR=/home/me/farsight/linux-3.0.8
#驱动程序代码所在的路径
CUR_DIR=$(shell pwd)
#驱动程序的名称
DRV_NAME1 = led_drv
APP_NAME = led_app
all:
make -C $(KERNEL_DIR) M=$(CUR_DIR) modules
arm-none-linux-gnueabi-gcc -o $(APP_NAME) $(APP_NAME).c
clean:
make -C $(KERNEL_DIR) M=$(CUR_DIR) clean
rm -rf $(APP_NAME)
install:
cp -raf *.ko $(APP_NAME) /opt/rootfs/drv_module
#到底要把哪个.c编译成模块
obj-m = $(DRV_NAME1).o
//应用层代码
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <asm-generic/ioctl.h>
#define ALL_LED_ON _IO('A',0x01)
#define ALL_LED_OFF _IO('A',0x02)
#define SEL_LED_ON _IOW('S',0x01,int)
#define SEL_LED_OFF _IOW('S',0x02,int)
#define SEL_LED1 0x01
#define SEL_LED2 0x02
int main(void)
{
int fd;
int led_cmd;
fd = open("/dev/led_drv",O_RDWR);
if(fd < 0)
{
perror("open");
exit(1);
}
while(1)
{
ioctl(fd, ALL_LED_ON);
sleep(1);
ioctl(fd, ALL_LED_OFF);
sleep(1);
ioctl(fd, SEL_LED_ON, SEL_LED1);
sleep(1);
ioctl(fd, SEL_LED_OFF, SEL_LED1);
sleep(1);
ioctl(fd, SEL_LED_ON, SEL_LED2);
sleep(1);
ioctl(fd, SEL_LED_OFF, SEL_LED2);
sleep(1);
}
close(fd);
return 0;
}
//内核驱动代码
#include <linux/init.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/device.h>
#include <asm/io.h>
#include <linux/slab.h>
#include <linux/gpio.h>
#include <asm/uaccess.h>
#include <asm-generic/ioctl.h>
#include <linux/cdev.h>
#define ALL_LED_ON _IO('A',0x01)
#define ALL_LED_OFF _IO('A',0x02)
#define SEL_LED_ON _IOW('S',0x01,int)
#define SEL_LED_OFF _IOW('S',0x02,int)
#define SEL_LED1 0x01
#define SEL_LED2 0x02
struct fs210_led{
dev_t dev_no;
struct cdev * c_dev;
struct class * clazz;
struct device *dev;
void * GPC0_CON;
void * GPC0_DAT;
};
struct fs210_led * fs210_led;
long led_drv_ioctl(struct file * filp, unsigned int cmd, unsigned long args)
{
int reg_value;
switch(cmd)
{
case ALL_LED_ON:
{
reg_value = __raw_readl(fs210_led->GPC0_DAT);
reg_value |= (0x03 << 3);
__raw_writel(reg_value, fs210_led->GPC0_DAT);
}
break;
case ALL_LED_OFF:
{
reg_value = __raw_readl(fs210_led->GPC0_DAT);
reg_value &= ~(0x03 << 3);
__raw_writel(reg_value, fs210_led->GPC0_DAT);
}
break;
case SEL_LED_ON:
{
if(args == SEL_LED1)
{
reg_value = __raw_readl(fs210_led->GPC0_DAT);
reg_value |= (0x01 << 3);
__raw_writel(reg_value, fs210_led->GPC0_DAT);
}
else
{
reg_value = __raw_readl(fs210_led->GPC0_DAT);
reg_value |= (0x01 << 4);
__raw_writel(reg_value, fs210_led->GPC0_DAT);
}
}
break;
case SEL_LED_OFF:
{
if(args == SEL_LED1)
{
reg_value = __raw_readl(fs210_led->GPC0_DAT);
reg_value &= ~(0x01 << 3);
__raw_writel(reg_value, fs210_led->GPC0_DAT);
}
else
{
reg_value = __raw_readl(fs210_led->GPC0_DAT);
reg_value &= ~(0x01 << 4);
__raw_writel(reg_value, fs210_led->GPC0_DAT);
}
}
break;
default:
break;
}
return 0;
}
const struct file_operations fops = {
.owner = THIS_MODULE,
.unlocked_ioctl = led_drv_ioctl,
};
static int __init led_drv_init(void)
{
int ret;
int reg_value;
// 0.初始化全局的结构体对象
fs210_led = kzalloc(sizeof(struct fs210_led), GFP_KERNEL);
if(fs210_led == NULL)
{
printk("kzalloc error\n");
return -ENOMEM;
}
// 1.申请/注册设备号(新方法)
#if 0
//注册设备号
fs210_led->dev_no = MKDEV(250, 0);
ret = register_chrdev_region(fs210_led->dev_no, 1, "led_drv");
if(ret < 0)
{
printk("register_chrdev_region error\n");
goto kzalloc_err;
}
#endif
//申请设备号
ret = alloc_chrdev_region(&fs210_led->dev_no, 0, 1, "led_drv");
if(ret < 0)
{
printk("alloc_chrdev_region error\n");
goto kzalloc_err;
}
//创建一个cdev对象
fs210_led->c_dev = cdev_alloc();
if(IS_ERR(fs210_led->c_dev))
{
printk("cdev_alloc error\n");
ret = PTR_ERR(fs210_led->c_dev);
goto register_chrdev_region_err;
}
cdev_init(fs210_led->c_dev, &fops);
cdev_add(fs210_led->c_dev, fs210_led->dev_no, 1);
// 2.创建类
// 创建类
//参数1:当前模块
//参数2:类描述(自定义)
fs210_led->clazz = class_create(THIS_MODULE, "led_class");
if(IS_ERR(fs210_led->clazz))
{
printk("register_chrdev error\n");
ret = PTR_ERR(fs210_led->clazz);
goto cdev_alloc_err;
}
// 3.创建设备节点
// mknod /dev/xxx c major minor
// 创建设备结点
// 参数1: 类对象
// 参数2: 父类
// 参数3: 设备号
// 参数4: 私有数据
// 参数5: 设备节点名称
fs210_led->dev = device_create(fs210_led->clazz, NULL, fs210_led->dev_no, NULL, "led_drv");
if(IS_ERR(fs210_led->dev))
{
printk("device_create error\n");
ret = PTR_ERR(fs210_led->dev);
goto class_create_err;
}
// 4.硬件初始化
fs210_led->GPC0_CON = ioremap(0xE0200060, 8);
fs210_led->GPC0_DAT = fs210_led->GPC0_CON + 4;
reg_value = readl(fs210_led->GPC0_CON);
reg_value &= ~(0xff << 12);
reg_value |= (0x11 << 12);
writel(reg_value, fs210_led->GPC0_CON);
reg_value = __raw_readl(fs210_led->GPC0_DAT);
reg_value &= ~(0x03 << 3);
__raw_writel(reg_value, fs210_led->GPC0_DAT);
return 0;
class_create_err:
class_destroy(fs210_led->clazz);
cdev_alloc_err:
cdev_del(fs210_led->c_dev);
register_chrdev_region_err:
unregister_chrdev_region(fs210_led->dev_no, 1);
kzalloc_err:
kfree(fs210_led);
return ret;
}
static void __exit led_drv_exit(void)
{
iounmap(fs210_led->GPC0_CON);
device_destroy(fs210_led->clazz, fs210_led->dev_no);
class_destroy(fs210_led->clazz);
cdev_del(fs210_led->c_dev);
unregister_chrdev_region(fs210_led->dev_no, 1);
kfree(fs210_led);
}
module_init(led_drv_init);
module_exit(led_drv_exit);
MODULE_LICENSE("GPL");