build_embed_linux_system

驱动基础接口

在学习和分析Linux驱动的时候,感受最大的问题是不理解内核提供的很多接口的功能和说明。在本篇中整理总结在开发中遇到的接口,对于具体功能依靠Linux/Documentation目录下说明、源码注释、以及自己开发中的理解总结。对这些接口的整理,也是梳理重新认识Linux框架和代码的过程,个人受益匪浅。另外本篇中肯定因为个人认知的局限,有纰漏的地方,因此会长期进行更新。

本项目的所有驱动相关的接口来自于Linux版本: Linux 6.1.5, 其它版本对应的接口可能不一致,如果有改动,不在特殊说明,可自行根据实际接口判断, 关于驱动接口函数的模板见后续说明。

conclusion

注意: 一部分接口有devm_和普通版本,其中devm表示释放由内核管理,不需要手动释放,这部分接口都只在文件驱动资源管理接口中说明,不在单独列出。

base_api

ioremap

//函数原型
void __iomem *ioremap(unsigned long phys_addr, unsigned long size);

//参数
phys_addr: 硬件访问的实际物理地址
size: 物理地址的长度
返回: 转换后的虚拟内存地址指针

//例程
usr_led {
    compatible = "rmk,usr-led";
    reg = <0x020c406c 0x04>,
        <0x020e0068 0x04>,
        <0x020e02f4 0x04>,
        <0x0209c000 0x04>,
        <0x0209c004 0x04>;
    status = "okay";
};

int ret;
u32 cfg0;
size_t *virual_cfg0;
struct device_node *led_node;
led_node = of_find_node_by_path("/usr_led");
ret = of_property_read_u32(led_node, "reg", &cfg0);
virual_cfg0 = ioremap(cfg0, 4);     //将cfg0对应的物理地址转换为虚拟内存地址,内核可以访问

iounmap

//函数原型
void iounmap(const volatile void __iomem *addr);

//参数
addr: 已经映射的虚拟地址

//例程
iounmap(virual_cfg0);

kmalloc

//函数原型
void * kmalloc(size_t size, gfp_t flags)

//参数
size: 申请数据的长度
gfp: 申请数据的类型
    GFP_KERNEL: 进程上下文申请的内存,GFP_KERNEL的标记可以引发直接的内存回收,从而导致进程阻塞睡眠,这在原子上下文显然是不允许的
    GFP_ATOMIC: 在中断、软中断、spinlock等原子上下文里面,申请内存,应该使用GFP_ATOMIC标记,申请尽可能不触发内存回收,不会休眠
返回: 成功返回一个指向分配的内存,失败则返回NULL

//例程
pm_info = kmalloc(sizeof(*pm_info), GFP_KERNEL);

kzalloc

//函数原型
static inline void *kzalloc(size_t size, gfp_t gfp)

//参数
size: 申请数据的长度
gfp: 申请数据的类型
    GFP_KERNEL: 进程上下文申请的内存,GFP_KERNEL的标记可以引发直接的内存回收,从而导致进程阻塞睡眠,这在原子上下文显然是不允许的
    GFP_ATOMIC: 在中断、软中断、spinlock等原子上下文里面,申请内存,应该使用GFP_ATOMIC标记,申请尽可能不触发内存回收,不会休眠
返回: 成功返回一个指向分配的内存,失败则返回NULL

//例程
struct spi_transfer *t;

t = kzalloc(sizeof(struct spi_transfer), GFP_KERNEL);    /* 申请内存 */
if(!t) {
    return -ENOMEM;
}

kfree

//函数原型
void kfree(void *p);

//参数
p:申请的指针

//例程
kfree(t)

is_err

//函数原型
static inline long __must_check IS_ERR(const void *ptr)
{
    return IS_ERR_VALUE((unsigned long)ptr);
}

//参数
ptr:判断是否出错的对象指针
返回:0表示正常,其它表示返回错误

//例程
imx->clk_32k = devm_clk_get_optional(&pdev->dev, "32k");
if (IS_ERR(imx->clk_32k)) {
    //do somethings
}

mkdev

//函数原型
#define MAJOR(dev)    ((dev)>>8)
#define MINOR(dev)    ((dev) & 0xff)
#define MKDEV(ma, mi)    ((ma)<<8 | (mi))

container_of

//函数原型
#define container_of(ptr, type, member) ({                \
    void *__mptr = (void *)(ptr);                    \
    static_assert(__same_type(*(ptr), ((type *)0)->member) ||    \
              __same_type(*(ptr), void),            \
              "pointer type mismatch in container_of()");    \
    ((type *)(__mptr - offsetof(type, member))); }) 

//参数
ptr 指向结构体中变量的指针
type:结构体数据类型
member: 变量在结构体中对应的对象
返回: 变量所在结构体的起始指针

//例程说明
struct ap3216_data
{         
    struct cdev cdev; 
    
    //...     
};

struct ap3216_data *chip;
chip = container_of(inode->i_cdev, struct ap3216_data, cdev);
filp->private_data = chip;

writel

//函数原型
static inline void writel(u32 value, volatile void __iomem *addr)

//参数
value: 向虚拟内存地址写入的值
addr: 指向虚拟内存memory地址的指针

//例程
info->regs = devm_platform_ioremap_resource(pdev, 0);
writel(0x01, info->regs);

readl

//函数原型
static inline u32 readl(const volatile void __iomem *addr)

//参数
addr: 指向虚拟内存memory地址的指针
返回: 从虚拟内存地址中读取的值

//例程
info->regs = devm_platform_ioremap_resource(pdev, 0);
u32 regval = readl(info->regs);

kref_init

// 函数原型
static inline void kref_init(struct kref *kref)

// 参数
kref:  是指向要初始化的kref结构体的指针

// 例程说明
struct kref kref_val;
kref_init(&kref_val);

kref_get

// 函数原型
static inline void kref_get(struct kref *kref)

// 参数
kref:  是指向要增加的的kref结构体的指针

// 例程说明
kref_get(&kref_val);

kref_put

// 函数原型
static inline int kref_put(struct kref *kref, void (*release)(struct kref *kref))

// 参数
kref:  是指向要释放的的kref结构体的指针
release 调用释放对象的回调函数
返回: 1表示对象已经被释放,其它则返回0

// 例程说明
kref_put(&mapping->kref, release_iommu_mapping)

kref_read

// 函数原型
static inline unsigned int kref_read(const struct kref *kref)

// 参数
kref:  是指向要获取的的kref结构体的指针
返回: 对象的引用计数的值

// 例程说明
int ref = kref_read(&kref_val);

platform_bus_api

platform_driver_register

// 函数原型
#define platform_driver_register(drv) \
    __platform_driver_register(drv, THIS_MODULE)
int __platform_driver_register(struct platform_driver *drv, struct module *owner);

// 参数
drv: 是指向要注册的platform_driver结构体的指针
owner:驱动模块的拥有者,一般为THIS_MODULE(驱动在编译时会生成)
返回: 0表示执行成功,其它值表示执行出错

// 例程说明
/* 
用于匹配platform总线下的节点,可通过ls /sys/bus/platform/devices/查看支持的接口
匹配属性为compatible,如usr_beep的属性查看
cat /sys/bus/platform/devices/usr_beep/of_node/compatible
*/
static const struct of_device_id of_match_beep[] = {
    { .compatible = "rmk,usr-beep"},
    { /* Sentinel */ }
};
MODULE_DEVICE_TABLE(of, of_match_beep);

static struct platform_driver platform_driver = {
    .driver = {
        .name = "usr_beep",     
        .of_match_table = of_match_beep,  
    },
    .probe = beep_probe,
    .remove = beep_remove,
};
platform_driver_register(&platform_driver);

/*
注意: 
有设备树情况下,在总线加载时会解析设备树并创建指定总线下的设备(如/sys/bus/i2c/devices/下)
无设备树情况,需要自己手动创建设备, 此时使用id_table匹配。
*/

platform_driver_unregister

//函数原型
void platform_driver_unregister(struct platform_driver *drv)

//参数
drv: 指向要注销的platform_driver结构体的指针

//例程
platform_driver_unregister(&platform_driver);

module_platform_driver

