目录: 一. bus-driver-device模型

    二. 运行结果,及错误解决

    三. 怎样利用以有的driver device驱动来写自已的beep-driver-device 驱动

        四. 总结

  怎样解决编译时出现内核提供的函数或变量没有定义,使用source insight搜索功能找到声明的头文件,然后包含该头件就行了:

  比如: error: implicit declaration of function 'copy_from_user'

  解决:使用source insight搜索功能,可以找到copy_from_user函数是在linux/uaccess.h 头文件中定义,所以包含此头文件就行了。

一. bus-driver-device模型:

  

二. 运行结果,及错误解决

步骤一:驱动运行结果:

从上图红色线可知,卸载led_dev失败原因是因为led_dev.c  platform_device中没有加release()函数;所以正确的方法如下:在led_dev.c 中:

static struct platform_device led_dev = {
    .name = "mini210_led",
    .id = 0,
    .dev = {
        .release = led_release,    //必须在.dev中加入
        //.platform_data = &smsc911x_config,
    },
    .num_resources = ARRAY_SIZE(led_resources),
    .resource = led_resources,
};

步骤二:改正步骤一的问题后,重新编译,下载到板上,又出现下面情况

错误:

通过开发板串口返回的错:[root@FriendlyARM driver]# rmmod led_dev
rmmod: remove 'led_dev': Device or resource busy

再查看编译出现的警告:

上图说led_dev_exit定义了,但没有使用,所以原来是modele_exit(led_dev_exit); //这里错了,会导致rmmod 失败:Device or resource busy;

正确写法:module_exit(led_dev_exit);

解决上面2个步骤后,这驱动程序问题就解决了。

三. 怎样利用以有的driver device驱动来写自已的beep-driver-device 驱动

  新建beep_dev.c  与 beep_drv.c文件

  1) 用source insight软件打开beep_dev.c:

  搜索platform_device 找到有platform_device 类型定义的变量,这里我找到的是3ds_debugboard.c参考此文件来编写自己的驱动,打开此文件并找到以下内容并复制到beep_dev.c文件中:

static struct resource smsc911x_resources[] = {
    {
        .flags = IORESOURCE_MEM,
    } , {
        .start = EXPIO_INT_ENET,
        .end = EXPIO_INT_ENET,
        .flags = IORESOURCE_IRQ,
    },
};static struct platform_device smsc_lan9217_device = {
    .name = "smsc911x",
    .id = 0,
    .dev = {
        .platform_data = &smsc911x_config,
    },
    .num_resources = ARRAY_SIZE(smsc911x_resources),
    .resource = smsc911x_resources,
};

beep_dev.c完整代码:

/*分配,设置,注册一个platform_device*/

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/sched.h>
#include <linux/poll.h>
#include <linux/irq.h>
#include <linux/interrupt.h>
#include <linux/platform_device.h>
#include <linux/cdev.h>
#include <linux/miscdevice.h>
#include <linux/serial_core.h>

/*分配,设置,注册一个platform_device*/

static struct resource beep_resources[] = {
    [0] = {
        /*.start = 0xE0200280, //0xE02000A0;
        .end = 0xE0200280 + 8 - 1,
        .flags = IORESOURCE_MEM,*/
        .start = 0xE02000A0, //;
        .end = 0xE02000A0 + 8 - 1,
        .flags = IORESOURCE_MEM,
    },
    [1] = {
        .start = 0,
        .start = 0,
        .flags = IORESOURCE_IRQ,
    }
};

static void beep_release(struct device *dev)
{
    printk("beep_release\n");
}

static struct platform_device beep_dev = {
    .name = "mini210_beep",
    .id = 0,
    .dev = {
        .release = beep_release,
        //.platform_data = &smsc911x_config,
    },
    .num_resources = ARRAY_SIZE(beep_resources),
    .resource = beep_resources,
};

static int beep_dev_init(void)
{
    platform_device_register(&beep_dev);
    return 0;
}

static void beep_dev_exit(void)
{
    platform_device_unregister(&beep_dev);
}

module_init(beep_dev_init);
//modele_exit(beep_dev_exit);  //这里错了,会导致rmmod 失败:Device or resource busy
module_exit(beep_dev_exit);

MODULE_LICENSE("GPL");

2) 用source insight软件打开beep_drv.c:

搜索platform_driver 找到有platform_driver 类型定义的变量,这里我使用的是88pm8607.c参考此文件来编写自己的驱动,打开此文件并找到以下内容并复制到beep_drv.c文件中:

