Linux那些事---我是U盘读书pdf笔记(1)

@TOC

Makefile

总体看一下makefile

.drivers/usb/storage/

EXTRA_CFLAGS := -Idrivers/scsi
obj-$(CONFIG_USB_STORAGE) += usb-storage.o
usb-storage-obj-$(CONFIG_USB_STORAGE_DEBUG) += debug.o
usb-storage-obj-$(CONFIG_USB_STORAGE_HP8200e) += shuttle_usbat.o
usb-storage-obj-$(CONFIG_USB_STORAGE_SDDR09) += sddr09.o
''''''
usb-storage-objs := scsiglue.o protocol.o transport.o usb.o \
initializers.o $(usb-storage-obj-y)

Kconfig关键选项
CONFIG_USB_STORAGE它所对应的模块叫 usb-storage,Makefile 中最后一行也说了,

usb-storage-objs := scsiglue.o protocol.o transport.o usb.o \
initializers.o $(usb-storage-obj-y)

只需要关注的文件scsiglue.c,protocol.c,transport.c,usb.c,initializers.c 以及它们同名的.h 头文件
学习方法!!!!!

模块机制

  • LK 2.6要求你编译模块之前,必须先在内核源代码目录下执行make,换言
    之,你必须先配置过内核,执行过 make,然后才能 make 你自己的模块.
  • drivers/usb/storage/usb.c 入口函数usb_stor_init,出口函数usb_stor_exit
    • /core/host/
  • 常见的 host controller有三种,分别叫做 EHCI,UHCI,OHCI,
    *注册: usb_register
    调用这个函数来向 usb core 注册,从而让usb core知道有这么一个设备
    卸载:usb_deregister()

总线结构

include/linux/device.h
** struct bus_type,struct device,struct device_driver**
pci总线,scsi 总线,usb 总线
pci_bus_type,scsi_bus_type,usb_bus_type

  • struct bus_type:重要的成员struct kset drivers 和 struct kset devices.kset和另一个叫做 kobject

总线, 设备, 和驱动( 上)

struct device
{
	struct bus_type *bus;
	strutct device_driver *drvier;
}
struct driver
{
	struct bus_type *bus ;
	 struct list_head devices;
}

**devices 记录的是这个驱动支持的那些设备(复数)
因为一个驱动程序可以支持一个或多个设备
**

device

usb core 的代码会进行整个 usb 系统的初始化,比如申请 struct bus_type
usb_bus_type,然后会扫描 usb 总线,看线上连接了哪些 usb 设备
连了一个 usb 键盘,那么就为它准备一个 struct device

drivers

drivers 链表呢?这个就不用 bus 方面主动了,而该由每一个 driver 本身去 bus 上面登记usb_register

总线, 设备, 和驱动( 下)

老设备:先查设备,后加载驱动
设备开启,总线扫描设备,struct device,完善devices 链表
然后驱动程序注册struct device_drvier,去devices链表上遍历,如果支持这个devices设备, 调用device_bind_driver
现在:热插拔

U盘驱动注册:
retval = usb_register(&usb_storage_driver);
drivers/usb/storage/usb.c

232 struct usb_driver usb_storage_driver = {
233 .owner = THIS_MODULE,
234 .name = "usb-storage",
235 .probe = storage_probe,
236 .disconnect = storage_disconnect,
237 .id_table = storage_usb_ids,
238 };

owner 用来给模块计数的,每个模块都这么用,赋值总是THIS_MODULE???到底是什么用搞清楚
一个模块可以被多个设备共用,才会有模块计数这么一个说法

idtable

const struct usb_device_id *id_table;

97 struct usb_device_id {
98 /* which fields to match against? */
99 __u16 match_flags;
100
101 /* Used for product specific matches; range is inclusive */
102 __u16 idVendor;
103 __u16 idProduct;
104 __u16 bcdDevice_lo;
105 __u16 bcdDevice_hi;
106
107 /* Used for device class matches */
108 __u8 bDeviceClass;
109 __u8 bDeviceSubClass;
110 __u8 bDeviceProtocol;
111
112 /* Used for interface class matches */
113 __u8 bInterfaceClass;
114 __u8 bInterfaceSubClass;
115 __u8 bInterfaceProtocol;
116
117 /* not matched against */
118 kernel_ulong_t driver_info;
119 };

