泰安市网站建设公司广告发布平台
上一篇中,我们分析了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_devicepdev->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->idif (pdev->id != -1)dev_set_name(&pdev->dev, "%s.%d", pdev->name, pdev->id);elsedev_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_pdatareturn 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进行赋值。