static int __devinit pm8607_regulator_probe(struct platform_device *pdev)
{
    struct pm860x_chip *chip = dev_get_drvdata(pdev->dev.parent);
    struct pm8607_regulator_info *info = NULL;
    struct regulator_init_data *pdata = pdev->dev.platform_data;
    struct resource *res;
    int i;

res = platform_get_resource(pdev, IORESOURCE_IO, 0);
    if (res == NULL) {
        dev_err(&pdev->dev, "No I/O resource!\n");
        return -EINVAL;
    }
    for (i = 0; i < ARRAY_SIZE(pm8607_regulator_info); i++) {
        info = &pm8607_regulator_info[i];
        if (info->desc.id == res->start)
            break;
    }
    if ((i < 0) || (i > PM8607_ID_RG_MAX)) {
        dev_err(&pdev->dev, "Failed to find regulator %llu\n",
            (unsigned long long)res->start);
        return -EINVAL;
    }
    info->i2c = (chip->id == CHIP_PM8607) ? chip->client : chip->companion;
    info->chip = chip;

/* check DVC ramp slope double */
    if ((i == PM8607_ID_BUCK3) && info->chip->buck3_double)
        info->slope_double = 1;

/* replace driver_data with info */
    info->regulator = regulator_register(&info->desc, &pdev->dev,
                         pdata, info);
    if (IS_ERR(info->regulator)) {
        dev_err(&pdev->dev, "failed to register regulator %s\n",
            info->desc.name);
        return PTR_ERR(info->regulator);
    }

platform_set_drvdata(pdev, info);
    return 0;
}

static int __devexit pm8607_regulator_remove(struct platform_device *pdev)
{
    struct pm8607_regulator_info *info = platform_get_drvdata(pdev);

platform_set_drvdata(pdev, NULL);
    regulator_unregister(info->regulator);
    return 0;
}

static struct platform_driver pm8607_regulator_driver = {
    .driver        = {
        .name    = "88pm860x-regulator",
        .owner    = THIS_MODULE,
    },
    .probe        = pm8607_regulator_probe,
    .remove        = __devexit_p(pm8607_regulator_remove),
};

beep_drv.c完整代码:

  #include <linux/module.h>

#include <linux/init.h>
#include <linux/fs.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/sched.h>
#include <linux/pm.h>
#include <linux/slab.h>
#include <linux/sysctl.h>
#include <linux/proc_fs.h>
#include <linux/delay.h>
#include <linux/platform_device.h>
#include <linux/input.h>
#include <linux/uaccess.h>

#include <asm/io.h>

static int major;

static struct class *cls;  //可加可不加,作用: 系统自动帮我们创建设备节点
static volatile unsigned long *GPIOCON;
static volatile unsigned long *GPIODAT;
static int pin;

static int beep_open(struct inode *inode, struct file *file)
{
    /* 配制为输出*/
    *GPIOCON &= ~(0xf<<(pin*4));
    *GPIOCON |= (0x1<<(pin*4));
    return 0;
}

static ssize_t beep_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos)
{
    int val;
    copy_from_user(&val, buf, count);
    printk("beep_write: val:%d, pin:%d\n", val, pin);
    //val = 0;
    if (val == 1) {
        //off beep
        *GPIODAT &= ~(1<<pin);
    }else {
        //on beep
        *GPIODAT |= (1<<pin);
    }
    return 0;
}

static struct file_operations beep_fops = {
    .owner = THIS_MODULE,
    .open  = beep_open,
    .write = beep_write,
};

static int beep_probe(struct platform_device *pdev)
{
    struct resource *res;
    /* 根据platform_device的资源进行ioremap*/

  /* 这里res将获取beep_dev中beep_resources*/
    res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
    GPIOCON = ioremap(res->start, res->end - res->start + 1);
    GPIODAT = GPIOCON + 1;

res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
    pin = res->start;    //获取.start 的内容
    
    /* 注册字符设备驱动程序*/
    printk("beep_probel, found beep\n");
    major = register_chrdev(0, "mini210_beep", &beep_fops);
    cls = class_create(THIS_MODULE, "mini210_beep");  //
    device_create(cls, NULL, MKDEV(major, 0), NULL, "mini210_beep");

        /* 在开发板上建立/dev/mini210_beep 系统节点*/
    //register_chrdev_region(,unsigned count,const char * name);
    //*GPIODAT = 1;
    return 0;
}

static int beep_remove(struct platform_device *pdev)
{
    /*卸载字符设备驱动程序*/
    /* iounmap */
    printk("beep_remove, remove beep\n");

device_destroy(cls, MKDEV(major, 0));

class_destroy(cls);
    unregister_chrdev(major, "mini210_beep");
    iounmap(GPIOCON);
    
    return 0;
}

static struct platform_driver beep_drv = {
    .probe        = beep_probe,
    .remove        = __devexit_p(beep_remove),
    .driver        = {
        .name    = "mini210_beep",   //用来与beep_dev文件中:.name来匹配;因为bus是使          // 用.name搜索并匹配,才能对应。
        .owner    = THIS_MODULE,
/*#ifdef CONFIG_PM
        .pm    = &gpio_keys_pm_ops,
#endif*/
    }
};

static int beep_drv_init(void)
{
    platform_driver_register(&beep_drv);
    return 0;
}

static void beep_drv_exit(void)
{
    platform_driver_unregister(&beep_drv);    
}

module_init(beep_drv_init);
module_exit(beep_drv_exit);

MODULE_LICENSE("GPL");

