关于AT91开发板的led的驱动

来源:互联网 发布:ipower充电软件下载 编辑:程序博客网 时间:2024/06/06 04:18

 下面是我以前写的AT91开发板的了led的驱动,希望对初学者有帮助

1:直接操作地址的编写方式

#include <linux/mm.h>
#include <asm/io.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/string.h>
#include <linux/rtc.h> /* get the user-level API */
#include <linux/list.h>
#include <linux/timer.h>
#include <linux/delay.h>
#include <mach/at91_pio.h>
#include <mach/gpio.h>
#include <linux/kdev_t.h>
#include <linux/types.h>
#include <linux/cdev.h>
#include <linux/platform_device.h>
#include <linux/version.h>
/*通过测试也是可以的*/
#define DEV_NAME     "led"    /* 加载模式后,执行”cat /proc/devices”命令看到的设备名称 */
#define DEV_MAJOR     231          /* 主设备号 */
//#define DEV_MAJOR 0    
#define DEV_MINOR 0

struct led_dev
{
 dev_t devno; //变量是设备号
 int major;
 int minor;
 struct class_device *class_dev;
 struct class *class;
 struct cdev cdev;
};


#define LED_ON    0    /* 应用程序执行ioctl(fd, cmd, arg)时的第2个参数 */
#define LED_OFF   1

static void __iomem *pio_base;
 


/* 应用程序对设备文件/dev/led执行open(...)时, * 就会调用led_open函数 */
static int baite_led_open( struct inode *inode,
    struct file *file)
 {   
 pio_base = ioremap(0xFFFFF400,512);  //PIOA开始的地址 以及空间512字节               
 writel(0x00000040, pio_base + PIO_PER);  //PIO的使能寄存器  表示向该寄存器写入0x00000040的数据      
 writel(0x00000040, pio_base + PIO_PUER); //pull—up 使能寄存器  表示向该寄存器写入0x00000040的数据         
 writel(0x00000040, pio_base + PIO_ODSR); //输出数据状态寄存器  表示向该寄存器写入0x00000040的数据       
 writel(0x00000040, pio_base + PIO_OER);  //输出使能寄存器  表示向该寄存器写入0x00000040的数据
        printk(KERN_INFO " open LED\n");
 return 0;
 }
static int baite_led_ioctl( struct inode *inode,
    struct file *filp,
    unsigned int cmd,
    unsigned long arg)
{       
 long   mode=0x00000040;         
 switch(cmd){     
  case LED_OFF:
    writel(mode, pio_base + PIO_SODR);
             printk(KERN_INFO " LED_OFF\n");
    break;     
  case LED_ON:
    writel(mode, pio_base + PIO_CODR);
    printk(KERN_INFO " LED_ON\n");
    break;               
  default: return -EINVAL;break;        
 }            
 return 0;
}

static struct file_operations led_fops =
{     
 .owner = THIS_MODULE,     
 .open  = baite_led_open,        
 .ioctl = baite_led_ioctl,
};
struct led_dev *at91_led;
static int led_init(void)
{     
 int result,err;
 printk(DEV_NAME " led_init\n");
 at91_led = kmalloc(sizeof(struct led_dev), GFP_KERNEL); 
 
 if( DEV_MAJOR != 0){      /*静态申请设置号*/
  at91_led->devno = MKDEV(DEV_MAJOR,DEV_MINOR);
  result = register_chrdev_region(at91_led->devno,1,DEV_NAME);
  at91_led->major = DEV_MAJOR;
  at91_led->minor = DEV_MINOR;
 }else {
  result = alloc_chrdev_region(&at91_led->devno,DEV_MINOR,1,DEV_NAME); /*动态申请设置号*/
  at91_led->major = MAJOR(at91_led->devno);
  at91_led->minor = DEV_MINOR;
 }
 if(result < 0){
  printk(KERN_ERR"led:can't get major\n");
  kfree(at91_led);
  return result;
 }

 cdev_init(&at91_led->cdev,&led_fops);      /*设置注册 初始化设备*/
 at91_led->cdev.owner = THIS_MODULE;
 at91_led->cdev.ops = &led_fops;
 err = cdev_add(&at91_led->cdev,at91_led->devno,1);
 if(err){
  printk(KERN_NOTICE"error %d adding led\n",err);
 }

 at91_led->class = class_create(THIS_MODULE, DEV_NAME);  /*创建一个类*/
 if( IS_ERR(at91_led->class) ){              /*IS_ERR() PTR_ERR()等函数是专门用来处理CLASS之类的返回错误代码 */
  return PTR_ERR(at91_led->class);
 }

 at91_led->class_dev = device_create(at91_led->class, NULL,/*创建在/dev目录下创建相应的设备节点。这样,加载模块的时候,*/
                                                           /* 用户空间中的udev会自动响应device_create(…)函数,去/sysfs下寻找对应的类从而创建设备节点。*/
                 //   第一个参数指定所要创建的设备所从属的类,第二个参数是这个设备的父设备,如果没有就指定为NULL,第三个参数是设备号,第四个参数是设备名称,第五个参数是从设备号

          at91_led->devno,
          NULL,DEV_NAME);
 if( IS_ERR(at91_led->class_dev) ){
  return PTR_ERR(at91_led->class_dev);
 }  
 return 0;
}

