【内核】总线、设备、驱动

本文详细介绍了Linux内核中总线、设备和驱动的管理机制,包括设备和驱动的注册、初始化、添加和移除过程,以及bus_register、device_add和driver_register等关键函数的使用示例。
摘要由CSDN通过智能技术生成

一、概述

总线(bus):负责管理挂载对应总线的设备以及驱动;
设备(device):挂载在某个总线的物理设备;
驱动(driver):与特定设备相关的软件,负责初始化该设备以及提供一些操作该设备的操作方式;

总线-设备-驱动 模式下的操作
总线管理着两个链表:设备链表 和 驱动链表。
当我们向内核注册一个驱动时,便插入到总线的驱动链表。
当我们向内核注册一个设备时,便插入到总线的设备链表。
在插入的同时,总线会执行一个 bus_type 结构体中的 match 方法对新插入的 设备/驱动进行匹配。(例如以名字的方式匹配)
匹配成功后,会调用 驱动 device_driver 结构体中的 probe 方法,通常在 probe中获取设备的资源信息。
在移除设备或驱动时,会调用 device_driver 结构体中的 remove 方法。

二、函数接口

int bus_register(struct bus_type *bus)
void bus_unregister(struct bus_type *bus)

void device_initialize(struct device *dev)
int device_add(struct device *dev)
void device_del(struct device *dev)
struct device *device_create(struct class *class, struct device *parent, dev_t devt, void *drvdata, const char *fmt, ...)

struct device *get_device(struct device *dev)
void put_device(struct device *dev)

int device_register(struct device *dev)
void device_unregister(struct device *dev)

int driver_register(struct device_driver *drv)
void driver_unregister(struct device_driver *drv)

三、代码示例

#include <linux/device.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/string.h>
#include <linux/kobject.h>
#include <linux/sysfs.h>
#include <linux/slab.h>

MODULE_AUTHOR("hpz");
MODULE_LICENSE("Dual BSD/GPL");

#define hp_prt(fmt, arg...)  printk("[%s,%d] "fmt, __FUNCTION__, __LINE__, ##arg);

static int hp_bus_match(struct device *dev, struct device_driver *drv)
{
	return 1;
}

static int hp_bus_uevent(struct device *dev, struct kobj_uevent_env *env)
{

    int i = 0;
    hp_prt("enter!\n");
    
    add_uevent_var(env, "hp_TYPE=%s", "happy");
    while( i < env->envp_idx){
            hp_prt("%s\n",env->envp[i]);
            i++;
    }
    return 0;
}

static int hp_bus_probe(struct device *dev)
{
    hp_prt("enter!\n");
    return 0;
}

static int hp_bus_remove(struct device *dev)
{
    hp_prt("enter!\n");
	return 0;
}

static struct bus_type  hp_bus_type = {
    .name		= "hp_bus",
    .match		= hp_bus_match,
    .uevent		= hp_bus_uevent,
    .probe		= hp_bus_probe,
    .remove		= hp_bus_remove,
//  .shutdown	= hp_bus_shutdown,
//  .pm		= &hp_bus_pm_ops,
};

static void hp_release_device(struct device *dev)
{
     hp_prt("enter!\n");
     kfree(dev);
}

struct attribute test_attr = {
        .name = "hp_attr",
        .mode = S_IRUGO,
};

static struct attribute *hp_std_attrs[] = {
	&test_attr,
	NULL,
};
ATTRIBUTE_GROUPS(hp_std);

static struct device_type hp_type = {
	.groups = hp_std_groups,
};

static struct device *hpdev;

static struct device *alloc_hp_device(void)
{
    struct device *dev = kzalloc(sizeof(struct device), GFP_KERNEL);
    if (!dev)
        return NULL;       
    dev_set_name(dev, "%s", "hp_device");  
    device_initialize(dev);

    dev->parent = NULL;
    dev->bus = &hp_bus_type;
    dev->release = hp_release_device;
    dev->type = &hp_type;
    return dev;
}
static int hp_blk_probe(struct device *dev)
{
    hp_prt("enter!\n");
    return 0;
}
static int hp_blk_remove(struct device *dev)
{
    hp_prt("enter!\n");
    return 0;
}

static struct device_driver hp_driver = {

    .name	= "hp_drv",
//    .pm	= &hp_blk_pm_ops,

    .probe		= hp_blk_probe,
    .remove		= hp_blk_remove,
//    .shutdown	= hp_blk_shutdown,
};

static int code_case_device_init(void)
{
    int ret;
    hp_prt("enter!\n");

    ret = bus_register(&hp_bus_type);
    if(ret != 0) {
        hp_prt("bus_register error!\n"); 
        return -1;
    }

    hpdev = alloc_hp_device();
    if(hpdev == NULL) {
        hp_prt("alloc_hp_device error!\n"); 
        goto ERR1;

    }

    ret = device_add(hpdev);
    if(ret != 0) {
        hp_prt("device_add error!\n"); 
        goto ERR0;
    }

    hp_driver.bus = &hp_bus_type;
    ret = driver_register(&hp_driver);
    if(ret != 0) {
        hp_prt("device_add error!\n"); 
        goto ERR0;
    }
    return ret;
ERR0:
    kfree(hpdev);
ERR1:
    bus_unregister(&hp_bus_type);
    return -1;
}
static void code_case_device_exit(void)
{
    hp_prt("enter!\n"); 
    device_del(hpdev);
    put_device(hpdev);
    bus_unregister(&hp_bus_type);
    driver_unregister(&hp_driver);

    kfree(hpdev);
}

module_init(code_case_device_init);
module_exit(code_case_device_exit);
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值