W1:达拉斯的单总线

作者:

David Fries

内核 W1 API 内部

include/linux/w1.h

W1 内核 API 函数。

struct w1_reg_num

分解出的从设备 ID

定义:

struct w1_reg_num {
#if defined(__LITTLE_ENDIAN_BITFIELD);
    __u64 family:8,id:48, crc:8;
#elif defined(__BIG_ENDIAN_BITFIELD);
    __u64 crc:8,id:48, family:8;
#else;
#error "Please fix <asm/byteorder.h>";
#endif;
};

成员

family

标识设备类型

id

与 family 一起是唯一的设备 ID

crc

其他字节的校验和

crc

其他字节的校验和

id

与 family 一起是唯一的设备 ID

family

标识设备类型

struct w1_slave

保存总线上的单个从设备

定义:

struct w1_slave {
    struct module           *owner;
    unsigned char           name[W1_MAXNAMELEN];
    struct list_head        w1_slave_entry;
    struct w1_reg_num       reg_num;
    atomic_t refcnt;
    int ttl;
    unsigned long           flags;
    struct w1_master        *master;
    struct w1_family        *family;
    void *family_data;
    struct device           dev;
    struct device           *hwmon;
};

成员

owner

指向单线 “wire” 内核模块。

name

设备 ID 是 ascii。

w1_slave_entry

链表的数据

reg_num

二进制的从设备 ID

refcnt

引用计数,当为 0 时删除

ttl

每次搜索此从设备未找到时递减,在 0 时分离

flags

W1_SLAVE_ACTIVE W1_SLAVE_DETACH 的位标志

master

此从设备所在的总线

family

设备系列类型的模块

family_data

供系列模块使用的指针

dev

内核设备标识符

hwmon

指向 hwmon 设备的指针

struct w1_bus_master

可在总线主控器上执行的操作

定义:

struct w1_bus_master {
    void *data;
    u8 (*read_bit)(void *);
    void (*write_bit)(void *, u8);
    u8 (*touch_bit)(void *, u8);
    u8 (*read_byte)(void *);
    void (*write_byte)(void *, u8);
    u8 (*read_block)(void *, u8 *, int);
    void (*write_block)(void *, const u8 *, int);
    u8 (*triplet)(void *, u8);
    u8 (*reset_bus)(void *);
    u8 (*set_pullup)(void *, int);
    void (*search)(void *, struct w1_master *, u8, w1_slave_found_callback);
    char *dev_id;
};

成员

data

以下所有函数中的第一个参数

read_bit

采样线路电平并返回读取的电平(0 或 1)

write_bit

设置线路电平

touch_bit

用于真正支持单总线协议的设备的最低级别函数。 touch_bit(0) = write-0 周期 touch_bit(1) = write-1 / read 周期 返回读取的位(0 或 1)

read_byte

读取一个字节。与 8 次 touch_bit(1) 调用相同。返回读取的字节

write_byte

写入一个字节。与 8 次 touch_bit(x) 调用相同。

read_block

与一系列 read_byte() 调用相同 返回读取的字节数

write_block

与一系列 write_byte() 调用相同

triplet

组合两次读取和一个智能写入,用于 ROM 搜索 返回 bit0=Id bit1=comp_id bit2=dir_taken

reset_bus

长时间的 write-0,用于检测存在脉冲 返回 -1=错误,0=设备存在,1=没有设备存在

set_pullup

输出指定时长的强上拉脉冲。返回 -1=错误,0=完成

search

真正优秀的硬件可以处理不同类型的 ROM 搜索,w1_master* 传递给找到的从设备回调。u8 是 search_type,W1_SEARCH 或 W1_ALARM_SEARCH

dev_id

可选的设备 ID 字符串,w1 从设备可以使用它来创建名称,然后建立与 w1 主控器的连接

注意

read_bit 和 write_bit 是非常低级别的函数,只应与不支持真正单总线操作的硬件一起使用,例如并行/串行端口。要么定义 read_bit 和 write_bit,要么至少定义 touch_bit 和 reset_bus。

enum w1_master_flags

w1_master.flags 中使用的位域

常量

W1_ABORT_SEARCH

在关闭时提前中止搜索

W1_WARN_MAX_COUNT

达到最大计数时限制警告

struct w1_master

每个总线主控器一个

定义:

struct w1_master {
    struct list_head        w1_master_entry;
    struct module           *owner;
    unsigned char           name[W1_MAXNAMELEN];
    struct mutex            list_mutex;
    struct list_head        slist;
    struct list_head        async_list;
    int max_slave_count, slave_count;
    unsigned long           attempts;
    int slave_ttl;
    int initialized;
    u32 id;
    int search_count;
    u64 search_id;
    atomic_t refcnt;
    void *priv;
    int enable_pullup;
    int pullup_duration;
    long flags;
    struct task_struct      *thread;
    struct mutex            mutex;
    struct mutex            bus_mutex;
    struct device_driver    *driver;
    struct device           dev;
    struct w1_bus_master    *bus_master;
    u32 seq;
};

