目录: 一. 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. 搭建一个简单的Struts2框架

    1  创建一个web项目. 2 导入必要的JAR文件. 放在WEB-INF下lib包里. 3 添加web.xml配置,添加启动配置. <?xml version="1.0" ...

  2. word2010表格中的内容怎么设置行距

    选中表格,然后根据箭头指示点击 弹出如下对话框,选择行距

  3. python语法笔记(一)

    1. python中多个函数或者类定义可以放在一个.py 文件中,视为一个模块.模块的.py文件中,一般要写 if __name__ == '__mian__' 用来单独执行该模块内的某些函数. 2. ...

  4. java 集合(set)

    Interface ListIterator<E> 特有的方法: hasPrevious() 判断是否存在上一个元素. previous() 当前指针先向上移动一个单位,然后再取出当前指针 ...

  5. java 异常2

    自定义异常类: import java.util.Scanner; /** * Created by lenovo on 2016/8/12. */ class NoMoneyException ex ...

  6. as的Enter_Frame与Timer

    As3中的Timer和Event.EnterFrame是有明显的区别的. Evnet.EnterFrame是定时间隔多少时间出发.如果执行时间比间隔时间长,则会间隔执行时间这么久. 举个例子: Fla ...

  7. jmeter 建立一个JMS主题测试计划

    创建两个线程组和组 每一个到10迭代. 总消息线程(6)x(1消息) (重复10次)= 60消息. 建立测试计划,您将使用 以下元素: 线程组 , JMS的出版商 , JMS用户 , 图结果 . 一般 ...

  8. 10款实用Android UI 开发框架

    1. ActionBarSherlock ActionBarSherlock是一个独立的Android设计库,可以让Android 2.x的系统也能使用ActionBar.此外,ActionBarSh ...

  9. 《javascript高级程序设计》第四章 Variables,scope,and memory

    4.1 基本类型和引用类型的值 primitive and reference values 4.1.1 动态的属性 dynamic properties 4.1.2 复制变量值 copying va ...

  10. Qt之QSystemTrayIcon

    简述 QSystemTrayIcon类为应用程序在系统托盘中提供一个图标. 现代操作系统通常在桌面上提供一个特殊的区域,称为系统托盘或通知区域,长时间运行的应用程序可以显示图标和短消息. 简述 内容 ...