小结:
1、通过文件名可以看出,这个文件是和平台有关的函数
2、声明了结构体struct platform_object,作为platform_device平台设备的载体
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
函数列表:
@@@@@ 平台资源的操作模块
struct resource *platform_get_resource(struct platform_device *dev, unsigned int type,
unsigned int num)
获取平台资源,根据资源类型和索引号,获取指定平台设备的资源
int platform_get_irq(struct platform_device *dev, unsigned int num)
获取平台设备的中断资源,实际操作是以IORESOURCE_IRQ为资源类型获取资源
struct resource *platform_get_resource_byname(struct platform_device *dev, unsigned int type, char *name)
根据平台设备的设备名获取指定类型的资源
int platform_get_irq_byname(struct platform_device *dev, char *name)
根据设备名获取平台设备的中断资源,同platform_get_irq操作
@@@@@ 平台设备的操作模块
int platform_add_devices(struct platform_device **devs, int num)
添加一组平台设备,**devs为平台设备数组,核心操作是platform_device_register
struct platform_device *platform_device_alloc(const char *name, int id)
申请平台设备platform_object,并初始化其平台设备成员,最后返回平台设备
int platform_device_add_resources(struct platform_device *pdev, struct resource *res, unsigned int num)
将资源res添加到平台设备pdev中
int platform_device_add_data(struct platform_device *pdev, const void *data, size_t size)
将平台数据data添加到平台设备pdev中(pdev->dev.platform_data)
int platform_device_add(struct platform_device *pdev)
//平台设备添加,主要操作如下:
//1、设置设备的父设备(父设备不存在则指定到平台总线上)
//2、设置平台总线的操作函数
//3、设置设备总线的ID
//4、检查资源的设置,如果没设置则设置默认值
//5、调用core.c的device_add函数添加设备
void platform_device_del(struct platform_device *pdev)
平台设备的删除,先device_del删除设备,然后释放资源
由于添加资源的时候只有MEM和IO型的资源是加进资源树中的,所以这里只释放这两种类型的资源
int platform_device_register(struct platform_device * pdev)
平台设备的注册,先执行core.c文件中的device_initialize初始化设备,然后platform_device_add
void platform_device_unregister(struct platform_device * pdev)
平台设备的反注册,实际操作是platform_device_del删除设备,然后释放(put)设备引用
struct platform_device *platform_device_register_simple(char *name, int id,
struct resource *res, unsigned int num)
//创建并注册一个平台设备,并返回新注册的设备,具体操作如下:
//1、申请一个新的平台设备并初始化
//2、添加资源到平台设备中
//3、调用platform_device_add函数添加平台设备
@@@@@ 平台的驱动操作模块
int platform_driver_register(struct platform_driver *drv)
平台驱动的注册,具体操作是将驱动的总线设置为平台总线,关联驱动的函数,最后调用driver.c中的driver_register函数对驱动进行注册
这里要关注一下平台驱动函数的调用,实际就是直接调用drv上对应的函数,所以在关联函数的时候要先判断drv->probe是否指定
void platform_driver_unregister(struct platform_driver *drv)
平台驱动的反注册,直接调用驱动的反注册
int __init_or_module platform_driver_probe(struct platform_driver *drv,
int (*probe)(struct platform_device *))
用指定的probe探测函数指定平台驱动
@@@@@
int __init platform_bus_init(void)
平台总线的初始化,系统初始化的时候自动调用,具体操作是先device_register注册平台设备platform_bus,然后在注册总线platform_bus_type
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
//根据驱动获取平台驱动结构体
#define to_platform_driver(drv) (container_of((drv), struct platform_driver, driver))
//platform_driver结构体定义的是一些函数,和设备驱动driver
//声明平台总线
struct device platform_bus = {
.bus_id = "platform",
};
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
//获取平台设备的资源
struct resource *platform_get_resource(
struct platform_device *dev, //平台设备
unsigned int type, //资源类型
unsigned int num) //资源索引
{
int i;
//根据指定的资源类型和资源索引,返回资源
for (i = 0; i < dev->num_resources; i++) {
struct resource *r = &dev->resource[i];
if ((r->flags & (IORESOURCE_IO | IORESOURCE_MEM|
IORESOURCE_IRQ |IORESOURCE_DMA)) == type)
if (num-- == 0) return r;
}
return NULL;
}
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
//获取平台资源的中断资源
int platform_get_irq(struct platform_device *dev, unsigned int num)
{
struct resource *r = platform_get_resource(dev, IORESOURCE_IRQ, num);
return r ? r->start : -ENXIO;
}
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
//根据设备名获取资源
struct resource *platform_get_resource_byname(
struct platform_device *dev, //平台设备
unsigned int type, //资源类型
char *name) //设备名
{
int i;
for (i = 0; i < dev->num_resources; i++) {
struct resource *r = &dev->resource[i];
if ((r->flags & (IORESOURCE_IO|IORESOURCE_MEM|
IORESOURCE_IRQ|IORESOURCE_DMA)) == type)
if (!strcmp(r->name, name)) return r;
}
return NULL;
}
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
//根据设备名获取中断资源
int platform_get_irq_byname(struct platform_device *dev, char *name)
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
//添加一组平台设备,**devs为平台设备数组,核心操作是平台设备的注册
int platform_add_devices(struct platform_device **devs, int num)
{
int i, ret = 0;
for (i = 0; i < num; i++) {
ret = platform_device_register(devs[i]); //平台设备注册(实现在后)
if (ret) { //注册失败,反注册之前注册的函数
while (--i >= 0) platform_device_unregister(devs[i]);
break;
}
}
return ret;
}
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
//声明结构体,该结构体是平台设备的载体
struct platform_object {
struct platform_device pdev; //平台设备
char name[1];
};
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
void platform_device_put(struct platform_device *pdev)
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
//平台设备的释放
static void platform_device_release(struct device *dev)
{
//根据设备获取平台目标结构体
struct platform_object *pa = container_of(dev, struct platform_object, pdev.dev);
kfree(pa->pdev.dev.platform_data); //释放平台设备的私有数据
kfree(pa->pdev.resource); //释放平台资源
kfree(pa);
}
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
//申请平台设备,并初始化,最后返回平台设备
struct platform_device *platform_device_alloc(const char *name, int id)
{
struct platform_object *pa;
//申请平台目标
pa = kzalloc(sizeof(struct platform_object) + strlen(name), GFP_KERNEL);
if (pa) { //设置成员变量
strcpy(pa->name, name); //复制平台目标名
pa->pdev.name = pa->name; //设置平台设备的设备名
pa->pdev.id = id; //平台设备的id号
device_initialize(&pa->pdev.dev); //平台设备的初始化
pa->pdev.dev.release = platform_device_release; //设置平台设备的释放函数
}
return pa ? &pa->pdev : NULL; //返回平台设备
}
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
//平台设备添加资源,成功返回0
int platform_device_add_resources(
struct platform_device *pdev, //平台设备
struct resource *res, //要添加的资源
unsigned int num) //资源数量
{
struct resource *r;
//申请内存
r = kmalloc(sizeof(struct resource) * num, GFP_KERNEL);
if (r) { //申请成功,复制资源
memcpy(r, res, sizeof(struct resource) * num);
pdev->resource = r;
pdev->num_resources = num;
}
return r ? 0 : -ENOMEM;
}
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
//为平台设备添加数据,操作同上,只是关联的位置是pdev->dev.platform_data
int platform_device_add_data(
struct platform_device *pdev,
const void *data,
size_t size)
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
//平台设备添加,主要操作如下:
//1、设置设备的父设备(父设备不存在则指定到平台总线上)
//2、设置平台总线的操作函数
//3、设置设备总线的ID
//4、检查资源的设置,如果没设置则设置默认值
//5、调用core.c的device_add函数添加设备
int platform_device_add(struct platform_device *pdev)
{
int i, ret = 0;
//参数为NULL,出错
if (!pdev) return -EINVAL;
//设备的父设备没设置,将父设备指定到平台总线上
if (!pdev->dev.parent) pdev->dev.parent = &platform_bus;
//设置平台总线的操作函数
pdev->dev.bus = &platform_bus_type;
//设备ID不是-1,将设备的总线ID设置为“设备名.设备ID”
//否则,总线ID为设备名
if (pdev->id != -1)
snprintf(pdev->dev.bus_id, BUS_ID_SIZE, "%s.%d", pdev->name,
pdev->id);
else
strlcpy(pdev->dev.bus_id, pdev->name, BUS_ID_SIZE);
//资源的默认设置
for (i = 0; i < pdev->num_resources; i++) {
struct resource *p, *r = &pdev->resource[i];
//资源名为空,重设资源名为总线名
if (r->name == NULL) r->name = pdev->dev.bus_id;
p = r->parent;
//资源没有指定父资源,根据资源的类型设置默认的父资源
if (!p) {
if (r->flags & IORESOURCE_MEM) //MEM资源
p = &iomem_resource;
else if (r->flags & IORESOURCE_IO) //IO资源
p = &ioport_resource;
}
//关联上了父资源,将资源插入到资源树中
//如果父资源不存在,则资源将不插入到资源树中
if (p && insert_resource(p, r)) {
ret = -EBUSY;
goto failed;
}
}
//设备的添加(core.c中实现)
ret = device_add(&pdev->dev);
if (ret == 0) return ret;
//操作失败,释放资源
failed:
while (--i >= 0)
if (pdev->resource[i].flags & (IORESOURCE_MEM|IORESOURCE_IO))
release_resource(&pdev->resource[i]);
return ret;
}
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
//平台设备的删除,先调用core.c中的device_del函数删除设备,然后再依次释放资源
void platform_device_del(struct platform_device *pdev)
{
int i;
if (pdev) {
device_del(&pdev->dev);
for (i = 0; i < pdev->num_resources; i++) {
struct resource *r = &pdev->resource[i];
if (r->flags & (IORESOURCE_MEM|IORESOURCE_IO))
release_resource(r);
}
}
}
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
//平台设备的注册,先设备初始化,然后执行平台设备的添加函数
int platform_device_register(struct platform_device * pdev)
{
device_initialize(&pdev->dev);
return platform_device_add(pdev);
}
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
//平台设备的反注册,实际操作是平台设备的删除函数,然后释放平台设备计数
void platform_device_unregister(struct platform_device * pdev)
{
platform_device_del(pdev);
platform_device_put(pdev);
}
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
//创建并注册一个平台设备,并返回新注册的设备,具体操作如下:
//1、申请一个新的平台设备并初始化
//2、添加资源到平台设备中
//3、调用platform_device_add函数添加平台设备
struct platform_device *platform_device_register_simple(
char *name, //平台设备名
int id, //平台设备的ID
struct resource *res, //平台设备资源
unsigned int num) //资源数量
{
struct platform_device *pdev;
int retval;
//申请一个新的平台设备并初始化
pdev = platform_device_alloc(name, id);
//资源存在,添加资源到平台设备中
if (num) {
retval = platform_device_add_resources(pdev, res, num);
if (retval) goto error;
}
//添加这个平台设备
retval = platform_device_add(pdev);
if (retval) goto error;
return pdev; //返回平台设备
error:
platform_device_put(pdev);
return ERR_PTR(retval);
}
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
//设备驱动的探测函数,根据输入的设备获取设备对应的驱动,并调用驱动的probe
static int platform_drv_probe(struct device *_dev)
{
struct platform_driver *drv = to_platform_driver(_dev->driver);
struct platform_device *dev = to_platform_device(_dev);
return drv->probe(dev);
}
//探测失败
static int platform_drv_probe_fail(struct device *_dev)
{
return -ENXIO;
}
//设备驱动的remove,shutdown,suspend,resume函数的调用
static int platform_drv_remove(struct device *_dev)
static void platform_drv_shutdown(struct device *_dev)
static int platform_drv_suspend(struct device *_dev, pm_message_t state)
static int platform_drv_resume(struct device *_dev)
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
//平台驱动的注册,具体操作是将驱动的总线设置为平台总线,关联驱动的函数,最后调用driver.c中的driver_register函数对驱动进行注册
//这里要关注一下平台驱动函数的调用,实际就是直接调用drv上对应的函数,所以在关联函数的时候要先判断drv->probe是否镇定
//注册成功
int platform_driver_register(struct platform_driver *drv)
{
drv->driver.bus = &platform_bus_type;
if (drv->probe) drv->driver.probe = platform_drv_probe;
if (drv->remove) drv->driver.remove = platform_drv_remove;
if (drv->shutdown) drv->driver.shutdown = platform_drv_shutdown;
if (drv->suspend) drv->driver.suspend = platform_drv_suspend;
if (drv->resume) drv->driver.resume = platform_drv_resume;
return driver_register(&drv->driver);
}
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
//平台驱动的反注册函数,直接调用驱动的反注册
void platform_driver_unregister(struct platform_driver *drv)
{
driver_unregister(&drv->driver);
}
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
//用指定的probe探测函数注册平台驱动
//__init_or_module在模块的时候为空,非模块的时候为init
int __init_or_module platform_driver_probe(
struct platform_driver *drv,
int (*probe)(struct platform_device *))
{
int retval, code;
//设置驱动的probe函数为指定函数,对drv进行注册
//指定probe,这样注册驱动的时候,设备驱动的probe就会指定
drv->probe = probe;
retval = code = platform_driver_register(drv);
//将probe函数挂空(可能是注册的使用用完就不用了)
//如果注册失败,且驱动的设备链表为空,返回错误
//探测函数指定为错误返回的函数
spin_lock(&platform_bus_type.klist_drivers.k_lock);
drv->probe = NULL;
if (code == 0 && list_empty(&drv->driver.klist_devices.k_list))
retval = -ENODEV;
drv->driver.probe = platform_drv_probe_fail;
spin_unlock(&platform_bus_type.klist_drivers.k_lock);
//如果有错误,反注册
if (code != retval) platform_driver_unregister(drv);
return retval;
}
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
//获取平台设备的设备名
static ssize_t modalias_show(struct device *dev, struct device_attribute *a, char *buf)
{
//获取平台设备,将平台设备的设备名打印到buf中
struct platform_device *pdev = to_platform_device(dev);
int len = snprintf(buf, PAGE_SIZE, "platform:%s\n", pdev->name);
return (len >= PAGE_SIZE) ? (PAGE_SIZE - 1) : len;
}
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
//声明平台设备的属性,初始只有两个
static struct device_attribute platform_dev_attrs[] = {
__ATTR_RO(modalias), //只读属性
__ATTR_NULL, //空属性
};
#define __ATTR_RO(_name) { \
.attr = { .name = __stringify(_name), .mode = 0444 }, \ //只读
.show = _name##_show, \
}
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
//平台设备的uevent操作
static int platform_uevent(struct device *dev, struct kobj_uevent_env *env)
{
struct platform_device *pdev = to_platform_device(dev);
add_uevent_var(env, "MODALIAS=platform:%s", pdev->name);
return 0;
}
//match匹配函数
static int platform_match(struct device * dev, struct device_driver * drv)
{
struct platform_device *pdev = container_of(dev, struct platform_device, dev);
return (strncmp(pdev->name, drv->name, BUS_ID_SIZE) == 0);
}
//suspend挂起函数,实际是执行驱动的挂起函数
static int platform_suspend(struct device *dev, pm_message_t mesg)
{
int ret = 0;
if (dev->driver && dev->driver->suspend)
ret = dev->driver->suspend(dev, mesg);
return ret;
}
//挂起之后,恢复之前,恢复,实际都是直接调用设备驱动的对应的函数
static int platform_suspend_late(struct device *dev, pm_message_t mesg)
static int platform_resume_early(struct device *dev)
static int platform_resume(struct device * dev)
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
//声明平台总线的操作函数
struct bus_type platform_bus_type = {
.name = "platform", //总线名
.dev_attrs = platform_dev_attrs, //属性(show,store)
.match = platform_match,
.uevent = platform_uevent,
.suspend = platform_suspend,
.suspend_late = platform_suspend_late,
.resume_early = platform_resume_early,
.resume = platform_resume,
};
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
//平台总线的初始化,系统自动调用
int __init platform_bus_init(void)
{
int error;
//总线设备注册
error = device_register(&platform_bus);
if (error) return error;
//平台总线注册
error = bus_register(&platform_bus_type);
if (error) device_unregister(&platform_bus);
return error;
}
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
//通过网上搜索到的资料说明,这个函数是驱动用来寻找最佳DMA掩码的方法
u64 dma_get_required_mask(struct device *dev)
{
u32 low_totalram = ((max_pfn - 1) << PAGE_SHIFT);
u32 high_totalram = ((max_pfn - 1) >> (32 - PAGE_SHIFT));
u64 mask;
if (!high_totalram) {
low_totalram = (1 << (fls(low_totalram) - 1));
low_totalram += low_totalram - 1;
mask = low_totalram;
} else {
high_totalram = (1 << (fls(high_totalram) - 1));
high_totalram += high_totalram - 1;
mask = (((u64)high_totalram) << 32) + 0xffffffff;
}
return mask;
}