2023年12月20日发(作者:)

浅析libusb控制接口和mountd守护进程处理uevent切换usb设备的实现

浅析libusb控制接口和mountd守护进程处理uevent切换usb设备的实现

1. UMS mode (USB Mass-Storage mode) [ums]

2. 从usb_gadget_register_driver的实现来看,insmod ,然后重新插拔一下usb cable,那么pc再次枚举到的设备就是insmod 对应的设备了[ttp]

3. init进程没有对change event事件进行处理,mountd守护进程的detect_thread线程会等待该uevent事件到来,然后卸载前一个ko,加载欲成为设备的相应ko驱动[ttp].

4. 其实uevent已经在udc_uevent中将ret数值打入了uevent strings中了MODE=;NET_ENUM=;TESTMODE=;直接解析就可以了,所以就不需要read_usb_switch了[ttp].

5. libusb库链接程序时,可以使用 -static -lusb选项,将libusb静态编译到程序中,这样其他pc就不用单独安装libusb了[ttp].

====================================================================

usb_init=>我的是strncpy(usb_path, "/dev/bus/usb", sizeof(usb_path) -

1);"/dev/bus/usb"或者"/proc/bus/usb"

usb_find_busses=>然后将usb目录下的所有文件目录路径名bus->dirname添加到struct usb_bus *usb_busses = NULL;

链表上,比如:/dev/bus/usb下的001和002目录等.

usb_find_devices=>根据文件目录路径名遍历usb_busses文件夹下的所有文件对应的char节点,如果合法将dev添加bus->devices设备链表上.

同时将char节点的文件路径名作为访问文件节点的路径名存储起来.

//比如打开host控制器的2号hub下插入的第1个设备

//usb_path="/dev/bus/usb"

//dev->bus->dirname="002"

//dev->filename="001"

/* Get the device number */

ret = ioctl(fd, IOCTL_USB_CONNECTINFO, &connectinfo);

ret = read(fd, (void *)device_desc, DEVICE_DESC_LENGTH);

usb_parse_descriptor(device_desc, "bbWbbbbWWWbbbb",

&dev->descriptor);

可以看到我的pc主机usb-host2控制器挂接了4个usb设备,usb-host1控制器挂接了1个设备

luther@gliethttp:~$ tree /dev/bus/usb/

/dev/bus/usb/

|-- 001

| `-- 001

|-- 002

| |-- 001

| |-- 002

| |-- 003

| `-- 004

