欧美极品高清xxxxhd,国产日产欧美最新,无码AV国产东京热AV无码,国产精品人与动性XXX,国产传媒亚洲综合一区二区,四库影院永久国产精品,毛片免费免费高清视频,福利所导航夜趣136

 找回密碼
 立即注冊

QQ登錄

只需一步,快速開始

搜索
查看: 3979|回復: 0
打印 上一主題 下一主題
收起左側

platform驅動模型編程總結(基于mini2440平臺的LED驅動)

[復制鏈接]
跳轉到指定樓層
樓主
ID:60266 發表于 2014-8-18 02:24 | 只看該作者 回帖獎勵 |倒序瀏覽 |閱讀模式
sysfs與platform的相關基礎介紹可以參考博文【 sysfs   platform總線 】。
platform模型驅動編程,需要實現platform_device(設備)與platform_driver(驅動)在platform(虛擬總線)上的注冊、匹配,相互綁定,然后再做為一個普通的字符設備進行相應的應用,總之如果編寫的是基于字符設備的platform驅動,在遵循并實現platform總線上驅動與設備的特定接口的情況下,最核心的還是字符設備的核心結構:cdev、 file_operations(他包含的操作函數接口)、dev_t(設備號)、設備文件(/dev)等,因為用platform機制編寫的字符驅動,它的本質是字符驅動。

在一般情況下,2.6內核中已經初始化并掛載了一條platform總線在sysfs文件系統中。那么我們編寫platform模型驅動時,需要完成兩個工作:1:實現platform驅動 2:實現platform設備,然而在實現這兩個工作的過程中還需要實現其他的很多小工作,在后面介紹。platform模型驅動的實現過程核心架構就很簡單,如下所示。



platform驅動模型三個對象:platform總線、platform設備、platform驅動。
platform總線對應的內核結構:struct bus_type-->它包含的最關鍵的函數:match()
platform設備對應的內核結構:struct platform_device-->注冊:platform_device_register(unregiste)
platform驅動對應的內核結構:struct platform_driver-->注冊:platform_driver_register(unregiste)


簡單介紹下platform驅動的工作過程:設備(或驅動)注冊的時候,都會引發總線調用自己的match函數來尋找目前platform總線是否掛載有與該設備(或驅動)名字匹配的驅動(或設備),如果存在則將雙方綁定;如果先注冊設備,驅動還沒有注冊,那么設備在被注冊到總線上時,將不會匹配到與自己同名的驅動,然后在驅動注冊到總線上時,因為設備已注冊,那么總線會立即匹配與綁定這時的同名的設備與驅動,再調用驅動中的probe函數等;如果是驅動先注冊,同設備驅動一樣先會匹配失敗,匹配失敗將導致它的probe函數暫不調用,而是要等到設備注冊成功并與自己匹配綁定后才會調用。




接下來講解如下實現platform驅動與設備的詳細過程。
實現platform驅動的詳細過程



1:定義驅動實例 mini2440_led_platform_driver
static struct platform_driver mini2440_led_platform_driver = {
.probe  = mini2440_led_probe,
.remove = __devexit_p(mini2440_led_remove),
.driver = {
.name = "mini2440_led_platform_device_driver",
.owner = THIS_MODULE,
}
};

2:實現驅動實例成員函數:probe  mini2440_led_probe
probe函數中要實現的功能包括:設備號的申請,字符設備內核對象cdev的定義、初始化、綁定file_operations,注冊字符設備內核對象cdev,在/dev下動態創建設備文件。
3:platform模型驅動寫字符設備仍要實現字符設備的核心結構file_operations,第一步的cdev要用到
將file_operations結構體中open、write、read等要用到的接口函數實現。
4:實現驅動實例成員函數:remove mini2440_led_remove
remove函數中要實現的功能與probe中的相反,進行相關設備與資源的注銷。
【probe與remove函數其實對應前面用非platform機制寫驅動的時候所實現的模塊加載與卸載函數,而在platform機制中,模塊的加載與卸載函數調用的是 設備或驅動的注冊函數】
5:實現驅動的加載與卸載函數:
在加載函數中,調用驅動的注冊函數,platform_driver_register(...);
在卸載函數中,調用驅動的卸載函數,platform_driver_unregister(...);
實現platform設備的詳細過程

