×
单片机 > 单片机程序设计 > 详情

2416开发记录七: platform驱动之LED(misc)

发布时间:2020-08-26 发布时间:
|

platform驱动的简单介绍


前几篇介绍了最简单的LED驱动写法,在linux2.6中提出了platform驱动,具体为什么要这么做后面博客再解释吧。 


这里的platform驱动只是一个框架,并没有体现platform驱动的意义,因为在driver中没有使用device定义的资源。后面会再写一个真正的platfom。本篇算是入门练手,体会下吧。 


pltform机制本身使用并不复杂,由两部分组成:platform_device和platform_driver。通过platform机制开发底层驱动的大致流程为:定义platform_deive->注册platform_device->定义platform_driver->注册platform_driver 


好了,按照要求我们如果想编写一个platform驱动就需要编写两个模块了。一个设备模块dev。一个驱动模块driver。另外再编写一个应用程序来验证下。


platform_device

//my2416PlatformLedDev.c

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

/* 参考arch/arm/plat-s3c24xx/devs.c */



/*1. 根据芯片手册来获取资源*/

static struct resource led_resource[] = {

 [0] = {

  .start = S3C2410_GPBCON,//使用2416开发板的GPB1,暂时我只是定义了资源,但是在driver中并没有使用定义的资源(因为第一次写还不熟悉,后面会再写一个led的platform驱动来使用device定义的资源,这样才能发挥platform驱动的真正意义:platform机制将设备本身的资源注册进内核,由内核统一管理,在驱动中使用这些资源时通过platform device提供的标准结构进行申请并使用。这样提高了驱动和资源的独立性,并且具有较好的可移植性和安全性(这些标准接口是安全的))

  .end   = S3C2410_GPBDAT,

  .flags = IORESOURCE_MEM,

 },

 //[1] = {

 // .start = 5,

 // .end   = 5,

 // .flags = IORESOURCE_IRQ,

 //},

};


void led_release(struct device *dev)


}


/*1.构建平台设备结构体,将平台资源加入进来*/

struct platform_device led_device = {

 .name    = "myplatformled", /* 使用名为"myplatformled"的平台驱动 ,加载驱动之后在sys/bus/platform/devices/目录下生成myplatformled设备*/

 .id    = -1,

 .dev = {

  .release = led_release,

 },

 .num_resources   = ARRAY_SIZE(led_resource),

 .resource   = led_resource,

};


/*2。把我们的设备资源挂在到虚拟总线的设备连表中去*/

int led_dev_init(void)

{

 platform_device_register(&led_device);   

 return 0;

}


void led_dev_exit(void)

{

 platform_device_unregister(&led_device);

}


module_init(led_dev_init);

module_exit(led_dev_exit);


MODULE_LICENSE("GPL"); 



对应的makefile文件为


#Makefile for .c

ARCH=arm

CROSS_COMPILE=arm-linux-

ifneq ($(KERNELRELEASE),)

    obj-m := my2416PlatformLedDev.o

else

#bbblack kernel

KERNELDIR ?= /home/zyd/soft/s3c2416/20140409_HELPER2416/Helper2416/source/s3c-linux.jyx

PWD := $(shell pwd)

modules:

    make -C $(KERNELDIR) M=$(PWD) ARCH=$(ARCH) CROSS_COMPILE=$(CROSS_COMPILE) modules

modules_install:

    make -C $(KERNELDIR) M=$(PWD) ARCH=$(ARCH) CROSS_COMPILE=$(CROSS_COMPILE) modules_install

app: app.c

    $(CROSS_COMPILE)gcc -o app app.c

clean:

    $(MAKE) -C $(KDIR) M=$(PWD) clean

endif


playform driver

//my2416PlatformLedDriver.c

#include

 #include

 #include

 #include

 #include

 #include

 #include

 #include

 #include

 #include

 #include

 #include

 #include

 #include

 #include

 #include

 #include

 #include

 #include

 #include

 #include

 #include

 #include

 #include

#include


#define DEVICE_NAME "myleds"//加载驱动之后会在/dev/目录下发现myleds,应用程序可以使用


#define LED_ON 0 //根据原理图,0点亮led,1熄灭led

#define LED_OFF 1

 //定义GPIO管脚

 static unsigned long led_table [] =

  {

      S3C2410_GPB(1),  //不能是S3C2410_GPB5;  因为没有这样定义,可以通过#define S3C2410_GPB5 S3C2410_GPB(5)

      //S3C2410_GPF(1),

      //S3C2410_GPF(2),

      //S3C2410_GPF(3),

 };

 //设置管脚模式

 static unsigned int led_cfg_table [] =

  {

      S3C2410_GPIO_OUTPUT, //随内核版本中定义类型的变化,在arch/arm/mach-sc2410/include/mach/Regs-gpio.h文件中定义

      //S3C2410_GPIO_OUTPUT,

      //S3C2410_GPIO_OUTPUT,

      //S3C2410_GPIO_OUTPUT,

 };

 static int my2416_leds_ioctl(struct file* filp, unsigned int cmd,unsigned long arg)

 {

   switch(cmd)

   {

      case LED_ON:

         s3c2410_gpio_setpin(S3C2410_GPB(1), LED_ON);

         break;

      case LED_OFF:

         //s3c2410_gpio_setpin(led_table[arg], !cmd);

         s3c2410_gpio_setpin(S3C2410_GPB(1), LED_OFF);

         break;

      default:

         printk("LED control:no cmd\n");

         printk("LED control are LED_ON or LED_OFF\n");

         return(-EINVAL);

   }

   return 0;

 }

 //dev_fops操作指令集

 static struct file_operations my2416Led_fops =

 {

      .owner =THIS_MODULE,

      .unlocked_ioctl =my2416_leds_ioctl,//这里必须是unlocked_ioctl而不是ioctl。

 };

 //第三步:混杂设备定义

 static struct miscdevice my2416Ledmisc =

  {

      .minor = MISC_DYNAMIC_MINOR,

      .name = DEVICE_NAME,//加载驱动之后会在/dev/目录下发现myleds,应用程序可以使用

      .fops = &my2416Led_fops,

 };

