上一篇中,我们分析了request_mem_region的实现。
现在来看看board文件中是如何配置ssi和esai的。
现在做的项目是基于freescale平台的。
所以代码也是基于该平台代码进行分析。
先看看ssi。
首先定义了一个mxc_audio_platform_data结构体和一个platform_device结构体:
static struct mxc_audio_platform_data XXXX_data[] = {
{
.ssi_num = 1,
.src_port = 2,
.ext_port = 5,
.init = xxxx_init0,
.hp_gpio = -1,
},
};
static struct platform_device xxxx_device = {
.name = "xxxx",
};
/*
* This struct is to define the number of SSIs on a platform,
* DAM source port config, DAM external port config,
* regulator names, and other stuff audio needs.
*/
struct mxc_audio_platform_data {
int ssi_num;
int src_port;
int ext_port;
int intr_id_hp;
int ext_ram;
struct clk *ssi_clk[2];
int hp_gpio;
int hp_active_low; /* headphone irq is active low */
int mic_gpio;
int mic_active_low; /* micphone irq is active low */
int sysclk;
const char *codec_name;
int (*init) (void); /* board specific init */
int (*amp_enable) (int enable);
int (*clock_enable) (int enable);
int (*finit) (void); /* board specific finit */
void *priv; /* used by board specific functions */
};
struct platform_device {
const char * name;
int id;
struct device dev;
u32 num_resources;
struct resource * resource;
const struct platform_device_id *id_entry;
/* MFD cell pointer */
struct mfd_cell *mfd_cell;
/* arch specific additions */
struct pdev_archdata archdata;
};
然后调用mxc_register_device将上面定义的两个结构体进行注册。
mxc_register_device的实现:
int __init mxc_register_device(struct platform_device *pdev, void *data)
{
int ret;
// data即是前面的XXXX_data。pdev即是前面的xxxx_device
pdev->dev.platform_data = data;
/×
/**
* platform_device_register - add a platform-level device
* @pdev: platform device we're adding
*/
int platform_device_register(struct platform_device *pdev)
{
device_initialize(&pdev->dev);
return platform_device_add(pdev);
}
/**
* device_initialize - init device structure.
* @dev: device.
*
* This prepares the device for use by other layers by initializing
* its fields.
* It is the first half of device_register(), if called by
* that function, though it can also be called separately, so one
* may use @dev's fields. In particular, get_device()/put_device()
* may be used for reference counting of @dev after calling this
* function.
*
* NOTE: Use put_device() to give up your reference instead of freeing
* @dev directly once you have called this function.
*/
void device_initialize(struct device *dev)
{
dev->kobj.kset = devices_kset;
kobject_init(&dev->kobj, &device_ktype);
INIT_LIST_HEAD(&dev->dma_pools);
mutex_init(&dev->mutex);
lockdep_set_novalidate_class(&dev->mutex);
spin_lock_init(&dev->devres_lock);
INIT_LIST_HEAD(&dev->devres_head);
// device_pm_init - Initialize the PM-related part of a device object.
device_pm_init(dev);
set_dev_node(dev, -1);
}
static inline void set_dev_node(struct device *dev, int node)
{
dev->numa_node = node;
}
/**
* platform_device_add - add a platform device to device hierarchy
* @pdev: platform device we're adding
*
* This is part 2 of platform_device_register(), though may be called
* separately _iff_ pdev was allocated by platform_device_alloc().
*/
int platform_device_add(struct platform_device *pdev)
{
int i, ret = 0;
if (!pdev)
return -EINVAL;
if (!pdev->dev.parent)
pdev->dev.parent = &platform_bus;
pdev->dev.bus = &platform_bus_type;
// 前面只指定了pdev->name没有指定pdev->id
if (pdev->id != -1)
dev_set_name(&pdev->dev, "%s.%d", pdev->name, pdev->id);
else
dev_set_name(&pdev->dev, "%s", pdev->name);
for (i = 0; i < pdev->num_resources; i++) {
struct resource *p, *r = &pdev->resource[i];
if (r->name == NULL)
r->name = dev_name(&pdev->dev);
// 上一篇中,已经分析过resource的父子关系
p = r->parent;
if (!p) {
if (resource_type(r) == IORESOURCE_MEM)
p = &iomem_resource;
else if (resource_type(r) == IORESOURCE_IO)
p = &ioport_resource;
}
// 将resource添加到resource tree中。
/×
/**
* insert_resource - Inserts a resource in the resource tree
* @parent: parent of the new resource
* @new: new resource to insert
*
* Returns 0 on success, -EBUSY if the resource can't be inserted.
*/
int insert_resource(struct resource *parent, struct resource *new)
{
struct resource *conflict;
/×
/**
* insert_resource_conflict - Inserts resource in the resource tree
* @parent: parent of the new resource
* @new: new resource to insert
*
* Returns 0 on success, conflict resource if the resource can't be inserted.
*
* This function is equivalent to request_resource_conflict when no conflict
* happens. If a conflict happens, and the conflicting resources
* entirely fit within the range of the new resource, then the new
* resource is inserted and the conflicting resources become children of
* the new resource.
*/
struct resource *insert_resource_conflict(struct resource *parent, struct resource *new)
{
struct resource *conflict;
write_lock(&resource_lock);
conflict = __insert_resource(parent, new);
write_unlock(&resource_lock);
return conflict;
}
×/
conflict = insert_resource_conflict(parent, new);
return conflict ? -EBUSY : 0;
}
×/
if (p && insert_resource(p, r)) {
printk(KERN_ERR
"%s: failed to claim resource %d\n",
dev_name(&pdev->dev), i);
ret = -EBUSY;
goto failed;
}
}
pr_debug("Registering platform device '%s'. Parent at %s\n",
dev_name(&pdev->dev), dev_name(pdev->dev.parent));
ret = device_add(&pdev->dev);
if (ret == 0)
return ret;
failed:
while (--i >= 0) {
struct resource *r = &pdev->resource[i];
unsigned long type = resource_type(r);
if (type == IORESOURCE_MEM || type == IORESOURCE_IO)
release_resource(r);
}
return ret;
}
×/
ret = platform_device_register(pdev);
if (ret)
pr_debug("Unable to register platform device '%s': %d\n",
pdev->name, ret);
return ret;
}
接下来定义了imx_add_platform_device结构体:
static struct imx_ssi_platform_data xxx_ssi0_pdata = {
.flags = IMX_SSI_DMA | IMX_SSI_SYN,
};
然后调用imx6q_add_imx_ssi进行注册:
imx6q_add_imx_ssi(0, &xxx_ssi0_pdata);
imx6q_add_imx_ssi的实现:
#define imx6q_add_imx_ssi(id, pdata) \ imx_add_imx_ssi(&imx6_imx_ssi_data[id], pdata)
其中imx6_imx_ssi_data的定义:
const struct imx_imx_ssi_data imx6_imx_ssi_data[] __initconst = {
#define imx6q_imx_ssi_data_entry(_id, _hwid) \
imx_imx_ssi_data_entry(MX6Q, _id, _hwid, SZ_4K)
imx6q_imx_ssi_data_entry(0, 1),
imx6q_imx_ssi_data_entry(1, 2),
imx6q_imx_ssi_data_entry(2, 3),
};
#define imx_imx_ssi_data_entry(soc, _id, _hwid, _size) \
[_id] = { \
.id = _id, \
.iobase = soc ## _SSI ## _hwid ## _BASE_ADDR, \
.iosize = _size, \
.irq = soc ## _INT_SSI ## _hwid, \
.dmatx0 = soc ## _DMA_REQ_SSI ## _hwid ## _TX0, \
.dmarx0 = soc ## _DMA_REQ_SSI ## _hwid ## _RX0, \
.dmatx1 = soc ## _DMA_REQ_SSI ## _hwid ## _TX1, \
.dmarx1 = soc ## _DMA_REQ_SSI ## _hwid ## _RX1, \
}
soc ## _SSI ## _hwid ## _BASE_ADDR拼出来其实是:
MX6Q_SSI1_BASE_ADDR
MX6Q_SSI2_BASE_ADDR
MX6Q_SSI3_BASE_ADDR
看看它们的定义:
#define MX6Q_SSI1_BASE_ADDR (ATZ1_BASE_ADDR + 0x28000) /* slot 10 */ #define MX6Q_SSI2_BASE_ADDR (ATZ1_BASE_ADDR + 0x2C000) /* slot 11 */ #define MX6Q_SSI3_BASE_ADDR (ATZ1_BASE_ADDR + 0x30000) /* slot 12 */
与data sheet中一致。
再看imx_add_imx_ssi的实现:
struct platform_device *__init imx_add_imx_ssi(
const struct imx_imx_ssi_data *data,
const struct imx_ssi_platform_data *pdata)
{
struct resource res[] = {
{
.start = data->iobase,
.end = data->iobase + data->iosize - 1,
.flags = IORESOURCE_MEM,
}, {
.start = data->irq,
.end = data->irq,
.flags = IORESOURCE_IRQ,
},
#define DMARES(_name) { \
.name = #_name, \
.start = data->dma ## _name, \
.end = data->dma ## _name, \
.flags = IORESOURCE_DMA, \
}
DMARES(tx0),
DMARES(rx0),
DMARES(tx1),
DMARES(rx1),
};
// data->id是0.res就是前面定义的。pdata就是xxx_ssi0_pdata
return imx_add_platform_device("imx-ssi", data->id,
res, ARRAY_SIZE(res),
pdata, sizeof(*pdata));
}
static inline struct platform_device *imx_add_platform_device(
const char *name, int id,
const struct resource *res, unsigned int num_resources,
const void *data, size_t size_data)
{
return imx_add_platform_device_dmamask(
name, id, res, num_resources, data, size_data, 0);
}
struct platform_device *__init imx_add_platform_device_dmamask(
const char *name, int id,
const struct resource *res, unsigned int num_resources,
const void *data, size_t size_data, u64 dmamask)
{
int ret = -ENOMEM;
struct platform_device *pdev;
/**
* platform_device_alloc - create a platform device
* @name: base name of the device we're adding
* @id: instance id
*
* Create a platform device object which can have other objects attached
* to it, and which will have attached objects freed when it is released.
*/
pdev = platform_device_alloc(name, id);
if (!pdev)
goto err;
if (dmamask) {
/*
* This memory isn't freed when the device is put,
* I don't have a nice idea for that though. Conceptually
* dma_mask in struct device should not be a pointer.
* See http://thread.gmane.org/gmane.linux.kernel.pci/9081
*/
pdev->dev.dma_mask =
kmalloc(sizeof(*pdev->dev.dma_mask), GFP_KERNEL);
if (!pdev->dev.dma_mask)
/* ret is still -ENOMEM; */
goto err;
*pdev->dev.dma_mask = dmamask;
pdev->dev.coherent_dma_mask = dmamask;
}
/×
/**
* platform_device_add_resources - add resources to a platform device
* @pdev: platform device allocated by platform_device_alloc to add resources to
* @res: set of resources that needs to be allocated for the device
* @num: number of resources
*
* Add a copy of the resources to the platform device. The memory
* associated with the resources will be freed when the platform device is
* released.
*/
int platform_device_add_resources(struct platform_device *pdev,
const struct resource *res, unsigned int num)
{
struct resource *r = NULL;
if (res) {
r = kmemdup(res, sizeof(struct resource) * num, GFP_KERNEL);
if (!r)
return -ENOMEM;
}
kfree(pdev->resource);
pdev->resource = r;
pdev->num_resources = num;
return 0;
}
×/
if (res) {
// 此处add的resource在ssi的probe函数中调用platform_get_resource可以获取。
// platform_get_resource(pdev, IORESOURCE_MEM, 0)
ret = platform_device_add_resources(pdev, res, num_resources);
if (ret)
goto err;
}
/*
/**
* platform_device_add_data - add platform-specific data to a platform device
* @pdev: platform device allocated by platform_device_alloc to add resources to
* @data: platform specific data for this platform device
* @size: size of platform specific data
*
* Add a copy of platform specific data to the platform device's
* platform_data pointer. The memory associated with the platform data
* will be freed when the platform device is released.
*/
int platform_device_add_data(struct platform_device *pdev, const void *data,
size_t size)
{
void *d = NULL;
if (data) {
d = kmemdup(data, size, GFP_KERNEL);
if (!d)
return -ENOMEM;
}
kfree(pdev->dev.platform_data);
pdev->dev.platform_data = d;
return 0;
}
*/
if (data) {
ret = platform_device_add_data(pdev, data, size_data);
if (ret)
goto err;
}
ret = platform_device_add(pdev);
if (ret) {
err:
if (dmamask)
kfree(pdev->dev.dma_mask);
platform_device_put(pdev);
return ERR_PTR(ret);
}
return pdev;
}
从上面的代码看,imx6_imx_ssi_data只有3个成员。
当调用
imx6q_add_imx_ssi(3, &mx6_smartauto_ssi3_pdata);
时,访问了imx6_imx_ssi_data[3],超出了数组的界限。
难道刚好esai的data数组刚好在ssi的后面,所以imx6_imx_ssi_data[3]其实访问的是esai的数组?
但是为什么probe中打印出来的resource name是ssi-0呢?
看了下前面data数组的定义,其中没有name相关的内容。
再看res数组的定义,也没有name。
所以imx6_imx_ssi_data[3]访问了esai的data数组,但是data数组中并没有name信息,所以name还为ssi-0。
这个name从哪儿来的呢?
又看了一遍代码,也没发现哪儿对resource name进行赋值。
listview_item.xml如下:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content" >
<RelativeLayout
android:id="@+id/coupon_item_relativeLayout"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="20dip"
android:layout_marginRight="20dip"
android:layout_marginTop="15dip"
android:background="@android:color/black" >
<RelativeLayout
android:id="@+id/coupon_item_thumb_rl"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_marginLeft="10dip" >
<ProgressBar
android:id="@+id/coupon_item_progressBar"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true" />
<ImageView
android:id="@+id/coupon_item_thumb"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:scaleType="centerCrop"
android:src="/blog_article/@drawable/ic_launcher/index.html" />
</RelativeLayout>
<RelativeLayout
android:id="@+id/coupon_item_content_rl"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_marginRight="25dip"
android:layout_marginTop="5dip"
android:layout_toRightOf="@id/coupon_item_thumb_rl"
android:layout_marginLeft="10dip"
>
<TextView
android:id="@+id/coupon_item_couponLimit"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="couponLimitcouponLimit"
android:textSize="10sp" >
</TextView>
<TextView
android:id="@+id/coupon_item_description"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="10dip"
android:maxLines="4"
android:text="descriptiondescriptiondescriptiondescription"
android:textSize="20sp" >
</TextView>
</RelativeLayout>
<ImageView
android:id="@+id/coupon_item_arrow"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_centerVertical="true"
android:layout_marginRight="10dip"
android:scaleType="fitEnd"
android:src="/blog_article/@drawable/arrow/index.html" />
<RelativeLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignRight="@id/coupon_item_arrow"
android:layout_alignParentBottom="true"
android:layout_below="@id/coupon_item_content_rl"
>
<TextView
android:id="@+id/coupon_item_date"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="2013/03/01" />
</RelativeLayout>
</RelativeLayout>
</RelativeLayout>
效果图如下:
上传源码时最好把空格行去掉,以前介绍了使用notepad++,现在发现,习惯用source insight的人士也可以很easy的去掉了:
Options->Perferences->Files-> Remove extra white space when saving。保存时自动去除每行尾部的空格和tab。
以下是另一个兄弟的心得:
http://blog.csdn.net/ison81/article/details/3510043
用si有好几年了,零零散散也累积了不少心得,但总觉得还有一些内容是不知道的,所以今天干脆来个大清扫,把所有的选项都研究一遍,并把自认为有用的内容在这里整理一下。
si的主要配置都在Options->Perferences菜单里,
1、General
Project File Synchronization->Remove missing file from project选上可以避免因文件找不到而弹出错误对话框。
把Misc->Use stricter confirmation dialog选项去掉可以使确认时不输入"yes"。
2、Typing
Source Editing->Indent commands affect #-preprocessor statements。去掉后(默认值),进行多行缩进时不会影响预处理语句(如#if...#endif)。
Auto Completion->Use detailed completion window,选上后,联想时可以出现该函数的详细信息。见下图:
(简单)
(详细)
Auto Completion->Insert paremeters for functions,去掉后,自动联想不会把整个参数都输出到当前行。
Browsing in Lists->Match syllables while typing(slower)。在symbol list框检索符号时是否采用音节匹配方式,如对于函数FindNext,输入find或者next都可以找到该函数。该功能可能导致反应缓慢(视工程和机器配置而定),建议关闭,因为即使在关闭状态下也可以通过先输入空格再输入单词来动态启用该功能。
注意Browsing in Lists里其实有两个功能,但一般我们只能看到Match syllables while typing这一条,应该是si的菜单设计没有做好,导致在中文windows下不能显示全,另一个功能是Match members while typing,用于打开/关闭按成员变量名来检索类/结构体的功能。
3、Files
Opening Files->Sharing: Let other programs modify files,以共享方式打开文件,这个很重要,保证可以在其它编辑中同时编辑该文件。典型的场景就是用ide环境去动态编译调试,而用si静态阅读。
Customize 'Open' Command...,用于设置Ctrl+O打开的页面,默认选项是 Project File list view in Project Window,建议保持默认。
Saving Files->Preserve Undo data and revision marks after saving,如果发现保存后就不能undo了,请检查该选项是否选中。
Remove extra white space when saving。保存时自动去除每行尾部的空格和tab。建议选中。
4、Languages
自定义其它编程语言的语法解析,这个...还是另写一篇来讲吧。
Conditional Parsing不要错过了,这里的Conditions功能实在让人喜欢。Conditions是什么意思呢?我们的代码中一般都会有一些开关宏,通过在Conditions中配置这些宏的默认值,可以让si把配置为不开启的宏视为无效代码,从而不进行符号检索。
如果源代码中的开关宏太多,还可以使用Condition Parsing中的Scan Files来自动找出所有开关宏。
5、Symbol Lookups
没太多特别的。
6、Display
显示配置和个人喜好和显示器的状态有关,偶用的x60小本,屏幕资源有限,所以在Display Elements里把Project Window, Status Bar, Tool Bar,Clip Window都关了,基本用快捷键可以代替它们。
Options->Horizontal scroll bars for each new window。很多大师都教导我们说一行不要写太多代码。在这个指导思想下,我们不需要这个东东。
Show exact case of file names。如果看不惯si把所有的文件名首字母都大写就勾上这个选项吧。
Tile source and destination windows for Source Link commands。Source Link很多时候用于外部命令输出结果的解析(如Make, lint),这个功能会把解析结果与目标窗口自动tile,很实用。
Trim long path names with ellipses。这个建议不要选中。事实上这个主要影响标题栏,但一般来说标题栏上的空间是充裕的,选上之后往往会令我们不知道所编辑文件的具体位置。
7、Color
这个不用多说了。自己怎么喜欢怎么配吧。
8、Syntax Formatting
如果让大家说出喜欢si的几个理由,我想语法着色一定会是其中之一。
Basics->Use only color formatting。只启用style中关于颜色的设置。其它如粗体、斜体、阴影等都不启用。
Apply Styles for Lanugage Elements。把分类启用style,都选上吧。
Symbol Reference Lookups->Qualify references to members。检测成员的有效性,如果不是类/结构体中的一部分,则不启用style。虽然可能导致性能降低,但还是建议打开。同样Qualify references to functions也是。
这里有个按钮可以进入Doc Types页面(Options菜单也可以进入),里面有很多重要选项:
Editing Options中,
Expand tabs, Visible tabs可以帮助我们发现并转换tab。
Show right margint和Margin width可以提醒我们是否把一行写得太长。
Symbol Window选项建议关闭(因为有快捷键)。
Auto Indent对话框中,
如果没有特别喜好,建议把Smart Indent Options的两个勾都去掉。同时Auto Indent Type选Smart。
9、Syntax Decorations
可以把一些符号转换成特殊形式显示,如->转换成→。如果要使用该功能,不能开启Syntax Formatting->Basics->Use only color formatting。
Auto annotations下的三个功能都比较有用,
Show arrows at goto statements可以在goto时显示一个向上或向下的箭头,表示是向上goto还是向下goto。不过我们还是尽量不要用goto了。
Annotate closing braces with end-statement。在"}"后显示标识,表示该"}"与哪个if/switch配对。而下面的Annotate closing braces only for long blocks则是一个补充选项,表示只在较长的语句块时才显示标识。
10、Searching
没什么特别的,注意Automatically load selection into Find pattern。
11、Remote
与远程登录相关的一些选项。可以提高远程使用的显示性能。
12、Folders
没什么特别的。
最后简单说下si的配置文件。可以通过Options->Load Configuration/Save Configuration来导入/导出配置,可以导出全部,也可以导出某几个部分(如style)。si的配置有两级,一是全局配置,一是项目配置。出入方便考虑,统一一个配置就好了,在创建项目时选择用全局配置(默认值)。
导入配置也可以通过双击配置文件来完成。