platform設備的實現有兩種方法:
     1:最笨的一種:直接在內核源代碼里面添加相關的資源代碼,\arch\arm\mach-s3c2440\mach-mini2440.c
     2:編寫設備模塊,用insmod命令加載該設備模塊到platform總線上。
當然用第二種了,不過這兩種方法的原理與要寫的代碼都是一樣的,但是第一種不用自己注冊,因為系統初始化的時候會將mach-mini2440.c中struct platform_device *mini2440_devices[] __initdata 設備數組中包含的所有設備注冊到總線上。而第二種手動注冊,一個字活。
1:定義設備與資源實例
static struct resource mini2440_led_resource[] = {
        [0] = {
                .start = 0x56000010,
                .end   = 0x56000010 + 12,
                .flags = IORESOURCE_MEM
        },
};
static struct platform_device mini2440_platform_device_led = {
        .name           = " mini2440_led_platform_device_driver ",
        .id             = -1,
        .num_resources  = ARRAY_SIZE(mini2440_led_resource),
        .resource       =  mini2440_led_resource ,
        .dev            = {
              .release  = mini2440_led_platform_device_release,
        },
};

2:實現設備的成員函數release  
static void mini2440_led_platform_device_release(struct device * dev)
{
    return ;
}
3:實現設備的加載與卸載函數:
在加載函數中,調用設備的注冊函數,platform_device_register(...);
在卸載函數中,調用設備的卸載函數,platform_device_unregister(...);

多個設備的同時注冊:platform_add_devices(struct platform_devices **devs,int num);
struct platform_devices **devs設備數組,num包含的設備數目

驅動與設備是否成功注冊,我們都可以在/sys/bus/platform/devices(drivers)/下查看

下面是代碼清單:
//////////////////////////////
設備模塊:
#include <linux/init.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <asm/io.h>
#include <asm/uaccess.h>
#include <linux/device.h>
#include <linux/cdev.h>
#include <linux/platform_device.h>

static void mini2440_led_platform_device_release(struct device * dev)
{
    return ;
}
static struct resource mini2440_led_resource[] = {
        [0] = {
                .start = 0x56000010,
                .end   = 0x56000010 + 12,
                .flags = IORESOURCE_MEM
        },
};
static struct platform_device mini2440_platform_device_led = {
        .name           = "mini2440_led_platform_device_driver",
        .id             = -1,
        .num_resources  = ARRAY_SIZE(mini2440_led_resource),
        .resource       = mini2440_led_resource,
        .dev            = {
              .release  = mini2440_led_platform_device_release,
        },
};
static int __init mini2440_led_platform_device_init(void)
{
    printk("mini2440_led_platform_device add ok!\n");
return platform_device_register(&mini2440_platform_device_led);
}
static void __exit mini2440_led_platform_device_exit(void)
{
    printk("mini2440_led_platform_device remove ok!\n");
platform_device_unregister(&mini2440_platform_device_led);
}
MODULE_AUTHOR("xxxx");
MODULE_LICENSE("GPL");
module_init(mini2440_led_platform_device_init);
module_exit(mini2440_led_platform_device_exit);
//////////////////////////////
驅動模塊:
#include <linux/init.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <asm/io.h>
#include <asm/uaccess.h>
#include <linux/device.h>
#include <linux/cdev.h>
#include <linux/platform_device.h>

#define GLOBAL_LED_MAJOR  250

static unsigned int global_led_major = GLOBAL_LED_MAJOR;
static struct cdev *led_cdev = NULL;
static struct class *led_class = NULL;

static volatile unsigned long *gpfcon = NULL;
static volatile unsigned long *gpfdat = NULL;
static volatile unsigned long *gpfup = NULL;

static int mini2440_led_open(struct inode * inode,struct file * file)
{
printk("mini2440_open[kernel_space]\n");
*gpfcon &=~((0x3<<0) | (0x3<<8) |(0x3<<10) |(0x3<<12)|(0x3<<14));
*gpfcon |= (0x1<<0) | (0x1<<8) |(0x1<<10) |(0x1<<12)|(0x1<<14);
return 0;
}
static ssize_t mini2440_led_read(struct file * file,const char __user * in,size_t size,loff_t * off)
{
printk("mini2440_read[kernel_space]\n");
return 0;
}
static ssize_t mini2440_led_write(struct file * file,const char __user * in,size_t size,loff_t * off)
{
    int ret;
char ker_buf;
printk("mini2440_write[kernel_space]\n");
ret = copy_from_user(&ker_buf,in,size);
printk("ker_buf =%d\n",ker_buf);
if(ker_buf)
{
*gpfdat &=~((0x1<<4)|(0x1<<5)|(0x1<<6)|(0x1<<7));
      
*gpfdat |= (0x1<<0);
}
else
{
*gpfdat |=(0x1<<4)|(0x1<<5)|(0x1<<6)|(0x1<<7);
*gpfdat &= ~(0x1<<0);
}
return 0;
}
struct file_operations led_fops = {
.owner = THIS_MODULE,
.open  = mini2440_led_open,
.read  = mini2440_led_read,
.write = mini2440_led_write,
};
static int __devinit mini2440_led_probe(struct platform_device *pdev)
{
int ret;
int err;
dev_t devno;
struct resource *pIORESOURCE_MEM;
devno = MKDEV(global_led_major,0);
printk(KERN_ALERT"mini2440_led_probe!\n");
if (devno) {
ret = register_chrdev_region(devno,1,"mini2440_led_platfor_driver");
} else {
ret = alloc_chrdev_region(&devno,0,1,"mini2440_led_platfor_driver");
global_led_major = MAJOR(devno);
}
if (ret < 0) {
return ret;
}
led_cdev = cdev_alloc();
cdev_init(led_cdev,&led_fops);
led_cdev->owner = THIS_MODULE;
err = cdev_add(led_cdev,devno,1);
led_class = class_create(THIS_MODULE,"mini2440_led_platfor_driver");
device_create(led_class,NULL,MKDEV(global_led_major,0),NULL,"platfor_driver_for_mini2440_led");
pIORESOURCE_MEM = platform_get_resource(pdev,IORESOURCE_MEM,0);
gpfcon = ioremap(pIORESOURCE_MEM->start,pIORESOURCE_MEM->end - pIORESOURCE_MEM->start);
gpfdat = gpfcon + 1;
gpfup  = gpfcon + 2;
if (err) {
printk(KERN_NOTICE"Error %d adding led_cdev",err);
return -1;
} else {
printk(KERN_NOTICE"platform_driver_for_mini2440_led init ok!\n");
return 0;
}
}




static int __devexit mini2440_led_remove(struct platform_device *pdev)
{
    printk("mini2440_led_remove!\n");
cdev_del(led_cdev);
iounmap(gpfcon);
unregister_chrdev_region(MKDEV(global_led_major,0),1);
device_destroy(led_class, MKDEV(global_led_major,0));
class_destroy(led_class);
return 0;
}
static struct platform_driver mini2440_led_platform_driver = {
.probe  = mini2440_led_probe,
.remove = __devexit_p(mini2440_led_remove),
.driver = {
.name = "mini2440_led_platform_device_driver",
.owner = THIS_MODULE,
}
};
static int __init mini2440_led_platform_driver_init(void)
{
    printk("platform_driver_for_mini2440_led init\n");
return platform_driver_register(&mini2440_led_platform_driver);
}

static void __exit mini2440_led_platform_driver_exit(void)
{
    printk("platform_driver_for_mini2440_led exit\n");
platform_driver_unregister(&mini2440_led_platform_driver);
}
MODULE_AUTHOR("xxx");
MODULE_LICENSE("GPL");
module_param(global_led_major,int,S_IRUGO);
module_init(mini2440_led_platform_driver_init);
module_exit(mini2440_led_platform_driver_exit);
///////////////////////
Makefiel

ifneq ($(KERNELRELEASE), )
obj-m  := mini2440_led_platform_driver.o
else
KDIR := /home/tools/linux-2.6.32.2
all:
make -C $(KDIR)  M=/linux_prg/platform_driver_device_module/driver_module/  modules  modules
clean:
rm -f *.ko  *.o  *.mod.o  *.mod.c  *.symvers
endif




分享到:  QQ好友和群QQ好友和群 QQ空間QQ空間 騰訊微博騰訊微博 騰訊朋友騰訊朋友
收藏收藏 分享淘帖 頂 踩
回復

使用道具 舉報

您需要登錄后才可以回帖 登錄 | 立即注冊

本版積分規則

小黑屋|51黑電子論壇 |51黑電子論壇6群 QQ 管理員QQ:125739409;技術交流QQ群281945664

Powered by 單片機教程網

快速回復 返回頂部 返回列表