//函数原型
#define module_platform_driver(__platform_driver) \
        module_driver(__platform_driver, platform_driver_register, \
                platform_driver_unregister)

//参数
__platform_driver: 管理platform_driver结构体的对象

//例程
static struct platform_driver platform_driver = {
    .driver = {
        .name = "usr_beep",     
        .of_match_table = of_match_beep,  
    },
    .probe = beep_probe,
    .remove = beep_remove,
};
module_platform_driver(platform_driver);

module_platform_driver_probe

//函数原型
#define module_platform_driver_probe(__platform_driver, __platform_probe) \
static int __init __platform_driver##_init(void) \
{ \
    return platform_driver_probe(&(__platform_driver), \
                        __platform_probe);    \
} \
module_init(__platform_driver##_init); \
static void __exit __platform_driver##_exit(void) \
{ \
    platform_driver_unregister(&(__platform_driver)); \
} \
module_exit(__platform_driver##_exit);

//参数
__platform_driver: 管理platform_driver结构体的对象
__platform_probeprobe加载的函数

//例程
module_platform_driver_probe(imx2_wdt_driver, imx2_wdt_probe);

platform_device_register

//函数原型
int platform_device_register(struct platform_device *pdev)

//参数
pdev: 指向要注册的platform_device结构体的指针
返回: 0表示执行成功,其它值表示执行出错

//例程
static struct w1_gpio_platform_data foo_w1_gpio_pdata = {
    .ext_pullup_enable_pin  = -EINVAL,
};

static struct platform_device foo_w1_device = {
    .name       = "w1-gpio", //设备和驱动匹配时,对应的驱动名称
    .id         = -1,
    .dev.platform_data  = &foo_w1_gpio_pdata,
};
platform_device_register(&foo_w1_device);

/* 
注意: 
有设备树时,内核启动时解析设备树自动创建
不使用设备树时需要自己手动创建总线,驱动使用id_table匹配name选项。
目前主流是设备树方案,此接口很少使用。
*/

platform_device_unregister

//函数原型
void platform_device_unregister(struct platform_device *)

//参数
drv:指向需要移除的platform_device结构体的指针

//例程
platform_device_unregister(&foo_w1_device);

platform_add_devices

//函数原型
int platform_add_devices(struct platform_device **devs, int num);

//参数
devs: 指向要注册的platform_device结构体的指针数组
nmu:注册的设备个数
返回: 0表示注册成功,其它值表示注册失败(任意一个失败都会直接返回)

//例程
static struct platform_device *devices[] __initdata = {
    &kb3886bl_device,
};
platform_add_devices(devices, ARRAY_SIZE(devices));

/*
注意:由platform_add_devices注册的设备,仍然用platform_device_unregister进行移除
*/

platform_get_irq

//函数原型+
int platform_get_irq(struct platform_device *dev, unsigned int num)

//参数
dev: 指向一个platform_device结构体的指针,该结构体代表了一个平台设备
num:用于指定要获取的中断的索引,支持多个interrupts时可以通过此区分
返回: 非负值表示返回的中断号,负值表示失败

//例程
//中断线号带两个参数类型,表示中断控制器为gpio1,对应gpio1的9号中断
interrput-parent = <&gpio1>;
interrupts = <9 IRQ_TYPE_LEVEL_LOW>;

//中断线号带的参数类型由所属控制器的#interrupt-cells决定
//gpio1的#interrupt-cells = <2>,中断类型省略
//interrupts = <中断类型,中断号偏移值,中断触发类型>
//中断类型
//GIC_IPI: inter processer interrupt, 中断号0~15
//GIC_PPI: peripheral processer interrupt, 中断号16~31
//GIC_SPI:shared processer interrupt, 中断号32~32+224
//GPI_SGI: software generated interruot
//中断触发类型
//IRQ_TYPE_NONE         0
//IRQ_TYPE_EDGE_RISING  1
//IRQ_TYPE_EDGE_FALLING 2
//IRQ_TYPE_EDGE_BOTH    3
//IRQ_TYPE_LEVEL_HIGH   4
//IRQ_TYPE_LEVEL_LOW    5
interrupts = <GIC_SPI 23 1> //对应中断线号32+23=55, 上升沿触发

int irq = platform_get_irq(pdev, 0); //取interrupts位置0对应的中断编号

platform_irq_count

//函数原型
int platform_irq_count(struct platform_device *dev);

//参数
dev: 指向一个platform_device结构体的指针,它包含了设备的各种信息,比如设备名称、资源(如内存区域、中断等)等
返回: 非负值表示查询到的interrupts属性中的中断个数,负值表示获取失败

//例程
int count = platform_irq_count(pdev);

platform_get_irq_byname

//函数原型
int platform_get_irq_byname(struct platform_device *dev, const char *name)

//参数
dev: 指向一个platform_device结构体的指针,它包含了设备的各种信息,比如设备名称、资源(如内存区域、中断等)等
name: 设备结构中的属性
返回: 成功返回对应名称的irq值,负值表示失败

//例程
//interrupt-name指定中断的name,通过platform_get_irq_byname访问
//返回<0 9 IRQ_TYPE_LEVEL_HIGH>;,值为9
interrupts = <0 8 IRQ_TYPE_LEVEL_HIGH>,
            <0 9 IRQ_TYPE_LEVEL_HIGH>;
interrupt-names = "edma-tx", "edma-err";
fsl_edma->errirq = platform_get_irq_byname(pdev, "edma-err")

platform_get_resource

//函数原型
struct resource *platform_get_resource(struct platform_device *dev, unsigned int type, unsigned int num);

//参数
dev:: 指向一个platform_device结构体的指针,它包含了设备的各种信息,比如设备名称、资源(如内存区域、中断等)等
type: 获取资源的类型,主要如下,
    IORESOURCE_IO   gpio类型资源
    IORESOURCE_MEM  reg寄存器类型资源
    IORESOURCE_IRQ  interrupt中断类型资源
    IORESOURCE_DMA  DMA类型的资源
index: 获取资源的索引值, 如果对于一个资源包含多个,按照索引值读取
返回: NULL表示获取失败,其它返回resoure对应的指针地址

//例程
//在设备树加载时,会将设备树内的节点中属性转换成对应的资源,后续可以通过此方法读取
{
    gpio = <&gpio5 2 GPIO_ACTIVE_LOW>;       //IORESOURCE_IO
    reg = <0x01c00000 4>, <0x01c00004 4>;    //IORESOURCE_MEM
    interrupts = <18 IRQ_TYPE_EDGE_FALLING>; //IORESOURCE_IRQ
    dmas = <&edma0 3 1
        &edma0 2 1>                          //IORESOURCE_DMA
}

//获取i/o属性
struct resource *io_rc = platform_get_resource(pdev, IORESOURCE_IO, 0);
devm_request_region(dev, io_rc->start, resource_size(io_rc), KBUILD_MODNAME)
led_data->io_base = io_rc->start;

//获取reg属性(IORESOURCE_MEM)
volatile ssize_t* regs[2];
struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if(!res)
    regs[0] = ioremap(res->start, (res->end-res->start)+1);
res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
if(!res)
    regs[1] = ioremap(res->start, (res->end-res->start)+1);

//获取irq属性(IORESOURCE_IRQ)
int irq;
struct resource *res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
if(!res)
    irq = res->start;

platform_get_resource_byname

//函数原型
struct resource *platform_get_resource_byname(struct platform_device *dev, unsigned int type, const char *name)

//参数
dev: 向一个platform_device结构体的指针,它包含了设备的各种信息,比如设备名称、资源(如内存区域、中断等)等
type: 资源的类型, IORESOURCE_IO, IORESOURCE_MEM, IORESOURCE_REG, IORESOURCE_IRQ, IORESOURCE_DMA, IORESOURCE_BUS
name: 资源的名称
返回: NULL表示获取失败,其它返回resoure对应的指针地址

//例程
//interrupt-name指定中断的name,通过platform_get_resource_byname访问
interrupts = <0 8 IRQ_TYPE_LEVEL_HIGH>,
            <0 9 IRQ_TYPE_LEVEL_HIGH>;
interrupt-names = "edma-tx", "edma-err";
fsl_edma->errirq = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "edma-err")

platform_set_drvdata

//函数原型
static inline void platform_set_drvdata(struct platform_device *pdev, void *data)

//参数
dev: 指向一个platform_device结构体的指针,它包含了设备的各种信息,比如设备名称、资源(如内存区域、中断等)等
data: 需要保存的私有数据信息

//例程
struct led_data *chip;

chip = devm_kzalloc(&pdev->dev, sizeof(struct led_data), GFP_KERNEL);
if(!chip){
    dev_err(&pdev->dev, "malloc error\n");
    return -ENOMEM;
}
platform_set_drvdata(pdev, chip);

platform_get_drvdata

//函数原型
static inline void *platform_get_drvdata(const struct platform_device *pdev)

//参数
dev: 指向一个platform_device结构体的指针,它包含了设备的各种信息,比如设备名称、资源(如内存区域、中断等)等
返回: 获取保存的私有数据信息

//例程
struct led_data *chip;

chip = platform_get_drvdata(pdev);

gpio_api

gpio_request

申请gpio资源,功能等同于devm_gpio_request, 见章节ch03-x3.

gpio_direction_input

//函数原型
static inline int gpio_direction_input(unsigned gpio)
{
    return gpiod_direction_input(gpio_to_desc(gpio));
}

//参数
gpio: 需要配置的引脚线号
返回:0表示设置成功,负值表示设置失败

//例程
gpio_request(gpio_det, "MMC detect");
if(ret)
    return ret;
gpio_direction_input(gpio_det);

gpio_direction_output

//函数原型
static inline int gpio_direction_output(unsigned gpio, int value)
{
    return gpiod_direction_output_raw(gpio_to_desc(gpio), value);
}

//参数
gpio: 需要配置的引脚线号
返回:0表示设置成功,负值表示设置失败

//例程
ret = devm_gpio_request(&pdev->dev, chip->gpio, "led");
if (ret < 0){
    dev_err(&pdev->dev, "request gpio failed!\n");
    return -EINVAL;   
}

gpio_direction_output(chip->gpio, 1);

gpio_free

//函数原型
static inline void gpio_free(unsigned gpio)

//参数
gpio: 已经申请的gpio线号


//例程
gpio_free(chip->gpio);

gpio_set_value

//函数原型
#define gpio_set_value __gpio_set_value
static inline void __gpio_set_value(unsigned gpio, int value)
{
    return gpiod_set_raw_value(gpio_to_desc(gpio), value);
}

//参数
gpio: 需要配置的引脚线号
value: 设置引脚的电平,写入原始值,不考虑

//例程
gpio_set_value(chip->gpio, 1);

gpio_get_value

//函数原型
#define gpio_set_value __gpio_get_value
static inline int __gpio_get_value(unsigned gpio)
{
    return gpiod_get_raw_value(gpio_to_desc(gpio));
}

//参数
gpio: 需要配置的引脚线号
返回: 读取引脚的电平值

//例程
value = gpio_get_value(chip->gpio);

gpio_is_valid

//函数原型
static inline bool gpio_is_valid(int number)
{
    /* only non-negative numbers are valid */
    return number >= 0;
}

//参数
gpio: 需要配置的引脚线号
返回: 引脚编号是否有效

//例程
if (!gpio_is_valid(template->gpio))
    return ERR_PTR(-ENOENT);

gpio_to_desc

//函数原型
struct gpio_desc *gpio_to_desc(unsigned gpio)

//参数:
gpio: gpio的值
返回: 获取I/O的资源

//例程
struct gpio_desc *desc;
desc = gpio_to_desc(chip->gpio); 

desc_to_gpio

//函数原型
int desc_to_gpio(const struct gpio_desc *desc)

//参数:
desc: gpio资源描述符
返回: 获取gpio线号

//例程
chip->gpio = desc_to_gpio(desc); 
//函数原型
static inline int gpio_export_link(struct device *dev, const char *name, unsigned gpio)

//参数
gpio: 请求的给gpio线号
name: 定义gpio的名称
gpio: gpio的线号

//例程
gpio_export_link(&pdev->dev, "gpiod", chip->key_gpio);

gpio_export

//函数原型
static inline int gpio_export(unsigned gpio, bool direction_may_change)

//参数
gpio: 请求的给gpio线号
direction_may_change: 定义是否允许方向改变

//例程
gpio_export(chip->key_gpio, 0);

gpio_unexport

//函数原型
static inline void gpio_unexport(unsigned gpio)

//参数
gpio: 已经导出的gpio线号

//例程
gpio_unexport(chip->key_gpio);

gpiod_direction_input

//函数原型
int gpiod_direction_input(struct gpio_desc *desc);

//参数
desc: 获取的gpio资源
返回: 0表示设置成功,其它则失败

//例程
static gpio_desc *desc = devm_gpiod_get(&pdev-dev, "key", GPIOD_IN);
gpiod_direction_input(desc);

gpiod_direction_output

//函数原型
int gpiod_direction_output(struct gpio_desc *desc, int value)

//参数
desc: 获取的gpio资源结构
value: gpio的引脚状态
返回: 0表示成功,其它则是错误码

//例程
static gpio_desc *desc = devm_gpiod_get(&pdev-dev, "beep", GPIOD_OUT_LOW);
gpiod_direction_output(desc);

gpiod_set_value

//函数原型
void gpiod_set_value(struct gpio_desc *desc, int value)

//参数
desc: 获取的gpio资源
value: 设置引脚的状态

//例程
static gpio_desc *desc = devm_gpiod_get(&pdev-dev, "beep", GPIOD_OUT_LOW);
gpiod_set_value(desc, 1);

gpiod_set_raw_value

//函数原型
void gpiod_set_raw_value(struct gpio_desc *desc, int value)

//参数
desc: 获取的gpio资源
value: 设置引脚的状态

//例程
static gpio_desc *desc = devm_gpiod_get(&pdev-dev, "beep", GPIOD_OUT_LOW);
gpiod_set_raw_value(desc, 1);

gpiod_to_irq

//函数原型
int gpiod_to_irq(const struct gpio_desc *desc);

//参数
desc: 获取的gpio资源
返回: 转换后的irq中断线号

//例程
static gpio_desc *desc = devm_gpiod_get(&pdev-dev, "beep", GPIOD_OUT_LOW);
int irq = gpiod_to_irq(desc);

gpiod_get_value

//函数原型
int gpiod_get_value(const struct gpio_desc *desc)

//参数
desc: 获取的gpio资源
返回: 获取的I/O状态值

//例程
static gpio_desc *desc = devm_gpiod_get(&pdev-dev, "beep", GPIOD_OUT_LOW);
int value = gpiod_get_value(desc);

gpiod_toggle_active_low

//函数原型
void gpiod_toggle_active_low(struct gpio_desc *desc)

//参数:
desc: gpio的资源描述符

//例程
struct gpio_desc *desc;
desc = gpio_to_desc(chip->gpio); 
gpiod_toggle_active_low(desc);

i2c_bus_api

i2c_add_driver

//函数原型
#define i2c_add_driver(driver) \
    i2c_register_driver(THIS_MODULE, driver)
int i2c_register_driver(struct module *owner, struct i2c_driver *driver);

//参数
owner:驱动模块的拥有者,固定为THIS_MODULE
driver: 驱动加载时,总线需要访问的驱动结构体
返回: 0表示执行成功,其它值表示执行出错

//例程
//设备树
ap3216@1e {
    compatible = "rmk,ap3216";
    reg = <0x1e>;
};

/* 
用于匹配i2c总线下的节点,可通过ls /sys/bus/i2c/devices/查看支持的接口
总线匹配成功设备树后创建资源,这里每个设备节点对应i2c_adpater接口点。
匹配属性为compatible,另外支持设备的名称为1-0038的格式,其中1为i2c编号,38为i2c设备地址
*/
static const struct of_device_id ap3216_of_match[] = {
    { .compatible = "rmk,ap3216" }, //匹配的为i2c总线下设备节点的compatible属性
    { /* Sentinel */ }
};
static struct i2c_driver ap3216_driver = {
    .probe = ap3216_probe,
    .remove = ap3216_remove,
    .driver = {
        .owner = THIS_MODULE,
        .name = "ap3216",
        .of_match_table = ap3216_of_match, 
    },
};
int ret = i2c_add_driver(&ap3216_driver);

i2c_del_driver

//函数原型
void i2c_del_driver(struct i2c_driver *driver);

//参数
driver: 驱动移除时,总线需要访问的驱动结构体
返回: 0表示执行成功,其它值表示执行出错

//例程
int ret = i2c_del_driver(&ap3216_driver);

i2c_transfer

//函数原型
int i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)

