久久久久久久999_99精品久久精品一区二区爱城_成人欧美一区二区三区在线播放_国产精品日本一区二区不卡视频_国产午夜视频_欧美精品在线观看免费

 找回密碼
 立即注冊

QQ登錄

只需一步,快速開始

搜索
查看: 3982|回復(fù): 0
收起左側(cè)

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

[復(fù)制鏈接]
ID:60266 發(fā)表于 2014-8-18 02:24 | 顯示全部樓層 |閱讀模式
sysfs與platform的相關(guān)基礎(chǔ)介紹可以參考博文【 sysfs   platform總線 】。
platform模型驅(qū)動編程,需要實(shí)現(xiàn)platform_device(設(shè)備)與platform_driver(驅(qū)動)在platform(虛擬總線)上的注冊、匹配,相互綁定,然后再做為一個(gè)普通的字符設(shè)備進(jìn)行相應(yīng)的應(yīng)用,總之如果編寫的是基于字符設(shè)備的platform驅(qū)動,在遵循并實(shí)現(xiàn)platform總線上驅(qū)動與設(shè)備的特定接口的情況下,最核心的還是字符設(shè)備的核心結(jié)構(gòu):cdev、 file_operations(他包含的操作函數(shù)接口)、dev_t(設(shè)備號)、設(shè)備文件(/dev)等,因?yàn)橛胮latform機(jī)制編寫的字符驅(qū)動,它的本質(zhì)是字符驅(qū)動。

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



platform驅(qū)動模型三個(gè)對象:platform總線、platform設(shè)備、platform驅(qū)動。
platform總線對應(yīng)的內(nèi)核結(jié)構(gòu):struct bus_type-->它包含的最關(guān)鍵的函數(shù):match()
platform設(shè)備對應(yīng)的內(nèi)核結(jié)構(gòu):struct platform_device-->注冊:platform_device_register(unregiste)
platform驅(qū)動對應(yīng)的內(nèi)核結(jié)構(gòu):struct platform_driver-->注冊:platform_driver_register(unregiste)


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




接下來講解如下實(shí)現(xiàn)platform驅(qū)動與設(shè)備的詳細(xì)過程。
實(shí)現(xiàn)platform驅(qū)動的詳細(xì)過程



1:定義驅(qū)動實(shí)例 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:實(shí)現(xiàn)驅(qū)動實(shí)例成員函數(shù):probe  mini2440_led_probe
probe函數(shù)中要實(shí)現(xiàn)的功能包括:設(shè)備號的申請,字符設(shè)備內(nèi)核對象cdev的定義、初始化、綁定file_operations,注冊字符設(shè)備內(nèi)核對象cdev,在/dev下動態(tài)創(chuàng)建設(shè)備文件。
3:platform模型驅(qū)動寫字符設(shè)備仍要實(shí)現(xiàn)字符設(shè)備的核心結(jié)構(gòu)file_operations,第一步的cdev要用到
將file_operations結(jié)構(gòu)體中open、write、read等要用到的接口函數(shù)實(shí)現(xiàn)。
4:實(shí)現(xiàn)驅(qū)動實(shí)例成員函數(shù):remove mini2440_led_remove
remove函數(shù)中要實(shí)現(xiàn)的功能與probe中的相反,進(jìn)行相關(guān)設(shè)備與資源的注銷。
【probe與remove函數(shù)其實(shí)對應(yīng)前面用非platform機(jī)制寫驅(qū)動的時(shí)候所實(shí)現(xiàn)的模塊加載與卸載函數(shù),而在platform機(jī)制中,模塊的加載與卸載函數(shù)調(diào)用的是 設(shè)備或驅(qū)動的注冊函數(shù)】
5:實(shí)現(xiàn)驅(qū)動的加載與卸載函數(shù):
在加載函數(shù)中,調(diào)用驅(qū)動的注冊函數(shù),platform_driver_register(...);
在卸載函數(shù)中,調(diào)用驅(qū)動的卸載函數(shù),platform_driver_unregister(...);
實(shí)現(xiàn)platform設(shè)備的詳細(xì)過程

platform設(shè)備的實(shí)現(xiàn)有兩種方法:
     1:最笨的一種:直接在內(nèi)核源代碼里面添加相關(guān)的資源代碼,\arch\arm\mach-s3c2440\mach-mini2440.c
     2:編寫設(shè)備模塊,用insmod命令加載該設(shè)備模塊到platform總線上。
當(dāng)然用第二種了,不過這兩種方法的原理與要寫的代碼都是一樣的,但是第一種不用自己注冊,因?yàn)橄到y(tǒng)初始化的時(shí)候會將mach-mini2440.c中struct platform_device *mini2440_devices[] __initdata 設(shè)備數(shù)組中包含的所有設(shè)備注冊到總線上。而第二種手動注冊,一個(gè)字活。
1:定義設(shè)備與資源實(shí)例
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:實(shí)現(xiàn)設(shè)備的成員函數(shù)release  
static void mini2440_led_platform_device_release(struct device * dev)
{
    return ;
}
3:實(shí)現(xiàn)設(shè)備的加載與卸載函數(shù):
在加載函數(shù)中,調(diào)用設(shè)備的注冊函數(shù),platform_device_register(...);
在卸載函數(shù)中,調(diào)用設(shè)備的卸載函數(shù),platform_device_unregister(...);

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

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

下面是代碼清單:
//////////////////////////////
設(shè)備模塊:
#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);
//////////////////////////////
驅(qū)動模塊:
#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




回復(fù)

使用道具 舉報(bào)

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

本版積分規(guī)則

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

Powered by 單片機(jī)教程網(wǎng)

快速回復(fù) 返回頂部 返回列表
主站蜘蛛池模板: 国产成人精品久久二区二区 | 成人免费在线网 | 中文二区| 亚洲欧美日韩精品久久亚洲区 | 视频一区二区中文字幕 | 久久99蜜桃综合影院免费观看 | 日韩aⅴ片| 日本电影韩国电影免费观看 | 黄色日批视频 | 91久久精品 | 国产欧美一区二区精品忘忧草 | 天天干天天操 | 国产精品久久久久无码av | 久久久久亚洲视频 | 亚洲综合久久久 | 国产成人小视频 | 日韩精品一区二区三区中文在线 | 亚洲精品视频在线 | 国产亚洲欧美日韩精品一区二区三区 | 欧美国产视频 | 日韩视频在线免费观看 | 亚洲一区二区视频 | 九九伦理电影 | 91亚洲国产| 伊人激情网 | 欧美性高潮 | 免费一区在线 | 99热.com| 一区二区在线观看免费视频 | 亚洲日韩欧美一区二区在线 | 欧美一区二区视频 | 久久电影一区 | 欧美国产免费 | 日韩av视屏 | 亚洲国产精品一区二区www | 日韩精品无码一区二区三区 | 91免费福利视频 | 2021狠狠天天天 | 亚洲欧美一区二区三区国产精品 | 呦呦在线视频 | 粉色午夜视频 |