usb_debugfs_init
/**
这个函数主要做了一下事情:
在debugfs中创建了一个文件,并指定了操作他的函数。
*/
static int usb_debugfs_init(void)
{
/**
在debugfs文件系统中创建一个目录。
"usb" : 目录的名称
NULL : 这个目录的父目录,如果时NULL,那么就放到debugfs目录下。(目录结构见图1)
*/
usb_debug_root = debugfs_create_dir("usb", NULL);
if (!usb_debug_root)
{
return -ENOENT;
}
/**
在/sys/kernel/debug/usb目录下创建 devices文件节点。权限是 0444 ,
向vfs层提供的接口函数是usbfs_devices_fops中定义的函数
const struct file_operations usbfs_devices_fops = {
.llseek = usb_device_lseek,
.read = usb_device_read,
.poll = usb_device_poll,
};
后面详细分析这些函数
*/
usb_debug_devices = debugfs_create_file("devices", 0444,usb_debug_root, NULL,&usbfs_devices_fops);
if (!usb_debug_devices)
{
debugfs_remove(usb_debug_root); //从debugfs中移除。
usb_debug_root = NULL;
return -ENOENT;
}
return 0;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
图 1
bus_register
/**
注册总线。总线也是一种设备。
这个函数在以前博文中已经说过,请参考我以前的博文
看一下usb总线,注册后会生成两个容器,分别盛放挂接再该总线下所有的驱动、设备。
struct bus_type usb_bus_type = {
.name = "usb",
.match = usb_device_match
.uevent = usb_uevent,
};
下面自己注册一条总线,看一下注册总线时涉及到的重要函数。
实验 见图2
*/
retval = bus_register(&usb_bus_type);
if (retval)
{
goto bus_register_failed;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
bus_register_notifier内核通知链
/**
usb总线通知链的注册。
对于通知链,再上篇电源管理赏析中我们就见过了,再冻结APP、内核线程前会通知各个驱动 再启动app、内核线程之后也会通知各个驱动,
看下面:当设备加入、卸载的时候 也 会发通知。
1 : 设备加入
devic_add()
{
if (dev->bus)
{
blocking_notifier_call_chain(&dev->bus->p->bus_notifier,BUS_NOTIFY_ADD_DEVICE, dev);
{
最终调用:
ret = nb->notifier_call(nb, val, v);
}
}
}
2 : 设备卸载
void device_del()
{
...
blocking_notifier_call_chain(&dev->bus->p->bus_notifier,BUS_NOTIFY_DEL_DEVICE, dev);
}
下面有一个小实验,来验证,见图3、4
*/
int bus_register_notifier(struct bus_type *bus, struct notifier_block *nb)
{
return blocking_notifier_chain_register(&bus->p->bus_notifier, nb);
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
图3:
int usb_major_init(void)
{
int error;
/**
注册一个字符设备。看清楚,**这里是bus**,不是usb_device.一条总线也是一个设备。
#define USB_MAJOR 180 主设备号 180
向vfs层提供的操作函数集合是usb_fops
看一下:
static const struct file_operations usb_fops = {
.owner = THIS_MODULE,
.open = usb_open,
.llseek = noop_llseek,
};
这个和input子系统中提供的及其类似。甚至usb_open 和 input_open的逻辑也是极其类似的。
只是usb_open中对临界区的保护机制使用的是读写锁,input_open使用的是互斥锁。
内核字符设备对于open函数大部分都是这样设计。那么这样设计就是驱动分层的体现吧。
由通用层转入具体设备提供的驱动层。
input_open函数的赏析请见我以前的博文:
http://blog.csdn.net/leesagacious/article/details/50245937
*/
error = register_chrdev(USB_MAJOR, "usb", &usb_fops);
if (error)
{
printk(KERN_ERR "Unable to get major %d for usb devices\n",USB_MAJOR);
}
return error;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
/**
他做了哪些事情呢?很简单,字符设备的基本函数。
1 : register_chrdev_region(USB_DEVICE_DEV, USB_DEVICE_MAX,"usb_device")
2 : cdev_init(&usb_device_cdev, &usbdev_file_operations)
3 : cdev_add(&usb_device_cdev, USB_DEVICE_DEV, USB_DEVICE_MAX)
4 : usb_register_notify(&usbdev_nb);
看一下 向vfs层提供的操作函数集
const struct file_operations usbdev_file_operations = {
.owner = THIS_MODULE,
.llseek = usbdev_lseek,
.read = usbdev_read,
.poll = usbdev_poll,
.unlocked_ioctl = usbdev_ioctl,
#ifdef CONFIG_COMPAT
.compat_ioctl = usbdev_compat_ioctl,
#endif
.open = usbdev_open,
.release = usbdev_release,
};
*/
retval = usb_devio_init();
if (retval)
{
goto usb_devio_init_failed;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
/**
这个函数请见上面的流程图。最终会调用bus_register()
#define usb_register(driver) \
usb_register_driver(driver, THIS_MODULE, KBUILD_MODNAME)
bus_register()这个函数的赏析请见我以前的博文:http://blog.csdn.net/leesagacious/article/details/50200053
*/
retval = usb_register(&usbfs_driver);
if (retval)
{
goto driver_register_failed;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
/**
USB设备文件系统的初始化。
现在你明白了usb设备文件系统是动态产生的了吧。和sys、proc一样都是动态产生的。
看他的实现:
int __init usbfs_init(void)
{
int retval;
retval = register_filesystem(&usb_fs_type);//注册usb设备文件系统
if (retval)
{
return retval;
}
usb_register_notify(&usbfs_nb); //usbfs_notify()函数会被调用。
usbdir = proc_mkdir("bus/usb", NULL); //创建挂载点。
return 0;
}
*/
retval = usbfs_init();
if (retval)
{
goto fs_init_failed;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
/**
hub的初始化。
详细请看我以前的博文:
http://blog.csdn.net/leesagacious/article/details/50506854
主要是注册了一个hub驱动、创建了一个内核守护线程来监测hub端口的状态变化。
*/
retval = usb_hub_init();
if (retval)
{
goto hub_init_failed;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
/**
终于再最后注册了usb_device的driver到usb的核心层了。
注意 : 是 usb设备驱动: usb_device_driver,不是usb_driver(每个接口对应了一个特定的功能,应有专门的驱动来和它沟通)
。
*/
retval = usb_register_device_driver(&usb_generic_driver, THIS_MODULE);
if (!retval)
{
goto out;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
U盘驱动
/**
这是一个内核线程。很重要。
你可能会问:是谁创建了这个内核线程,他的作用是什么?请往下看。
*/
static int usb_stor_control_thread(void * __us)
{
/**
这个内核线程是再函数 :
usb_stor_acquire_resources
{
....
第二个参数是 : us_data
要创建内核线程的信息被组织一个结构体 kthread_create_info 被挂接到 kthread_create_list链表上。
而且 二号进程也被唤醒了,二号进程要从kthread_create_list链表上获取、创建他了。
th = kthread_run(usb_stor_control_thread, us, "usb-storage");
下面是 3.4内核的代码: 相比上面4.1的代码,4.1的一部到位。
下面的wake_up_process(th)激活了他。
th = kthread_create(usb_stor_control_thread, us, "usb-storage");
....
wake_up_process(th);
}
转换成 us_data,这个us_data太重要了,整个架构中都有他的身影。详细分析他每一个成员再框架中的生命历程 放到下面。
*/
struct us_data * us = (struct us_data *)__us;
/**
是把u盘模拟成了一个 SCSI设备。所以再配置内核的时候,要增加对U盘的支持,
而且SCSI也要支持好。
既然底层是依赖SCSI,那么内核已经做了下面的事情:
1 : 为Scsi_host分配内存空间,使用函数 us_to_host()
2 : 添加到SCSI核心层 使用函数 us_add_host()
3 : Scsi_scan_host() 他会扫描添加的设备。
SCSI封装的很好,上层只要一个api就搞定了。
看一下 us_to_host()这个函数,他很重要,
源码的注释是这样说的 :
Convert between us_data and the corresponding Scsi_Host
就是再us_data和 Scsi_Host之间转换。这个函数让USB驱动与SCSI驱动关联了起来。
由us_data 可以获取Scsi_host ,由Scsi_Host可以获取到us_data
下面有一幅配置的图 可供参考。图5
下面还有一幅图来验证这个内核线程创建的流程 图6
*/
struct Scsi_Host *host = us_to_host(us);
/**
死循环。看他什么时候 能跳出来。
*/
for (;;) {
usb_stor_dbg(us, "*** thread sleeping\n");
/**
进程开始休眠。
有可能会从这儿跳出死循环。
看他的参数
&us->cmnd_ready : 是 0。
为什么?
static int storage_probe(struct usb_interface *intf,const struct usb_device_id *id)
{
int usb_stor_probe1(struct us_data **pus,
struct usb_interface *intf,
const struct usb_device_id *id,
struct us_unusual_dev *unusual_dev)
{
struct us_data *us;
....
init_completion(&us->cmnd_ready); 看这里,被初始化了。
init_completion(&(us->notify));
}
}
老版本用的是 信号量,这里用了完成量,那么 谁会调用completion()呢?
往下面看。图7实验验证。
他直接就睡了。
*/
if (wait_for_completion_interruptible(&us->cmnd_ready))
break;
/**
被唤醒后执行的代码
*/
usb_stor_dbg(us, "*** thread awakened\n");
mutex_lock(&(us->dev_mutex));
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
usb3.0的U盘。
下面是插入u盘后的log: 看 storage_probe()被调用了