成员

w1_master_entry

主控器链表

owner

模块所有者

name

动态分配总线名称

list_mutex

保护 slist 和 async_list

slist

从设备链表

async_list

要执行的 netlink 命令的链表

max_slave_count

一次搜索的最大从设备数量

slave_count

当前已知的从设备数量

attempts

运行的搜索次数

slave_ttl

从设备超时前的搜索次数

initialized

防止初始化/删除竞争条件

id

w1 总线编号

search_count

要运行的自动搜索次数,-1 表示无限制

search_id

允许继续搜索

refcnt

引用计数

priv

私有数据存储

enable_pullup

允许强上拉

pullup_duration

下一次强上拉的时间

flags

w1_master_flags 之一

thread

用于总线搜索和 netlink 命令的线程

mutex

保护大多数 w1_master

bus_mutex

保护并发总线访问

driver

sysfs 驱动程序

dev

sysfs 设备

bus_master

可用的 IO 操作

seq

用于 netlink 广播的序列号

struct w1_family_ops

系列类型的操作

定义:

struct w1_family_ops {
    int (*add_slave)(struct w1_slave *sl);
    void (*remove_slave)(struct w1_slave *sl);
    const struct attribute_group **groups;
    const struct hwmon_chip_info *chip_info;
};

成员

add_slave

add_slave

remove_slave

remove_slave

groups

sysfs 组

chip_info

指向 struct hwmon_chip_info 的指针

struct w1_family

引用计数的系列结构。

定义:

struct w1_family {
    struct list_head        family_entry;
    u8 fid;
    const struct w1_family_ops *fops;
    const struct of_device_id *of_match_table;
    atomic_t refcnt;
};

成员

family_entry

系列链表

fid

8 位系列标识符

fops

此系列的操作

of_match_table

开放固件匹配表

refcnt

引用计数器

module_w1_family

module_w1_family (__w1_family)

用于注册单总线系列的辅助宏

参数

__w1_family

w1_family 结构

描述

用于在模块 init/exit 中不做任何特殊处理的单总线系列的辅助宏。这消除了大量样板代码。每个模块只能使用此宏一次,并且调用它会替换 module_init()module_exit()

drivers/w1/w1.c

W1 核心函数。

执行 ROM 搜索并注册找到的任何设备。

参数

struct w1_master *dev

要搜索的主控器设备

u8 search_type

W1_SEARCH 用于搜索所有设备,或 W1_ALARM_SEARCH 用于仅返回处于报警状态的设备

w1_slave_found_callback cb

找到设备时要调用的函数

描述

单总线搜索是一个简单的二叉树搜索。对于地址的每一位,我们读取两位并写入一位。写入的位将使所有与该位不匹配的设备进入睡眠状态。当两次读取不同时,方向选择是显而易见的。当两位均为 0 时,我们必须选择一条路径。当我们可以扫描所有 64 位而无需选择路径时,我们就完成了。

请参阅 www.maxim-ic.com 上的 “Application note 187 1-wire search algorithm”

int w1_process_callbacks(struct w1_master *dev)

执行每个 dev->async_list 回调条目

参数

struct w1_master *dev

w1_master 设备

描述

必须持有 w1 主控器 list_mutex。

返回

如果存在要执行的命令,则为 1,否则为 0

drivers/w1/w1_family.c

允许注册设备系列操作。

int w1_register_family(struct w1_family *newf)

注册设备系列驱动程序

参数

struct w1_family *newf

要注册的系列

void w1_unregister_family(struct w1_family *fent)

注销设备系列驱动程序

参数

struct w1_family *fent

要注销的系列

drivers/w1/w1_internal.h

用于主控器设备的 W1 内部初始化。

struct w1_async_cmd

从 w1_process kthread 执行回调

定义:

struct w1_async_cmd {
    struct list_head        async_entry;
    void (*cb)(struct w1_master *dev, struct w1_async_cmd *async_cmd);
};

成员

async_entry

链接条目

cb

回调函数,必须在返回之前 list_del 和销毁此列表

描述

当插入到 w1_master async_list 中时,w1_process 将执行回调。将此嵌入到具有命令详细信息的结构中。

drivers/w1/w1_int.c

用于主控器设备的 W1 内部初始化。

int w1_add_master_device(struct w1_bus_master *master)

注册新的主控器设备

参数

struct w1_bus_master *master