连接probe

int (*probe) (struct usb_interface *intf,const struct usb_device_id *id);
void (*disconnect) (struct usb_interface *intf);

struct usb_device

struct usb_interface
struct usb_device

每一个 device 对应一个 struct device,针对 usb 设备,开发者们设计了一个叫做
struct usb_device
include/linux/usb.h

struct usb_device {
 struct device dev
}

struct device dev前面说的那个属于每个设备的 struct device 结构体变量
U 盘驱动里边并不会直接去处理这个结构体,因为对于一个 U 盘来说,她就是对应这么一个 struct
usb_device 的变量,这个变量由 usb core 负责申请和赋值
记住 struct device dev结构体变量,因为调用 usb core 提供的函数的时候,会把这个变量作为参数传递上去,因为很简单,要和 usb core 交流,
总得让人家知道我们是谁吧,比如后来要调用的一个函数,usb_buffer_alloc,它就需要这个参数.

???这里对于struct device dev和usb_device的关系。。。还是不太懂

struct usb_interface usb协议

usb 协议规定了,每个 usb 设备都得有些基本的元素,称为描述符,有四类描述符是任何一种 usb 设备都得
有的
device descriptor,configuration descriptor,interface descriptor,endpoint
descriptor

当我插入U盘,用cat /proc/scsi/scsi命令看一下的话,"Vendor"那一项显
示的肯定是 Intel
注意使用的命令!!!!why???

  • 关于这几种描述符,usb core 在总线扫描那会就会去读取,会去获得里边的信息
  • device 描述符描述的是整个 device
  • 这个 device 和咱们一直讲的 device 和 driver 那里的
    device 是不一样的.因为一个 usb device 实际上指的是一种宏观上的概念,它可以是一种多功能的设备
    一个键盘,上边带一个扬声器,它们用两个usb接口接到usb hub上去,而device描述符描述的就是这整个
    设备的特点.(???不是一个usb????)
  • configuration 描述符
    一个设备可以有一种或者几种配置
  • 一个interface对应一个usb设备驱动程序
    一个usb设备,两种功能,一个键盘,
    上面带一个扬声器,两个接口,那这样肯定得要两个驱动程序,一个是键盘驱动程序,一个是音频流驱动程序.
    道上的兄弟喜欢把这样两个整合在一起的东西叫做一个设备
    include/linux/usb.h:
115 struct usb_interface {
116 /* array of alternate settings for this interface,
117 * stored in no particular order */
118 struct usb_host_interface *altsetting;
119
120 struct usb_host_interface *cur_altsetting; /* the currently
121 * active alternate setting */
122 unsigned num_altsetting; /* number of alternate settings */
123
124 int minor; /* minor number this interface is bound to */
125 enum usb_interface_condition condition; /* state of binding */
126 struct device dev; /* interface specific device info */
127 struct class_device *class_dev;
128 };
129 #define to_usb_interface(d) container_of(d, struct usb_interface, dev)
130 #define interface_to_usbdev(intf) \
131 container_of(intf->dev.parent, struct usb_device, dev)

整个 U 盘驱动程序在后面任何一处提到的 struct usb_interface 都是同一个变量,这个
变量是在 usb core 总线扫描的时候就申请好了的.直接用
比如前面说过的 storage_probe(struct usb_interface *intf,const struct usb_device_id
*id),storage_disconnect(struct usb_interface *intf)这两个函数中的那个参数 intf

?什么时候申请的?要注意一下?如何用?我定义变量,它申请好带出来???

  • interface_to_usbdev
    struct usb_interface to struct usb_device
endpoint

usb 协议里规定了,usb 设备有四种通信方式,分别是控制传输,中断传输,批量传输,等时传输.
,等时传输显然是用于音频和视频一类的设备,这类设备期望能够有个比较稳定的数据流

虽然说 usb mass storage 的协议里边有一个叫做CBI的传输协议,
CBI就是Control/Bulk/Interrupt,即控制/批量/中断,这三种传输都会
用到,但这种传输协议并不适用于 U 盘