`-- devices -> .usbfs/devices

luther@gliethttp:~$ ll /dev/bus/usb/002/

total 0

crw-rw-r-- 1 root root 189, 128 2008-10-16 17:30 001

crw-rw-r-- 1 root root 189, 129 2008-10-16 17:30 002

crw-rw-r-- 1 root root 189, 130 2008-10-16 17:30 003

可以看到major都是189,因为是bus2,所以从128开始,一个bus现在最多支持128个usb设备.

//根据pid和vid查找设备是否已经存在

struct usb_device *find_device(int vendor, int product) {

struct usb_bus *bus;

struct usb_device *right_dev;

right_dev = NULL;

for (bus = usb_get_busses(); bus; bus = bus->next) {

struct usb_device *dev;

for (dev = bus->devices; dev; dev = dev->next) {

if (dev->or == vendor &&

dev->uct == product) {

right_dev = dev;

DevicesN++;

}

}

}

return right_dev;

}

然后调用usb_open打开find_device()返回的usb_device设备,

usb_dev_handle *usb_open(struct usb_device *dev)

{

usb_dev_handle *udev;

udev = malloc(sizeof(*udev));

if (!udev)

return NULL;

udev->fd = -1;

udev->device = dev;

udev->bus = dev->bus;

udev->config = udev->interface = udev->altsetting = -1;

if (usb_os_open(udev) < 0) {

free(udev);

return NULL;

}

return udev;

}

int usb_os_open(usb_dev_handle *dev)

{

dev->fd = device_open(dev->device);

return 0;

}

static int device_open(struct usb_device *dev)

{

char filename[PATH_MAX + 1];

int fd;

snprintf(filename, sizeof(filename) - 1, "%s/%s/%s",

usb_path, dev->bus->dirname, dev->filename);

//比如打开host控制器的2号hub下插入的第1个设备

//usb_path="/dev/bus/usb"

//dev->bus->dirname="002"

//dev->filename="001"

fd = open(filename, O_RDWR);

if (fd < 0) {

fd = open(filename, O_RDONLY);

if (fd < 0)

USB_ERROR_STR(-errno, "failed to open %s: %s",

filename, strerror(errno));

}

return fd;

}

====================================================================

链接程序时,可以使用 -static -lusb选项,将libusb静态编译到程序中,这样其他pc就不用单独安装libusb了[ttp].

以下代码摘自libusb-0.1.12

#define USB_MAXDRIVERNAME 255

struct usb_getdriver {

unsigned int interface;

char driver[USB_MAXDRIVERNAME + 1];

};

#define IOCTL_USB_CONTROL _IOWR('U', 0, struct usb_ctrltransfer)

#define IOCTL_USB_BULK _IOWR('U', 2, struct usb_bulktransfer)

#define IOCTL_USB_RESETEP _IOR('U', 3, unsigned int)

#define IOCTL_USB_SETINTF _IOR('U', 4, struct usb_setinterface)

#define IOCTL_USB_SETCONFIG _IOR('U', 5, unsigned int)

#define IOCTL_USB_GETDRIVER _IOW('U', 8, struct usb_getdriver)

#define IOCTL_USB_SUBMITURB _IOR('U', 10, struct usb_urb)

#define IOCTL_USB_DISCARDURB _IO('U', 11)

#define IOCTL_USB_REAPURB _IOW('U', 12, void *)

#define IOCTL_USB_REAPURBNDELAY _IOW('U', 13, void *)

#define IOCTL_USB_CLAIMINTF _IOR('U', 15, unsigned int)

#define IOCTL_USB_RELEASEINTF _IOR('U', 16, unsigned int)

#define IOCTL_USB_CONNECTINFO _IOW('U', 17, struct usb_connectinfo)

#define IOCTL_USB_IOCTL _IOWR('U', 18, struct usb_ioctl)

#define IOCTL_USB_HUB_PORTINFO _IOR('U', 19, struct

usb_hub_portinfo)

#define IOCTL_USB_RESET _IO('U', 20)

#define IOCTL_USB_CLEAR_HALT _IOR('U', 21, unsigned int)

#define IOCTL_USB_DISCONNECT _IO('U', 22)

#define IOCTL_USB_CONNECT _IO('U', 23)

int usb_reset(usb_dev_handle *dev)

{

int ret;

ret = ioctl(dev->fd, IOCTL_USB_RESET, NULL);

if (ret)

USB_ERROR_STR(-errno, "could not reset: %s", strerror(errno));

return 0;

}

int usb_get_driver_np(usb_dev_handle *dev, int interface, char *name,

unsigned int namelen)

{

struct usb_getdriver getdrv;

int ret;

ace = interface;

ret = ioctl(dev->fd, IOCTL_USB_GETDRIVER, &getdrv);

if (ret)

USB_ERROR_STR(-errno, "could not get bound driver: %s",

strerror(errno));

strncpy(name, , namelen - 1);

name[namelen - 1] = 0;

return 0;

}

int usb_detach_kernel_driver_np(usb_dev_handle *dev, int interface)

{

struct usb_ioctl command;

int ret;

= interface;

_code = IOCTL_USB_DISCONNECT;

= NULL;

ret = ioctl(dev->fd, IOCTL_USB_IOCTL, &command);

if (ret)

USB_ERROR_STR(-errno, "could not detach kernel driver from

interface %d: %s",

interface, strerror(errno));

return 0;

}

====================================================================

devh = usb_open(dev);

ret = usb_get_driver_np(devh, 0, buf, sizeof(buf));

ret = usb_detach_kernel_driver_np(devh, 0);//断开设备

ret = usb_claim_interface(devh, 0);//改变一个usb设备的接口,一个接口就是一个独立的功能

ret = usb_set_altinterface(devh, 0);//切换的实际动作并不在这里执行,而是由处理uevent事件的mountd完成[ttp].

ret = usb_bulk_write(devh, endpoint, message, length, 0);

ret = usb_release_interface(devh, 0);

ret = usb_close(devh);

int usb_bulk_write(usb_dev_handle *dev, int ep, char *bytes, int size,

int timeout)

{

/* Ensure the endpoint address is correct */

return usb_urb_transfer(dev, ep, USB_URB_TYPE_BULK, bytes, size,

timeout);

}

=>usb_urb_transfer

=>ret = ioctl(dev->fd, IOCTL_USB_SUBMITURB, &urb);//提交写操作

usb_detach_kernel_driver_np

=>ioctl(dev->fd, IOCTL_USB_IOCTL, &command);

=>kernel中调用usb_driver_release_interface

=>来将dev和driver拆开,同时device_is_registered如果有匹配的driver了=>device_release_driver释放和dev匹配上的driver彼此链表.

int usb_claim_interface(usb_dev_handle *dev, int interface)

{

int ret;

ret = ioctl(dev->fd, IOCTL_USB_CLAIMINTF, &interface);

if (ret < 0) {

if (errno == EBUSY && usb_debug > 0)

fprintf(stderr, "Check that you have permissions to write to %s/%s

and, if you don't, that you set up hotplug

(/) correctly.n",

dev->bus->dirname, dev->device->filename);

USB_ERROR_STR(-errno, "could not claim interface %d: %s", interface,

strerror(errno));

}

dev->interface = interface;

return 0;

}

usb_claim_interface

=>ioctl(dev->fd, IOCTL_USB_CLAIMINTF, &interface);

=>case USBDEVFS_CLAIMINTERFACE:

=>kernel中调用proc_claiminterface来重新设定usb设备的接口,接口信息有usb设备描述符和接口描述符中指定

int usb_set_altinterface(usb_dev_handle *dev, int alternate)

{

int ret;

struct usb_setinterface setintf;

if (dev->interface < 0)

USB_ERROR(-EINVAL);

ace = dev->interface;

ting = alternate;

ret = ioctl(dev->fd, IOCTL_USB_SETINTF, &setintf);

if (ret < 0)

USB_ERROR_STR(-errno, "could not set alt intf %d/%d: %s",

dev->interface, alternate, strerror(errno));

dev->altsetting = alternate;

return 0;

}

usb_set_altinterface

=>ioctl(dev->fd, IOCTL_USB_SETINTF, &setintf);

=>case USBDEVFS_SETINTERFACE:

=>kernel中调用proc_setintf改变kernel中对该usb设备的接口序号和描述符,同时u

sb_control_msg(dev, usb_sndctrlpipe(dev, 0),

USB_REQ_SET_INTERFACE, USB_RECIP_INTERFACE,

alternate, interface, NULL, 0, 5000);

下发数据到usb设备,让设备改变相应接口对应的驱动程序,这样设备当断开usb总线或者hub发送reset复位总线时,usb

设备就会发送指定接口对应的接口描述符下的endpoint端点信息供kernel使用.

====================================================================

include/linux/usbdevice_fs.h

#define USBDEVFS_MAXDRIVERNAME 255

struct usbdevfs_getdriver {

unsigned int interface;

char driver[USBDEVFS_MAXDRIVERNAME + 1];

};

#define USBDEVFS_CONTROL _IOWR('U', 0, struct usbdevfs_ctrltransfer)

#define USBDEVFS_BULK _IOWR('U', 2, struct usbdevfs_bulktransfer)

#define USBDEVFS_RESETEP _IOR('U', 3, unsigned int)

#define USBDEVFS_SETINTERFACE _IOR('U', 4, struct

usbdevfs_setinterface)

#define USBDEVFS_SETCONFIGURATION _IOR('U', 5, unsigned int)

#define USBDEVFS_GETDRIVER _IOW('U', 8, struct usbdevfs_getdriver)

#define USBDEVFS_SUBMITURB _IOR('U', 10, struct usbdevfs_urb)

#define USBDEVFS_SUBMITURB32 _IOR('U', 10, struct usbdevfs_urb32)

#define USBDEVFS_DISCARDURB _IO('U', 11)

#define USBDEVFS_REAPURB _IOW('U', 12, void *)

#define USBDEVFS_REAPURB32 _IOW('U', 12, __u32)

#define USBDEVFS_REAPURBNDELAY _IOW('U', 13, void *)

#define USBDEVFS_REAPURBNDELAY32 _IOW('U', 13, __u32)

#define USBDEVFS_DISCSIGNAL _IOR('U', 14, struct

usbdevfs_disconnectsignal)

#define USBDEVFS_CLAIMINTERFACE _IOR('U', 15, unsigned int)

#define USBDEVFS_RELEASEINTERFACE _IOR('U', 16, unsigned int)

#define USBDEVFS_CONNECTINFO _IOW('U', 17, struct usbdevfs_connectinfo)

#define USBDEVFS_IOCTL _IOWR('U', 18, struct usbdevfs_ioctl)

#define USBDEVFS_IOCTL32 _IOWR('U', 18, struct usbdevfs_ioctl32)

#define USBDEVFS_HUB_PORTINFO _IOR('U', 19, struct

usbdevfs_hub_portinfo)

#define USBDEVFS_RESET _IO('U', 20)

#define USBDEVFS_CLEAR_HALT _IOR('U', 21, unsigned int)

#define USBDEVFS_DISCONNECT _IO('U', 22)

#define USBDEVFS_CONNECT _IO('U', 23)

static int proc_getdriver(struct dev_state *ps, void __user *arg)

{

struct usbdevfs_getdriver gd;

struct usb_interface *intf;

int ret;

if (copy_from_user(&gd, arg, sizeof(gd)))

return -EFAULT;

intf = usb_ifnum_to_if(ps->dev, ace);

if (!intf || !intf->)

ret = -ENODATA;

else {

strncpy(, intf->->name,

sizeof());

ret = (copy_to_user(arg, &gd, sizeof(gd)) ? -EFAULT : 0);

}

return ret;

}

static int usbdev_ioctl(struct inode *inode, struct file *file,

unsigned int cmd, unsigned long arg)

{

struct dev_state *ps = file->private_data;

struct usb_device *dev = ps->dev;

void __user *p = (void __user *)arg;

int ret = -ENOTTY;

if (!(file->f_mode & FMODE_WRITE))

return -EPERM;

usb_lock_device(dev);

if (!connected(ps)) {

usb_unlock_device(dev);

return -ENODEV;

}

switch (cmd) {

case USBDEVFS_CONTROL:

...

}

const struct file_operations usbdev_file_operations = {

.owner = THIS_MODULE,

.llseek = usbdev_lseek,

.read = usbdev_read,

.poll = usbdev_poll,

.ioctl = usbdev_ioctl,

.open = usbdev_open,

.release = usbdev_release,

};

int __init usb_devio_init(void)

{

...

#define USB_DEVICE_DEV MKDEV(USB_DEVICE_MAJOR, 0)

#define USB_MAJOR 180

#define USB_DEVICE_MAJOR 189

#define USB_MAXBUS 64

#define USB_DEVICE_MAX USB_MAXBUS * 128

retval = register_chrdev_region(USB_DEVICE_DEV, USB_DEVICE_MAX,

"usb_device");

cdev_init(&usb_device_cdev, &usbdev_file_operations);

retval = cdev_add(&usb_device_cdev, USB_DEVICE_DEV,

USB_DEVICE_MAX);//添加字符节点到cdev_map

...

}

drivers/usb/core/usb.c

static int __init usb_init(void)

{

...

retval = usb_devio_init();

...

}

subsys_initcall(usb_init);

====================================================================

drivers/usb/gadget/file_storage.c

static int __init fsg_init(void)

{

int rc;

struct fsg_dev *fsg;

if ((rc = fsg_alloc()) != 0)

return rc;

fsg = the_fsg;

if ((rc = usb_gadget_register_driver(&fsg_driver)) != 0)

kref_put(&fsg->ref, fsg_release);

return rc;

}

module_init(fsg_init);

static struct usb_gadget_driver fsg_driver = {

...

.bind = fsg_bind,

...

};

fsg_bind

=>fsg->thread_task = kthread_create(fsg_main_thread, fsg,

"file-storage-gadget");

=>fsg_main_thread

=>do_scsi_command

static int do_scsi_command(struct fsg_dev *fsg)

{

...

#if defined(CONFIG_USB_MODE_SWITCH)

case SC_USB_MODESWITCH:

if(fsg->cmnd[11]==0x35)//switch to usbnet

{

printk(" SC_USB_MODESWITCH: usbnet mode: %dn",

fsg->cmnd[11]);

udc_sysfs_=USB_SWITCH_CMD;

udc_kobject_uevent(&udc_sysfs_data,KOBJ_CHANGE,1);

//init进程没有对change event事件进行处理,mountd守护进程的detect_thread线程会等待该uevent事件到来,然后

//卸载前一个ko,加载欲成为设备的相应ko驱动[ttp].

}

...

}

在使用libusb的应用程序中:

char

net_mode[]="55534243123456780cd6000000";//scsi命令.

将net_mode字符串转为hex之后调用usb_bulk_write(devh, endpoint,

message, length, 0);将转换后的net_mode下发下去.

static ssize_t switch_mode_show(struct device *dev,

struct device_attribute *attr,

char *buf)

{

return sprintf(buf, "%dn", udc_sysfs_);

}

static ssize_t switch_testmode_store(struct device *dev,

struct device_attribute *attr,

const char *buf, size_t count)

{

if(buf[0]=='1') {//input "echo 1 > testmode " in the console will

switch to usbnet mode

udc_sysfs_de=1;//testmode has 2 value, value 0 is

no-usbnet mode,value 1 usbnet mode.

udc_sysfs_=5;//mode=5,inform usbd to switch to usbnet

mode;

kobject_uevent(&udc_dev->kobj, KOBJ_CHANGE);

}

return count;

}

static ssize_t switch_net_show(struct device *dev,

struct device_attribute *attr,

char *buf)

{

return sprintf(buf, "%dn", udc_sysfs__enum);

}

static ssize_t switch_testmode_show(struct device *dev,

struct device_attribute *attr,

char *buf)

{

return sprintf(buf, "%dn", udc_sysfs_de);

}

DEVICE_ATTR(mode, S_IRUGO, switch_mode_show, NULL);

DEVICE_ATTR(net_enum, S_IRUGO, switch_net_show, NULL);

DEVICE_ATTR(testmode, 644, switch_testmode_show,

switch_testmode_store);

static int udc_uevent(struct device *dev, struct kobj_uevent_env *env)

{

if (add_uevent_var(env, "MODE=%d", udc_sysfs_))//传递出去,给mountd守护daemon程序

return -ENOMEM;

if (add_uevent_var(env, "NET_ENUM=%d", udc_sysfs__enum))

return -ENOMEM;

if (add_uevent_var(env, "TESTMODE=%d", udc_sysfs_de))

return -ENOMEM;

return 0;

}

udc_class_init=>udc_class->dev_uevent = udc_uevent;

void udc_kobject_uevent(struct udc_sysfs_data *data,

enum kobject_action action,bool uevent)

{

udc_sysfs_ = data->mode;

udc_sysfs__enum = data->net_enum;

if(data->net_enum!=0)

udc_sysfs_de=1;

else

udc_sysfs_de=0;

if(uevent)

kobject_uevent(&udc_dev->kobj, action);

}

arch/arm/mach-pxa/devices.c

struct platform_device pxa27x_device_udc = {

.name = "pxa27x-udc",

.id = -1,

.resource = pxa2xx_udc_resources,

.num_resources = ARRAY_SIZE(pxa2xx_udc_resources),

.dev = {

.platform_data = &pxa_udc_info,

.dma_mask = &udc_dma_mask,

#ifdef CONFIG_PXA3xx

.coherent_dma_mask = 0xffffffff,

#endif

}

};

drivers/usb/gadget/pxa27x_udc.c

static struct platform_driver udc_driver = {

.driver = {

.name = "pxa27x-udc",

},

.probe = pxa27x_udc_probe,

.remove = __exit_p(pxa27x_udc_remove),

#ifdef CONFIG_PM

/* with accessory detection module, usb client driver does not need

to handle PM */

//.suspend = pxa27x_udc_suspend,

//.resume = pxa27x_udc_resume

#endif

};

配对.

arch/arm/mach-pxa/luther.c

static void __init luther_init(void)

{

...

#if defined(CONFIG_USB_PXA27X_UDC) ||

defined(CONFIG_USB_PXA27X_UDC_MODULE)

if (device_is_enabled(device_udc)) {

pxa_set_udc_info(&luther_udc_info);

}

#endif

...

}

#if defined(CONFIG_USB_PXA27X_UDC) ||

defined(CONFIG_USB_PXA27X_UDC_MODULE)

int luther_udc_is_miniA(void)

{

return 0;

}

static struct pxa2xx_udc_mach_info luther_udc_info = {

.udc_is_miniA = luther_udc_is_miniA,

};

#endif

drivers/usb/gadget/pxa27x_udc.c

=>usb_gadget_register_driver

=>comp_register_driver

=>gadget_info_init(dev, gadget, driver);

=>dev->first_gadget = dev->active_gadget = info;

//从usb_gadget_register_driver的实现来看,insmod ,然后重新插拔一下usb cable,那么pc再次枚举到的设备就是

//insmod 对应的设备了[ttp]

_init [drivers/usb/gadget/file_storage.c]

=>usb_gadget_register_driver(&fsg_driver);

[drivers/usb/gadget/ether.c]

=>usb_gadget_register_driver(ð_driver);

drivers/usb/gadget/ether.c

static int __init init (void)

{

return usb_gadget_register_driver (ð_driver);

}

module_init (init);

drivers/usb/gadget/file_storage.c

static int __init fsg_init(void)

{

int rc;

struct fsg_dev *fsg;

if ((rc = fsg_alloc()) != 0)

return rc;

fsg = the_fsg;

if ((rc = usb_gadget_register_driver(&fsg_driver)) != 0)

kref_put(&fsg->ref, fsg_release);

return rc;

}

module_init(fsg_init);

static struct usb_gadget_driver fsg_driver = {

...

.bind = fsg_bind,

...

};

fsg_setup

=>standard_setup_req

=>将处理USB_REQ_GET_DESCRIPTOR等端点0的描述符请求处理

static int standard_setup_req(struct fsg_dev *fsg,

const struct usb_ctrlrequest *ctrl)

{

...

switch (ctrl->bRequest) {

case USB_REQ_GET_DESCRIPTOR:

if (ctrl->bRequestType != (USB_DIR_IN | USB_TYPE_STANDARD |

USB_RECIP_DEVICE))

break;

switch (w_value >> 8) {

case USB_DT_DEVICE:

VDBG(fsg, "get device descriptorn");

value = sizeof device_desc;

memcpy(req->buf, &device_desc, value);//拷贝设备描述符

break;

case USB_DT_DEVICE_QUALIFIER:

VDBG(fsg, "get device qualifiern");

if (!gadget_is_dualspeed(fsg->gadget))

break;

value = sizeof dev_qualifier;

memcpy(req->buf, &dev_qualifier, value);

break;

case USB_DT_OTHER_SPEED_CONFIG:

VDBG(fsg, "get other-speed config descriptorn");

if (!gadget_is_dualspeed(fsg->gadget))

break;

goto get_config;

case USB_DT_CONFIG:

VDBG(fsg, "get configuration descriptorn");

get_config:

value = populate_config_buf(fsg->gadget,

req->buf,

w_value >> 8,

w_value & 0xff);

break;

case USB_DT_STRING:

VDBG(fsg, "get string descriptorn");

/* wIndex == language code */

value = usb_gadget_get_string(&stringtab,

w_value & 0xff, req->buf);

break;

}

break;

...

}

#define CDC_VENDOR_NUM 0x0525 /* NetChip */

#define CDC_PRODUCT_NUM 0xa4a1 /* Linux-USB Ethernet Gadget

*/

#define DRIVER_VENDOR_ID 0x0525 // NetChip

#define DRIVER_PRODUCT_ID 0xa4a5 // Linux-USB File-backed

Storage Gadget

drivers/usb/gadget/file_storage.c

static struct usb_device_descriptor

device_desc = {

.bLength = sizeof device_desc,

.bDescriptorType = USB_DT_DEVICE,

.bcdUSB = __constant_cpu_to_le16(0x0200),

.bDeviceClass = USB_CLASS_PER_INTERFACE,

/* The next three values can be overridden by module parameters */

.idVendor = __constant_cpu_to_le16(DRIVER_VENDOR_ID),

.idProduct = __constant_cpu_to_le16(DRIVER_PRODUCT_ID),

.bcdDevice = __constant_cpu_to_le16(0xffff),

.iManufacturer = STRING_MANUFACTURER,

.iProduct = STRING_PRODUCT,

.iSerialNumber = STRING_SERIAL,

.bNumConfigurations = 1,

};

drivers/usb/gadget/ether.c

static struct usb_device_descriptor

device_desc = {

.bLength = sizeof device_desc,

.bDescriptorType = USB_DT_DEVICE,

.bcdUSB = __constant_cpu_to_le16 (0x0200),

.bDeviceClass = USB_CLASS_COMM,

#ifndef CONFIG_USB_COMPOSITE

.bDeviceSubClass = 0,

#else

.bDeviceSubClass = USB_CDC_SUBCLASS_ETHERNET,

#endif

.bDeviceProtocol = 0,

.idVendor = __constant_cpu_to_le16 (CDC_VENDOR_NUM),

.idProduct = __constant_cpu_to_le16 (CDC_PRODUCT_NUM),

.iManufacturer = STRING_MANUFACTURER,

.iProduct = STRING_PRODUCT,

.bNumConfigurations = 1,

};

====================================================================

/system/bin/mountd就是mountd守护daemon程序.

system/bin/78| sock_fd = socket(PF_NETLINK,

SOCK_RAW, NETLINK_KOBJECT_UEVENT);

system/bin/638| fd = socket(PF_NETLINK, SOCK_DGRAM,

NETLINK_KOBJECT_UEVENT);

system/bin/mountd/mountd.c

int main(int argc, char* argv[])

{

const char* configPath = "/system/etc/";

int i;

for (i = 1; i < argc; i++) {

const char* arg = argv[i];

if (strcmp(arg, "-f") == 0) {

if (i < argc - 1)

configPath = argv[++i];

}

}

ReadConfigFile(configPath);

StartAutoMounter();

start_detect_server();

return RunServer();

}

start_detect_server

=>pthread_create(&detect_pid, NULL, detect_thread, NULL);

=>detect_thread

=>sock_fd = socket(PF_NETLINK, SOCK_RAW, NETLINK_KOBJECT_UEVENT);

static void* detect_thread(void* arg)

{

...

is_test_mode();

...

if (0 == strncmp(((char *)usb_msghdr), USB_SWITCH_MSG,

strlen(USB_SWITCH_MSG))) {

ums2net_or_serial();//收到改变的uevent

}

...

}

static int is_test_mode(void)

{

usb_premode = parse_feature_conf();

switch (usb_premode) {

case TEST_MODE:

for (i = 0;i < TRY_NUM;i++) {

//尝试最大次数TRY_NUM

//在测试期间,所以默认加载g_模块[ttp]

if ((status = system("insmod

/system/lib/modules/g_") < 0)) {

LOG_ERROR("USB_DETECT: insmod g_

error!n");

continue;

} else {

usb_drv_state = NET_DRV;

break;

}

}

break;

case UMS_MODE:

break;

case NET_MODE:

break;

case SERIAL_MODE:

break;

default:

break;

}

return usb_premode;

}

#define FEATURE_CONF_DATA "/data/etc/"

#define FEATURE_CONF_SYSTEM "/system/etc/"

static int parse_feature_conf(void)

{

...

fp = fopen(FEATURE_CONF_DATA, "r");

buf = (char*) malloc(1024);

memset(buf, 0, 1024);

fread(buf, 1, 1020, fp);

if (strstr(buf, "tc_mod")) {

ret = TEST_MODE;

} else if (strstr(buf, "ums_mod")) {

ret = UMS_MODE;

} else if (strstr(buf, "net_mod")) {

ret = NET_MODE;

} else if (strstr(buf, "serial_mod")) {

ret = SERIAL_MODE;

} else {

ret = -1;

}

...

}

static int ums2net_or_serial(void)

{

...

ret = read_usb_switch();//其实uevent已经在udc_uevent中将ret数值打入了uevent strings中了

//MODE=;NET_ENUM=;TESTMODE=;直接解析就可以了,所以就可以不用调用read_usb_switch了[ttp].

...

if (UMS_DRV == usb_drv_state) {

...

system("/telephony/bin/busybox rmmod g_file_");//因为改变之前是驱动,所以先rmmod卸载掉它

...

}

...

if (UMS2NET == ret) {

...

system("insmod /system/lib/modules/g_");//欲切换到ethernet功能,所以insmod插入它的驱动.

...

}

...

if (UMS2SERIAL == ret) {

...

system("/telephony/bin/busybox insmod

/system/lib/modules/g_ use_acm=1");//欲切换到serial串口功能.

...

}

...

}

#define USB_SWITCH_MODE "/sys/class/udc/pxa27x_udc/mode"

static int read_usb_switch(void)

{

int usb_switch_mode;

int fd = 0;

fd = open(USB_SWITCH_MODE, O_RDONLY);//调用switch_mode_show读取

数据

//调用驱动中的注册的属性文件,对应的方法

//DEVICE_ATTR(mode, S_IRUGO, switch_mode_show, NULL);

//DEVICE_ATTR(net_enum, S_IRUGO, switch_net_show, NULL);

//DEVICE_ATTR(testmode, 644, switch_testmode_show,

switch_testmode_store);

if (fd < 0) {

LOG_ERROR("USB_DETECT: cannot open sys file %s!n",

USB_SWITCH_MODE);

return -1;

}

read(fd, ((void *)&usb_switch_mode), sizeof(int)); //read sys

interface

usb_switch_mode -= 0x30; //ascii to int

LOG_MOUNT("USB_DETECT: switched mode is '%d'n", usb_switch_mode);

close(fd);

return usb_switch_mode;

}

StartAutoMounter

=>pthread_create(&sAutoMountThread, NULL, AutoMountThread, NULL);

=>AutoMountThread

=>CreateUEventSocket

=>fd = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_KOBJECT_UEVENT);