//参数
adap: i2c适配器,i2c作为总线可以挂载多个i2c设备,这里每个设备创建一个适配器结构并指定编号,当指定adap时就可以获取对应的外部器件资源。
msgs: i2c传输的数据指针数组
num: 传递消息的个数
返回: 成功返回传递消息的个数,其它则为失败

//例程
struct i2c_msg msgs[2];
__be16 wbuf = cpu_to_be16(reg);
int ret;

//发送地址数据
msgs[0].flags = 0;
msgs[0].addr  = client->addr;   //i2c地址
msgs[0].len   = 2;
msgs[0].buf   = (u8 *)&wbuf;

//读取数据信息
msgs[1].flags = I2C_M_RD;
msgs[1].addr  = client->addr;
msgs[1].len   = len;
msgs[1].buf   = buf;

ret = i2c_transfer(client->adapter, msgs, 2);

i2c_type

struct i2c_adapter {
    unsigned int class;             /* classes to allow probing for */
    const struct i2c_algorithm *algo; /* the algorithm to access the bus */
    void *algo_data;

    /* data fields that are valid for all devices */
    const struct i2c_lock_operations *lock_ops;
    struct rt_mutex bus_lock;
    struct rt_mutex mux_lock;

    int timeout;            /* in jiffies */
    int retries;
    struct device dev;      /* the adapter device */
    unsigned long locked_flags; /* owned by the I2C core */
    #define I2C_ALF_IS_SUSPENDED    0
    #define I2C_ALF_SUSPEND_REPORTED    1

