/*******************************************/
#include <linux/init.h>
#include <linux/dma-mapping.h>
#include <linux/module.h>
#include <linux/sched.h>
#include <linux/completion.h>
#include <linux/interrupt.h>
#include <linux/clk.h>
#include <linux/platform_device.h>
#include <linux/atmel_pdc.h>
#include <asm/io.h>
#include <linux/semaphore.h>
#include <linux/kernel.h>
#include <linux/cdev.h>
#include <linux/types.h>
#include <linux/fs.h>
#include <mach/board.h>
#include <mach/gpio.h>
/*******************************************/
void led_on(unsigned int led_num)
{
at91_set_gpio_output(AT91_PIN_PA5 + led_num,0);
}
void led_off(unsigned int led_num)
{
at91_set_gpio_output(AT91_PIN_PA5 + led_num,1);
}
void led_init(void)
{
at91_set_GPIO_periph(AT91_PIN_PA5,0);
at91_set_GPIO_periph(AT91_PIN_PA6,0);
at91_set_GPIO_periph(AT91_PIN_PA7,0);
at91_set_GPIO_periph(AT91_PIN_PA8,0);
at91_set_A_periph(AT91_PIN_PA5,0);
at91_set_A_periph(AT91_PIN_PA6,0);
at91_set_A_periph(AT91_PIN_PA7,0);
at91_set_A_periph(AT91_PIN_PA8,0);
}
struct light_dev
{
struct cdev cdev;
unsigned char value;
};
struct light_dev *light_devp;
int light_major = 252;
MODULE_AUTHOR("launch");
MODULE_LICENSE("Dual BSD/GPL");
// 打开和关闭函数
int light_open(struct inode *inode,struct file *filp)
{
struct light_dev *dev;
// 获得设备结构体指针
dev = container_of(inode->i_cdev,struct light_dev,cdev);
// 让设备结构体作为设备的私有信息
filp->private_data = dev;
return 0;
}
int light_release(struct inode *inode,struct file *filp)
{
return 0;
}
// ioctl
int light_ioctl(struct inode *inode,struct file *filp,unsigned int cmd,
unsigned long arg)
{
struct light_dev *dev = filp->private_data;
switch(cmd)
{
case 0:
dev->value = 0;
led_off(arg);
break;
case 1:
dev->value = 1;
led_on(arg);
break;
default:
return -ENOTTY;
// break;
}
return 0;
}
struct file_operations light_fops =
{
.owner = THIS_MODULE,
.ioctl = light_ioctl,
.open = light_open,
.release = light_release,
};
// 设置字符设备cdev结构体
static void light_setup_cdev(struct light_dev *dev,int index)
{
int err,devno = MKDEV(light_major,index);
cdev_init(&dev->cdev,&light_fops);
dev->cdev.owner = THIS_MODULE;
dev->cdev.ops = &light_fops;
err = cdev_add(&dev->cdev,devno,1);
if(err)
{
printk(KERN_NOTICE "Error %d adding LED%d",err,index);
}
}
// 模块加载函数
int light_init(void)
{
int result;
dev_t dev = MKDEV(light_major,0);
// 申请字符设备号
if(light_major)
{
result = register_chrdev_region(dev,1,"leds");
}
if(result < 0)
{
return result;
}
// 分配设备结构体的内存
light_devp = kmalloc(sizeof(struct light_dev),GFP_KERNEL);
if(!light_devp)
{
result = - ENOMEM;
goto fail_malloc;
}
memset(light_devp,0,sizeof(struct light_dev));
light_setup_cdev(light_devp,0);
led_init();
return 0;
fail_malloc:unregister_chrdev_region(dev,light_devp);
return result;
}
// 模块卸载函数
void light_cleanup(void)
{
cdev_del(&light_devp->cdev); // 删除字符设备结构体
kfree(light_devp);
unregister_chrdev_region(MKDEV(light_major,0),1); // 删除字符设备
}
module_init(light_init);
#include <linux/init.h>
#include <linux/dma-mapping.h>
#include <linux/module.h>
#include <linux/sched.h>
#include <linux/completion.h>
#include <linux/interrupt.h>
#include <linux/clk.h>
#include <linux/platform_device.h>
#include <linux/atmel_pdc.h>
#include <asm/io.h>
#include <linux/semaphore.h>
#include <linux/kernel.h>
#include <linux/cdev.h>
#include <linux/types.h>
#include <linux/fs.h>
#include <mach/board.h>
#include <mach/gpio.h>
/*******************************************/
void led_on(unsigned int led_num)
{
at91_set_gpio_output(AT91_PIN_PA5 + led_num,0);
}
void led_off(unsigned int led_num)
{
at91_set_gpio_output(AT91_PIN_PA5 + led_num,1);
}
void led_init(void)
{
at91_set_GPIO_periph(AT91_PIN_PA5,0);
at91_set_GPIO_periph(AT91_PIN_PA6,0);
at91_set_GPIO_periph(AT91_PIN_PA7,0);
at91_set_GPIO_periph(AT91_PIN_PA8,0);
at91_set_A_periph(AT91_PIN_PA5,0);
at91_set_A_periph(AT91_PIN_PA6,0);
at91_set_A_periph(AT91_PIN_PA7,0);
at91_set_A_periph(AT91_PIN_PA8,0);
}
struct light_dev
{
struct cdev cdev;
unsigned char value;
};
struct light_dev *light_devp;
int light_major = 252;
MODULE_AUTHOR("launch");
MODULE_LICENSE("Dual BSD/GPL");
// 打开和关闭函数
int light_open(struct inode *inode,struct file *filp)
{
struct light_dev *dev;
// 获得设备结构体指针
dev = container_of(inode->i_cdev,struct light_dev,cdev);
// 让设备结构体作为设备的私有信息
filp->private_data = dev;
return 0;
}
int light_release(struct inode *inode,struct file *filp)
{
return 0;
}
// ioctl
int light_ioctl(struct inode *inode,struct file *filp,unsigned int cmd,
unsigned long arg)
{
struct light_dev *dev = filp->private_data;
switch(cmd)
{
case 0:
dev->value = 0;
led_off(arg);
break;
case 1:
dev->value = 1;
led_on(arg);
break;
default:
return -ENOTTY;
// break;
}
return 0;
}
struct file_operations light_fops =
{
.owner = THIS_MODULE,
.ioctl = light_ioctl,
.open = light_open,
.release = light_release,
};
// 设置字符设备cdev结构体
static void light_setup_cdev(struct light_dev *dev,int index)
{
int err,devno = MKDEV(light_major,index);
cdev_init(&dev->cdev,&light_fops);
dev->cdev.owner = THIS_MODULE;
dev->cdev.ops = &light_fops;
err = cdev_add(&dev->cdev,devno,1);
if(err)
{
printk(KERN_NOTICE "Error %d adding LED%d",err,index);
}
}
// 模块加载函数
int light_init(void)
{
int result;
dev_t dev = MKDEV(light_major,0);
// 申请字符设备号
if(light_major)
{
result = register_chrdev_region(dev,1,"leds");
}
if(result < 0)
{
return result;
}
// 分配设备结构体的内存
light_devp = kmalloc(sizeof(struct light_dev),GFP_KERNEL);
if(!light_devp)
{
result = - ENOMEM;
goto fail_malloc;
}
memset(light_devp,0,sizeof(struct light_dev));
light_setup_cdev(light_devp,0);
led_init();
return 0;
fail_malloc:unregister_chrdev_region(dev,light_devp);
return result;
}
// 模块卸载函数
void light_cleanup(void)
{
cdev_del(&light_devp->cdev); // 删除字符设备结构体
kfree(light_devp);
unregister_chrdev_region(MKDEV(light_major,0),1); // 删除字符设备
}
module_init(light_init);
module_exit(light_cleanup);
写LED驱动时,主要就是把物理地址和虚拟地址的关系没有对应好,把源代码看了下后,清晰了一些。
以下是Makefile文件
ARCH=arm
CROSS_COMPILE=arm-none-linux-gnueabi-
obj-m := leds.o
KDIR := /home/zhh/linux-2.6.27/
PWD := $(shell pwd)
modules:
$(MAKE) -C $(KDIR) M=$(PWD) modules
clean:
$(MAKE) -C $(KDIR) M=$(PWD) clean