Шина USB-ядро Linux Контроллер устройства USB3.0 Анализ конфигурации составного устройства USB-гаджета (7)
Шина USB-ядро Linux Контроллер устройства USB3.0 Анализ конфигурации составного устройства USB-гаджета (7)

1. Введение

configfs — это файловая система на базе оперативной памяти, функции которой отличаются от sysfs. Sysfs — это представление объектов ядра, основанное на файловой системе. Хотя некоторые атрибуты позволяют пользователям читать и писать, объекты создаются, регистрируются и уничтожаются в ядре, и ядро ​​контролирует их жизненный цикл. А configfs — это менеджер объектов ядра (или config_items), основанный на файловой системе. config_items явно создается в пространстве пользователя через mkdir и уничтожается с помощью rmdir. Соответствующие атрибуты появятся после mkdir. Эти атрибуты можно изменить в пространстве пользователя. написания, в отличие от sysfs, жизненный цикл этих объектов полностью контролируется пользовательским пространством, а ядру нужно только реагировать на операции в пользовательском пространстве. И configfs, и sysfs могут сосуществовать, но не могут заменять друг друга.

Ранний USB поддерживал только одно гаджет-устройство, и сценарий использования был относительно простым. Позже была добавлена ​​составная структура для поддержки гаджет-устройств с несколькими функциями. Привязка нескольких функций выполняется в ядре. необходимо изменить, он негибкий и неудобный. В Linux версии 3.11 представлены конфигурации USB-гаджетов, основанные на файлах configfs. USB-гаджет configfs повторно реализует уровень составного устройства. Пользователи могут настраивать и комбинировать функции ядра в пользовательском пространстве для гибкого создания составных USB-устройств, что значительно повышает эффективность работы.

2. Как использовать

Следующий скрипт настраивает uac2.0 через configfs USB-гаджета. Перед использованием ядру необходимо включить конфигурации, связанные с UAC2.0. Параметры uac2.0 находятся в файле /sys/kernel/config/usb_gadget/g1/configs/c.1/uac2.0. Можно настроить канал, формат, частоту дискретизации и т. д. Следующий скрипт использует файл. конфигурация по умолчанию.

Язык кода:javascript
копировать
#!/bin/bash
function start_uac2()
{
	# usb_gadget зависит от модуля libcomposite
	modprobe libcomposite
	# Смонтируйте файловую систему конфигурации
	mount -t configfs none /sys/kernel/config

	# Создайте каталог g1 и создайте экземпляр нового шаблона гаджета.
	
	echo "mkdir /sys/kernel/config/usb_gadget/g1"
	mkdir -m 0770 /sys/kernel/config/usb_gadget/g1

	# Установите VendorID, ProductID и номер версии спецификации USB продукта.
	echo "Setting Vendor Product ID's and bcdDevice"
	echo 0x2207 > /sys/kernel/config/usb_gadget/g1/idVendor
	echo 0x0019 > /sys/kernel/config/usb_gadget/g1/idProduct
	# Номер версии устройства
	echo 0x0200 > /sys/kernel/config/usb_gadget/g1/bcdDevice
	# USB 1.1: 0x0110
	# USB 2.0: 0x0200, USB 2.1: 0x0210, USB 2.5: 0x0250
	# USB 3.0: 0x0300, USB 3.1: 0x0310, USB 3.2: 0x0320
	# echo 0x0210 > /sys/kernel/config/usb_gadget/g1/bcdUSB
	
	# Создать экземпляр строк идентификатора разработчика, продукта и серийного номера на английском языке, записанных в ядро.
	echo "Setting English strings"
	mkdir -m 0770 /sys/kernel/config/usb_gadget/g1/strings/0x409
	echo "0123456789ABCDEF" > /sys/kernel/config/usb_gadget/g1/strings/0x409/serialnumber
	echo "rockchip"  > /sys/kernel/config/usb_gadget/g1/strings/0x409/manufacturer
	echo "USB Audio Device"  > /sys/kernel/config/usb_gadget/g1/strings/0x409/product

	# Creating Config
	echo "Creating Config"
	mkdir -m 0770 /sys/kernel/config/usb_gadget/g1/configs/c.1
	mkdir -m 0770 /sys/kernel/config/usb_gadget/g1/configs/c.1/strings/0x409
	echo "uac2" > /sys/kernel/config/usb_gadget/g1/configs/c.1/strings/0x409/configuration
	echo 500 > /sys/kernel/config/usb_gadget/g1/configs/c.1/MaxPower

	 
	# bind functions
	# uac2 need to put before uvc, otherwise uvc + uac2 enumerate failed in win10
	echo "Creating UAC2 gadget functionality : uac2.0"
	mkdir /sys/kernel/config/usb_gadget/g1/functions/uac2.0
	ln -s /sys/kernel/config/usb_gadget/g1/functions/uac2.0 /sys/kernel/config/usb_gadget/g1/configs/c.1

	# Binding USB Device Controller
	echo "Binding USB Device Controller"
	echo fe800000.dwc3 > /sys/kernel/config/usb_gadget/g1/UDC
}