    int nr;
    char name[48];
    struct completion dev_released;

    struct mutex userspace_clients_lock;
    struct list_head userspace_clients;

    struct i2c_bus_recovery_info *bus_recovery_info;
    const struct i2c_adapter_quirks *quirks;

    struct irq_domain *host_notify_domain;
    struct regulator *bus_regulator;
};

struct i2c_client {
    unsigned short flags;                       /* div., see below */
        #define I2C_CLIENT_PEC  0x04            /* Use Packet Error Checking */
        #define I2C_CLIENT_TEN  0x10            /* we have a ten bit chip address */
        #define I2C_CLIENT_SLAVE    0x20        /* we are the slave */
        #define I2C_CLIENT_HOST_NOTIFY  0x40    /* We want to use I2C host notify */
        #define I2C_CLIENT_WAKE     0x80        /* for board_info; true iff can wake */
        #define I2C_CLIENT_SCCB     0x9000      /* Use Omnivision SCCB protocol */

    unsigned short addr;                        /* chip address - NOTE: 7/10bit */
    /* addresses are stored in the */
    /* _LOWER_ 7 bits */
    char name[I2C_NAME_SIZE];
    struct i2c_adapter *adapter;                /* the adapter we sit on */
    struct device dev;                          /* the device structure */
    int init_irq;                               /* irq set at initialization */
    int irq;                                    /* irq issued by device */
    struct list_head detected;
    #if IS_ENABLED(CONFIG_I2C_SLAVE)
    i2c_slave_cb_t slave_cb;                    /* callback for slave mode    */
    #endif
    void *devres_group_id;                      /* ID of probe devres group    */
};

i2c_xxx_adapter

不使用设备树情况,需要自己在i2c总线下添加设备节点时涉及得接口,当使用设备树,这部分由内核加载设备树时解析自动生成,用户不需要自己开发。考虑到文档复杂度问题,这里只列出功能,不详细说明。

//在i2c总线下添加设备节点
int i2c_add_adapter(struct i2c_adapter *adap);

//在i2c总线下添加内核管理的设备节点
int devm_i2c_add_adapter(struct device *dev, struct i2c_adapter *adapter);

//删除i2c总线中的设备节点
void i2c_del_adapter(struct i2c_adapter *adap)

//根据编号获得i2c适配器资源
struct i2c_adapter *i2c_get_adapter(int nr);

//释放获得得i2c适配器资源
void i2c_put_adapter(struct i2c_adapter *adap)

i2c_set_clientdata

//函数原型
void i2c_set_clientdata(struct i2c_client *client, void *data);

//参数
client: i2c设备管理结构
data:设置的私有数据

//例程
i2c_set_clientdata(client, chip);

i2c_get_clientdata

//函数原型
void *i2c_get_clientdata(const struct i2c_client *client);

//参数
client: i2c设备管理结构
返回: 驱动保存的私有数据

//例程
chip = i2c_get_clientdata(client);

spi_bus_api

spi_setup

//函数原型
int spi_setup(struct spi_device *spi)

//参数
spi: spi设备管理结构
返回: spi是否配置成功

//例程
struct spi_device *spi;

spi->mode = SPI_MODE_0;
spi_setup(spi);

spi_register_driver

//函数原型
#define spi_register_driver(driver) \
    __spi_register_driver(THIS_MODULE, driver)
int __spi_register_driver(struct module *owner, struct spi_driver *sdrv);

//参数
owner:驱动模块的拥有者,固定为THIS_MODULE
sdrv: 驱动加载时,总线需要访问的驱动结构体
返回: 0表示执行成功,其它值表示执行出错

//例程
//设备树
spidev0:icm20608@0 {
    compatible = "rmk,icm20608";
    spi-max-frequency = <8000000>;
    reg = <0>;
};

/* 
用于匹配spi总线下的节点,可通过ls /sys/bus/spi/devices/查看支持的接口
总线匹配成功设备树后创建资源,这里每个设备节点对应spi_device。
匹配属性为compatible
*/
static const struct of_device_id icm20608_of_match[] = {
    { .compatible = "rmk,icm20608" },
    { /* Sentinel */ }
};

static struct spi_driver icm20608_driver = {
    .probe = icm20608_probe,
    .remove = icm20608_remove,
    .driver = {
        .owner = THIS_MODULE,
        .name = "icm20608",
        .of_match_table = icm20608_of_match, 
    },
};
int ret = spi_register_driver(&icm20608_driver);

spi_unregister_driver

//函数原型
void spi_unregister_driver(struct spi_driver *driver);

//参数
driver: 驱动移除时,总线需要访问的驱动结构体

//例程
int ret = spi_register_driver(&icm20608_driver);

spi_message_init

//函数原型
static inline void spi_message_init(struct spi_message *m)

//参数
m: 定义初始化的message消息

//例程
struct spi_message m;
spi_message_init(&m);

spi_message_add_tail

//函数原型
static inline void spi_message_add_tail(struct spi_transfer *t, struct spi_message *m)

//参数
t: 增加的spi数据实体
m: 已经初始化的message消息

//例程
struct spi_message m;
struct spi_transfer t;
unsigned char txdata[32];
unsigned char rxdata[32];

txdata[0] = reg | 0x80;
t->tx_buf = txdata;
t->rx_buf = rxdata;
t->len = len+1;
spi_message_init(&m);
spi_message_add_tail(&t, &m);

spi_sync

//函数原型
int spi_sync(struct spi_device *spi, struct spi_message *message)

//参数
spi: 选择要进行spi通讯的设备结构
message: 要发送的消息
返回: 0表示通讯成功, 其它表示通讯失败

//例程
struct spi_message m;
struct spi_transfer t;
struct spi_device *spi; //probe时提供的消息
int ret;

"...."
spi_message_init(&m);
spi_message_add_tail(&t, &m);
ret = spi_sync(spi, &m); 
if(!ret)
{
    memcpy(rx_buf, &t->rx_buf[1], t->len-1);
}

/*
spi在发送的同时会进行接收,所以接收的实际长度为rx_req+tx_len
例如发送寄存器地址长度1,实际发送和接收长度都需要为rx_req+1, 
*/

spi_sync_transfer

//函数原型
int spi_sync_transfer(struct spi_device *spi, struct spi_transfer *xfers, unsigned int num_xfers)

