zoukankan      html  css  js  c++  java
  • 学习控制发光二极管代码心得

    LED的完整驱动代码

    #include <linux/fs.h>

    #include <linux/cdev.h>

    #include <linux/pci.h>

    #include <asm/uaccess.h>

    #include <mach/map.h>

    #include <mach/regs-gpio.h>

    #include <mach/gpio-bank-m.h>

    #define DEVICE_NAME "s3c6410_leds"

    #define DEVICE_COUNT 1               //  设备数量

    #define S3C6410_LEDS_MAJOR 0   // 默认主设备号

    #define S3C6410_LEDS_MINOR 234  // 默认次设备号

    #define PARAM_SIZE  3 //定义数组长度

    static unsigned char mem[4]; // 保存4Leds的设置状态

    static int major = S3C6410_LEDS_MAJOR;

    static int minor = S3C6410_LEDS_MINOR;

    static dev_t dev_number; //  设备号

    static int leds_state = 1;

    static char *params[] = {"string1", "string2","string3"};

    static int param_size = PARAM_SIZE;

    static struct class *leds_class = NULL;

    /*********5.控制LED**********/

    // s3c6410_leds_ioctl函数用于接收向LED驱动传递的命令和参数,通过I/O命令控制LED

    static long s3c6410_leds_ioctl(struct file *filp, unsigned int cmd,

            unsigned long arg)

    {

      //命令只能是01

      switch (cmd)

      {

        unsigned tmp;

        case 0:

        case 1:

        if (arg > 4)

        {

          return -EINVAL;

        }

      //读取GPMDAT寄存器的当前值

      tmp = ioread32(S3C64XX_GPMDAT);

      if (cmd == 1)

      {

        tmp &= (~(1 << arg));

      }

      else

      {

        tmp |= (1 << arg);

      }

      //GPMDAT寄存器写入数据

      iowrite32(tmp, S3C64XX_GPMDAT);

      return 0;

      default:

      return -EINVAL;

      }

    }

    //s3c6410_leds_write函数用于接收向/dev/s3c6410_leds设备文件写入的字符串

    static ssize_t s3c6410_leds_write(struct file *file, const char __user *buf,

            size_t count, loff_t *ppos)

    {

      unsigned tmp = count;

      unsigned long i = 0;

      memset(mem, 0, 4);//mem数组所有元素的值都设为0

      //最多写入4个字符,多余的字符将忽略

      if (count > 4)

      {

        tmp = 4;

      }

      if (copy_from_user(mem, buf, tmp))

      {

        return -EFAULT;

      }

      else

      {

        for (i = 0; i < 4; i++)

        {

          tmp = ioread32(S3C64XX_GPMDAT);

          if (mem[i] == '1')

          {

            tmp &= (~(1 << i));

          }

          else

          {

            tmp |= (1 << i);

          }

          iowrite32(tmp, S3C64XX_GPMDAT);

        }

      return count;

      }

    }

    static struct file_operations dev_fops ={ .owner = THIS_MODULE, .unlocked_ioctl = s3c6410_leds_ioctl, .write =   s3c6410_leds_write };

    static struct cdev leds_cdev;

    /********2.创建设备文件(/dev/s3c6410_leds********/

    static int leds_create_device(void)

    {

      int ret = 0;

      int err = 0;

      // 1步: 初始化cdev的成员,并建立cdevfile_operations之间的连接

      cdev_init(&leds_cdev, &dev_fops);

      leds_cdev.owner = THIS_MODULE;

      //2步:主设备号>0,通过指定设备号的方式注册字符设备区域

      if (major > 0)

      {

        //指定设备号的两种方式:直接在代码中指定(硬编码),动态分配

        //  获取设备号(主设备号和次设备号)

        dev_number = MKDEV(major, minor);

        err = register_chrdev_region(dev_number, DEVICE_COUNT, DEVICE_NAME);

        if (err < 0)

        {

          printk(KERN_WARNING "register_chrdev_region() failed ");

          return err;

        }

      }

      else

      {

        err = alloc_chrdev_region(&leds_cdev.dev, 10, DEVICE_COUNT,

             DEVICE_NAME);

        if (err < 0)//注册字符设备区域失败

        {

          printk(KERN_WARNING "alloc_chrdev_region() failed ");

          return err;

        }

        //一般采用分别指定主设备号和次设备号的方式指定设备号。

        major = MAJOR(leds_cdev.dev);

        minor = MINOR(leds_cdev.dev);

        //dev_number = MKDEV(major, minor);

        dev_number = leds_cdev.dev; 

      }

      //3步:将字符设备添加到内核中的字符设备数组中

      ret = cdev_add(&leds_cdev, dev_number, DEVICE_COUNT);

      //4步:使用class_create宏创建struct class

      leds_class = class_create(THIS_MODULE, DEVICE_NAME);

      //5步:创建设备文件

      device_create(leds_class, NULL, dev_number, NULL, DEVICE_NAME);

      return ret;

    }

    /********4.设置寄存器与初始化LED驱动*******/

    static void leds_init_gpm(int leds_default)

    {

      int tmp = 0;

      //  初始化端口配置寄存器

      tmp = ioread32(S3C64XX_GPMCON);

      tmp &= (~0xFFFF);

      tmp |= 0x1111; // 0001000100010001

      iowrite32(tmp, S3C64XX_GPMCON);

      //  初始化端口上拉电路寄存器

      tmp = ioread32(S3C64XX_GPMPUD);

      tmp &= (~0xFF);

      tmp |= 0xAA; // 01010101

      iowrite32(tmp, S3C64XX_GPMPUD);

       //  初始化端口数据寄存器

      tmp = ioread32(S3C64XX_GPMDAT);

      tmp &= (~0xF);

      tmp |= leds_default;

      iowrite32(tmp, S3C64XX_GPMDAT);

    }

    /********1. 初始化LED驱动*********/

    static int leds_init(void)

    {

      int ret;

      ret = leds_create_device();

      leds_init_gpm(~leds_state);

      printk(DEVICE_NAME" initialized ");

      //输出params数组中的值

      printk("param0 %s ", params[0]);

      printk("param1 %s ", params[1]);

      printk("param2 %s ", params[2]);

      return ret;

    }

    /*********3.卸载LED驱动的设备文件*********/

    static void leds_destroy_device(void)

    {  //移除通过device_create函数建立的字符设备

      device_destroy(leds_class, dev_number);

      if (leds_class)  //销毁struct class

        class_destroy(leds_class);

      //注销字符设备区域

      unregister_chrdev_region(dev_number, DEVICE_COUNT);

      return;

    }

    static void leds_exit(void)

    {

      leds_destroy_device();//卸载LED驱动的设备文件

      printk(DEVICE_NAME" exit! ");

    }

    //LED驱动的模块参数

    module_init(leds_init);

    module_exit(leds_exit);

    module_param(leds_state, int, S_IRUGO|S_IWUSR);

    //下面一行是指定数组类型模块参数的相关信息

    module_param_array(params, charp, ¶m_size, S_IRUGO|S_IWUSR);

    MODULE_LICENSE("GPL");

    MODULE_AUTHOR("Lining");

  • 相关阅读:
    c#设计模式工厂模式
    海量数据,SQL查询优化
    正则判断字符串是否为数字
    NSString的用法
    HTML常用标签及属性图
    ADO的东西还是很多啊!
    MVC3中的tempdata,viewdata,viewbag总结
    sql 查询,删除重复的记录
    MVC3 Razor语法
    Winform TreeView 节点CheckBox选中,取消
  • 原文地址:https://www.cnblogs.com/zhanghui4521/p/5516382.html
Copyright © 2011-2022 走看看