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 ...
随机推荐
- centos7 修改selinux 开机导致 faild to load SELinux policy freezing 错误
centos7 修改selinux 开机导致 faild to load SELinux policy freezing 错误 之前把selinux关闭了,这次想打开selinux,于是修改了 /e ...
- dede会员指定栏目发布文章
后台——核心——网站栏目管理——修改栏目——常规选项——支持投稿
- OneProxy wiki上线了
文档的敏捷开发方式,希望把文档做好. http://www.onexsoft.com/dokuwiki/doku.php?id=oneproxy
- 使用分布式数据库集群做大数据分析之OneProxy
一.十亿数据,轻松秒出 实时监控领域有两个显著的特点,一是数据来源很多而且数据量大,有来自监控摄像头.GPS.智能设备等:二是需要实时处理.我们的客户在做实时处理时,就遇到这样的问题.客户的某个数据表 ...
- oneproxy---为实战而生之安装篇
OneProxy是一款数据库中间件,与目前市面上的TDDL.MySQL-Proxy属于同类型产品.我们坚持研发OneProxy是基于如下几点考虑: 1. 我们不想被某一种开发语言绑定 ...
- worker中加载本地文件报错的解决方案
如果在一个swf的主线程中加载文件时,报安全沙箱的错误, 网上有诸多的解决方案.但是如果在一个worker中加载本地文件报类似如下的错误: *** 安全沙箱冲突 *** SecurityError: ...
- 【bzoj3160】【xsy1726】万径人踪灭
[bzoj3160]万径人踪灭 题意 给定一个由'a'和'b'构成的字符串,求不连续回文子序列的个数. \(n\leq 100000\) 分析 还是蛮不错的. 这道题基本上是自己想到的. 除了没有利用 ...
- BeautifulSoup 常用方法
#输出所得标签的‘’属性值 获取 head里面的第一个meta的content值 soup.head.meta['content'] 获取第一个span的内容 soup.span.string 获取第 ...
- Loadrunner基础:Loadrunner Controller基本概念和使用
Loadrnner Controller 介绍 当Vuser脚本开发完成以后,可以使用Controller将这个执行脚本的用户从单用户转化为多用户,从而模拟大量用户的操作,形成负载(多用户单循环,多用 ...
- 错误 undefined reference to __cxa_guard_acquire/release
用gcc编译 c++ 程序时,出现错误 undefined reference to __cxa_guard_acquire linker error, 但是用icc可以正常编译, 问题出在stati ...