//参数
spi: 选择要进行spi通讯的设备结构
xfers: 要发送的数据数组
num_xfer: 要发送的数据数组数目
返回: 0表示通讯成功, 其它表示通讯失败

//例程
struct spi_transfer t[2];
struct spi_device *spi; //probe时提供的消息

t[0]->tx_buf = txdata;
t[0]->rx_buf = rxdata;
t[0]->len = len+1;
t[1]->tx_buf = txdata;
t[1]->rx_buf = rxdata;
t[1]->len = len+1;
spi_sync_transfer(spi, t, ARRAY_SIZE(t));

spi_write_then_read

//函数原型
int spi_write_then_read(struct spi_device *spi, const void *txbuf, unsigned n_tx, void *rxbuf, unsigned n_rx)

//参数
spi: 选择要进行spi通讯的设备结构
txbuf: 发送数据的首地址
n_tx: 发送数据的长度
rx_buf:接收数据的首地址
n_rx:接收数据的长度
返回: 0表示通讯成功, 其它表示通讯失败

//举例
u8 txbuf[1];
u8 rxbuf[6];
struct spi_device *spi; //probe时提供的消息

int ret = spi_write_then_read(spi, txbuf, 1, rxbuf, 6);

spi_set_drvdata

//函数原型
void spi_set_drvdata(struct spi_device *spi, void *data);

//参数
spi: spi设备结构
data:设备需要保存的私有数据

//例程
spi_set_drvdata(spi, chip);

spi_get_drvdata

//函数原型
void *spi_get_drvdata(struct spi_device *spi);

//参数
spi: spi设备结构
返回: 设备保存的私有数据

//例程
chip = spi_get_drvdata(spi);

regmap_api

regmap_init_spi

//函数原型
#define regmap_init_spi(dev, config)    \
    __regmap_lockdep_wrapper(__regmap_init_spi, #config,    \
            dev, config)
struct regmap *__regmap_init_spi(struct spi_device *spi,
                const struct regmap_config *config,
                struct lock_class_key *lock_key,
                const char *lock_name)

//参数
dev: spi总线设备结构
config: spi管理器件的配置信息
返回: 管理spi总线的regmap资源

//例程
const struct regmap_config icm20608_regmap_config = {
    .reg_bits = 8,          /* 寄存器bit数 */
    .val_bits = 8,          /* 读取单个字节的bit数 */
    .read_flag_mask = 0x80, /* 读标志掩码,会与寄存器地址或 */ 
    .max_register = 255,    /* 允许输入的最大寄存器地址 */
};
struct spi_device *spi;

chip->map = devm_regmap_init_spi(spi, &icm20608_regmap_config);

regmap_init_i2c

//函数原型
#define regmap_init_i2c(i2c, config)    \
    __regmap_lockdep_wrapper(__regmap_init_i2c, #config,    \
            i2c, config)
struct regmap *__regmap_init_i2c(struct i2c_client *i2c,
            const struct regmap_config *config,
            struct lock_class_key *lock_key,
            const char *lock_name)

//参数
dev: i2c总线设备结构
config: i2c管理器件的配置信息
返回: 管理i2c总线的regmap资源

//例程
const struct regmap_config ap3216_regmap_config = {
    .reg_bits = 8,
    .val_bits = 8,
    .max_register = 255,
};
map = regmap_init_i2c(client, &ap3216_regmap_config);

regmap_init_mmio

//函数原型
#define regmap_init_mmio(dev, regs, config)        \
    regmap_init_mmio_clk(dev, NULL, regs, config)
#define devm_regmap_init_mmio_clk(dev, clk_id, regs, config)        \
    __regmap_lockdep_wrapper(__devm_regmap_init_mmio_clk, #config,    \
    dev, clk_id, regs, config)
struct regmap *__regmap_init_mmio_clk(struct device *dev, const char *clk_id,
    void __iomem *regs,
    const struct regmap_config *config,
    struct lock_class_key *lock_key,
    const char *lock_name);

//参数
dev: 匹配的设备节点信息
regs: 寄存器地址信息
config:寄存器的配置定义
返回: 管理内存映射I/O(mmio)regmap资源实例

//例程
struct regmap_config icst_regmap_conf = {
    .reg_bits = 32,
    .val_bits = 32,
    .reg_stride = 4,
};
struct regmap *map;

map = regmap_init_mmio(dev, base, &icst_regmap_conf);

regmap_init_mmio_clk

//函数原型
#define regmap_init_mmio_clk(dev, clk_id, regs, config)          \
    __regmap_lockdep_wrapper(__regmap_init_mmio_clk, #config,    \
                dev, clk_id, regs, config)

//参数
dev: 驱动匹配设备节点的struct device结构体
clk_id: 寄存器使能需要启动的时钟名称,会调用相应的clk_perpare接口进行使能
regs: 寄存器地址信息
config:寄存器的配置定义
返回: 管理内存映射I/O(mmio)regmap资源实例

//例程
struct device *dev = &pdev->dev;
wdev->regmap = devm_regmap_init_mmio_clk(dev, NULL, base,
                        &imx2_wdt_regmap_config);

regmap_exit

//函数原型
void regmap_exit(struct regmap *map)

//参数
map: 已经申请的regmap资源

//例程
regmap_exit(map);

regmap_read

//函数原型
int regmap_read(struct regmap *map, unsigned int reg, unsigned int *val)

//参数
map: 已经申请的regmap资源
reg: 访问的器件寄存器地址
val: 读取的地址内数据
返回: 0表示写入成功,其它则写入失败

//例程
int retval;

ret = regmap_read(chip->map, AP3216C_SYSTEMCONG, &val);

regmap_write

//函数原型
int regmap_write(struct regmap *map, unsigned int reg, unsigned int val)

//参数
map: 已经申请的regmap资源
reg: 访问的器件寄存器地址
val: 写入的数据
返回: 0表示写入成功,其它则写入失败

//例程
int ret;

ret = regmap_write(chip->map, AP3216C_SYSTEMCONG, 0x04);

regmap_bulk_read

//函数原型
int regmap_bulk_read(struct regmap *map, unsigned int reg, void *val,
        size_t val_count)

//参数
map: 已经申请的regmap资源
reg: 访问的器件寄存器起始地址
val: 存放读取数据的首地址
val_count: 读取数据的长度
返回: 0表示读取成功,其它则读取失败

//例程
int ret;

ret = regmap_bulk_read(chip->map, ICM20_ACCEL_XOUT_H, readbuf, 14);

regmap_bulk_write

//函数原型
int regmap_bulk_write(struct regmap *map, unsigned int reg, const void *val,
            size_t val_count)

//参数
map: 已经申请的regmap资源
reg: 访问的器件寄存器地址
val: 写入的数据的首地址
val_count: 写入数据的长度
返回: 0表示写入成功,其它则写入失败

//例程
int ret;
char data;

data = 0x80;
ret = regmap_bulk_write(chip->map, ICM20_PWR_MGMT_1, &data, 1);

regmap_update_bits

//函数原型
static inline int regmap_update_bits(struct regmap *map, unsigned int reg,
    unsigned int mask, unsigned int val)
{
    return regmap_update_bits_base(map, reg, mask, val, NULL, false, false);
}
int regmap_update_bits_base(struct regmap *map, unsigned int reg,
    unsigned int mask, unsigned int val,
    bool *change, bool async, bool force)

//参数
map: 已经申请的regmap资源
reg: 访问的器件寄存器地址
mask: 要更改的位掩码
val: 要更改的值
返回: 0表示写入成功,其它表示更改失败

//例程
struct regmap *gpr;

/* set FEC clock from internal PLL clock source */
gpr = syscon_regmap_lookup_by_compatible("fsl,imx6sl-iomuxc-gpr");
if (!IS_ERR(gpr)) {
    regmap_update_bits(gpr, IOMUXC_GPR1,
        IMX6SL_GPR1_FEC_CLOCK_MUX2_SEL_MASK, 0);
    regmap_update_bits(gpr, IOMUXC_GPR1,
        IMX6SL_GPR1_FEC_CLOCK_MUX1_SEL_MASK, 0);
} else {
    pr_err("failed to find fsl,imx6sl-iomux-gpr regmap\n");
}