要注册的主控器总线设备

void w1_remove_master_device(struct w1_bus_master *bm)

注销主控器设备

参数

struct w1_bus_master *bm

要删除的主控器总线设备

drivers/w1/w1_io.c

W1 输入/输出。

u8 w1_touch_bit(struct w1_master *dev, int bit)

生成一个写 0 或写 1 周期,并采样电平。

参数

struct w1_master *dev

主设备

int bit

0 - 写入 0,1 - 写入 0 并读取电平

void w1_write_8(struct w1_master *dev, u8 byte)

写入 8 位。

参数

struct w1_master *dev

主设备

u8 byte

要写入的字节

u8 w1_triplet(struct w1_master *dev, int bdir)
  • 执行三元组操作 - 用于搜索 ROM 地址。

参数

struct w1_master *dev

主设备

int bdir

如果 id_bit 和 comp_bit 都为 0,则写入该位

描述

返回值

bit 0 = id_bit,bit 1 = comp_bit,bit 2 = dir_taken

如果 bit 0 和 bit 1 都被设置,则应重新启动搜索。

返回

位域 - 请参阅上文

u8 w1_read_8(struct w1_master *dev)

读取 8 位。

参数

struct w1_master *dev

主设备

返回

读取的字节

void w1_write_block(struct w1_master *dev, const u8 *buf, int len)

写入一系列字节。

参数

struct w1_master *dev

主设备

const u8 *buf

指向要写入的数据的指针

int len

要写入的字节数

void w1_touch_block(struct w1_master *dev, u8 *buf, int len)

触摸一系列字节。

参数

struct w1_master *dev

主设备

u8 *buf

指向要写入的数据的指针

int len

要写入的字节数

u8 w1_read_block(struct w1_master *dev, u8 *buf, int len)

读取一系列字节。

参数

struct w1_master *dev

主设备

u8 *buf

指向要填充的缓冲区的指针

int len

要读取的字节数

返回

读取的字节数

int w1_reset_bus(struct w1_master *dev)

发出总线复位序列。

参数

struct w1_master *dev

主设备

返回

0 = 设备存在,1 = 设备不存在或出错

int w1_reset_select_slave(struct w1_slave *sl)

复位并选择从设备

参数

struct w1_slave *sl

要选择的从设备

描述

复位总线,然后通过发送跳过 ROM 命令或匹配 ROM 命令来选择从设备。如果总线上只注册了一个设备,则发送跳过 ROM 命令。必须持有 w1 主设备锁。

返回

0 = 成功,其他任何值 = 错误

int w1_reset_resume_command(struct w1_master *dev)

恢复,而不是另一个匹配 ROM

参数

struct w1_master *dev

主设备

描述

当多个从设备中的一个从设备的工作流程需要几个连续的命令,并且每个命令之间需要复位时,此函数类似于对上次匹配的 ROM 执行复位,然后执行匹配 ROM。优点是跳过了匹配 ROM 步骤,而使用恢复命令。当然,从设备必须支持该命令。

如果总线只有一个从设备,传统上跳过匹配 ROM 并执行 “跳过 ROM” 以提高效率。在多从设备总线上,这当然不起作用,但恢复命令是次好的选择。

必须持有 w1 主设备锁。

void w1_next_pullup(struct w1_master *dev, int delay)

注册强上拉

参数

struct w1_master *dev

主设备

int delay

以毫秒为单位的时间

描述

在下一次写入操作后,输出指定持续时间的强上拉。并非所有硬件都支持强上拉。不支持强上拉的硬件将在写入操作后休眠给定的时间,而没有强上拉。这是下一次写入的单次请求,指定零将清除先前的请求。必须持有 w1 主设备锁。

返回

0 = 成功,其他任何值 = 错误

void w1_write_bit(struct w1_master *dev, int bit)

生成写 0 或写 1 周期。

参数

struct w1_master *dev

主设备

int bit

要写入的位

描述

仅当 dev->bus_master->touch_bit 为 NULL 时才调用

void w1_pre_write(struct w1_master *dev)

写入前操作

参数

struct w1_master *dev

主设备

描述

写入前操作,目前仅支持强上拉。如果已请求强上拉并且硬件支持,则为强上拉配置硬件。

void w1_post_write(struct w1_master *dev)

写入后选项

参数

struct w1_master *dev

主设备

描述

写入后操作,目前仅支持强上拉。如果请求了强上拉,则清除它(如果硬件支持),否则执行延迟。在任何一种情况下,都要清除请求。

u8 w1_read_bit(struct w1_master *dev)

生成写 1 周期,并采样电平。

参数

struct w1_master *dev

主设备

描述

仅当 dev->bus_master->touch_bit 为 NULL 时才调用