正常情况下, 我们可以通过module_param()在module相应目录下创建一个文件, 以用作user space与kernel space的交互.
如果需要在/sys/bus/usb/devices/usbx目录下创建相应文件, 则需要用到sysfs_create_group()函数。
// 初始化一个全局变量epStatusErr_default , 即最终在sys目录下产生的属性文件
unsigned epStatusErr_default = 0;
EXPORT_SYMBOL_GPL(epStatusErr_default);
Module_param(epStatusErr_default, int,S_IRUGO|S_IWUSR);
MODULE_PAR_DESC(epStatusErr_default,
“Default USB endpoint status: 0 is ep enough, 1 is not enough”);
// usb_host_epStatusErr_default_show/ usb_host_epStatusErr_default_store对应文件的读/写//操作. 在命令行通过echo向epStatusErr_default写数据将会调用到store, cat命令读数据时//则会调用到show.
static ssize_tusb_host_epStatusErr_default_show(struct device *dev,
struct device_attribute *attr,
char *buf)
{
Return 0;
}
static ssize_tusb_host_epStatusErr_default_store(struct device *dev,
struct device_attribute *attr,
const char*buf, size_t size)
{
Return0;
}
// --------------------
static DEVIC_ATTR(epStatusErr_default,0644,
usb_host_epStatusErr_default_show,
usb_host_epStatusErr_default_store);
static struc attribute *usb_endpoint_status[] = {
&dev_attr_epStatusErr_default.attr,
NULL,
};
Static struct attribute_groupusb_endpoint_status_group={
.name= NULL,
.attrs= usb_endpoint_status,
};
//在初始化时,调用sysfs_create_group()来创建sysfs
Retval = sysfs_create_group(&rhdev->dev.kobj,&usb_endpoint_status_group);
If(retval < 0)
{
printk(KERNEL_ERR“Cannot register USB endpoint status: %d\n”,retval);
gotoerror_create_attr_group;
}
//在退出时,调用sysfs_remove_group()来删除sysfs
Sysfs_remove_group(&rhdev->dev.kobj,&usb_endpoint_status_group);
---------------- cut line -------- chrovery ----------
原以为故事到这里可以结束了, 结果不知道LG的哪个engineer抽风,要求将parameter的路径从 /sys/bus/usb/devices/usb1 换到/sys/bus/usb/devices/1-0:1.0 . 好端端的usb1 / usb2 /usb3路径多好,分别代表controller host 1/2/3 , 简洁不缺详实, 明确不乏生动. 却偏偏要求改到1-0:1.0/ 2-0:1.0 / 3-0:1.0.
只能来看看代表interface的1-0:1.0下面有哪些变量了
shell@android:/sys/bus/usb/devices/1-0:1.0# ls
bAlternateSetting
bInterfaceClass
bInterfaceNumber
bInterfaceProtocol
bInterfaceSubClass
bNumEndpoints
driver
ep_81
modalias
port1
power
subsystem
supports_autosuspend
uevent
对应在如下结构体: usb_interface_descriptor
350 /*USB_DT_INTERFACE: Interface descriptor */
351 struct usb_interface_descriptor{
352 __u8 bLength;
353 __u8 bDescriptorType;
354
355 __u8 bInterfaceNumber;
356 __u8 bAlternateSetting;
357 __u8 bNumEndpoints;
358 __u8 bInterfaceClass;
359 __u8 bInterfaceSubClass;
360 __u8 bInterfaceProtocol;
361 __u8 iInterface;
362 } __attribute__((packed));
363
364 #define USB_DT_INTERFACE_SIZE 9
第一步先在该结构体中增加一个成员变量:
__u8 epStatusErr;
然后在sysfs.c里面添加如下操作
<span style="color: rgb(120, 120, 120);">831 usb_intf_attr(bInterfaceNumber, "%02x\n")
832 usb_intf_attr(bAlternateSetting, "%2d\n")
833 usb_intf_attr(bNumEndpoints, "%02x\n")
834 usb_intf_attr(bInterfaceClass, "%02x\n")
835 usb_intf_attr(bInterfaceSubClass, "%02x\n")
836 usb_intf_attr(bInterfaceProtocol, "%02x\n")
</span><span style="color:#ff0000;">837 usb_intf_attr(epStatusErr, "%02x\n")</span><span style="color:#787878;">
</span>
<span style="color:#787878;">903 static struct attribute *intf_attrs[] = {
904 &dev_attr_bInterfaceNumber.attr,
905 &dev_attr_bAlternateSetting.attr,
906 &dev_attr_bNumEndpoints.attr,
907 &dev_attr_bInterfaceClass.attr,
908 &dev_attr_bInterfaceSubClass.attr,
909 &dev_attr_bInterfaceProtocol.attr,
910 &dev_attr_modalias.attr,
911 &dev_attr_supports_autosuspend.attr,
9xx </span><span style="color:#ff0000;">&dev_attr_epStatusErr.attr,</span><span style="color:#787878;">
912 NULL,
913 };
</span>
这样在1-0:1.0 / 2-0:1.0 / 3-0:1.0目录下就生成了 epStatusErr这个文件了. 当然不仅限于这三个目录下,因为我们所修改的是interfacedescriptor structure, 所以在
/sys/bus/usb/devices目录下有关interface的都会包含该变量.
1-0:1.0 1-1.1.2:1.0 1-1.1.2:1.4 1-1.1:1.0 2-0:1.0 usb3
1-1 1-1.1.2:1.1 1-1.1.2:1.5 1-1.2 3-0:1.0
1-1.1 1-1.1.2:1.2 1-1.1.3 1-1.2:1.0 usb1
1-1.1.2 1-1.1.2:1.3 1-1.1.3:1.0 1-1:1.0 usb2
简要提一下Linux/drivers/usb/core/sysfs.c这个文件, 从目录结构来看, 基本可以断定该文件是用于创建和usb相关的system file.
结构比较简单, usb_intf_attr宏定义了show函数, 通过cat查看该parameter时即调用的该function.
818 /* Interface fields */
819 #define usb_intf_attr(field, format_string) \
820 static ssize_t \
821 show_##field(struct device *dev, struct device_attribute *attr, \
822 char *buf) \
823 { \
824 struct usb_interface *intf = to_usb_interface(dev); \
825 \
826 return sprintf(buf, format_string, \
827 intf->cur_altsetting->desc.field); \
828 } \
829 static DEVICE_ATTR(field, S_IRUGO, show_##field, NULL);
830
831 usb_intf_attr(bInterfaceNumber, "%02x\n")
832 usb_intf_attr(bAlternateSetting, "%2d\n")
833 usb_intf_attr(bNumEndpoints, "%02x\n")
834 usb_intf_attr(bInterfaceClass, "%02x\n")
835 usb_intf_attr(bInterfaceSubClass, "%02x\n")
836 usb_intf_attr(bInterfaceProtocol, "%02x\n")
<span style="color:#ff0000;">837 usb_intf_attr(epStatusErr, "%02x\n")</span>
下一步就是如何给epStatusErr赋值了, 这里所定义的epStatusErr用来表示当前port EP 是否足够, 如果不够则写1, 否则写0. 因此写1的动作放在MGC_CheckFreeEndpoint()
Struct usb_device *parent;
for(parent = dev->parent; parent->parent; parent = parent->parent);
parent->config->interface[0]->cur_altsetting->desc.epStatusErr = 0x1;
首先通过for循环得到root hub的device structure, 然后通过一系列操作将0x1 写到epStatusErr这一个变量.