regmap_write_bits

//函数原型
static inline int regmap_write_bits(struct regmap *map, unsigned int reg,
    unsigned int mask, unsigned int val)
{
    return regmap_update_bits_base(map, reg, mask, val, NULL, false, true);
}

//参数
map: 指向regmap对象的指针,该对象表示要访问的寄存器空间
reg: 要访问的寄存器的地址偏移量
mask: 一个位掩码,指定了要更新的位字段。只有与mask相对应的位才会被改变,其他位保持不变
val:要写入到指定位字段的值。这个值应该与mask相对应,即只有mask中设置为1的位才在val中有意义
返回: 操作成功返回0,其它则返回错误码

//例程
regmap_write_bits(wdev->regmap, IMX2_WDT_WICR, IMX2_WDT_WICR_WTIS, IMX2_WDT_WICR_WTIS);

syscon_regmap_lookup_by_phandle

//函数原型
struct regmap *syscon_regmap_lookup_by_phandle(
        struct device_node *np,
        const char *property);

//参数
np: 指向设备的device_node节点的指针
property: 节点关键字属性
返回: 获取的regmap资源

//例程
priv->syscon = syscon_regmap_lookup_by_phandle(np, "gpio,syscon-dev");

syscon_regmap_lookup_by_compatible

//函数原型
struct regmap *syscon_regmap_lookup_by_compatible(const char *s)

//参数
s: 设备节点的compatible说明
返回: 获取的regmap资源

//例程
//dts
gpr: iomuxc-gpr@20e4000 {
    compatible = "fsl,imx6ul-iomuxc-gpr",
                "fsl,imx6q-iomuxc-gpr", "syscon";
    reg = <0x020e4000 0x4000>;
};

struct regmap *gpr;
gpr = syscon_regmap_lookup_by_compatible("fsl,imx6ul-iomuxc-gpr");

device_create_api

misc_register

//函数原型
int misc_register(struct miscdevice *misc);

//参数
misc:需要注册的杂项设备结构体
返回: 0表示注册成功,失败返回负的错误码

//例程说明
static const struct file_operations lsi_fops = {
    .open   = mraid_mm_open,
    .unlocked_ioctl = mraid_mm_unlocked_ioctl,
    .compat_ioctl = compat_ptr_ioctl,
    .owner    = THIS_MODULE,
    .llseek = noop_llseek,
};

static struct miscdevice megaraid_mm_dev = {
    .minor  = MISC_DYNAMIC_MINOR, //指定的子设备号,不能够是已存在的子设备
    .name   = "megadev0",
    .fops   = &lsi_fops,
};

int err;
err = misc_register(&megaraid_mm_dev);

//注册时会将megaraid_mm_dev作为地址加入到drvdata中
//filep->private_data为dev数据

misc_deregister

//函数原型
void misc_deregister(struct miscdevice *misc);

//参数
misc:需要移除的杂项设备结构体

//例程说明
misc_deregister(&megaraid_mm_dev);

register_chrdev

//函数原型
int register_chrdev(unsigned int major, const char *name, const struct file_operations *fops)

//参数
major:申请的字符型设备主设备号(0值申请对应设备号,0则动态申请),设备号已存在会导致申请失败
name:设备或者驱动的名称
fops:字符型设备的操作接口
返回: 返回申请到的主设备号,负值表示失败

//例程说明
int major;

static const struct file_operations dsp56k_fops = {
    .owner        = THIS_MODULE,
    .read        = dsp56k_read,
    .write        = dsp56k_write,
    .unlocked_ioctl    = dsp56k_ioctl,
    .open        = dsp56k_open,
    .release    = dsp56k_release,
    .llseek        = noop_llseek,
};
major = register_chrdev(DSP56K_MAJOR, "dsp56k", &dsp56k_fops)

unregister_chrdev

//函数原型
void unregister_chrdev(unsigned int major, const char *name)

//参数
major:已注册的字符型设备号
name:设备或者驱动的名称
返回: 0表示申请成功,负的错误值表示申请失败

//例程说明
unregister_chrdev(DSP56K_MAJOR, "dsp56k");

register_chrdev_region

//函数原型
int register_chrdev_region(dev_t from, unsigned count, const char *name);

//参数
from:申请的设备号起始值(主设备号+子设备号)
count:申请的设备号数目
name:设备或者驱动的名称
返回: 0表示申请成功,负的错误值表示申请失败

//例程说明
dev_t devid = MKDEV(65, 0);
int ret;

ret = register_chrdev_region(devid, 1, "led");

alloc_chrdev_region

//函数原型
int alloc_chrdev_region(dev_t *dev, unsigned baseminor, unsigned count, const char *name)

//参数
dev: 需要申请的设备号指针地址
baseminor: 允许申请的设备号最小值
count: 申请设备号的数量
name: 设备的名称
返回: 0表示申请成功,负的错误值表示申请失败

//例程说明
dev_t devid;
int ret;

ret = alloc_chrdev_region(&devid, 01, "led");

unregister_chrdev_region

//函数原型
void unregister_chrdev_region(dev_t from, unsigned count)

//参数
from: 已申请的设备号起始值(主设备号)
count: 已申请的设备号数目

//例程说明
unregister_chrdev_region(devid, 1);

cdev_init

//函数原型
void cdev_init(struct cdev *cdev, const struct file_operations *fops)

//参数
cdev: 待初始化的字符设备结构体
fops: 设备支持的访问接口结构体

//例程说明
struct cdev cdev;
static struct file_operations beep_fops = {
    .owner = THIS_MODULE,
    .open = beep_open,
    .read = beep_read,
    .write = beep_write,
    .unlocked_ioctl = beep_ioctl,
    .release = beep_release,
};

cdev_init(&cdev, &beep_fops);
cdev.owner = THIS_MODULE;

cdev_add

//函数原型
int cdev_add(struct cdev *p, dev_t dev, unsigned count)

//参数
p: 需要添加到内核的字符设备结构
dev: 关联设备号
count: 添加内核的设备数目
返回:0表示绑定成功,其它值则为失败

//例程说明
int ret;
ret = cdev_add(&cdev, devid, 1);

cdev_del

//函数原型
void cdev_del(struct cdev *p)

//参数
p: 需要删除的字符设备

//例程说明
cdev_del(&cdev);

class_create

//函数原型
#define class_create(owner, name)        \
({                        \
    static struct lock_class_key __key;    \
    __class_create(owner, name, &__key);    \
})
struct class * __must_check __class_create(struct module *owner, const char *name, struct lock_class_key *key)

//参数
owner: 驱动模块的拥有者
name: 驱动模块名称
返回: 类指针,IS_ERR(class)0则正常,其它异常可通过PTR_ERR(class)读取异常值

//例程说明
static struct class *aoe_class;
int result;
aoe_class = class_create(THIS_MODULE, "aoe");
if (IS_ERR(aoe_class)){
    result = PTR_ERR(aoe_class);
}

class_destroy

//函数原型
void class_destroy(struct class *cls)

//参数
cls: 已经创建成功的设备类

//例程说明
class_destroy(aoe_class);

device_create

//函数原型
struct device *device_create(struct class *cls, struct device *parent, dev_t devt, void *drvdata, const char *fmt, ...);

//参数
cls: 已经创建成功的设备类结构
parent: 指向父设备的指针,不存在为NULL
devt: 之前创建设备对应的设备号
drvdata: 添加到设备中以回调的数据,没有则为NULL, 通过 dev_get_drvdata()获取
fmt:设备名称
成功: 返回设备指针,IS_ERR(device)0则正常,其它异常可通过PTR_ERR(device)读取异常值

//例程说明
ur->bsr_device = device_create(bsr_class, NULL, cur->bsr_dev, cur, "%s", cur->bsr_name);
if (IS_ERR(cur->bsr_device)) {
    printk(KERN_ERR "device_create failed for %s\n", cur->bsr_name);
}

device_destroy

//函数原型
void device_destroy(struct class *class, dev_t devt)

//参数
cls: 已经创建成功的设备类结构
devt: 之前创建设备对应的设备号

//例程说明
device_destroy(bsr_class, cur->bsr_dev);

