驱动学习,字符驱动例程。在AT91SAM9260开发板上的驱动开发
1 驱动编写
#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 <asm/system.h>
#include <asm/uaccess.h>
#include <linux/semaphore.h>
#include <linux/kernel.h>
#include <linux/cdev.h>
#include <linux/types.h>
#include <linux/fs.h>
#include <linux/input.h>
#include <linux/errno.h>
#include <linux/irq.h>
#include <linux/debugfs.h>
#include <linux/seq_file.h>
#include <linux/list.h>
#include <mach/board.h>
#include <mach/gpio.h>
#include <mach/irqs.h>
#include <mach/hardware.h>
#include <mach/at91_pio.h>
#define MY_LED_MAJOR 250
#define LED_ON 0
#define LED_OFF 1
struct global_dev{
struct cdev cdev;
};
struct global_dev *global_devp;
static int led_open(struct inode *inode, struct file *filp)
{
filp->private_data = global_devp;
return 0;
}
static int led_release(struct inode *inode, struct file *file)
{
return 0;
}
static int led_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long data)
{
switch(cmd)
{
case LED_ON:
at91_set_gpio_value(AT91_PIN_PA29, 0);
break;
case LED_OFF:
at91_set_gpio_value(AT91_PIN_PA29, 1);
break;
default:
printk("no valid cmd input!\n");
break;
}
return 0;
}
struct file_operations my_led_ctl_ops ={
.owner = THIS_MODULE,
.open = led_open,
.release = led_release,
.ioctl = led_ioctl,
};
static void led_setup(struct global_dev *dev, int index)
{
int err;
int devno = MKDEV(MY_LED_MAJOR, index);
cdev_init(&dev->cdev, &my_led_ctl_ops);
dev->cdev.owner = THIS_MODULE;
dev->cdev.ops = &my_led_ctl_ops;
err = cdev_add(&dev->cdev, devno, 1);
if(err)
printk("add my led setup failed!\n");
}
static int led_init(void)
{
int ret;
dev_t devno = MKDEV(MY_LED_MAJOR, 0);
printk("my first driver--led!\n");
at91_set_GPIO_periph(AT91_PIN_PA29, 1);
at91_set_gpio_output(AT91_PIN_PA29, 1);
ret = register_chrdev_region(devno, 1, "my_led");
if( ret < 0) {
printk("my_led init_module failed with %d\n", ret);
return ret;
}
else
printk("my_led init_module success!\n");
global_devp = kmalloc(sizeof(struct global_dev), GFP_KERNEL);
memset(global_devp, 0, sizeof(struct global_dev));
led_setup(global_devp, 0);
return ret;
}
static void led_exit(void)
{
cdev_del(&global_devp->cdev);
kfree(global_devp);
unregister_chrdev_region(MKDEV(MY_LED_MAJOR, 0), 1);
}
MODULE_LICENSE("MYGPL");
MODULE_AUTHOR("WHF");
module_init(led_init);
module_exit(led_exit);
3 添加完毕后,编写相应的测试程序
#include <stdio.h> #include <string.h> #include <stdlib.h> #include <fcntl.h> #include <unistd.h> #define DEVICE_NAME "/dev/leds" #define LED_ON 0 #define LED_OFF 1 int main(void) { int fd; int ret; int i; printf("led_driver test!\n"); fd = open(DEVICE_NAME, O_RDONLY); if(fd == -1) printf("open device %s error!\n", DEVICE_NAME); printf("fd = %d\n", fd); for(i = 0; i < 50; i++) { ioctl(fd, LED_OFF); sleep(1); ioctl(fd, LED_ON); sleep(1); } ret = close(fd); printf("ret = %d\n", ret); printf("Close led_driver!\n"); return 0; }4编写Makefile文件
ARCH=arm CROSS_COMPILE=arm-none-linux-gnueabi- all:leds $(CROSS_COMPILE)gcc -o leds leds.c $(CROSS_COMPILE)strip leds clean: @rm -vf leds *.o *~5 编译生成可执行文件
以上是在网络资料的基础是对简单驱动开发的笔记整理,中在学习驱动的基本框架。