/*3。实现probe函数*/

static int led_probe(struct platform_device *dev)

{

   int ret;


   int i;

   ////这里只定义了一个io口GPB1

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

   {

       s3c2410_gpio_cfgpin(led_table[i], led_cfg_table[i]);

       s3c2410_gpio_setpin(led_table[i], 0);

   }

   ret = misc_register(&my2416Ledmisc);


   printk (DEVICE_NAME"\tinitialized\n");


   return ret;

}


int led_remove(struct platform_device *dev)

{

   misc_deregister(&my2416Ledmisc);

}


/*1。构建平台驱动结构体,不知道的时候可以看别人的*/

static struct platform_driver led_driver = {

 .probe  = led_probe,     /* 平台总线下增加一个平台设备时,调用枚举函数 */

 .remove  = led_remove,    /* 平台总线下去掉一个平台设备时,调用remove函数 */

 .driver  = {

  .name = "myplatformled",       /* 能支持名为"myplatformled"的平台设备 */

  .owner = THIS_MODULE,

 },

};


/*2。注册,把我们的驱动加入到平台设备驱动连表中去*/

static int led_drv_init(void)

{

   int ret;

   //网上的例子有    通常采用函数platform_device *platform_device_alloc(const char *name, int id)动态申请,通常name就是需要申请的设备名,而id为-1。然后采用int platform_device_add(struct platform_device *pdev)或者int platform_device_register(struct platform_device *pdev)

   //这里只使用了platform_device_register也成功了,具体为什么以后再分析。

    注册定义好的设备即可。

   ret=platform_driver_register(&led_driver);

   return ret;

}


static void __exit led_drv_exit(void)

 {

    platform_driver_unregister(&led_driver);

 }


module_init(led_drv_init);

module_exit(led_drv_exit);


MODULE_LICENSE("GPL"); 


对应的makefile文件如下


#Makefile for .c

ARCH=arm

CROSS_COMPILE=arm-linux-

ifneq ($(KERNELRELEASE),)

    obj-m := my2416PlatformLedDriver.o

else

#bbblack kernel

KERNELDIR ?= /home/zyd/soft/s3c2416/20140409_HELPER2416/Helper2416/source/s3c-linux.jyx

PWD := $(shell pwd)

modules:

    make -C $(KERNELDIR) M=$(PWD) ARCH=$(ARCH) CROSS_COMPILE=$(CROSS_COMPILE) modules

modules_install:

    make -C $(KERNELDIR) M=$(PWD) ARCH=$(ARCH) CROSS_COMPILE=$(CROSS_COMPILE) modules_install

app: app.c

    $(CROSS_COMPILE)gcc -o app app.c

clean:

    $(MAKE) -C $(KDIR) M=$(PWD) clean

endif


测试应用程序

#include

#include

#include

#include

#include

#include

#include



#define DEVICE_NAME "/dev/myleds"


#define LED_ON 0

#define LED_OFF 1


int main()

{

    int fd;

    int ret;

    char *i;

    char count=0;


    printf("My2416 led dev test!\n");


    fd=open(DEVICE_NAME,O_RDWR);

    printf("fd=%d\n",fd);

    if(fd==-1)

    {

        printf("open device %s error\n",DEVICE_NAME);

    }

    else

    {

        for(count=0;count<10;count++)

        {

            ioctl(fd,LED_OFF);

            sleep(1);

            ioctl(fd,LED_ON);

            sleep(1);

        }

        ret=close(fd);

        printf("ret =%d\n",ret);

        printf("Close ledapp succeed!\n");

    }

    return 0;

}



驱动加载的说明


首先加载设备,这里编译出来的是my2416PlatformLedDev.ko,加载之后在/sys/bus/platform/device目录下生成myplatformled。也就是和.name = “myplatformled”名称一致。


然后加载驱动,这里编译出来是my2416PlatformLedDriver.ko,加载之后在/sys/bus/platform/driver目录下生成myplatformled。也就是和.name = “myplatformled”名称一致。同时在/dev目录下生成myleds。应用程序就是使用的/dev/myleds。来操作设备的。


这里只是一个简单的platform驱动,只是在device中定义了资源,但是再driver中并没有使用资源(没有调用platform_get_resource函数。)因此这里并没有体现出platform的意义。后面会修改程序,做一个真正的platform驱动来。


下面几篇先介绍一下platform的基本知识,为写一个真正的platform驱动作个理论基础吧。

关键字:2416  platform  驱动之LED 

『本文转载自网络,版权归原作者所有,如有侵权请联系删除』

热门文章 更多
STM32 USB HID 键盘