《Android深度探索(卷1):HAL与驱动开发》——1.7节见识一下什么叫Linux驱动:LED-阿里云开发者社区

开发者社区> 开发与运维> 正文
登录阅读全文

《Android深度探索(卷1):HAL与驱动开发》——1.7节见识一下什么叫Linux驱动:LED

简介:

本节书摘来自异步社区《Android深度探索(卷1):HAL与驱动开发》一书中的第1章,第1.7节见识一下什么叫Linux驱动:LED,作者李宁,更多章节内容可以访问云栖社区“异步社区”公众号查看

1.7 见识一下什么叫Linux驱动:LED
Android深度探索(卷1):HAL与驱动开发
Linux驱动这个家伙到现在为止仍然是只见其声,未见其人,不过在本节会向读者展示一下Linux驱动到底是个什么东西。如果读者看到Linux驱动的代码感到头晕,这属于正常现象。因为如果一看就明白的话,那就没有阅读本书的必要了。本节的目的只为向读者展示Linux驱动程序的结构,以及使读者对Linux驱动有一个大致的印象,读者无须理解其中的细节。当读者阅读完本书时,自然会对这些细节部分了如指掌。

下面给出一个简单的Linux驱动的核心代码(用C语言实现),这个驱动的作用就是控制S3C6410开发板上的4个LED(关于开发板的使用方法将在后面详细介绍)。我们姑且将其称为LED驱动。LED驱动属于字符设备驱动,核心代码如下:

#include <linux/miscdevice.h>
… …
//此处包含了多个头文件

// 定义了设备名,驱动程序会在/dev目录下建立一个leds设备文件,通过访问该设备文件可以访问LED驱动
#define DEVICE_NAME "leds"
// 向LED发送数据及从LED读取数据
static long s3c6410_leds_ioctl(struct file *filp, unsigned int cmd,
    unsigned long arg)
{
switch (cmd)
{
  unsigned tmp;
  case 0:
  case 1:
  if (arg > 4)
  {
      return -EINVAL;
  }
  tmp = readl(S3C64XX_GPMDAT);

  if (cmd == 0) // 关闭LED
  {
     tmp &= (~(1 << arg));
  }
  else     // 打开LED
  {
     tmp |= (1 << arg);
  }
   // 向LED设备写数据
  writel(tmp, S3C64XX_GPMDAT);
   // 输出调试信息
  printk(DEVICE_NAME"_lining: %d %d\n", arg, cmd);
  return 0;
  default:
  return -EINVAL;
}
}
// 描述设备文件的操作和相关数据的结构体
static struct file_operations dev_fops =
{ .owner = THIS_MODULE, .unlocked_ioctl = s3c6410_leds_ioctl, };

static struct miscdevice misc =
{ .minor = MISC_DYNAMIC_MINOR, .name = DEVICE_NAME, .fops = &dev_fops, };
// 驱动的初始化函数
static int _init dev_init(void)
{
int ret;

unsigned tmp;

//gpm0-3 pull up
tmp = readl(S3C64XX_GPMPUD);
tmp &= (~0xFF);
tmp |= 0xaa;
writel(tmp,S3C64XX_GPMPUD);

//gpm0-3 output mode
tmp =readl(S3C64XX_GPMCON);
tmp &= (~0xFFFF);
tmp |= 0x1111;
writel(tmp,S3C64XX_GPMCON);

//gpm0-3 output 0
tmp = _raw_readl(S3C64XX_GPMDAT);
tmp |= 0x10;
writel(tmp,S3C64XX_GPMDAT);

ret = misc_register(&misc);

printk (DEVICE_NAME"\tinitialized\n");

return ret;
}

static void _exit dev_exit(void)
{
misc_deregister(&misc);
}

module_init( dev_init);
module_exit( dev_exit);
// 指定了当前驱动在哪个协议下发布,在这里是GPL协议
MODULE_LICENSE("GPL");

LED驱动的代码涉及了很多系统的函数和结构体,如readl、writel、printk、miscdevice 、module_exit 、file_operations、miscdevice等。读者目前并不需要了解这些函数和结构体的作用和使用方法。只要知道任何的Linux驱动都有一个装载函数(装载驱动时调用)和一个卸载函数(卸载驱动时调用)即可。装载函数和卸载函数分别通过mobule_init和module_exit宏指定。

版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。

分享:
开发与运维
使用钉钉扫一扫加入圈子
+ 订阅

集结各类场景实战经验,助你开发运维畅行无忧

其他文章