function stop_uac2()
{
	# Disabling the gadget
	echo "Disabling the USB gadget"
	echo "" > /sys/kernel/config/usb_gadget/g1/UDC

	# Remove functions from configurations
	rm /sys/kernel/config/usb_gadget/g1/configs/c.1/uac2.0
	# Remove strings directories in configurations
	rmdir /sys/kernel/config/usb_gadget/g1/configs/c.1/strings/0x409
	# remove the configurations
	rmdir /sys/kernel/config/usb_gadget/g1/configs/c.1

	# Remove functions (function modules are not unloaded, though)
	rmdir /sys/kernel/config/usb_gadget/g1/functions/uac2.0

	# Remove strings directories in the gadget
	rmdir /sys/kernel/config/usb_gadget/g1/strings/0x409

	# finally remove the gadget
	rmdir /sys/kernel/config/usb_gadget/g1
}

usage()
{
    echo "Usage: ./usb-gadget-uac2.sh start|stop"
    echo " options:"
    echo "    start           start uac2.0 gadget"
    echo "    stop            stop uac2.0 gadget"
}

case $1 in
start)
	start_uac2
	;;
stop)
	stop_uac2
	;;
*)
	usage
	exit 1
	;;
esac
exit 0

После выполнения приведенного выше сценария состав файлов в каталоге /sys/kernel/config/usb_gadget/g1/ выглядит следующим образом. Файлы, начинающиеся с b, используются для настройки дескрипторов устройств. Файлы в каталоге функций используются для настройки параметров функционального драйвера.

Язык кода:javascript
копировать
├── bcdDevice
├── bcdUSB
├── bDeviceClass
├── bDeviceProtocol
├── bDeviceSubClass
├── bMaxPacketSize0
├── configs
│   └── c.1
│       ├── bmAttributes
│       ├── MaxPower
│       ├── strings
│       │   └── 0x409
│       │       └── configuration
│       └── uac2.0 -> ../../../../usb_gadget/g1/functions/uac2.0
├── functions
│   └── uac2.0
│       ├── c_chmask      # Маска канала записи, по умолчанию 0x3.
│       ├── c_srate       # Частота дискретизации записи, по умолчанию 64000.
│       ├── c_ssize       # Количество бит, занимаемое одним кадром записи данных, по умолчанию 16 бит.
│       ├── p_chmask      # Маска канала воспроизведения, по умолчанию 0x3
│       ├── p_srate       # Частота дискретизации воспроизведения, по умолчанию 48000.
│       ├── p_ssize       # Биты, занимаемые воспроизведением одного кадра данных, по умолчанию — 16 бит.
│       └── req_number    # Выделить количество запросов USB, по умолчанию 2
├── idProduct
├── idVendor
├── os_desc
│   ├── b_vendor_code
│   ├── qw_sign
│   └── use
├── strings
│   └── 0x409
│       ├── manufacturer
│       ├── product
│       └── serialnumber
└── UDC    # Используется для установки имени привязанного USB-контроллера.

3. Анализ кода

3.1.Инициализация

Функция инициализации модуля конфигурации USB-гаджета — гаджет_cfs_init. После вызова этой функции подсистема будет зарегистрирована в configfs и описана с помощью структуры configfs_subsystem. Подсистемы можно разделить на группы, которые описываются с помощью config_group. В группе есть члены, которые описываются с помощью config_item. USB-гаджет configfs является членом подсистемы configfs. Имя этого элемента — «usb_gadget». Тип элемента описывается config_item_type. Тип элемента содержит функцию инициализации gadgets_ops. Поэтому подсистема configfs USB-гаджета окончательно инициализируется вызовом ignores_make. При загрузке модуля libcomposite.ko в каталоге /sys/kernel/config/ будет создан каталог usb_gadget.