device_create_file

//函数原型
struct attribute {
    char                    *name;      //文件名称
    struct module           *owner;     //文件拥有者,一般是THIS_MODULE
    umode_t                 mode;       //文件权限,0666
};
struct device_attribute {
    struct attribute    attr;
    ssize_t (*show)(struct device *dev, struct device_attribute *attr,      //对应应用文件的读取接口
            char *buf); 
    ssize_t (*store)(struct device *dev, struct device_attribute *attr,     //对应应用文件的写入接口
            const char *buf, size_t count);
};
int device_create_file(struct device *dev, const struct device_attribute *attr)

//参数
dev: 管理资源的设备,一般为总线匹配的设备
attr: 设备文件的配置属性描述符
返回: 0表示创建成功,其它表示创建失败

//例程
//在/sys/devices/platform/led/下创建led文件
chip->led_attr.attr.name = DEVICE_NAME;
chip->led_attr.attr.mode = 0666;
chip->led_attr.show = led_show;
chip->led_attr.store = led_store;
ret = device_create_file(&pdev->dev, &chip->led_attr);
if(ret != 0)
{
    dev_info(&pdev->dev, "device create file failed!\n");
    goto exit_device_create;
}

device_remove_file

//函数原型
void device_remove_file(struct device *dev, const struct device_attribute *attr)

//参数
dev: 管理资源的设备,一般为总线匹配的设备
attr: 设备文件的配置属性描述符

//例程
device_remove_file(&pdev->dev, &chip->led_attr);

dev_get_platdata

//函数原型
static inline void *dev_get_platdata(const struct device *dev)

//参数
dev: 管理资源的设备,一般为总线匹配的设备
返回: 指向设备私有数据的指针

//例程
struct gpio_led_platform_data *pdata = dev_get_platdata(&pdev->dev)

input_device_api

input_set_drvdata

//函数原型
static inline void input_set_drvdata(struct input_dev *dev, void *data)

//参数
dev: input设备结构
data:设备需要保存的私有数据

//例程
input_set_drvdata(input, chip);

input_get_drvdata

//函数原型
static inline void *input_get_drvdata(struct input_dev *dev)

//参数
dev: input设备结构
返回: 设备需要保存的私有数据

//例程
chip = input_get_drvdata(input);

input_set_capability

//函数原型
void input_set_capability(struct input_dev *dev, unsigned int type, unsigned int code)

//参数
dev: input设备结构。
type: 支持的设备类型。

#define EV_SYN            0x00  //用于事件间的分割标志。事件可能按时间或空间进行分割,就像在多点触摸协议中的例子。
#define EV_KEY            0x01  //用来描述键盘,按键或者类似键盘设备的状态变化。
#define EV_REL            0x02  //用来描述相对坐标轴上数值的变化,例如:鼠标向左方移动了5个单位。
#define EV_ABS            0x03  //用来描述相对坐标轴上数值的变化,例如:描述触摸屏上坐标的值。
#define EV_MSC            0x04  //当不能匹配现有的类型时,使用该类型进行描述。
#define EV_SW             0x05  //用来描述具备两种状态的输入开关。
#define EV_LED            0x11  //用于控制设备上的 LED 灯的开和关。
#define EV_SND            0x12  //用来给设备输出提示声音。
#define EV_REP            0x14  //用于可以自动重复的设备(autorepeating)。
#define EV_FF             0x15  //用来给输入设备发送强制回馈命令
#define EV_PWR            0x16  //特别用于电源开关的输入
#define EV_FF_STATUS      0x17  //用于接收设备的强制反馈状态。

code: 支持的设备Code(根据Event,会在input子系统进一步说明)

//例程
input_set_capability(chip->input_dev, EV_KEY, KEY_0);

input_set_abs_params

//函数原型
void input_set_abs_params(struct input_dev *dev, unsigned int axis,
                int min, int max, int fuzz, int flat)

//参数
dev: input设备结构。
axis: 指定轴的方向
min:指定轴的最小值
max: 指定轴的最大值
fuzz: 用于过滤噪声的fuzz
flat: 在此值内的值将被事件流丢弃, 然后当作0报告

//例程
input_set_abs_params(joy->input, axes[i].code,
                axes[i].range[0], axes[i].range[1],
                axes[i].fuzz, axes[i].flat);

input_register_device

//函数原型
int input_register_device(struct input_dev *dev)

//参数
dev: 待注册的input设备结构
返回: 0表示成功,其它则表示注册失败

//例程
button_dev = input_allocate_device();
if (!button_dev) {
    printk(KERN_ERR "button.c: Not enough memory\n");
    error = -ENOMEM;
    goto err_free_irq;
}

button_dev->evbit[0] = BIT_MASK(EV_KEY);
button_dev->keybit[BIT_WORD(BTN_0)] = BIT_MASK(BTN_0);

error = input_register_device(button_dev);
if (error) {
    printk(KERN_ERR "button.c: Failed to register device\n");
    goto err_free_dev;
}

input_unregister_device

//函数原型
void input_unregister_device(struct input_dev *dev)

//参数
dev: 待移除的input设备

//例程
input_unregister_device(button_dev)

input_setup_polling

//函数原型
int input_setup_polling(struct input_dev *dev,
        void (*poll_fn)(struct input_dev *dev))

//参数
dev: 注册的input设备
poll_fn: 周期性执行的回调函数

//例程
static void adc_joystick_poll(struct input_dev *input) {
}

input_setup_polling(input, adc_joystick_poll);

input_set_poll_interval

//函数原型
void input_set_poll_interval(struct input_dev *dev, unsigned int interval)

//参数
dev: 注册的input设备
interval: 周期性执行回调函数间隔

//例程
input_set_poll_interval(input, poll_interval);

input_report_xx

input_report相关接口都是对于input_evnet的封装,代码如下。

//向应用层提交按键事件
static inline void input_report_key(struct input_dev *dev, unsigned int code, int value)
{
    input_event(dev, EV_KEY, code, !!value);
}

//向应用层提交相对地址
static inline void input_report_rel(struct input_dev *dev, unsigned int code, int value)
{
    input_event(dev, EV_REL, code, value);
}

//向应用层提交绝对地址
static inline void input_report_abs(struct input_dev *dev, unsigned int code, int value)
{
    input_event(dev, EV_ABS, code, value);
}

static inline void input_report_ff_status(struct input_dev *dev, unsigned int code, int value)
{
    input_event(dev, EV_FF_STATUS, code, value);
}

//向应用层提交开关状态
static inline void input_report_switch(struct input_dev *dev, unsigned int code, int value)
{
    input_event(dev, EV_SW, code, !!value);
}

//同步命令,提交所有数据
static inline void input_sync(struct input_dev *dev)
{
    input_event(dev, EV_SYN, SYN_REPORT, 0);
}

static inline void input_mt_sync(struct input_dev *dev)
{
    input_event(dev, EV_SYN, SYN_MT_REPORT, 0);
}

input_event

//函数原型
void input_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)

//参数
dev: 提交数据的input设备
type: 事件类型,参考input_set_capability
code: 事件的值,对应input_set_capabilitycode
value: 事件附带数据,可以额外告知上层应用

//例程
static inline void input_report_key(struct input_dev *dev, unsigned int code, int value)
{
    input_event(dev, EV_KEY, code, !!value);
}
input_report_key(input, KEY_0, 1);

fb_api

framebuffer_alloc

//函数原型
struct fb_info *framebuffer_alloc(size_t size, struct device *dev)

//参数
size: 申请的数据长度
dev: fb指向管理设备的指针
返回: 申请的管理fb结构的数据指针

//例程
myfb = framebuffer_alloc(sizeof(struct fb_info), &spi->dev);

framebuffer_release

//函数原型
void framebuffer_release(struct fb_info *info)

//参数
info: 已经申请的fb设备管理结构


//例程
framebuffer_release(myfb)

register_framebuffer

//函数原型
int
register_framebuffer(struct fb_info *fb_info)

//参数
fb_info: 已经申请的fb设备管理结构
返回: 0表示注册成功,其它则表示失败

