腾讯微群加入QQ群

 找回密码
 加入我们

!connect_header_login!

!connect_header_login_tip!

搜索
查看: 639|回复: 0

基于S3C2440开发板LED灯驱动移植

[复制链接]
发表于 2016-8-23 13:24:21 | 显示全部楼层 |阅读模式

上一篇文章简述了如何写一个实用性较强的驱动模板,今天我们给这个模板填充一些必要的代码,让它变成一个可用的led驱动程序,实际上大多数字符类驱动也都是基于这种模板形式。


#include <linux/miscdevice.h>
#include <linux/delay.h>
#include <asm/irq.h>
#include <mach/regs-gpio.h>
#include <mach/hardware.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/mm.h>
#include <linux/fs.h>
#include <linux/types.h>
#include <linux/delay.h>
#include <linux/moduleparam.h>
#include <linux/slab.h>
#include <linux/errno.h>
#include <linux/ioctl.h>
#include <linux/cdev.h>
#include <linux/string.h>
#include <linux/list.h>
#include <linux/pci.h>
#include <asm/uaccess.h>
#include <asm/atomic.h>
#include <asm/unistd.h>

/*以上头文件包含如果搞不懂具体起什么作用,建议从系统驱动中拷贝*/ 

/*#define definition*/
#define DEVICE_NAME "gpio_drv"  //设备名称  和文件系统里设备节点名称区分开
#define FIRST_MAJOR 0  //主设备号


#define LED_ON 1   //点亮
#define LED_OFF 0 //熄灭


static unsigned long led_table[] =
{
 S3C2410_GPB5,
 S3C2410_GPB6,
 S3C2410_GPB7,
 S3C2410_GPB8,
  
};

static unsigned int led_cfg_table[] =
{
 S3C2410_GPB5_OUTP,
 S3C2410_GPB6_OUTP,
 S3C2410_GPB7_OUTP,
 S3C2410_GPB8_OUTP,
};

/*上面两个数组采用源码的基于S3C2410头文件配置好的,如果需要自己配置 参考S3C2440用户手册*/

//.open func 应用程序将来调用的open函数 主要配置io口
static int myfirst_drv_open(struct inode *inode, struct file *filp)
{
 int i;
 for(i = 0; i < 4; i++)
 {
  s3c2410_gpio_cfgpin(led_table, led_cfg_table);  
 }
 printk("myfirst_drv_open\n");
 /*配置GPIB5 6 7 8 为输出*/
 
 return 0;
}

//.write func 应用程序将来调用write部分 *file问文件句柄 *buf传入的用户(应用程序)数据地址  count为字节长度 一般为4的整数倍 前面buf为地址 一条指令4个字节 

static ssize_t myfirst_drv_write (struct file *file, const char __user *buf, size_t count, loff_t *ppos)
{
 int val;   //接收用户数据
 int i;;

 printk("myfirst_drv_write\n");
 copy_from_user(&val, buf, count); // copy_to_user();  将用户空间地址buf的数据交互到内核空间 val地址上
 if (val == 1)  //点亮LED灯
  {
   for(i = 0; i < 4; i++)
   {
    s3c2410_gpio_setpin(led_table, 0);
    
   }
   printk("led on\n");
  }
 else
  {
   
   for(i = 0; i < 4; i++)
   {
    s3c2410_gpio_setpin(led_table, 1);
   }
   printk("led off\n");
  }
 
 return 0;
}

//ioctl控制  应用程序将来调用的ioctl函数*file为应用层返回的文件句柄,cmd为操作命令 arg为传入的参数
static int gpio_ioctl(
 struct inode *inode,
 struct file *file,
 unsigned int cmd,
 unsigned long arg)
{
 if (arg > 4)
 {
  return -EINVAL;
 }

 switch(cmd)
 {
  case LED_ON:
   // 璁剧疆鎸囧畾寮曡剼鐨勮緭鍑虹數骞充负0
   s3c2410_gpio_setpin(led_table[arg], 0);
   return 0;

  case LED_OFF:
   // 璁剧疆鎸囧畾寮曡剼鐨勮緭鍑虹數骞充负1
   s3c2410_gpio_setpin(led_table[arg], 1);
   return 0;

  default:
   return -EINVAL;
 }
}


//define the file_operations   file_operations结构体
static struct file_operations myfirst_drv_fops = {
 .owner = THIS_MODULE,
 .open =  myfirst_drv_open,
 .write = myfirst_drv_write,
 .ioctl =  gpio_ioctl,
};