Язык кода:javascript
копировать
[drivers/usb/gadget/configfs.c]
static struct configfs_group_operations gadgets_ops = {
	.make_group     = &gadgets_make,
	.drop_item      = &gadgets_drop,
};

static struct config_item_type gadgets_type = {
	.ct_group_ops   = &gadgets_ops,
	.ct_owner       = THIS_MODULE,
};

static struct configfs_subsystem gadget_subsys = {
	.su_group = {
		.cg_item = {
			.ci_namebuf = "usb_gadget",
			.ci_type = &gadgets_type,
		},
	},
	.su_mutex = __MUTEX_INITIALIZER(gadget_subsys.su_mutex),
};
static int __init gadget_cfs_init(void)
{
	int ret;
	config_group_init(&gadget_subsys.su_group);
	ret = configfs_register_subsystem(&gadget_subsys);
#ifdef CONFIG_USB_CONFIGFS_UEVENT
	android_class = class_create(THIS_MODULE, "android_usb");
	if (IS_ERR(android_class))
		return PTR_ERR(android_class);
#endif
	return ret;
}
module_init(gadget_cfs_init);

Основная работа функции ignore_make заключается в установке структуры данных составного устройства usb_composite_dev и структуры данных составного драйвера устройства usb_composite_driver. Рабочий процесс выглядит следующим образом:

Язык кода:javascript
копировать
[drivers/usb/gadget/configfs.c]
static struct configfs_group_operations gadgets_ops = {
	.make_group     = &gadgets_make,
	.drop_item      = &gadgets_drop,
};

static struct config_item_type gadgets_type = {
	.ct_group_ops   = &gadgets_ops,
	.ct_owner       = THIS_MODULE,
};

static struct configfs_subsystem gadget_subsys = {
	.su_group = {
		.cg_item = {
			.ci_namebuf = "usb_gadget",
			.ci_type = &gadgets_type,
		},
	},
	.su_mutex = __MUTEX_INITIALIZER(gadget_subsys.su_mutex),
};
static int __init gadget_cfs_init(void)
{
	int ret;
	config_group_init(&gadget_subsys.su_group);
	ret = configfs_register_subsystem(&gadget_subsys);
#ifdef CONFIG_USB_CONFIGFS_UEVENT
	android_class = class_create(THIS_MODULE, "android_usb");
	if (IS_ERR(android_class))
		return PTR_ERR(android_class);
#endif
	return ret;
}
module_init(gadget_cfs_init);