//例程
myfb->fobs = &myfb_obs;
gmem_size = 240*240*2; //设置显存大小
gmem_addr = kmalloc(gmem_size, GFP_KERNEL);
if (!gmem_addr) {
    return -1;
}
myfb->pseudo_palette = pseudo_palette; //调色板缓冲区
myfb->var = myfb_var; //设置分辨率参数
//...
ret = register_framebuffer(myfb);

unregister_framebuffer

//函数原型
void
unregister_framebuffer(struct fb_info *fb_info)

//参数
fb_info: 已经注册fb设备管理结构

//例程
unregister_framebuffer(myfb);

fb_deferred_io_init

//函数原型
int fb_deferred_io_init(struct fb_info *info)

//参数
fb_info: 已申请的fb设备管理结构
返回: 0表示初始化成功,其它则表示失败

//例程
fb_deferred_io_init(myfb);

fb_deferred_io_cleanup

//函数原型
void fb_deferred_io_cleanup(struct fb_info *info)

//参数
fb_info: 已经开启刷新机制的fb管理结构

//例程
fb_deferred_io_cleanup(myfb);

sys_fillrect

//函数原型
void sys_fillrect(struct fb_info *p, const struct fb_fillrect *rect)

//参数
fb_info: 已经注册的fb管理结构
rect: 用于填充的矩形参数

struct fb_fillrect {
    __u32 dx;   /* screen-relative */
    __u32 dy;
    __u32 width;
    __u32 height;
    __u32 color;
    __u32 rop;
};

//例程
static struct fb_ops myfb_ops = {
    .fb_fillrect = sys_fillrect,
};

sys_copyarea

//函数原型
void sys_copyarea(struct fb_info *p, const struct fb_copyarea *area)

//参数
fb_info: 已经注册的fb管理结构
area: 用于复制的区域信息

struct fb_copyarea {
    __u32 dx;
    __u32 dy;
    __u32 width;
    __u32 height;
    __u32 sx;
    __u32 sy;
};

//例程
static struct fb_ops myfb_ops = {
    .fb_copyarea = sys_copyarea,
};

sys_imageblit

//函数原型
void sys_imageblit(struct fb_info *p, const struct fb_image *image)

//参数
fb_info: 已经注册的fb管理结构
image: 图片的具体信息

struct fb_image {
    __u32 dx;           /* Where to place image */
    __u32 dy;
    __u32 width;        /* Size of image */
    __u32 height;
    __u32 fg_color;     /* Only used when a mono bitmap */
    __u32 bg_color;
    __u8  depth;        /* Depth of the image */
    const char *data;   /* Pointer to image data */
    struct fb_cmap cmap;    /* color map info */
};

//例程
static struct fb_ops myfb_ops = {
    .fb_imageblit = sys_imageblit,
};

functional_api

device_property_read_xx_array

//函数原型
int device_property_read_u8_array(struct device *dev, const char *propname, u8 *val, size_t nval);
int device_property_read_u16_array(struct device *dev, const char *propname, u16 *val, size_t nval);
int device_property_read_u32_array(struct device *dev, const char *propname, u32 *val, size_t nval);
int device_property_read_u64_array(struct device *dev, const char *propname, u64 *val, size_t nval);
int device_property_read_string_array(struct device *dev, const char *propname, const char **val, size_t nval);
int device_property_read_string(struct device *dev, const char *propname, const char **val);

//参数
dev: 匹配的设备
propname: 属性的名称
val: 存储获取数据的数组
nval: 数组的长度
返回:如果valNULL,成功返回数据的数目,不为NULL0表示成功,其它表示失败。

//例程
adc1: adc@2198000 {
    //...
    fsl,adck-max-frequency = <30000000>, <40000000>,
                <20000000>;
};
device_property_read_u32_array(dev, "fsl,adck-max-frequency", info->max_adck_rate, 3);

device_property_read_xx

//函数原型
static inline int device_property_read_u8(struct device *dev,
    const char *propname, u8 *val)
{
    return device_property_read_u8_array(dev, propname, val, 1);
}
int device_property_read_u16(struct device *dev, const char *propname, u16 *val);
int device_property_read_u32(struct device *dev, const char *propname, u32 *val);
int device_property_read_u64(struct device *dev, const char *propname, u64 *val);

//参数
dev: 匹配的设备
propname: 属性的名称
val: 存储获取数据的地址
返回:如果valNULL,成功返回数据的数目,不为NULL0表示成功,其它表示失败。

//例程
adc1: adc@2198000 {
    //...
    fsl,adck-max-frequency = <30000000>, <40000000>,
                <20000000>;
};
device_property_read_u32(dev, "fsl,adck-max-frequency", &info->adck_rate); 

device_property_count_xx

//函数原型
static inline int device_property_count_u8(struct device *dev, const char *propname)
{
    return device_property_read_u8_array(dev, propname, NULL, 0);
}
static inline int device_property_count_u16(struct device *dev, const char *propname)
static inline int device_property_count_u32(struct device *dev, const char *propname)
static inline int device_property_count_u64(struct device *dev, const char *propname)

//参数
dev: 匹配的设备
propname: 属性的名称
返回:正数表示数目,负数表示不存在

//例程
adc1: adc@2198000 {
    //...
    fsl,adck-max-frequency = <30000000>, <40000000>,
                <20000000>;
};
int count = device_property_count_u32(dev, "fsl,adck-max-frequency"); 

copy_from_user

//函数原型
int copy_from_user(void *to, const void __user volatile *from, unsigned long n)

//参数
to:目的地址,内核空间
from: 源地址,用户空间
n:数据长度
返回: 0表示成功,否则返回未拷贝成功的字节数

//例程说明
copy_from_user(&zrange, argp, sizeof(struct blk_zone_range))

copy_to_user

//函数原型
int copy_to_user(void __user volatile *to, const void *from, unsigned long n)

//参数
to:目的地址,用户空间
from: 源地址,内核空间
n:数据长度
返回: 0表示成功,否则返回未拷贝成功的字节数

//例程说明
copy_to_user(cp, &c, 1)

printk

//函数原型
#define printk(fmt, ...) printk_index_wrap(_printk, fmt, ##__VA_ARGS__)

//参数
fmt: 打印的字符串

//例程说明
printk(KERN_EMERG"logger infomation!");

#define KERN_EMERG      KERN_SOH "0"    /* system is unusable */
#define KERN_ALERT      KERN_SOH "1"    /* action must be taken immediately */
#define KERN_CRIT       KERN_SOH "2"    /* critical conditions */
#define KERN_ERR        KERN_SOH "3"    /* error conditions */
#define KERN_WARNING    KERN_SOH "4"    /* warning conditions */
#define KERN_NOTICE     KERN_SOH "5"    /* normal but significant condition */
#define KERN_INFO       KERN_SOH "6"    /* informational */
#define KERN_DEBUG      KERN_SOH "7"    /* debug-level messages */

dev_dbg

//函数原型
#define dev_dbg(dev, fmt, ...)  \
    dev_printk(KERN_DEBUG, dev, dev_fmt(fmt), ##__VA_ARGS__)

//参数
dev:当前所属的身边
fmt: 打印的字符串

//例程说明
dev_dbg(&pdev->dev, "device create success!");

dev_info

//函数原型
#define dev_info(dev, fmt, ...) \
    dev_printk_index_wrap(_dev_info, KERN_INFO, dev, dev_fmt(fmt), ##__VA_ARGS__)

//参数
dev:当前所属的身边
fmt: 打印的字符串

//例程说明
dev_info(&pdev->dev, "device create success!");

dev_warn

//函数原型
#define dev_warn(dev, fmt, ...) \
    dev_printk_index_wrap(_dev_warn, KERN_WARNING, dev, dev_fmt(fmt), ##__VA_ARGS__)

//参数
dev:当前所属的身边
fmt: 打印的字符串

//例程说明
dev_warn(&pdev->dev, "device create success!");

dev_err

//函数原型
#define dev_err(dev, fmt, ...) \
    dev_printk_index_wrap(_dev_err, KERN_ERR, dev, dev_fmt(fmt), ##__VA_ARGS__)

//参数
dev:当前所属的身边
fmt: 打印的字符串

//例程说明
dev_err(&pdev->dev, "device create failed!");

next_chapter

返回目录

直接开始下一节说明: 内核设备树接口