U 盘使用的是一个叫做 Bulk-Only 的传输协议.使用这种
协议的设备只有两种传输方式,一种是批量传输,另一种是控制传输,
ps:控制传输是任何一种 usb 设
备都必须支持的,它专门用于传输一些控制信息.

U盘有两个bulk端点,是因为端点也是有方向的,一个叫
做 Bulk in,一个叫做 Bulk out,

usb 里边所有的数据传输都是有主机发起的

storage_probe()

get_device_info,get_protocol,get_transport,get_pipes. usb_stor_Bulk_man_lun().
drivers/usb/storage/usb.c

926 /* Probe to see if we can drive a newly-connected USB device */
927 static int storage_probe(struct usb_interface *intf,
928 const struct usb_device_id *id)
929 {
930 struct us_data *us;//us 者,usb storage 
931 const int id_index = id - storage_usb_ids;
932 int result;
933
934 US_DEBUGP("USB Mass Storage device detected\n");
935
936 /* Allocate the us_data structure and initialize the mutexes */
937 us = (struct us_data *) kmalloc(sizeof(*us), GFP_KERNEL);
25
938 if (!us) {
939 printk(KERN_WARNING USB_STORAGE "Out of memory\n");
940 return -ENOMEM;
941 }
942 memset(us, 0, sizeof(struct us_data));

注意参数struct usb_interface和struct usb_device_id
这里虽然知道struct usb_interface和struct usb_device_id两个指针来自usb core那一层???

us_data

usb-storage模块里边自己定义的数据结构 us_data
drivers/usb/storage/usb.h:


每一个 device 都有的,换句话说,我们会为每一个 device 申请一个 us_data

debug
54 #ifdef CONFIG_USB_STORAGE_DEBUG
55 void usb_stor_show_command(struct scsi_cmnd *srb);
56 void usb_stor_show_sense( unsigned char key,
57 unsigned char asc, unsigned char ascq );
58 #define US_DEBUGP(x...) printk( KERN_DEBUG USB_STORAGE x )
59 #define US_DEBUGPX(x...) printk( x )
60 #define US_DEBUG(x) x
61 #else
62 #define US_DEBUGP(x...)
63 #define US_DEBUGPX(x...)
64 #define US_DEBUG(x)
65 #endif
66
67 #endif

934 行这个 US_DEBUGP,是一个宏,来自 drivers/usb/storage/debug.h
这些调试信息得是我们打开了编译选项 CONFIG_USB_STORAGE_DEBUG
??如果我不是打开配置项,而是define呢????

设备花名册

继续贴 storage_probe

943 init_MUTEX(&(us->dev_semaphore));
944 init_MUTEX_LOCKED(&(us->sema));
945 init_completion(&(us->notify));
946 init_waitqueue_head(&us->dev_reset_wait);
947 init_waitqueue_head(&us->scsi_scan_wait);
948 init_completion(&us->scsi_scan_done);
949
950 /* Associate the us_data structure with the USB device */
951 result = associate_dev(us, intf);
952 if (result)
953 goto BadDevice;
954
955 /*
956 * Get the unusual_devs entries and the descriptors
957 *
958 * id_index is calculated in the declaration to be the index number
959 * of the match from the usb_device_id table, so we can find the
960 * corresponding entry in the private table.
961 */
962 get_device_info(us, id_index);
id_index

id_index=id-storage_usb_ids,经赋给 usb_storage_driver 的成员 id_table 的值.
storage_usb_ids 同样来自 drivers/usb/storage/usb.c

119 { USB_DEVICE_VER(id_vendor, id_product, bcdDeviceMin,bcdDeviceMax) }
120
121 static struct usb_device_id storage_usb_ids [] = {
122
123 # include "unusual_devs.h"
124 #undef UNUSUAL_DEV
125 /* Control/Bulk transport for all SubClass values */
126 { USB_INTERFACE_INFO(USB_CLASS_MASS_STORAGE, US_SC_RBC,
US_PR_CB) },
127 { USB_INTERFACE_INFO(USB_CLASS_MASS_STORAGE, US_SC_8020,
US_PR_CB) },

USB_INTERFACE_INFO

include/linux/usb.h

473 /**
474 * USB_INTERFACE_INFO - macro used to describe a class of usb interfaces
475 * @cl: bInterfaceClass value
476 * @sc: bInterfaceSubClass value
477 * @pr: bInterfaceProtocol value
478 *
479 * This macro is used to create a struct usb_device_id that matches a
480 * specific class of interfaces.
481 */
482 #define USB_INTERFACE_INFO(cl,sc,pr) \
483 .match_flags = USB_DEVICE_ID_MATCH_INT_INFO, .bInterfaceClass =
(cl), .bInterfaceSubClass = (sc), .bInterfaceProtocol = (pr)

每一个 USB_INTERFACE_INFO 就是构造一个 struct usb_device_id 的结构体变量

struct usb_device_id 的定义,这里实际上就是为其中的四个元素赋了值,它们是
match_flags,bInterfaceClass,bInterfaceSubClass,bInterfaceProtocol.

这里几个id??搞得有点晕

首先每个 Interface 属于一个 Class
,(为什么是把 Interface 分类,而不把 Device 分类?前面讲过了,
在 usb 设备驱动中,不用再提 Device,因为每个设备驱动对应的是一种 Interface,而不是一种 Device)


后Class下面又分了SubClass,完了SubClass下面又按各种设备所遵循的不同的通信协议继续细分

usb协议里边为每一种 Class,每一种 SubClass,每一种 Protocol 定义一个数值
比如 mass storage 的 Class就是0x08,而这里USB_CLASS_MASS_STORAGE这个宏在include/linux/usb_ch9.h中定义,其值正是 8
例子:

{ USB_INTERFACE_INFO(USB_CLASS_MASS_STORAGE, US_SC_RBC, US_PR_CB) },

宏展开,定义了这么一个 usb_device_id 结构体变量
match_flags=USB_DEVICE_ID_MATCH_INT_INFO
bInterfaceClass=USB_CLASS_MASS_STORAGE,
bInterfaceSubClass=US_SC_RBC
bInterfaceProtocol=US_PR_CB.
USB_CLASS_MASS_STORAGE这个驱动程序所支持的每一种设备都是属于这个类,或者说这个 Class.但是这个 Class 里边包含不同的 SubClass,
subclass 02 为 CD-ROM 设备,04 为软盘驱动器,06 为通用 SCSI 类设备.而通信协议则主要有 CBI 协议和 Bulk-Only 协议.

像 US_SC_RBC 这些关于 sub class 的宏的定义是在文件 drivers/usb/storage/protocol.h

47 /* Sub Classes */
48
49 #define US_SC_RBC 0x01 /* Typically, flash devices */
50 #define US_SC_8020 0x02 /* CD-ROM */
51 #define US_SC_QIC 0x03 /* QIC-157 Tapes */
52 #define US_SC_UFI 0x04 /* Floppy */
53 #define US_SC_8070 0x05 /* Removable media */
54 #define US_SC_SCSI 0x06 /* Transparent */
55 #define US_SC_ISD200 0x07 /* ISD200 ATA */

US_PR_CB 这些关于传输协议的宏drivers/usb/storage/transport.h

#define US_PR_CBI 0x00 /* Control/Bulk/Interrupt */
#define US_PR_CB 0x01 /* Control/Bulk w/o interrupt */
#define US_PR_BULK 0x50 /* bulk only *

这个文件中还定义了更多的协议,不过我们暂时只需要知道这三种,因为其她协议都是专门针对一些特殊设
备的
storage_usb_ids 数组中使用宏 USB_INTERFACE_INFO 定义的 usb_device_id 都只是用的
这三种协议.(US_PR_CBI 和 US_PR_CB 这两种协议在 usb 协议中都唤作 CBI,不过之间有点差别.)

usb协议中规定,U盘的Subclass是属于US_SC_SCSI的.而其通信协议使用的是 Bulk-Only

match_flag:USB_INTERFACE_INFO
USB_DEVICE_ID_MATCH_INT_INFO
include/linux/usb.h

435 #define USB_DEVICE_ID_MATCH_INT_INFO \
436 (USB_DEVICE_ID_MATCH_INT_CLASS |
USB_DEVICE_ID_MATCH_INT_SUBCLASS | USB_DEVICE_ID_MATCH_INT_PROTOCOL)

pag31
总共200页,需要

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值