static void __exit led_exit(void)
{     
 device_destroy(at91_led->class, at91_led->devno);
 class_destroy(at91_led->class);                          ////还定义了class_destroy(…)函数,用于在模块卸载时删除类。
 cdev_del(&at91_led->cdev);
 unregister_chrdev_region(at91_led->devno,1);
 kfree(at91_led);    
 printk(DEV_NAME " led_exit\n");
}

module_init(led_init);
module_exit(led_exit);

MODULE_AUTHOR("zhd wangyulu");
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("at91sam9g20 led");
/*****Kconfig*******************************
config baite_LED
 tristate "baite_led"
 default m
******************************************/

/****Makeflie********************************
obj-$(CONFIG_baite_LED)  +=baite_led.o
******************************************/

2:这也是AT91的led的驱动,只是用的是led的标准函数

#include <linux/mm.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/string.h>
#include <linux/rtc.h> /* get the user-level API */
#include <linux/list.h>
#include <linux/timer.h>
#include <linux/delay.h>
#include <linux/kdev_t.h>
#include <linux/types.h>
#include <linux/cdev.h>
#include <linux/platform_device.h>
#include <linux/version.h>
#include <linux/miscdevice.h>
#include <linux/delay.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/moduleparam.h>
#include <linux/errno.h>
#include <linux/ioctl.h>
#include <linux/pci.h>
#include <linux/input.h>
#include <linux/serio.h>
#include <linux/platform_device.h>
#include <linux/clk.h>
#include <linux/mutex.h>
#include <linux/gpio.h>
#include <linux/io.h>
#include <linux/pci.h>
#include <linux/input.h>
#include <asm/atomic.h>
#include <asm/unistd.h>
#include <asm/uaccess.h>
#include <asm/mach/irq.h>
#include <asm/irq.h>
#include <asm/io.h>
#include <asm/uaccess.h>
#include <asm/leds.h>
#include <asm/mach-types.h>
#include <mach/at91_pio.h>
#include <mach/gpio.h>
#include <mach/hardware.h>
#include <mach/hardware.h>
//boy
/*
     通过测试成功 AT91 的开发板 内核是2.6.27
*/
#define DEVICE_NAME     "led"  /* 加载模式后,执行”cat /proc/devices”命令看到的设备名称 */ 
#define LED_MAJOR       231     /*  */
#define IOCTL_LED_ON    0       /* 应用程序执行ioctl(fd, cmd, arg)时的第2个参数 */
#define IOCTL_LED_OFF   1
#define LED0    AT91_PIN_PA6
static unsigned long led_table [] = {   /* 用来指定LED所用的GPIO引脚 */
     AT91_PIN_PA6,
     AT91_PIN_PA6
};

//应用程序对设备文件/dev/leds执行open(...)时,就会调用s3c2410_leds_open函数
static int S5PC100_leds_open(struct inode *inode, struct file *file)
{
        printk(DEVICE_NAME " S5PC100_LEDS_OPEN \n");
        at91_set_gpio_output(AT91_PIN_PA6, 1);    /* I/O 口设置*/
        at91_set_deglitch(AT91_PIN_PA6, 1);
        printk(DEVICE_NAME " LEDS_OPEN_END\n");
        return 0;
 }                                                       
