Linux那些事儿 之 戏说USB(16)接口是设备的接口(一)

来源:互联网 发布:mysql 表索引 编辑:程序博客网 时间:2024/03/28 23:40
      宋正说天盛是球迷的天盛
      张玉说张玉是导演的张玉
      任小强说房子是人民的房子
前面的前面已经说了,接口是设备的接口。设备可以有多个接口,每个接口代表一个功能,每个接口对应着一个驱动。Linux设备模型的device落实在USB子系统,成了两个结构,一个是struct usb_device,一个是struct usb_interface,一个石头砸了两个坑,一支箭射下来两只麻雀,你说怪不怪。怪不怪还是听听复旦人甲怎么说,一个usb设备,两种功能,一个键盘,上面带一个扬声器,两个接口,那这样肯定得要两个驱动程序,一个是键盘驱动程序,一个是音频流驱动程序。道上的兄弟喜欢把这样两个整合在一起的东西叫做一个设备,那好,让他们去叫吧,我们用interface来区分这两者行了吧。于是有了这里提到的那个数据结构,struct usb_interface。
90 /**
91 * struct usb_interface - what usb device drivers talk to
92 * @altsetting: array of interface structures, one for each alternate
93 *      setting that may be selected. Each one includes a set of
94 *      endpoint configurations. They will be in no particular order.
95 * @num_altsetting: number of altsettings defined.
96 * @cur_altsetting: the current altsetting.
97 * @driver: the USB driver that is bound to this interface.
98 * @minor: the minor number assigned to this interface, if this
99 *      interface is bound to a driver that uses the USB major number.
100 *      If this interface does not use the USB major, this field should
101 *      be unused. The driver should set this value in the probe()
102 *      function of the driver, after it has been assigned a minor
103 *      number from the USB core by calling usb_register_dev().
104 * @condition: binding state of the interface: not bound, binding
105 *      (in probe()), bound to a driver, or unbinding (in disconnect())
106 * @is_active: flag set when the interface is bound and not suspended.
107 * @needs_remote_wakeup: flag set when the driver requires remote-wakeup
108 *      capability during autosuspend.
109 * @dev: driver model's view of this device
110 * @usb_dev: if an interface is bound to the USB major, this will point
111 *      to the sysfs representation for that device.
112 * @pm_usage_cnt: PM usage counter for this interface; autosuspend is not
113 *      allowed unless the counter is 0.
114 *
115 * USB device drivers attach to interfaces on a physical device. Each
116 * interface encapsulates a single high level function, such as feeding
117 * an audio stream to a speaker or reporting a change in a volume control.
118 * Many USB devices only have one interface. The protocol used to talk to
119 * an interface's endpoints can be defined in a usb "class" specification,
120 * or by a product's vendor. The (default) control endpoint is part of
121 * every interface, but is never listed among the interface's descriptors.
122 *
123 * The driver that is bound to the interface can use standard driver model
124 * calls such as dev_get_drvdata() on the dev member of this structure.
125 *
126 * Each interface may have alternate settings. The initial configuration
127 * of a device sets altsetting 0, but the device driver can change
128 * that setting using usb_set_interface(). Alternate settings are often
129 * used to control the use of periodic endpoints, such as by having
130 * different endpoints use different amounts of reserved USB bandwidth.
131 * All standards-conformant USB devices that use isochronous endpoints
132 * will use them in non-default settings.
133 *
134 * The USB specification says that alternate setting numbers must run from
135 * 0 to one less than the total number of alternate settings. But some
136 * devices manage to mess this up, and the structures aren't necessarily
137 * stored in numerical order anyhow. Use usb_altnum_to_altsetting() to
138 * look up an alternate setting in the altsetting array based on its number.
139 */
140 struct usb_interface {
141         /* array of alternate settings for this interface,
142          * stored in no particular order */
143         struct usb_host_interface *altsetting;
144
145         struct usb_host_interface *cur_altsetting;      /* the currently
146                                          * active alternate setting */
147         unsigned num_altsetting;        /* number of alternate settings */
148
149         int minor;                      /* minor number this interface is
150                                          * bound to */
151         enum usb_interface_condition condition;         /* state of binding */
152         unsigned is_active:1;           /* the interface is not suspended */
153         unsigned needs_remote_wakeup:1; /* driver requires remote wakeup */
154
155         struct device dev;              /* interface specific device info */
156         struct device *usb_dev;         /* pointer to the usb class's device, if any */
157         int pm_usage_cnt;               /* usage counter for autosuspend */
158 };
生在红旗下,长在21世纪,我们的责任是重大的,没看那些专家都在慈眉善目忧国忧民的说,房子降价了我方经济要倒退多少年,我辈都是热血青年,好不容易有个报国的窗户,怎么着也得一起扶着房地产这个柱子,上头都说了,这是支柱产业,倒不得。不过,一屋不扫何以扫天下,精忠报国要从看代码开始,那个柱子先让专家们扶着,看代码也并不是容易的事,理解是万岁他爹,各有各的难处。
咱们这里瞅瞅,这么长的结构,猛的一看都要让人华丽丽的摔倒了,不过还好大都是注释,三分之一是海水,三分之二是火焰。话说回来,应该感到庆幸在看的是USB这块的代码,写代码的都比较的勤奋,不厌其烦的写了那么多的注释,当然不是说其它块的开发者不勤奋,因为时间和注释实在是一对不可调和的矛盾。
143行,这里有个altsetting成员,只用耗费一个脑细胞就可以明白它的意思就是alternate setting,可选的设置。那么再耗费一个脑细胞就可以知道145行的cur_altsetting表示当前正在使用的设置,147行的num_altsetting表示这个接口具有可选设置的数量。前面提过过USB设备的配置,那这里的设置是嘛意思?这可不是耗费一两个脑细胞就可以明白的了,不过不要怕,虽然说脑细胞是不可再生资源,但并不是多宝贵的东东,不然咋黄金煤炭的股票都在疯长,就不见人的工资长。
咱们是难得糊涂几千年了,不会去区分配置还有设置有什么区别,起码我平时即使是再无聊也不会去想这个,但老外不一样,他们不知道老子也不知道郑板桥,所以说他们挺较真儿这个,还分了两个词,配置是configuration,设置是setting。先说配置,一个手机可以有多种配置,比如可以摄像,可以接在电脑里当做一个U盘,那么这两种情况就属于不同的配置,在手机里面有相应的选择菜单,你选择了哪种它就按哪种配置进行工作,供你选择的这个就叫做配置。很显然,当你摄像的时候你不可以访问这块U盘,当你访问这块U盘的时候你不可以摄像,因为你做了选择。第二,既然一个配置代表一种不同的功能,那么很显然,不同的配置可能需要的接口就不一样,我假设你的手机里从硬件上来说一共有5个接口,那么可能当你配置成U盘的时候它只需要用到某一个接口,当你配置成摄像的时候,它可能只需要用到另外两个接口,可能你还有别的配置,然后你可能就会用到剩下那两个接口。
再说说设置,一个手机可能各种配置都确定了,是振动还是铃声已经确定了,各种功能都确定了,但是声音的大小还可以变吧,通常手机的音量是一格一格的变动,大概也就5、6格,那么这个可以算一个setting吧。
声明一下,这个手机的例子是复旦人甲举出来的,以后要是哪里再用到复旦人甲的话就不声明了,毕竟大家探索linux背后哲学的决心都是一样的。不过你还是不明白啥是配置啥是设置的话,那我多说一下,就直接用大小关系来理解好了,毕竟大家对互相之间的大小关系都更敏感一些,不要说不是,一群mm走过来的时候,你的眼神已经背叛了你。这么说吧,设备大于配置,配置大于接口,接口大于设置,更准确的说是设备可以有多个配置,配置里可以包含一个或更多的接口,而接口通常又具有一个或更多的设置。
149行,minor,分配给接口的次设备号。地球人都知道,linux下所有的硬件设备都是用文件来表示的,俗称设备文件,在/dev目录下边儿,为了显示自己并不是普通的文件,它们都会有一个主设备号和次设备号,比如
brw-r----- 1 root disk 8, 0 Sep 26 09:17 /dev/sda
brw-r----- 1 root disk 8, 1 Sep 26 09:17 /dev/sda1
crw-r----- 1 root tty 4, 1 Sep 26 09:17 /dev/tty1
这是在我的系统里使用ls –l命令查看的,当然只是显示了其中的几个来表示表示而已。作为改革开放春风沐浴下的新一代年轻人,咱们对数字都是比较敏感的,一眼就能看到,在每一行的日期前面有两个逗号隔开的数字,对于普通文件而言这个位置显示的是文件的长度,而对于设备文件,这里显示的两个数字表示了该设备的主设备号和次设备号。一般来说,主设备号表明了设备的种类,也表明了设备对应着哪个驱动程序,而次设备号则是因为一个驱动程序要支持多个设备而为了让驱动程序区分它们而设置的。也就是说,主设备号用来帮你找到对应的驱动程序,次设备号给你的驱动用来决定对哪个设备进行操作。上面就显示了俺的移动硬盘主设备号为8,系统里tty设备的主设备为4。
设备要想在linux里分得一个主设备号,有个立足之地,也并不是那么容易的,主设备号虽说不是什么特别稀缺的资源,但还是需要设备先在驱动里提出申请,获得系统的批准才能拥有一个。因为一部分的主设备号已经被静态的预先指定给了许多常见的设备,你申请的时候要避开它们,选择一个里面没有列出来的,也就是名花还没有主的,很严肃的说,挖墙角是很不道德的。这些已经被分配掉的主设备号都列在Documentation/devices.txt文件里。当然,如果你是用动态分配的形式,就可以不去理会这些,直接让系统为你作主,替你选择一个即可。
很显然,任何一个有理智有感情的人都会认为USB设备是很常见的,linux理应为它预留了一个主设备号。看看include/linux/usb.h文件
7 #define USB_MAJOR                       180
8 #define USB_DEVICE_MAJOR                189
苏格拉底说过,学的越多,知道的越多,知道的越多,发现需要知道更多。当我们知道了主设备号,满怀激情与向往的来寻找USB的主设备号时,我们却发现这里在上演真假李逵。这两个哪个才是我们苦苦追寻的她?
你可以在内核里搜索它们都曾经出现什么地方,或者就跟随我回到usb_init函数。
880         retval = usb_major_init();
881         if (retval)
882                 goto major_init_failed;
883         retval = usb_register(&usbfs_driver);
884         if (retval)
885                 goto driver_register_failed;
886         retval = usb_devio_init();
887         if (retval)
888                 goto usb_devio_init_failed;
889         retval = usbfs_init();
890         if (retval)
891                 goto fs_init_failed;
前面只提了句883~891是与usbfs相关的就简单的飘过了,这里略微说的多一点。usbfs为咱们提供了在用户空间直接访问usb硬件设备的接口,但是世界上没有免费的午餐,它需要内核的大力支持,usbfs_driver就是用来完成这个光荣任务的。咱们可以去usb_devio_init函数里看一看,它在drivers/usb/devio.c文件里定义
         retval = register_chrdev_region(USB_DEVICE_DEV, USB_DEVICE_MAX,
                          "usb_device");
         if (retval) {
                 err("unable to register minors for usb_device");
                 goto out;
         }
