Linux之访问/dev/hidraw

本文详细介绍了Linux下HIDRAW接口的用途,它用于与USB和Bluetooth的人类交互设备进行原始通信,不依赖于解析器。HIDRAW适用于需要自定义HID设备控制或与非标准设备交互的场景。文章还详细阐述了HIDRAW API的read、write和ioctl函数的用法,并给出了一个简单的HidrawManager类实现示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、HIDRAW overview

HIDRAW -原生的USB 和Bluetooth 人类交互设备
==================================================================

hidraw驱动提供了原生的接口为USB 和Bluetooth 人类交互设备。它与hiddev的不同之处在于,发送和接收的报表没有被hiddev解析器解析,而是从未修改的设备中发送到和接收到的。

如果用户空间应用程序知道怎么恰当和硬件设备通信,和能够手动构建HID 报表,那么hidraw应该被使用。这通常是在用户控件驱动自定义HID 设备的时候。

Hidraw与不符合规范的HID 设备通信也是有利 的,这些设备以一种不符合报表描述符不一致的方式发送和接收数据。因为Hiddev解析器通过他发送和接收报表,检测设备的报表描述符,这样的通信是不可能使用hiddev。Hidraw是唯一的选择,为这些不兼容的设备编写一个定制的内核驱动程序。

Hidraw一个好处是用户空间应用程序使用独立的底层硬件类型。当前,hidraw是通过bluetooth 和 usb实现。在将来,随着硬件总线的发展,hidraw将支持更多的类型。

二、The HIDRAW API

read()

========
read() 将读取从HID 设备接收的报表队列。在USB 设备,使用 read() 读取从设备在 INTERRUPT IN 终端发送的报表。默认的,read()是堵塞的,直到有报表数据可读。read()也可以是非阻塞的,通过在open()参数中设置O_NONBLOCK 标识,或者使用fcntl()设置ononblock标志来进行非阻塞

在使用报表编号的设备上,返回的数据的第一个字节将是报表 ID;报告数据如下,报表数据从第二个字节开始。对于不使用报表编号的设备,报表数据将从第一个byte开始

write()

========
write()函数写入报表到设备。例如USB设备,如果这个设备有一个INTERRUPT OUT 终端,报表将发送到该终端,如果没有,报表将被发送到控制端点,使用SET_REPORT传递

这个传入write()函数的buffer的第一个字节应该是报表id,如果这个设备不使用报表号,那么第一个字节应该设置成0,报表自身应该从第二个字节开始。

ioctl()

=======
Hidraw支持以下ioctls:
HIDIOCGRDESCSIZE:得到报表描述符大小
这个ioctl将得到设备的报表描述符大小

HIDIOCGRDESC:得到报表描述符
这个ioctl返回设备的报表描述符使用一个hidraw_report_descriptor结构体。确保hidraw_report_descriptor 结构体size字段是从HIDIOCGRDESCSIZE返回的size

HIDIOCGRAWINFO:得到原生的信息
这个ioctl将返回一个hidraw_devinfo结构体,包含设备的总线类型、VID和PID。总线类型可以是以下之一:
BUS_USB
BUS_HIL
BUS_BLUETOOTH
BUS_VIRTUAL
定义在uapi/linux/input.h.

HIDIOCGRAWNAME(len):得到原生的名字
这个ioctl返回一个包含设备vendor和produce的字符串。这个字符串是Unicode ,UTF-8编码

HIDIOCGRAWPHYS(len):得到物理地址
这个ioctl返回一个字符串代表设备的物理地址。对于USB设备,字符串包含设备的物理路径(USB控制器、集线器、端口等)。对于蓝牙设备,这个字符串包含硬件(MAC)地址。

HIDIOCSFEATURE(len):发送一个特性报表
这个ioctl发送一个特性报表到设备。根据HID报表说明,特性报表总是使用控制端点发送。将提供的buffer的第一个字节设置为报表号。不使用报表号的报表,将第一个字节设置为0。报表数据从第二个字节开始。确保将len设置为一个比报表更大的长度(要考虑报表的数量)。

HIDIOCGFEATURE(len):
这个ioctl通过从设备的控制端点请求特性报表。应该将提供的buffer的第一个字节设置为请求报表的报表号。对于设备没有报表号,应该设置为0。该报告将从buffer的第一个字节开始返回(即:报告号没有返回)。

三、Example

HidrawManager.h

#ifndef HIDRAW_MANAGER_H
#define  HIDRAW_MANAGER_H
#include <linux/types.h>
#include <sys/types.h>
#include <dirent.h>
#include <string.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/types.h>
#define HIDRAW_DIR              "/dev/"
#define HIDRAW_PATH_SIZE        20
class HidrawManager{
public:
    HidrawManager();
    virtual ~HidrawManager();
    int openHidraw();
    int writeHidraw(char* buf,unsigned int size);
    int readHidraw(char* buf,unsigned int size);
    int closeHidraw();
    bool isSelfHidraw();
private:
    int fd;

};

#endif

HidrawMananger.cpp

#include"HidrawManager.h"

HidrawManager::HidrawManager():fd(-1){
}

HidrawManager::~HidrawManager(){
    closeHidraw();
}
bool HidrawManager::isSelfHidraw(){
    struct hidraw_devinfo raw_info;
    struct hidraw_report_descriptor rep_des;
    int desc_size = 0;

    if(-1 == ioctl(fd, HIDIOCGRAWINFO, &raw_info)){
        return false;
       }

    if(ioctl(fd, HIDIOCGRDESCSIZE, &desc_size) < 0) {
        return false;
    }
      rep_des.size = desc_size;
    if(4096 == raw_info.product && 1546 == raw_info.vendor)//
    {
        return true;
    }
    return false;
}
int HidrawManager::openHidraw(){
    int result=-1;
    DIR *dir = NULL;
       struct dirent *hidraw = NULL;
    char path[HIDRAW_PATH_SIZE];
    dir = opendir(HIDRAW_DIR);
       if(dir == NULL) 
    {
      return -1;
       }
    memset(path,0x00,sizeof(path));
    strcpy(path,HIDRAW_DIR);
    do{
        if(!(hidraw = readdir(dir))){
            goto EXIT;
        }
        if(hidraw!=NULL){
           if(hidraw->d_name == NULL){
                 continue;
             }
             }
        if(!strstr(hidraw->d_name,"hidraw"))
        {
            continue;
        }
        memset(&path[sizeof(HIDRAW_DIR)-1],0x00,sizeof(path)-sizeof(HIDRAW_DIR));
        strcpy(&path[sizeof(HIDRAW_DIR)-1],hidraw->d_name);
        fd=open(path,O_RDWR);
        if(fd<0){
            continue;
        }
        if(isSelfHidraw()){
            result=fd;
        }
    }while(hidraw != NULL);

    EXIT:   
    closedir(dir);

    return result;
}
int HidrawManager::writeHidraw(char* buf,unsigned int size){
    int ret = -1;
    ret = write(fd,buf,size);
    return ret;
}
int HidrawManager::readHidraw(char* buf,unsigned int size){
    int ret = -1;
    ret = read(fd,buf,size);
    return ret;
}

int HidrawManager::closeHidraw(){
    int ret = -1;
    ret = close(fd);
    return ret;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值