S5PV210之beep-bus模型 linux3.0.8驱动的更多相关文章

  1. (转)S5pv210 HDMI 接口在 Linux 3.0.8 驱动框架解析 (By liukun321 咕唧咕唧)

    作者:liukun321 咕唧咕唧 日期:2014.1.18 转载请标明作者.出处:http://blog.csdn.net/liukun321/article/details/18452663 本文 ...

  2. S5pv210 HDMI 接口在 Linux 3.0.8 驱动框架解析

    作者:liukun321 咕唧咕唧 日期:2014.1.18 转载请标明作者.出处:http://blog.csdn.net/liukun321/article/details/18452663 本文 ...

  3. S5PV210之GPIO模拟I2c时序之pcf8591与at24xx linux3.0.8驱动

    目录:一. 说明 二. 驱动程序说明及问题 三. 案例一       四. 案例二 一. 说明 mini210开发板上带了at24c08, 看了linux内核自带的at24.c的驱动程序,编译下载到看 ...

  4. S5PV210之添加缺少的-内核提供的'.h'文件 linux3.0.8驱动

    怎样解决编译时出现内核提供的函数或变量没有定义,使用source insight搜索功能找到声明的头文件,然后包含该头件就行了: 比如: error: implicit declaration of ...

  5. linux-3.0下input_dev模型按键驱动

    该代码在FL2440开发板上测试通过,为方便教学,将驱动中的platform_device和platform_driver故意分为两个驱动模块. [guowenxue@centos6 input_kb ...

  6. Linux内核源码分析--内核启动之(6)Image内核启动(do_basic_setup函数)(Linux-3.0 ARMv7)【转】

    原文地址:Linux内核源码分析--内核启动之(6)Image内核启动(do_basic_setup函数)(Linux-3.0 ARMv7) 作者:tekkamanninja 转自:http://bl ...

  7. linux-3.0内核移植到fl2440开发板(以MINI2440为模板)

    我们的fl2440开发板使用的是s3c2440的芯片,与MINI2440十分相似,因此需要改动的地方不多,移植也比较容易. 1.[weishusheng@localhost kernel]$ sudo ...

  8. Fixflow引擎解析(二)(模型) - BPMN2.0读写

    Fixflow引擎解析(四)(模型) - 通过EMF扩展BPMN2.0元素 Fixflow引擎解析(三)(模型) - 创建EMF模型来读写XML文件 Fixflow引擎解析(二)(模型) - BPMN ...

  9. Linux内核源码分析--内核启动之(3)Image内核启动(C语言部分)(Linux-3.0 ARMv7)

    http://blog.chinaunix.net/uid-20543672-id-3157283.html Linux内核源码分析--内核启动之(3)Image内核启动(C语言部分)(Linux-3 ...

随机推荐

  1. centos7 修改selinux 开机导致 faild to load SELinux policy freezing 错误

    centos7 修改selinux 开机导致 faild to load SELinux policy  freezing 错误 之前把selinux关闭了,这次想打开selinux,于是修改了 /e ...

  2. dede会员指定栏目发布文章

    后台——核心——网站栏目管理——修改栏目——常规选项——支持投稿

  3. OneProxy wiki上线了

    文档的敏捷开发方式,希望把文档做好. http://www.onexsoft.com/dokuwiki/doku.php?id=oneproxy

  4. 使用分布式数据库集群做大数据分析之OneProxy

    一.十亿数据,轻松秒出 实时监控领域有两个显著的特点,一是数据来源很多而且数据量大,有来自监控摄像头.GPS.智能设备等:二是需要实时处理.我们的客户在做实时处理时,就遇到这样的问题.客户的某个数据表 ...

  5. oneproxy---为实战而生之安装篇

       OneProxy是一款数据库中间件,与目前市面上的TDDL.MySQL-Proxy属于同类型产品.我们坚持研发OneProxy是基于如下几点考虑:       1. 我们不想被某一种开发语言绑定 ...

  6. worker中加载本地文件报错的解决方案

    如果在一个swf的主线程中加载文件时,报安全沙箱的错误, 网上有诸多的解决方案.但是如果在一个worker中加载本地文件报类似如下的错误: *** 安全沙箱冲突 *** SecurityError: ...

  7. 【bzoj3160】【xsy1726】万径人踪灭

    [bzoj3160]万径人踪灭 题意 给定一个由'a'和'b'构成的字符串,求不连续回文子序列的个数. \(n\leq 100000\) 分析 还是蛮不错的. 这道题基本上是自己想到的. 除了没有利用 ...

  8. BeautifulSoup 常用方法

    #输出所得标签的‘’属性值 获取 head里面的第一个meta的content值 soup.head.meta['content'] 获取第一个span的内容 soup.span.string 获取第 ...

  9. Loadrunner基础:Loadrunner Controller基本概念和使用

    Loadrnner Controller 介绍 当Vuser脚本开发完成以后,可以使用Controller将这个执行脚本的用户从单用户转化为多用户,从而模拟大量用户的操作,形成负载(多用户单循环,多用 ...

  10. 错误 undefined reference to __cxa_guard_acquire/release

    用gcc编译 c++ 程序时,出现错误 undefined reference to __cxa_guard_acquire linker error, 但是用icc可以正常编译, 问题出在stati ...