昨天博文《linux下无线鼠标驱动执行流程》中有一行输出信息很让我迷惑,如下所示:

[ 3597.864715] generic-usb :1D57:0016.0006: input,hidraw2: USB HID v1. Mouse [HID Wireless Mouse HID Wireless Mouse] on usb-::1d.-1.2/input0

该行信息中最后 "input,hidraw2: USB HID v1.10 Mouse [HID Wireless Mouse HID Wireless Mouse] on usb-0000:00:1d.7-1.2/input0"这一部分内容

对应hid_info的第二个参数(位于drivers/hid/hid-core.c):

hid_info(hdev, "%s: %s HID v%x.%02x %s [%s] on %s\n", buf, bus, hdev->version >> , hdev->version & 0xff, type, hdev->name, hdev->phys)

但是该行前面的"generic-usb 0003:1D57:0016.0006:"却不知道是从哪儿生成的,因此我想追踪一下hid_info函数的执行过程。

hid_info定义如下(include/linux/hid.h):

#define hid_info(hid, fmt, arg...)            \
dev_info(&(hid)->dev, fmt, ##arg)

而dev_info函数定义如下(include/linux/device.h):

#define dev_info(dev, fmt, arg...) _dev_info(dev, fmt, ##arg)

_dev_info函数定义如下(drivers/base/core.c):

#ifdef CONFIG_PRINTK

int __dev_printk(const char *level, const struct device *dev,
struct va_format *vaf)
{
if (!dev)
return printk("%s(NULL device *): %pV", level, vaf); return printk("%s%s %s: %pV",
level, dev_driver_string(dev), dev_name(dev), vaf);
}
EXPORT_SYMBOL(__dev_printk); int dev_printk(const char *level, const struct device *dev,
const char *fmt, ...)
{
struct va_format vaf;
va_list args;
int r; va_start(args, fmt); vaf.fmt = fmt;
vaf.va = &args; r = __dev_printk(level, dev, &vaf);
va_end(args); return r;
}
EXPORT_SYMBOL(dev_printk); #define define_dev_printk_level(func, kern_level) \
int func(const struct device *dev, const char *fmt, ...) \
{ \
struct va_format vaf; \
va_list args; \
int r; \
\
va_start(args, fmt); \
\
vaf.fmt = fmt; \
vaf.va = &args; \
\
r = __dev_printk(kern_level, dev, &vaf); \
va_end(args); \
\
return r; \
} \
EXPORT_SYMBOL(func); define_dev_printk_level(dev_emerg, KERN_EMERG);
define_dev_printk_level(dev_alert, KERN_ALERT);
define_dev_printk_level(dev_crit, KERN_CRIT);
define_dev_printk_level(dev_err, KERN_ERR);
define_dev_printk_level(dev_warn, KERN_WARNING);
define_dev_printk_level(dev_notice, KERN_NOTICE);
define_dev_printk_level(_dev_info, KERN_INFO); #endif

上面这部分函数定义只有在定义CONFIG_PRINTK时才有效,需要查看内核配置文件是否有其定义.

查看当前内核配置:

$uname -a
Linux debian 3.2.---pae # SMP Debian 3.2.- i686 GNU/Linux

查看 /boot/config-3.2.0-4-686-pae文件中确实定义了CONFIG_RPINTK:

CONFIG_PRINTK=y

上面的函数定义实际上就是将最终调用下面内容:

printk("%s%s %s: %pV", KERN_INFO, dev_driver_string(dev), dev_name(dev), vaf);

KERN_INFO定义如下(include/linux/printk.h):

#define KERN_INFO    "<6>"    /* informational            */

dev_driver_string定义如下(drivers/base/core.c):

const char *dev_driver_string(const struct device *dev)
{
struct device_driver *drv; /* dev->driver can change to NULL underneath us because of unbinding,
* so be careful about accessing it. dev->bus and dev->class should
* never change once they are set, so they don't need special care.
*/
drv = ACCESS_ONCE(dev->driver);
return drv ? drv->name :
(dev->bus ? dev->bus->name :
(dev->class ? dev->class->name : ""));
}
EXPORT_SYMBOL(dev_driver_string);

dev_name函数定义如下(include/linux/device.h):

static inline const char *dev_name(const struct device *dev)
{
/* Use the init name until the kobject becomes available */
if (dev->init_name)
return dev->init_name; return kobject_name(&dev->kobj);
}

dev_driver_string获取驱动的字符串,最终使用的驱动是usbhid,其定义如下(drivers/hid/usbhid/hid-core.c):

static struct hid_driver hid_usb_driver = {
.name = "generic-usb",
.id_table = hid_usb_table,
};

所以驱动名称就是generic-usb。

而dev_name中则查看其init_name的值是否为空,如果不为空返回init_name,如果为空,则返回其kobj的名称。
此处init_name为空(默认值为NULL,在源代码中也没有找到相关的赋值),所以使用的是kobj的名称。
在函数hid_add_device(drivers/hid/hid-core.c)中有下面的代码:

dev_set_name(&hdev->dev, "%04X:%04X:%04X.%04X", hdev->bus,
hdev->vendor, hdev->product, atomic_inc_return(&id));

该行代码将kobj的值设定成总线、vendor、product以及id连接成的字符串。
从我的前一篇博文中提到vendor和product分别是0x1d57和0x0016,此处使用%04X,那么中间的vendor和product
应该分别是1D57和0016,这与上面的输出信息是一致的。

hid_info函数大致执行流程就这样,但是我还是没弄清楚usbhid和hid模块之间是如何有机联系起来的,等到对usb模块
有了更深入了解后再回头来看二者之间的联系。

hid_info函数分析的更多相关文章

  1. split(),preg_split()与explode()函数分析与介

    split(),preg_split()与explode()函数分析与介 发布时间:2013-06-01 18:32:45   来源:尔玉毕业设计   评论:0 点击:965 split()函数可以实 ...

  2. string函数分析

    string函数分析string函数包含在string.c文件中,经常被C文件使用.1. strcpy函数原型: char* strcpy(char* str1,char* str2);函数功能: 把 ...

  3. start_amboot()函数分析

    一.整体流程 start_amboot()函数是执行完start.S汇编文件后第一个C语言函数,完成的功能自然还是初始化的工作 . 1.全局变量指针r8设定,以及全局变量区清零 2.执行一些类初始化函 ...

  4. uboot的jumptable_init函数分析

    一.函数说明 函数功能:安装系统函数指针 函数位置:common/exports.c 二.函数分析 void jumptable_init (void) { int i; gd->jt = (v ...

  5. Linux-0.11内核源代码分析系列:内存管理get_free_page()函数分析

    Linux-0.11内存管理模块是源码中比較难以理解的部分,如今把笔者个人的理解发表 先发Linux-0.11内核内存管理get_free_page()函数分析 有时间再写其它函数或者文件的:) /* ...

  6. 31.QPainter-rotate()函数分析-文字旋转不倾斜,图片旋转实现等待

    在上章和上上上章: 28.QT-QPainter介绍 30.QT-渐变之QLinearGradient. QConicalGradient.QRadialGradient 学习了QPainter基础绘 ...

  7. 如何验证一个地址可否使用—— MmIsAddressValid函数分析

    又是一篇内核函数分析的博文,我个人觉得Windows的内核是最好的老师,当你想实现一个功能之前可以看看Windows内核是怎么做的,说不定就有灵感呢:) 首先看下官方的注释说明: /*++ Routi ...

  8. STM32F10X固件库函数——串口清状态位函数分析

    STM32F10X固件库函数——串口清状态位函数分析 最近在测试串口热插拔功能的时候,意外发现STM32F10X的串口库函数中,清理串口状态位函数稍稍有点不解.下面是改函数的源码: /******** ...

  9. 常用string函数分析

    string函数分析string函数包含在string.c文件中,经常被C文件使用.1. strcpy函数原型: char* strcpy(char* str1,char* str2);函数功能: 把 ...

随机推荐

  1. c++打印蛇形矩阵

    一个m*n的矩阵里按照下图形式填充,最后形成的矩阵即为蛇形矩阵,下图是m=4, n =5时的蛇形矩阵: 方法一:逐层循环 #include <iostream> using namespa ...

  2. win10 安装anaconda 无法使用pip 报错缺少SSL模块

    在anaconda prompt里可以正常使用pip,普通cmd下activate后也可以使用.但不激活就不行. 解决方法: 是环境变量的问题. 安装anaconda需要添加三个环境变量,而不是只添加 ...

  3. 简洁的BP及RBF神经网络代码

    BP神经网络 function [W,err]=BPTrain(data,label,hiddenlayers,nodes,type) %Train the bp artial nueral net ...

  4. MySQL:习题(单表多条件查询二)

    Sutdent表的定义 字段名 字段描述 数据类型 主键 外键 非空 唯一 自增 Id 学号 INT(10) 是 否 是 是 是 Name 姓名 VARCHAR(20) 否 否 是 否 否 Sex 性 ...

  5. Ubuntu配置apache2.4配置虚拟主机遇到的问题

    update: 偶然看到了 apache的更新说明,直接贴个地址过来吧. http://httpd.apache.org/docs/2.4/upgrading.html 最近想把web开发目录从/va ...

  6. [效果不错] nginx 高并发参数配置及linux内核参数优化,完整的内核优化设置。PHP-FPM高负载解决办法。

    背景:对vps小资源的实践中对,https://justwinit.cn/post/7536/ 的再优化,再实践,再优化,特别是Nginx,PHP,内核: 零)Nginx: error_log /da ...

  7. SpringMVC基于代码的配置方式(零配置,无web.xml)

    基于配置文件的web项目维护起来可能会更方便,可是有时候我们会有一些特殊的需求,比方防止客户胡乱更改配置,这时候我们须要给配置隐藏到代码中. 1.创建一个动态web项目(无需web.xml) 2.右键 ...

  8. 初识Modbus TCP/IP-------------C#编写Modbus TCP客户端程序(二)

    由于感觉上一次写的篇幅过长,所以新开一贴,继续介绍Modbus TCP/IP的初步认识, 书接上回 3).03(0x03)功能码--------读保持寄存器 请求与响应格式 这是一个请求读寄存器108 ...

  9. 【BZOJ3316】JC loves Mkk 分数规划+单调队列

    [BZOJ3316]JC loves Mkk Description Input 第1行,包含三个整数.n,L,R.第2行n个数,代表a[1..n]. Output 仅1行,表示询问答案.如果答案是整 ...

  10. vue组件父子组件之间传递数据

    举个栗子: <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF ...