S5PV210之beep-bus模型 linux3.0.8驱动
目录: 一. 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驱动的更多相关文章
- (转)S5pv210 HDMI 接口在 Linux 3.0.8 驱动框架解析 (By liukun321 咕唧咕唧)
作者:liukun321 咕唧咕唧 日期:2014.1.18 转载请标明作者.出处:http://blog.csdn.net/liukun321/article/details/18452663 本文 ...
- S5pv210 HDMI 接口在 Linux 3.0.8 驱动框架解析
作者:liukun321 咕唧咕唧 日期:2014.1.18 转载请标明作者.出处:http://blog.csdn.net/liukun321/article/details/18452663 本文 ...
- S5PV210之GPIO模拟I2c时序之pcf8591与at24xx linux3.0.8驱动
目录:一. 说明 二. 驱动程序说明及问题 三. 案例一 四. 案例二 一. 说明 mini210开发板上带了at24c08, 看了linux内核自带的at24.c的驱动程序,编译下载到看 ...
- S5PV210之添加缺少的-内核提供的'.h'文件 linux3.0.8驱动
怎样解决编译时出现内核提供的函数或变量没有定义,使用source insight搜索功能找到声明的头文件,然后包含该头件就行了: 比如: error: implicit declaration of ...
- linux-3.0下input_dev模型按键驱动
该代码在FL2440开发板上测试通过,为方便教学,将驱动中的platform_device和platform_driver故意分为两个驱动模块. [guowenxue@centos6 input_kb ...
- Linux内核源码分析--内核启动之(6)Image内核启动(do_basic_setup函数)(Linux-3.0 ARMv7)【转】
原文地址:Linux内核源码分析--内核启动之(6)Image内核启动(do_basic_setup函数)(Linux-3.0 ARMv7) 作者:tekkamanninja 转自:http://bl ...
- linux-3.0内核移植到fl2440开发板(以MINI2440为模板)
我们的fl2440开发板使用的是s3c2440的芯片,与MINI2440十分相似,因此需要改动的地方不多,移植也比较容易. 1.[weishusheng@localhost kernel]$ sudo ...
- Fixflow引擎解析(二)(模型) - BPMN2.0读写
Fixflow引擎解析(四)(模型) - 通过EMF扩展BPMN2.0元素 Fixflow引擎解析(三)(模型) - 创建EMF模型来读写XML文件 Fixflow引擎解析(二)(模型) - BPMN ...
- Linux内核源码分析--内核启动之(3)Image内核启动(C语言部分)(Linux-3.0 ARMv7)
http://blog.chinaunix.net/uid-20543672-id-3157283.html Linux内核源码分析--内核启动之(3)Image内核启动(C语言部分)(Linux-3 ...
随机推荐
- 数据存储之SQLite
SQLite是目前主流的嵌入式关系型数据库,其最主要的特点就是轻量级.跨平台,当前很多嵌入式操作系统都将其作为数据库首选.虽然SQLite是一款轻型数据库,但是其功能也绝不亚于很多大型关系数据库.学习 ...
- RT-thread学习笔记(一)
我的基础:能在现有C程序下做些修改,不会移植,不会写驱动,很难从头到尾自己写程序. RT-thread基础:之前看了一点rtthread_manual.zh.pdf(即RT-thread使用手册),发 ...
- Sun Grid Engine (SGE)大型集群作业调度系统
Oracle Grid Engine 作业调度系统的简介(目前为止我用过PBS和SGE) SGE作业调度系统学习笔记 SGE作业调度 USE of Sun Grid Engine(SGE) 待续~
- [转] Android OkHttp完全解析 是时候来了解OkHttp了
http://blog.csdn.net/lmj623565791/article/details/47911083: 本文出自:[张鸿洋的博客] 一.概述 最近在群里听到各种讨论okhttp的话题, ...
- 如何设计一个RPC系统
版权声明:本文由韩伟原创文章,转载请注明出处: 文章原文链接:https://www.qcloud.com/community/article/162 来源:腾云阁 https://www.qclou ...
- sublime2配置python环境
只需要在以下文件写入python编译器的路径: 在工具栏点击Preferences,打开Browse Packages.在打开的文件夹中找到Python,并打开这个文件夹.找到文件Python.sub ...
- @ControllerAdvice
@ControllerAdvice,是spring3.2提供的新注解,从名字上可以看出大体意思是控制器增强.让我们先看看@ControllerAdvice的实现: @Target(ElementTyp ...
- 006-Selenium简介
1.产生背景 Selenium工具诞生的时间已经超过了10年,目前已经在软件开发公司中得到大规模的应用.2004年,在ThoughtWorks公司,一个名为Jason Huggins的测试同行为了减少 ...
- 从Oracle迁移到Mysql之前必须知道的50件事
1. 对子查询的优化表现不佳. 2. 对复杂查询的处理较弱 3. 查询优化器不够成熟 4. 性能优化工具与度量信息不足 5. 审计功能相对较弱 6. 安全功能不成熟,甚至可以说很粗糙.没有用户组与角色 ...
- 在excel单元格中提取信息
平时在excel中处理数据的时候,肯定会遇到在单元格提取信息的情况,比如在地址中提取省.市.地区等,如果数据源内容规整的话,可以直接使用left().right().mid()等函数直接提取,但是大多 ...