Основная работа функции ignore_make заключается в установке структуры данных составного устройства usb_composite_dev и структуры данных составного драйвера устройства usb_composite_driver. Рабочий процесс выглядит следующим образом:

  1. распространять Структура гаджета_info,gi->group.default_groupsэто вторичный указатель,Первый уровень указывает наgi->default_groups,gi->default_groupsэто массив указателей,сохраненоfunctions_group、configs_group、strings_group、os_desc_groupадрес。Таким образом, вы можете пройти``gi->groupнайти всеconfig_group`。
  2. Инициализируйте функции_group, configs_group, strings_group и os_desc_group, и их config_item_type указывает на Function_type, config_desc_type, gadget_strings_strings_type и os_desc_type соответственно, и определяется с помощью макроса USB_CONFIG_STRINGS_LANG.
  3. Инициализировать драйвер составного устройстваструктура данныхusb_composite_driver,использовать USB gadget Когда используется configfs, пользователь может напрямую привязать функциональный драйвер в пользовательском пространстве без необходимости использования функций привязки и отмены привязки, поэтому реализация configfs_do_nothing и configfs_do_nothing пуста. Композитное устройство с приводом usb_gadget_driver указывает на configfs_driver_template. usb_gadget_driver — это мост между функциональным драйвером и драйвером UDC, что очень важно.
  4. Инициализируйте структуру составного устройства datausb_composite_dev и установите дескриптор USB-устройства.
  5. настраиватьgi->groupизconfig_item_typeориентированныйgadget_root_type,usb gadget Когда configfs инициализируется, сначала вызывается гаджет_root_type.
  6. наконец, чтобыconfigfsСистема возвращаетgi->group。Данзай/sys/kernel/configСоздать в каталогеusb_gadgetчас,configfsСистема позвонитgi->groupиgi->group.default_groupsдержатьизconfig_item_type。Также сразу Гаджет Функция calls_make устанавливает гаджет_корневой_тип, функции_тип, config_desc_type, гаджет_строки_строки_тип, os_desc_type.
Язык кода:javascript
копировать
[drivers/usb/gadget/configfs.c]
static struct config_group *gadgets_make(
		struct config_group *group, const char *name)
{
    ......
    /* выделить структуру Структура гаджета_info */
    gi = kzalloc(sizeof(*gi), GFP_KERNEL);
    ......
	/* настраиватьgroup,gadgets_makeв конце концов вернутьсяиздаgi->group */
	gi->group.default_groups = gi->default_groups;
	gi->group.default_groups[0] = &gi->functions_group;
	gi->group.default_groups[1] = &gi->configs_group;
	gi->group.default_groups[2] = &gi->strings_group;
	gi->group.default_groups[3] = &gi->os_desc_group;

    /* Установите groups_group для настройки параметров функционального драйвера. */
	config_group_init_type_name(&gi->functions_group, "functions",
			&functions_type);
    /* Установите configs_group для настройки параметров USB-устройства. */
	config_group_init_type_name(&gi->configs_group, "configs",
			&config_desc_type);
    /* Установите strings_group, настраиваемые параметры строки. */
	config_group_init_type_name(&gi->strings_group, "strings",
			&gadget_strings_strings_type);
    /* Установите os_desc_group для настройки дескриптора операционной системы. */
	config_group_init_type_name(&gi->os_desc_group, "os_desc",
			&os_desc_type);

	/* Инициализировать составной драйвер устройства-usb_composite_driver */
	gi->composite.bind = configfs_do_nothing;    // Реализован как пустой
	gi->composite.unbind = configfs_do_nothing;  // Реализован как пустой
	gi->composite.suspend = NULL;
	gi->composite.resume = NULL;
	gi->composite.max_speed = USB_SPEED_SUPER;   // Поддержка USB3.0

	/* Инициализировать составное устройство-usb_composite_dev */
	composite_init_dev(&gi->cdev);
	/* Установить составной дескриптор устройства */
	gi->cdev.desc.bLength = USB_DT_DEVICE_SIZE;
	gi->cdev.desc.bDescriptorType = USB_DT_DEVICE;
	gi->cdev.desc.bcdDevice = cpu_to_le16(get_default_bcdDevice());

	/* Установите usb_gadget_driver в configfs */
	gi->composite.gadget_driver = configfs_driver_template;
	gi->composite.gadget_driver.function = kstrdup(name, GFP_KERNEL);
	gi->composite.name = gi->composite.gadget_driver.function;

	/* Установить config_group */
	config_group_init_type_name(&gi->group, name,
				&gadget_root_type);
	/* КconfigfsСистема возвращает&gi->group */
	return &gi->group;
}
/* usb gadget usb_gadget_driver определяется configfs */
static const struct usb_gadget_driver configfs_driver_template = {
	.bind           = configfs_composite_bind,
	.unbind         = configfs_composite_unbind,
#ifdef CONFIG_USB_CONFIGFS_UEVENT
	.setup          = android_setup,
	.reset          = android_disconnect,
	.disconnect     = android_disconnect,
#else
	.setup          = composite_setup,
	.reset          = composite_disconnect,
	.disconnect     = composite_disconnect,
#endif
	.suspend	    = composite_suspend,
	.resume		    = composite_resume,

	.max_speed	    = USB_SPEED_SUPER,
	.driver = {
		.owner      = THIS_MODULE,
		.name		= "configfs-gadget",
	},
};

Ниже приведены несколько операций config_item_type и configfs_group_operations, определенных конфигурациями USB-гаджетов. Когда новый экземпляр гаджета (g1) создается в каталоге /sys/kernel/config/usb_gadget/, сначала вызывается ignore_root_type для создания bDeviceClass, bDeviceSubClass, bDeviceProtocol, bMaxPacketSize0, idVendor, idProduct, bcdDevice, bcdUSB, файла свойств UDC, пользователей. можно настроить его в пользовательском пространстве ; Затем вызовите function_type для создания каталога функций в каталоге g1. После привязки функционального драйвера файл свойств функционального драйвера будет экспортирован в этот каталог для изменения пользователем, затем вызовите config_desc_type для создания каталога конфигураций в каталоге g1; затем вызовите гаджет_strings_strings_type, создайте каталог строк в каталоге g1, который содержит такую ​​информацию, как английский идентификатор, представленный строками, разработчиком, продуктом и серийным номером. Наконец, вызовите os_desc_type, чтобы создать каталог os_desc в каталоге g1, который содержит информацию об операционной системе и обычно не требует установки.

Язык кода:javascript
копировать
[drivers/usb/gadget/configfs.c]
static struct configfs_attribute *gadget_root_attrs[] = {
	&gadget_dev_desc_attr_bDeviceClass,
	&gadget_dev_desc_attr_bDeviceSubClass,
	&gadget_dev_desc_attr_bDeviceProtocol,
	&gadget_dev_desc_attr_bMaxPacketSize0,
	&gadget_dev_desc_attr_idVendor,
	&gadget_dev_desc_attr_idProduct,
	&gadget_dev_desc_attr_bcdDevice,
	&gadget_dev_desc_attr_bcdUSB,
	&gadget_dev_desc_attr_UDC,
	NULL,
};
static struct config_item_type gadget_root_type = {
	.ct_item_ops	= &gadget_root_item_ops,
	.ct_attrs	= gadget_root_attrs,
	.ct_owner	= THIS_MODULE,
};


static struct configfs_group_operations functions_ops = {
	.make_group     = &function_make,
	.drop_item      = &function_drop,
};
static struct config_item_type functions_type = {
	.ct_group_ops   = &functions_ops,
	.ct_owner       = THIS_MODULE,
};


static struct configfs_group_operations config_desc_ops = {
	.make_group     = &config_desc_make,
	.drop_item      = &config_desc_drop,
};
static struct config_item_type config_desc_type = {
	.ct_group_ops   = &config_desc_ops,
	.ct_owner       = THIS_MODULE,
};


/* Макрос, определяющий gadget_strings_strings_type */
USB_CONFIG_STRINGS_LANG(gadget_strings, gadget_info);
[include/linux/usb/gadget_configfs.h]
#define USB_CONFIG_STRINGS_LANG(struct_in, struct_member)	\
	......                                                   \
static struct configfs_group_operations struct_in##_strings_ops = {	\
	.make_group     = &struct_in##_strings_make,			\
	.drop_item      = &struct_in##_strings_drop,			\
};									\
									\
static struct config_item_type struct_in##_strings_type = {		\
	.ct_group_ops   = &struct_in##_strings_ops,			\
	.ct_owner       = THIS_MODULE,					\
}


static struct configfs_item_operations os_desc_ops = {
	.release        = os_desc_attr_release,
	.allow_link		= os_desc_link,
	.drop_link		= os_desc_unlink,
};
static struct config_item_type os_desc_type = {
	.ct_item_ops	= &os_desc_ops,
	.ct_attrs	= os_desc_attrs,
	.ct_owner	= THIS_MODULE,
};

3.2. Основной анализ процесса вызова.

Следующее объединяет сценарий настройки пользовательского пространства uac2.0 и код configfs USB-гаджета в ядре для анализа того, что происходит в ядре при настройке пользовательского пространства. Сосредоточьтесь на процессах выполнения, связанных с драйверами.

3.2.1.Создать конфигурацию

Когда команда mkdir -m 0770 /sys/kernel/config/usb_gadget/g1/configs/c.1 выполняется в пространстве пользователя, будет вызвана функция config_desc_make из configfs. Основной рабочий процесс:

  1. Выделите структуру config_usb_cfg1, которая содержит структуру usb_configuration и сохраняет информацию о конфигурации USB-устройства.
  2. Устанавливает определенные параметры дескриптора конфигурации USB-устройства. Например, bConfigurationValue (устанавливается в соответствии с именем созданного каталога конфигурации, например c.1, имеет значение 1), MaxPower, bmAttributes.
  3. Экспортируйте файл свойств конфигурации в пространство пользователя, чтобы упростить настройку пользователя.
  4. Вызовите функцию usb_add_config_only, чтобы повесить конфигурацию в список конфигураций usb_composite_dev.
3.2.2. Получить экземпляр функции.

Как упоминалось ранее, функциональный драйвер имеет две важные структуры данных: usb_function_instance и usb_function. Ниже приведен процесс получения usb_function_instance. Как показано на рисунке ниже, когда в пользовательском пространстве выполняется mkdir /sys/kernel/config/usb_gadget/g1/functions/uac2.0, ядро ​​вызывает функцию function_make из конфигурации USB-гаджета. Основная задача функции function_make — это. для получения данных usb_function_instance функционального драйвера. Структура и процесс выполнения следующие:

  1. Вызовите функцию usb_get_function_instance API функций гаджета, просмотрите связанный список func_list и сопоставьте его по имени. Если в пользовательском пространстве введено значение uac2, оно будет соответствовать драйверу uac2. Он определен в файле f_uac2.c.
  2. Если совпадение прошло успешно, вызывается функция alloc_inst, определенная драйвером функции обратного вызова. Для uac2 вызывается функция afunc_alloc_inst.
    1. Сначала выделите f_uac2_optsструктуру данные, внутри содержит usb_function_instance.
    2. Установите для config_item_type uac2 значение f_uac2_func_type. f_uac2_func_type экспортирует файл атрибутов для настройки параметров звука uac2 в каталог /sys/kernel/config/usb_gadget/g1/functions/uac2.0, чтобы облегчить настройку пользовательского пространства.
    3. Установите значение параметров звука по умолчанию, которое может быть изменено пользователем в пользовательском пространстве.
  3. Повесьте полученный экземпляр usb_function_instance uac2 в связанный список доступной_функции гаджета_info.
3.2.3. Получить функцию

Ниже приведен процесс получения usb_function. Как показано на рисунке ниже, когда в пользовательском пространстве выполняется ln -s /sys/kernel/config/usb_gadget/g1/functions/uac2.0 /sys/kernel/config/usb_gadget/g1/configs/c.1, ядро вызовет USB. Функция config_usb_cfg_link гаджета configfs. Основная задача функции config_usb_cfg_link — получить управляемую функцией структуру данных usb_function. Процесс выполнения выглядит следующим образом:

  1. по гаджету funcation API вызывает функцию afunc_alloc драйвера uac2.
    1. Назначить f_uac2структура данные, внутри содержит usb_function.
    2. заполнить usb_functionструктура данных,Важно установить функцию обратного вызова,usb_gadget_driver вызовет эту функцию в соответствующее время. Например, когда драйвер привязан, он вызовет функцию afunc_bind.,При отмене привязки будет вызвана функция afunc_unbind.,При настройке конфигурации будет вызвана функция afunc_set_alt и т.д.
  2. Повесьте полученную usb_function из uac2 в связанный список func_list из config_usb_cfg.
3.2.4.Привязка драйвера

Как показано на рисунке ниже, когда пользовательское пространство выполняет echo fe800000.dwc3 > /sys/kernel/config/usb_gadget/g1/UDC, ядро ​​вызовет USB gadget Функция гаджета_dev_desc_UDC_store из configfs. Основная задача функции gadget_dev_desc_UDC_store — привязать usb_gadget_driver к базовому USB-контроллеру. usb_gadget_driver эквивалентен мосту. Два конца моста — это функциональный драйвер и драйвер UDC. Процесс выполнения следующий:

  1. Определите имя входного USB-контроллера. Если выходные данные пусты или отсутствуют, отмените привязку usb_gadget_driver и базового USB-контроллера. В противном случае вызовите функцию usb_udc_attach_driver для соответствия контроллеру USB-устройства.
  2. Просмотрите связанный список udc_list и найдите контроллер USB-устройства fe800000.dwc3.
  3. Если соответствующий контроллер USB-устройства найден, сохраните привязанный usb_gadget_driver, то есть configfs_driver_template.
  4. Функция обратного вызова configfs_composite_bind. Основное содержание его работы следующее:
    1. Выделите usb_request конечной точки, выделите буфер, установите функцию обратного вызова usb_request, сбросьте все конечные точки и обнулите количество конечных точек гаджета.
    2. Функциональный драйвер сохраняет соответствующую конфигурацию и вызывает функцию привязки функционального драйвера. Для uac2 он вызывает функцию afunc_bind.
    3. Если вы используете строку ОС, вам необходимо выделить запрос строки ОС.
  5. Вызовите интерфейс драйвера UDC usb_gadget_udc_start, чтобы включить контроллер USB-устройства.
  6. Вызовите интерфейс драйвера UDC usb_udc_connect_control для подключения к хост-контроллеру USB, чтобы хост USB мог идентифицировать и перечислять USB-устройства.

4. Резюме

В этом разделе в качестве примера используется uac2, чтобы представить использование пользовательского пространства конфигурации USB-гаджета и рабочий процесс в ядре. configfs USB-устройства предоставляет удобный метод настройки. Пользователи могут гибко организовывать функциональные драйверы USB для формирования составных устройств USB-устройств с различными функциями. После завершения настройки configfs USB-устройства не участвует в рабочем процессе составного устройства USB-устройства. Структура данных usb_gadget_driver эквивалентна мосту. Вместе с функциональным драйвером и драйвером UDC configfs USB-гаджета обеспечивает реализацию usb_gadget_driver как configfs_driver_template. Для устаревшего драйвера его реализация отличается. В этом разделе не рассматривается рабочий процесс драйвера uac2, а также процесс отправки и получения данных. Они будут подробно описаны в главе о драйвере uac2.

boy illustration
Неразрушающее увеличение изображений одним щелчком мыши, чтобы сделать их более четкими артефактами искусственного интеллекта, включая руководства по установке и использованию.
boy illustration
Копикодер: этот инструмент отлично работает с Cursor, Bolt и V0! Предоставьте более качественные подсказки для разработки интерфейса (создание навигационного веб-сайта с использованием искусственного интеллекта).
boy illustration
Новый бесплатный RooCline превосходит Cline v3.1? ! Быстрее, умнее и лучше вилка Cline! (Независимое программирование AI, порог 0)
boy illustration
Разработав более 10 проектов с помощью Cursor, я собрал 10 примеров и 60 подсказок.
boy illustration
Я потратил 72 часа на изучение курсорных агентов, и вот неоспоримые факты, которыми я должен поделиться!
boy illustration
Идеальная интеграция Cursor и DeepSeek API
boy illustration
DeepSeek V3 снижает затраты на обучение больших моделей
boy illustration
Артефакт, увеличивающий количество очков: на основе улучшения характеристик препятствия малым целям Yolov8 (SEAM, MultiSEAM).
boy illustration
DeepSeek V3 раскручивался уже три дня. Сегодня я попробовал самопровозглашенную модель «ChatGPT».
boy illustration
Open Devin — инженер-программист искусственного интеллекта с открытым исходным кодом, который меньше программирует и больше создает.
boy illustration
Эксклюзивное оригинальное улучшение YOLOv8: собственная разработка SPPF | SPPF сочетается с воспринимаемой большой сверткой ядра UniRepLK, а свертка с большим ядром + без расширения улучшает восприимчивое поле
boy illustration
Популярное и подробное объяснение DeepSeek-V3: от его появления до преимуществ и сравнения с GPT-4o.
boy illustration
9 основных словесных инструкций по доработке академических работ с помощью ChatGPT, эффективных и практичных, которые стоит собрать
boy illustration
Вызовите deepseek в vscode для реализации программирования с помощью искусственного интеллекта.
boy illustration
Познакомьтесь с принципами сверточных нейронных сетей (CNN) в одной статье (суперподробно)
boy illustration
50,3 тыс. звезд! Immich: автономное решение для резервного копирования фотографий и видео, которое экономит деньги и избавляет от беспокойства.
boy illustration
Cloud Native|Практика: установка Dashbaord для K8s, графика неплохая
boy illustration
Краткий обзор статьи — использование синтетических данных при обучении больших моделей и оптимизации производительности
boy illustration
MiniPerplx: новая поисковая система искусственного интеллекта с открытым исходным кодом, спонсируемая xAI и Vercel.
boy illustration
Конструкция сервиса Synology Drive сочетает проникновение в интрасеть и синхронизацию папок заметок Obsidian в облаке.
boy illustration
Центр конфигурации————Накос
boy illustration
Начинаем с нуля при разработке в облаке Copilot: начать разработку с минимальным использованием кода стало проще
boy illustration
[Серия Docker] Docker создает мультиплатформенные образы: практика архитектуры Arm64
boy illustration
Обновление новых возможностей coze | Я использовал coze для создания апплета помощника по исправлению домашних заданий по математике
boy illustration
Советы по развертыванию Nginx: практическое создание статических веб-сайтов на облачных серверах
boy illustration
Feiniu fnos использует Docker для развертывания личного блокнота Notepad
boy illustration
Сверточная нейронная сеть VGG реализует классификацию изображений Cifar10 — практический опыт Pytorch
boy illustration
Начало работы с EdgeonePages — новым недорогим решением для хостинга веб-сайтов
boy illustration
[Зона легкого облачного игрового сервера] Управление игровыми архивами
boy illustration
Развертывание SpringCloud-проекта на базе Docker и Docker-Compose