static struct class *myfirst_drv_class;  //定义一个类 方便在/dev目录下建立一个节点
int major;  //自动分配主设备号
int first_drv_init(void)
{
 //int ret;
 //ret = register_chrdev(FIRST_MAJOR, DEVICE_NAME, &myfirst_drv_fops);
 major = register_chrdev(FIRST_MAJOR, DEVICE_NAME, &myfirst_drv_fops);
 //if(ret < 0)//
 if(major < 0)
  {
    printk("myfirst_drv can not register major number!\n");
    return major;
  }
 /*注册一个类  使得mdev可以在/dev目录下自动建立设备节点 不需要手动mknod dev c 224 0这样的操作*/
 myfirst_drv_class = class_create(THIS_MODULE, DEVICE_NAME);
 if(IS_ERR(myfirst_drv_class))
  {
    printk("error, fail to init myfirst_drv_class");
    return -1;
  }
 /*如果上面成功注册进mdev的话 下面自动在/dev目录下创建一个设备节点*/
 device_create(myfirst_drv_class, NULL, MKDEV(major, 0), NULL, "GPIO_DRV"); //这个就是在/dev下创建的MYFIRST_DRV 设备节点了 应用程序调用
 printk("MYFIRST_DRV initialized! \n");
 return 0;
}

void first_drv_exit(void)
{
 unregister_chrdev(major, DEVICE_NAME);  //卸载驱动
 device_destroy(myfirst_drv_class, MKDEV(major, 0)); //删掉设备节点
 class_destroy(myfirst_drv_class);  //注销类
 printk("rm -rm MYFIRST_DRV! \n");
 
}

module_init(first_drv_init);
module_exit(first_drv_exit);

MODULE_LICENSE("GPL");  //获得授权

 该驱动makefile和上一篇一样 这里不再重复填上

下面看我们的测试程序 如何通过write open ioctl来操作硬件的?

#include <unistd.h>
#include <sys/ioctl.h>
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>


#define LED_ON 1
#define LED_OFF 0

static int fd;  //用于存放打开设备时返回的文件句柄

//例如我们想通过设备文件向驱动写入数据的时候 我们的main函数应该设置成下面的方式,下面的参数如何理解呢?我这里贴上一段参考----

int main(int argc, char **argv)

argc是命令行中的参数的个数
argv[]对应每一个参数

例如
./a.exe 1 bb
argc将会是3
其中
argv[0]“./a.exe”
argv[1]“1”
argv[2]“bb”

 

int main(int argc, char **argv)
{
 int led_no = 0;
 int val ;
 int ret;
 fd = open("/dev/GPIO_DRV", O_RDWR);  //打开设备  并读写权限 上一篇我们后面的参数写的是0 这里需要为O_RDWR,意思是赋予驱动读写权限
 if(fd < 0)  //成功打开fb返回的肯定是个非零值
  {
   perror("open device failed");
   exit(1);
  } 
  
 while(1)    //每个应用程序都是死循环
  {
   for(led_no = 0; led_no < 4; led_no++)
    {
     ioctl(fd, LED_ON, led_no);  //点亮一盏灯 这里采用循环点亮方式
     sleep(2);
    }
   led_no = 0;
   for(led_no = 0; led_no < 4; led_no++)   //又熄灭一个led灯 熄灭2个。。。。。
    {
     ioctl(fd, LED_OFF, led_no);  //熄灭一盏灯
     sleep(1);
    }
   led_no = 0;
   if(argc != 2)    //如果传入参数不是2个的话 提示信息退出 ./gpio_test on  一定要这种方式
    {
     printf("Usage :\n");
     printf("%s <on|off>\n", argv[0]);
     return 0;   //退出重新运行应用程序
    }
   
   if (strcmp(argv[1], "go") != 0)  //如果第二个参数不是go  如果./gpio_test go 则运行流水灯 上面部分
   {
    if (strcmp(argv[1], "on") == 0)  //如果第二个参数为on  
    {
     printf("led app on\n");
     val  = 1;
    }
    else if (strcmp(argv[1], "off") == 0) //第二个参数为off
    {
     printf("led app off\n");
     val = 0;
    }
     ret = write(fd, &val, 4);  //写入 fd为文件句柄  传入要写的数据的地址&val  我们就要么1 要么0  所以一个地址就可以了 长度4字节
    if(ret < 0)   //如果写入成功 返回写入的个数 否则返回-1
     {
       printf("write failed ret = %d\n", ret);
       return 1;
     }
    return 0;
   }
 
   
  }
 //close(fd); //关闭设备
 return 0;
}

 编写该应用程序的makefile  为了以后开发方便 这里makefile较上篇做了一点改变

CROSS=arm-linux-
DRIVER=gpio_drvtest.c
FILENAME=gpio_test

all: $(FILENAME)

$(FILENAME) : $(DRIVER)
 $(CROSS)gcc -g -o $(FILENAME) $(DRIVER)
# $(CROSS)strip FILENAME
clean:
 @rm -vf $(FILENAME) *.o *~

 

 

 

0
0

转自:http://blog.csdn.net/cumtgao/article/details/8669642?locationNum=1
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 加入我们

本版积分规则

QQ|手机版|Archiver|小黑屋|一起疯|苦咖啡 ( 新ICP备12000197号  

GMT+8, 2018-4-27 11:09 , Processed in 0.212306 second(s), 12 queries , Memcache On.

Powered by Discuz! X3.2

© 2001-2013 Comsenz Inc.

快速回复 返回顶部 返回列表