register_chrdev_region函数获得了设备usb_device对应的设备编号,设备usb_device对应的驱动当然就是usbfs_driver,参数USB_DEVICE_DEV也在同一个文件里有定义
         #define USB_DEVICE_DEV             MKDEV(USB_DEVICE_MAJOR, 0)
终于再次见到了USB_DEVICE_MAJOR,也终于明白它是为了usbfs而生,为了让广大人民群众能够在用户空间直接和usb设备通信而生。因此,它并不是我们所要寻找的。
那么答案很明显了,USB_MAJOR就是咱们苦苦追寻的那个她,就是linux为USB设备预留的主设备号。事实上,前面usb_init函数的880行,usb_major_init函数已经使用USB_MAJOR注册了一个字符设备,名字就叫usb。我们可以在文件/proc/devices里看到它们。
localhost:/usr/src/linux/drivers/usb/core # cat /proc/devices
Character devices:
 1 mem
 2 pty
 3 ttyp
 4 /dev/vc/0
 4 tty
 4 ttyS
 5 /dev/tty
 5 /dev/console
 5 /dev/ptmx
 7 vcs
10 misc
13 input
14 sound
29 fb
116 alsa
128 ptm
136 pts
162 raw
180 usb
189 usb_device
/proc/devices文件里显示了所有当前系统里已经分配出去的主设备号,当然上面只是列出了字符设备,Block devices被有意的飘过了。很明显,咱们前面提到的usb_device和usb都在里面。
不过到这里还没完,USB设备有很多种,并不是都会用到这个预留的主设备号。比如俺的移动硬盘显示出来的主设备号就是8,你的摄像头在linux显示的主设备号也绝对不会是这里的USB_MAJOR。坦白的说,咱们经常遇到的大多数usb设备都会与input、video等子系统关联,并不单单只是作为usb设备而存在。如果usb设备没有与其它任何子系统关联,就需要在对应驱动的probe函数里使用usb_register_dev函数来注册并获得主设备号USB_MAJOR,你可以在drivers/usb/misc目录下看到一些例子,drivers/usb/ usb-skeleton.c文件也属于这种。如果usb设备关联了其它子系统,则需要在对应驱动的probe函数里使用相应的注册函数,USB_MAJOR也就该干吗干吗去,用不着它了。比如,usb键盘关联了input子系统,驱动对应drivers/hid/usbhid目录下的usbkbd.c文件,在它的probe函数里可以看到使用了input_register_device来注册一个输入设备。
准确的说,这里的USB设备应该说成USB接口,毕竟一个USB接口才对应着一个USB驱动。当USB接口关联有其它子系统,也就是说不使用USB_MAJOR作为主设备号时,struct usb_interface的字段minor可以简单的忽略。minor只在USB_MAJOR起作用时起作用。
说完了设备号,回到struct usb_interface的151行,condition字段表示接口和驱动的绑定状态,enum usb_interface_condition类型,在include/linux/usb.h里定义
83 enum usb_interface_condition {
84         USB_INTERFACE_UNBOUND = 0,
85         USB_INTERFACE_BINDING,
86         USB_INTERFACE_BOUND,
87         USB_INTERFACE_UNBINDING,
88 };
前面说linux设备模型的时候说了,设备和驱动是相生相依的关系,总线上的每个设备和驱动都在等待着命中的那个她,找到了,执子之手与子偕老,找不到,孤苦伶仃北冰洋。enum usb_interface_condition形象的描绘了这个过程中接口的个中心情,孤苦、期待、幸福、分开,人生又何尝不是如此?
152行,153行与157行都是关于挂起和唤醒的。协议里规定,所有的usb设备都必须支持挂起状态,就是说为了达到节电的目的,当设备在指定的时间内,3ms吧,如果没有发生总线传输,就要进入挂起状态。当它收到一个non-idle的信号时,就会被唤醒。152行is_active表示接口是不是处于挂起状态。153行needs_remote_wakeup表示是否需要打开远程唤醒功能。远程唤醒允许挂起的设备给主机发信号,通知主机它将从挂起状态恢复,注意如果主机处于挂起状态,就会唤醒主机,不然主机仍然在睡着,设备自个醒过来干吗用。协议里并没有要求USB设备一定要实现远程唤醒的功能,即使实现了,从主机这边儿也可以打开或关闭它。157行pm_usage_cnt,pm就是电源管理,usage_cnt就是使用计数,当它为0时,接口允许autosuspend。什么叫autosuspend?用过笔记本吧,曾经拥有过一台DELL,现在正在拥有另一台DELL,好无奈啊,为什么不是小黑或小白?有时合上笔记本后,它会自动进入休眠,这就叫autosuspend。但不是每次都是这样的,就像这里只有当pm_usage_cnt为0时才会允许接口autosuspend。至于这个计数在哪里统计,暂时还是飘过吧。
接下来就剩下155行的struct device dev和156行的struct device *usb_dev,看到struct device没,它们就是linux设备模型里的device嵌在这儿的对象,我们的心中要时时有个模型。不过这么想当然是不正确的,两个里面只有dev才是模型里的device嵌在这儿的,usb_dev则不是。当接口使用USB_MAJOR作为主设备号时,usb_dev才会用到,你找遍整个内核,也只在usb_register_dev和usb_deregister_dev两个函数里能够看到它,usb_dev指向的就是usb_register_dev函数里创建的usb class device。
 
原创粉丝点击