//应用程序对设备文件/dev/leds执行ioclt(...)时,就会调用s3c2410_leds_ioctl函数
static int S5PC100_leds_ioctl(
    struct inode *inode,
    struct file *file,
    unsigned int cmd,
    unsigned long arg)
{
     printk(DEVICE_NAME"leds_ioctl\n");
    if (arg > 4) {
        return -EINVAL;
    }
    switch(cmd) {
    case IOCTL_LED_ON:
        // 设置指定引脚的输出电平为0
        printk(DEVICE_NAME" IOCTL_LED_ON\n");
        at91_set_gpio_value(led_table [arg], 0);
        printk(DEVICE_NAME" LED1_ON\n");
        return 0;

    case IOCTL_LED_OFF:
         printk(DEVICE_NAME" IOCTL_LED_OFF\n");
         at91_set_gpio_value(led_table [arg], 1);
         printk(DEVICE_NAME" LED1_OFF\n");
        return 0;
    default:
         printk(DEVICE_NAME" leds_ioctl_default\n");
        return -EINVAL;
    }

}

//字符设备驱动程序的核心,当应用程序操作设备文件时所调用的open、read、write等函数,最终会调用这个>结构中指定的对应函数
static struct file_operations S5PC100_leds_fops = {
    .owner  =   THIS_MODULE,
    .open   =   S5PC100_leds_open,
    .ioctl  =   S5PC100_leds_ioctl,
};

/*static struct miscdevice misc = {  //使用与2.6.29的内核 不是使用与2.6.27的内核
        .minor = MISC_DYNAMIC_MINOR,
        .name = DEVICE_NAME,
        .fops = &S5PC100_leds_fops,
};
*/
static int  S5PC100_leds_init(void)
{   
     printk(DEVICE_NAME "S5PC100_LEDS_INIT\n");
     int ret;
     //ret = misc_register(&misc); //使用与2.6.29的内核 不是使用与2.6.27的内核
     ret = register_chrdev(LED_MAJOR, DEVICE_NAME, &S5PC100_leds_fops);
     printk(DEVICE_NAME " S5PC100_LEDS_INIT_END\n");
    return ret;          
}
static void  S5PC100_leds_exit(void)
{
        //misc_deregister(&misc); //使用与2.6.29的内核 不是使用与2.6.27的内核
        unregister_chrdev(LED_MAJOR, DEVICE_NAME);
        printk(DEVICE_NAME "s5pc100_leds_exit\n");
}
module_init(S5PC100_leds_init);   /* 指定驱动程序的初始化函数和卸载函数 */
module_exit(S5PC100_leds_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("luckyboy");
//表示在make menuconfig 里面可以选着////
/*****Kconfig****************************
        config BUTTONS
 tristate "buttons"
 default m
******************************************/

/****Makeflie*****************************
obj-$(CONFIG_BUTTONS)   +=at91sam9g20_buttons.o
******************************************/
//表示编译为模块////
/****Makeflie*****************************
obj-m   +=leds.o
******************************************/


 

 

3: 对驱动的应用测试就是;

#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/ioctl.h>
/////成功的测试程序/////
int main(int argc, char **argv)
{
        int on;
        int led_no;
        int fd;
        if(argc != 3 ||sscanf(argv[1],"%d",&led_no) !=1 ||
                       sscanf(argv[2],"%d",&on) !=1 ||
                on < 0 || on > 1 || led_no <0 || led_no>3)
        {
                fprintf(stderr,"Usage:Leds led_no 0|1\n");
                exit(1);
        }
        //打开/dev/leds0设备文件
      // fd=open("/dev/leds0",0);
      // if(fd<0)
      // {
           //fd = open("/dev/leds",0);// ceshi leds
           fd = open("/dev/led",0);// ceshi led
           perror("open device led success");
          // perror("open device leds success");
       //}
       //if(fd <0 )
       //{
       //     perror("open device leds");
       //     exit(1);
      // }
       //通过系统调用ioctl和输入的参数控制led
       ioctl(fd,on,led_no);
       perror("open device led success ioctl");
       //关闭设备句柄
       close(fd);
       return 0;
}
/*
int main(void)
{
        int on=1;
        int led;
        int fd;
       //打开/dev/leds0设备文件
        fd = open("/dev/leds",0);
        if(fd <0 )
        {
              perror("open device leds");
              exit(1);
        }
        printf( " led_test_show press ctrl+c to exit\n");
        //通过系统调用ioctl和输入的参数控制led
        while(1)
        {
            for(led=0;led<4;led++)
            {
                ioctl(fd, on, led);
                usleep(50000);
            }
            on=!on;
        }
        //关闭设备句柄
        close(fd);
        perror("led test ");
       return 0;
}
*/
以上是我自己学习驱动的时候写的,现在贴出来,希望对初学者有一点帮助!

 

原创粉丝点击