RT-Thread 的设备模型是建立在内核对象模型基础之上的,设备被认为是一类对象,被纳入对象管理器的范畴。每个设备对象都是由基对象派生而来,每个具体设备都可以继承其父类对象的属性,并派生出其私有属性,下图是设备对象的继承和派生关系示意图。
设备对象
```c
struct rt_device
{
struct rt_object parent; /* 内核对象基类 */
enum rt_device_class_type type; /* 设备类型 */
rt_uint16_t flag; /* 设备参数 */
rt_uint16_t open_flag; /* 设备打开标志 */
rt_uint8_t ref_count; /* 设备被引用次数 */
rt_uint8_t device_id; /* 设备 ID,0 - 255 */
/* 数据收发回调函数 */
rt_err_t (*rx_indicate)(rt_device_t dev, rt_size_t size);
rt_err_t (*tx_complete)(rt_device_t dev, void *buffer);
const struct rt_device_ops *ops; /* 设备操作方法 */
/* 设备的私有数据 */
void *user_data;
};
typedef struct rt_device *rt_device_t;
I/O 设备类型
```c
RT_Device_Class_Char /* 字符设备 */
RT_Device_Class_Block /* 块设备 */
RT_Device_Class_NetIf /* 网络接口设备 */
RT_Device_Class_MTD /* 内存设备 */
RT_Device_Class_RTC /* RTC 设备 */
RT_Device_Class_Sound /* 声音设备 */
RT_Device_Class_Graphic /* 图形设备 */
RT_Device_Class_I2CBUS /* I2C 总线设备 */
RT_Device_Class_USBDevice /* USB device 设备 */
RT_Device_Class_USBHost /* USB host 设备 */
RT_Device_Class_SPIBUS /* SPI 总线设备 */
RT_Device_Class_SPIDevice /* SPI 设备 */
RT_Device_Class_SDIO /* SDIO 设备 */
RT_Device_Class_Miscellaneous /* 杂类设备 */
设备控制结构体
struct rt_device_ops
{
/* common device interface */
rt_err_t (*init) (rt_device_t dev);
rt_err_t (*open) (rt_device_t dev, rt_uint16_t oflag);
rt_err_t (*close) (rt_device_t dev);
rt_size_t (*read) (rt_device_t dev, rt_off_t pos, void *buffer, rt_size_t size);
rt_size_t (*write) (rt_device_t dev, rt_off_t pos, const void *buffer, rt_size_t size);
rt_err_t (*control)(rt_device_t dev, int cmd, void *args);
};
驱动创建和注册相关函数原型
//创建
rt_device_t rt_device_create(int type, int attach_size);
//删除/销毁
void rt_device_destroy(rt_device_t device);
//注册
rt_err_t rt_device_register(rt_device_t dev, const char* name, rt_uint8_t flags);
//注销
rt_err_t rt_device_unregister(rt_device_t dev);
//查找
rt_device_t rt_device_find(const char* name);
//打开
rt_err_t rt_device_open(rt_device_t dev, rt_uint16_t oflags);
//关闭
rt_err_t rt_device_close(rt_device_t dev);
//控制
rt_err_t rt_device_control(rt_device_t dev, rt_uint8_t cmd, void* arg);
//读
rt_size_t rt_device_read(rt_device_t dev, rt_off_t pos,void* buffer, rt_size_t size);
//写
rt_size_t rt_device_write(rt_device_t dev, rt_off_t pos,const void* buffer, rt_size_t size);
//数据收发回调
//当硬件设备收到数据时,可以通过如下函数回调另一个函数来设置数据接收指示,通知上层应用线程有数据到达
//收
rt_err_t rt_device_set_rx_indicate(rt_device_t dev, rt_err_t (*rx_ind)(rt_device_t dev,rt_size_t size));
//发
rt_err_t rt_device_set_tx_complete(rt_device_t dev, rt_err_t (*tx_done)(rt_device_t dev,void *buffer));
flags 参数支持下列参数 (可以采用或的方式支持多种参数):
#define RT_DEVICE_FLAG_RDONLY 0x001 /* 只读 */
#define RT_DEVICE_FLAG_WRONLY 0x002 /* 只写 */
#define RT_DEVICE_FLAG_RDWR 0x003 /* 读写 */
#define RT_DEVICE_FLAG_REMOVABLE 0x004 /* 可移除 */
#define RT_DEVICE_FLAG_STANDALONE 0x008 /* 独立 */
#define RT_DEVICE_FLAG_SUSPENDED 0x020 /* 挂起 */
#define RT_DEVICE_FLAG_STREAM 0x040 /* 流模式 */
#define RT_DEVICE_FLAG_INT_RX 0x100 /* 中断接收 */
#define RT_DEVICE_FLAG_DMA_RX 0x200 /* DMA 接收 */
#define RT_DEVICE_FLAG_INT_TX 0x400 /* 中断发送 */
#define RT_DEVICE_FLAG_DMA_TX 0x800 /* DMA 发送 */
oflags (rt_device_open函数)支持以下的参数:
#define RT_DEVICE_OFLAG_CLOSE 0x000 /* 设备已经关闭(内部使用)*/
#define RT_DEVICE_OFLAG_RDONLY 0x001 /* 以只读方式打开设备 */
#define RT_DEVICE_OFLAG_WRONLY 0x002 /* 以只写方式打开设备 */
#define RT_DEVICE_OFLAG_RDWR 0x003 /* 以读写方式打开设备 */
#define RT_DEVICE_OFLAG_OPEN 0x008 /* 设备已经打开(内部使用)*/
#define RT_DEVICE_FLAG_STREAM 0x040 /* 设备以流模式打开 */
#define RT_DEVICE_FLAG_INT_RX 0x100 /* 设备以中断接收模式打开 */
#define RT_DEVICE_FLAG_DMA_RX 0x200 /* 设备以 DMA 接收模式打开 */
#define RT_DEVICE_FLAG_INT_TX 0x400 /* 设备以中断发送模式打开 */
#define RT_DEVICE_FLAG_DMA_TX 0x800 /* 设备以 DMA 发送模式打开 */
rt_device_control函数
参数 cmd 的通用设备命令可取如下宏定义:
#define RT_DEVICE_CTRL_RESUME 0x01 /* 恢复设备 */
#define RT_DEVICE_CTRL_SUSPEND 0x02 /* 挂起设备 */
#define RT_DEVICE_CTRL_CONFIG 0x03 /* 配置设备 */
#define RT_DEVICE_CTRL_SET_INT 0x10 /* 设置中断 */
#define RT_DEVICE_CTRL_CLR_INT 0x11 /* 清中断 */
#define RT_DEVICE_CTRL_GET_INT 0x12 /* 获取中断状态 */
简单设备驱动例程
device.c
//一个简单的rt-thread驱动例程
rt_err_t demo_init(rt_device_t dev)
{
rt_kprintf("demo_init...\n");
return 0;
}
rt_err_t demo_open(rt_device_t dev, rt_uint16_t oflag)
{
rt_kprintf("demo_open...\n");
return 0;
}
rt_err_t demo_close(rt_device_t dev)
{
rt_kprintf("demo_close...\n");
return 0;
}
int rt_demo_init(void)
{
//定义一个rt_device_t指针demo_drv
rt_device_t demo_drv;
//通过rt_device_create函数创建一个驱动
demo_drv=rt_device_create(RT_Device_Class_Char, 32);
//判断驱动是否创建成功
if(demo_drv==RT_NULL)
return -ENOMEM;
//将驱动函数指针传过来
demo_drv->init=demo_init;
demo_drv->close=demo_close;
demo_drv->open=demo_open;
//注册驱动
rt_device_register(demo_drv, "demo", RT_DEVICE_FLAG_RDWR);
return 0;
}
INIT_BOARD_EXPORT(rt_demo_init);
main.c
rt_device_t did;
int main(void)
{
did = rt_device_find("demo");
if(did==RT_NULL)
{
rt_kprintf("device find failed\n");
return -EINVAL;
}
rt_device_init(did);
rt_device_open(did, RT_DEVICE_OFLAG_RDWR);
rt_device_close(did);
return RT_EOK;
}