Анализ структуры драйвера контроллера устройства USB3.0 ядра Linux (4)
Анализ структуры драйвера контроллера устройства USB3.0 ядра Linux (4)

1. Обзор

Как показано на рисунке ниже, USB-контроллер может иметь два разных состояния. Когда USB-контроллер выступает в роли хоста, он называется хост-контроллером USB и использует драйвер хост-контроллера USB. Когда USB-контроллер выступает в качестве устройства, он называется контроллером USB-устройства и использует драйвер UDC (контроллер USB-устройства). В этом разделе анализируется структура драйверов только в том случае, если контроллер USB используется в качестве устройства.

Когда USB-контроллер используется в качестве устройства, структуру драйверов можно разделить на 5 уровней. Верхний уровень — это драйвер функции гаджета, который представляет собой драйвер конкретного устройства, например драйвер устройства хранения данных большой емкости (U-диск, мобильный жесткий диск и т. д.), драйвер устройства связи (последовательный порт USB, виртуальная сеть USB). карта и т. д.), драйвер UAC (микрофон USB, аудиоустройства USB, например звуковые карты USB). Далее идет уровень API функции гаджета, который представляет собой уровень абстракции, который обеспечивает унифицированный API вверх и вниз, скрывая различия и улучшая совместимость драйверов. Композитный уровень — это дополнительный средний уровень, который может эффективно поддерживать многофункциональные устройства с помощью одной или нескольких конфигураций, упрощая разработку драйверов составных USB-устройств. В настоящее время наиболее популярным является использование конфигов USB-гаджетов, реализованных на базе Composite и configfs, позволяющих гибко настраивать USB-устройства в пользовательском пространстве. Драйвер UDC напрямую обращается к оборудованию и управляет связью между USB-устройством и USB-хостом. Контроллер USB-устройства подключается к хост-контроллеру USB через USB-кабель и отвечает за отправку и получение данных USB.

2.Драйвер функции гаджета

Все драйверы функции USB-гаджета ядра Linux находятся в каталоге driver/usb/gadget/function/, включая класс коммуникационного устройства. Class) драйвер (f_acm.c, f_ecm, f_serial.c и т. д.), драйвер класса аудиоустройства USB (f_uac1.c, f_uac2.c, u_audio.c), драйвер запоминающего устройства (f_mass_storage.c), видеоустройство USB класс Драйвер (f_uvc.c) и т.д.

Вход драйвера функции гаджета описывается структурой данных usb_function_driver, и драйвер должен реализовать функции alloc_inst и alloc_func. alloc_inst создает структуру данных usb_function_instance и инициализирует ее. alloc_func создает usb_function и инициализирует ее. Целью является установка внутри функции обратного вызова. Обычно структура данных usb_function не используется напрямую, а встроена в структуру данных драйвера. Композитный драйвер будет вызывать функции alloc_inst и alloc_func через API функции гаджета. usb_function описывает драйвер функции гаджета. Целью драйвера функции гаджета является реализация этих функций обратного вызова.

Язык кода:javascript
копировать
[include/linux/usb/composite.h]
struct usb_function_driver {
    const char *name;
    struct module *mod;
    struct list_head list;
    // Создайте usb_function_instance и инициализируйте его.
    struct usb_function_instance *(*alloc_inst)(void);
    // Создайте usb_function и инициализируйте ее.
    struct usb_function *(*alloc_func)(struct usb_function_instance *inst);
};
struct usb_function {  // описывает гаджет Функциональный драйвер
    const char			*name;  // gadget Функциональный драйверимя    struct usb_gadget_strings	**strings;  // Таблица строк, идентификаторов языка, предоставленных запросами на распределение привязки и управление.
    struct usb_descriptor_header	**fs_descriptors; // full дескриптор скорости
    struct usb_descriptor_header	**hs_descriptors; // high дескриптор скорости
    struct usb_descriptor_header	**ss_descriptors; // super дескриптор скорости
    struct usb_configuration	*config;  // Конфигурация добавлена ​​функцией usb_add_function
    // Функция обратного вызова привязки драйвера выделяет ресурсы, необходимые драйверу, такие как конфигурация, конечные точки, буферы ввода-вывода и т. д.
    int	(*bind)(struct usb_configuration *, struct usb_function *);
    // Освободить ресурсы, выделенные привязкой
    void (*unbind)(struct usb_configuration *, struct usb_function *);
    void (*free_func)(struct usb_function *f);  // выпустить usb_function
    // Установите дополнительные конфигурации. Иногда драйвер может иметь несколько конфигураций, и вам нужно использовать set_alt для переключения.
    int (*set_alt)(struct usb_function *, unsigned interface, unsigned alt);
    // Получите дополнительную конфигурацию текущих настроек. Если нескольких конфигураций нет, по умолчанию будет использоваться конфигурация 0 и будет возвращено 0.
    int (*get_alt)(struct usb_function *, unsigned interface);
    // disable gadget функциональный драйвер, используемый при перезагрузке хоста, перенастройке гаджетов и отключении хоста.
    void (*disable)(struct usb_function *);
    // Управляющие запросы для конкретных интерфейсов
    int	(*setup)(struct usb_function *, const struct usb_ctrlrequest *);
    // Проверьте, могут ли быть обработаны запросы определенных классов устройств.
    bool (*req_match)(struct usb_function *, const struct usb_ctrlrequest *);
    void (*suspend)(struct usb_function *);
    void (*resume)(struct usb_function *);
    /* USB 3.0 additions */
    // Запросить GetStatus для возврата текущего гаджета Функциональный Статус водителя
    int (*get_status)(struct usb_function *);  
    // Когда получен SetFeature(FUNCTION_SUSPEND), выполните обратный вызов этой функции.
    int (*func_suspend)(struct usb_function *, u8 suspend_opt);
    /* private: internals */
    struct list_head		list;
    DECLARE_BITMAP(endpoints, 32);  // растровое изображение конечной точки
    const struct usb_function_instance *fi;
    unsigned int		bind_deactivated:1;
};

usb_function_driver обычно определяется и инициализируется с помощью макроса DECLARE_USB_FUNCTION_INIT. После расширения макроса он определяет экземпляр структуры usb_function_driver, который в основном устанавливает члены alloc_inst и alloc_func. Префикс используется для создания usb_function_instance, который представляет экземпляр функции гаджета. Последний используется для создания и инициализации usb_function. Методы в usb_function реализуют определенные драйверы функции гаджета. Функции usb_function_register и usb_function_unregister завершают регистрацию и отмену регистрации структуры usb_function_driver.

Язык кода:javascript
копировать
[include/linux/usb/composite.h]
#define DECLARE_USB_FUNCTION_INIT(_name, _inst_alloc, _func_alloc)	\
    DECLARE_USB_FUNCTION(_name, _inst_alloc, _func_alloc)		\
    static int __init _name ## mod_init(void)			\
    {								\
        return usb_function_register(&_name ## usb_func);	\  // Зарегистрируйте драйвер устройства UAC
    }								\
    static void __exit _name ## mod_exit(void)			\
    {								\
        usb_function_unregister(&_name ## usb_func);		\  // Отмените регистрацию драйвера устройства UAC
    }								\
    module_init(_name ## mod_init);					\  // Инициализация модуля
    module_exit(_name ## mod_exit)                     // Удаление модуля

#define DECLARE_USB_FUNCTION(_name, _inst_alloc, _func_alloc)		\
    // Гаджет, определяющий UAC2.0 Функциональный драйвер с именем uac2_usb_func
    static struct usb_function_driver _name ## usb_func = {		\
        .name = __stringify(_name),				\  // Имя драйвера — uac2.
        .mod  = THIS_MODULE,					\
        .alloc_inst = _inst_alloc,				\
        .alloc_func = _func_alloc,				\
    };								\
    MODULE_ALIAS("usbfunc:"__stringify(_name));

3.Gadget Function API

API функции гаджета — это уровень абстракции. Верхний драйвер функции гаджета использует API функции гаджета для регистрации и отмены регистрации, а нижний составной драйвер использует API функции гаджета и привязку и сопоставление драйвера функции гаджета. Драйвер функции гаджета должен реализовать структуру данных usb_function_driver и зарегистрироваться на уровне API функции гаджета.

Ниже приведены основные API-интерфейсы API функции гаджета. usb_function_register помещает зарегистрированный usb_function_driver в связанный список func_list. Функция usb_function_instance обойдет связанный список func_list, сравнит имя параметра с именем usb_function_driver, если имена совпадают, совпадение будет успешным, затем вызовет функцию обратного вызова alloc_inst в успешно совпавшем usb_function_driver, чтобы получить usb_function_instance, а затем установит указатель usb_function_driver на usb_function_instance Наконец, возвращает указатель на usb_function_instance. Функция usb_get_function получает и инициализирует usb_function посредством функции обратного вызова alloc_func. Информацию о других API см. в исходном коде.

Язык кода:javascript
копировать
[drivers/usb/gadget/functions.c]
// В гаджет Function Гаджет регистрации уровня API Функциональный драйвер
int usb_function_register(struct usb_function_driver *newf)
// Выйти из гаджета Функциональный драйвер
void usb_function_unregister(struct usb_function_driver *fd)
// Из гаджета Function Уровень API получает usb_function_instance
struct usb_function_instance *usb_get_function_instance(const char *name)
// Обратный вызов free_func_inst уничтожает usb_function_instance
void usb_put_function_instance(struct usb_function_instance *fi)
// Из гаджета Function Уровень API получает usb_function_instance
struct usb_function *usb_get_function(struct usb_function_instance *fi)
// Обратный вызов free_func уничтожает usb_function
void usb_put_function(struct usb_function *f)

4.Композитный слой

Основная структура данных USB Composite — usb_composite_driver. Композитный драйвер должен реализовывать дескриптор устройства и привязывать функции обратного вызова.

Составные (составные) устройства описываются с помощью структуры данных usb_composite_dev. Эта структура данных автоматически создается ядром перед вызовом функции привязки драйвера при регистрации составного драйвера и не требует создания драйвера.

гаджет указывает на usb_gadget в структуре dwc3. req выделяется заранее при регистрации составного драйвера и используется для ответа на запросы управления, отправленные хостом. config указывает на текущую используемую конфигурацию USB. desc — дескриптор текущего устройства, который устанавливается при регистрации составного драйвера. driver указывает на соответствующий usb_composite_driver. Структура usb_composite_driver содержит структуру данных usb_gadget_driver, которая используется для представления драйвера USB-устройства.

Язык кода:javascript
копировать
[include/linux/usb/composite.h]
struct usb_composite_driver {
    const char  *name;  // Имя водителя
    const struct usb_device_descriptor *dev;  // Дескриптор устройства, должен быть определен
    struct usb_gadget_strings  **strings;
    enum usb_device_speed  max_speed;  // Максимальная скорость, поддерживаемая устройством
    unsigned  needs_serial:1;
    // Используется для выделения ресурсов, общих для всего устройства, используйте usb_add_config для добавления конфигурации, необходимо реализовать
    int  (*bind)(struct usb_composite_dev *cdev);  
    int  (*unbind)(struct usb_composite_dev *);       // Уничтожить ресурсы
    void  (*disconnect)(struct usb_composite_dev *);  // Дополнительное отключение драйвера method
    /* global suspend hooks */
    void  (*suspend)(struct usb_composite_dev *);
    void  (*resume)(struct usb_composite_dev *);
    // Слой составного драйвера предоставляет реализацию по умолчанию, а именно complex_driver_template.
    struct usb_gadget_driver  gadget_driver;  
};
struct usb_composite_dev {  // Композитное оборудование
    // Только для чтения, абстракция контроллера USB-устройства, указывающая на usb_gadget в структуре dwc3.
	struct usb_gadget		*gadget;  
	struct usb_request		*req;     // Буфер, используемый для ответа на запросы управления, выделяется заранее.
	struct usb_request		*os_desc_req;  // Буфер, используемый в ответ на дескрипторы ОС, выделяется заранее.
	struct usb_configuration	*config;  // В настоящее время используется конфигурация
    //  qwSignature part of the OS string
	u8		qw_sign[OS_STRING_QW_SIGN_LEN]; 
	u8		b_vendor_code; // bMS_VendorCode part of the OS string
	struct usb_configuration *os_desc_config;  // Конфигурация, используемая дескрипторами ОС
	unsigned int			use_os_string:1;
	unsigned int			suspended:1;
	struct usb_device_descriptor desc; // дескриптор устройства
	struct list_head		configs;
	struct list_head		gstrings;
	struct usb_composite_driver	*driver;  // Укажите на составной драйвер
    ......
};

4.1.legacy

Большинство устаревших драйверов USB-гаджетов, которые напрямую используют составной уровень ядра Linux, находятся в каталоге driver/usb/gadget/legacy/, например, файл драйвера аудиоустройства USB audio.c, файл драйвера виртуального Ethernet-устройства USB ether. .c и драйвер устройства HID. Устаревший драйвер может напрямую использовать макрос Module_usb_composite_driver, предоставляемый ядром, чтобы легко определить составной драйвер. Параметром является структура usb_composite_driver. Используйте usb_composite_probe для регистрации составного драйвера. Используйте функцию usb_composite_unregister, чтобы отменить регистрацию драйвера Composite.

Язык кода:javascript
копировать
[include/linux/usb/composite.h]
#define module_usb_composite_driver(__usb_composite_driver) \
	module_driver(__usb_composite_driver, usb_composite_probe, \
		       usb_composite_unregister)

[include/linux/device.h]
#define module_driver(__driver, __register, __unregister, ...) \
static int __init __driver##_init(void) \  // функция инициализации
{ \
    return __register(&(__driver) , ##__VA_ARGS__); \
} \
module_init(__driver##_init); \
static void __exit __driver##_exit(void) \  // функция выхода из системы
{ \
    __unregister(&(__driver) , ##__VA_ARGS__); \
} \
module_exit(__driver##_exit);

Функции usb_composite_probe и usb_composite_unregister определяются следующим образом. usb_composite_probe инициализирует составной драйвер устройства, usb_composite_unregister удаляет составной драйвер устройства.

Язык кода:javascript
копировать
[include/linux/usb/composite.h]
/**
 * usb_composite_probe() - register a composite driver
 * @driver: the driver to register
 *
 * Context: single threaded during gadget setup
 *
 * This function is used to register drivers using the composite driver
 * framework.  The return value is zero, or a negative errno value.
 * Those values normally come from the driver's @bind method, which does
 * all the work of setting up the driver to match the hardware.
 *
 * On successful return, the gadget is ready to respond to requests from
 * the host, unless one of its components invokes usb_gadget_disconnect()
 * while it was binding.  That would usually be done in order to wait for
 * some userspace participation.
 */
int usb_composite_probe(struct usb_composite_driver *driver)
/**
 * usb_composite_unregister() - unregister a composite driver
 * @driver: the driver to unregister
 *
 * This function is used to unregister drivers using the composite
 * driver framework.
 */
void usb_composite_unregister(struct usb_composite_driver *driver)

Ядро реализует usb_gadget_driver, который представляет собой переменную complex_driver_template, на уровне составного драйвера. Все составные устройства используют эту структуру данных и не требуют реализации драйвера.

Когда составной драйвер регистрируется с помощью usb_composite_probe, ядро ​​скопирует данные из Composite_driver_template в элемент гаджет_драйвер usb_composite_driver.

Язык кода:javascript
копировать
[drivers/usb/gadget/composite.c]
static const struct usb_gadget_driver composite_driver_template = {  // Драйвер USB-устройства, реализованный ядром
	.bind		= composite_bind,
	.unbind		= composite_unbind,
	.setup		= composite_setup,
	.reset		= composite_disconnect,
	.disconnect	= composite_disconnect,
	.suspend	= composite_suspend,
	.resume		= composite_resume,
	.driver	= {
		.owner		= THIS_MODULE,
	},
};

4.2.USB Gadget Configfs

Configfs — это файловая система на основе оперативной памяти, которая может напрямую управлять объектами ядра в пользовательском пространстве. Она в основном подходит для модулей с множеством конфигураций объектов ядра, таких как составные USB-устройства. В Linux версии 3.11 представлены настройки USB-гаджетов. На уровне пользователя любая функция и конфигурация устройства USB-гаджета может быть определена через открытый API, что значительно упрощает настройку и использование составных USB-устройств. Принципы и использование будут подробно представлены далее в этом разделе. USB Gadget Configfs реализован в файле driver/usb/gadget/configfs.c.

5. УДК-драйвер

5.1.Функциональный интерфейс

Модуль драйвера UDC определяется следующим образом. Он инициализируется во время инициализации ядра или загрузки модуля, создает udc_class и устанавливает функцию обратного вызова uevent в значение usb_udc_uevent.

Язык кода:javascript
копировать
[drivers/usb/gadget/udc/core.c]
static struct class *udc_class;
static int __init usb_udc_init(void)
{
	udc_class = class_create(THIS_MODULE, "udc");
    ......
    udc_class->dev_uevent = usb_udc_uevent;
    return 0;
}
subsys_initcall(usb_udc_init);

static void __exit usb_udc_exit(void)
{
	class_destroy(udc_class);
}
module_exit(usb_udc_exit);

Используйте usb_add_gadget_udc для регистрации драйвера UDC. Сначала выделите структуру данных usb_udc, инициализируйте соответствующие элементы и, наконец, поместите usb_udc в связанный список udc_list. После успешной регистрации статус UDC будет USB_STATE_NOTATTACHED. Используйте usb_del_gadget_udc для удаления драйвера UDC. Сначала выполните обратный вызов для отключения, затем выполните обратный вызов udc_stop для остановки контроллера USB-устройства и, наконец, удалите usb_udc из связанного списка udc_list.

Язык кода:javascript
копировать
[drivers/usb/gadget/udc/core.c]
/**
 * usb_add_gadget_udc - adds a new gadget to the udc class driver list
 * @parent: the parent device to this udc. Usually the controller
 * driver's device.
 * @gadget: the gadget to be added to the list
 *
 * Returns zero on success, negative errno otherwise.
 */
int usb_add_gadget_udc(struct device *parent, struct usb_gadget *gadget)
/**
 * usb_del_gadget_udc - deletes @udc from udc_list
 * @gadget: the gadget to be removed.
 *
 * This, will call usb_gadget_unregister_driver() if
 * the @udc is still busy.
 */
void usb_del_gadget_udc(struct usb_gadget *gadget)

Композитный драйвер вызывает usb_gadget_probe_driver для сопоставления с драйвером UDC. Он сначала проходит по связанному списку udc_list. Если член драйвера usb_udc пуст, это означает, что совпадение выполнено успешно. Затем составной драйвер привязывается к драйверу UDC, устанавливая адрес. из usb_composite_driver.gadget_driver составного драйвера с usb_udc Привязка завершается в члене .driver, и, наконец, udc_start вызывается обратно для запуска контроллера USB-устройства. Вызовите usb_gadget_unregister_driver, чтобы отменить привязку составного драйвера и драйвера UDC.

Язык кода:javascript
копировать
[drivers/usb/gadget/udc/core.c]
int usb_gadget_probe_driver(struct usb_gadget_driver *driver)
int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)

Уровень UDC также предоставляет некоторые интерфейсы функциональному драйверу USB-устройства для включения и выключения контроллеров USB-устройств, включения и отключения конечных точек, постановки в очередь/удаления из очереди запросов ввода-вывода, выделения и освобождения usb_requests, сопоставления конечных точек и т. д. Эти функции будут внутренне вызывать драйвер UDC конкретного контроллера USB-устройства. На платформе RK3399 будет вызываться драйвер UDC, реализованный dwc3. Что касается конкретного содержания, оно будет подробно объяснено при анализе драйвера UDC dwc3 в следующих главах.

Язык кода:javascript
копировать
[drivers/usb/gadget/udc/core.c]
int usb_ep_enable(struct usb_ep *ep)   // включить конечную точку
int usb_ep_disable(struct usb_ep *ep)  // запретить конечную точку
int usb_ep_queue(struct usb_ep *ep, struct usb_request *req, gfp_t gfp_flags)  // queues usb_request 
int usb_ep_dequeue(struct usb_ep *ep, struct usb_request *req)  // dequeue usb_request
struct usb_request *usb_ep_alloc_request(struct usb_ep *ep, gfp_t gfp_flags)  // выделить usb_request 
void usb_ep_free_request(struct usb_ep *ep, struct usb_request *req)  // Отпустить usb_request 
// Соответствует конечной точке для использования на основе дескриптора
int usb_gadget_ep_match_desc(struct usb_gadget *gadget, struct usb_ep *ep,
		struct usb_endpoint_descriptor *desc, struct usb_ss_ep_comp_descriptor *ep_comp)

5.2.Структура данных

Драйвер UDC описывается с использованием структуры данных usb_udc, и все зарегистрированные структуры данных usb_udc будут связаны со связанным списком udc_list. Функции драйвера UDC в основном реализуются гаджетом-членом, то есть структурой данных usb_gadget. struct usb_gadget_driver реализуется составным слоем и используется для подключения функционального драйвера USB и драйвера UDC. usb_gadget_ops — это функция аппаратной работы контроллера USB-устройства, включая такие функции, как запуск контроллера USB-устройства, остановка контроллера USB-устройства и подача питания vbus. ep0 представляет конечную точку 0, которая будет выделена заранее при регистрации драйвера и будет использоваться для ответа на запросы управления. Помимо конечной точки 0, драйвер устройства USB также будет использовать другие конечные точки, и эти структуры данных конечной точки связаны со связанным списком ep_list. скорость представляет текущую скорость контроллера USB-устройства. max_speed указывает максимальную скорость контроллера USB-устройства.

Язык кода:javascript
копировать
[drivers/usb/gadget/udc/core.c]
static LIST_HEAD(udc_list);
struct usb_udc {  // Описать контроллер USB-устройства
    // Укажите на составной драйвервusb_gadget_driver
	struct usb_gadget_driver *driver;
    // Структура, реализующая драйвер UDC, включая функцию работы аппаратного обеспечения контроллера USB-устройства.
	struct usb_gadget		*gadget;  
	struct device			dev;
    // Структура usb_udc может формировать связанный список.
	struct list_head		list;
	bool		vbus;  // Это значение всегда верно для UDC, которым не важен статус vbus.
};
[include/linux/usb/gadget.h]
struct usb_gadget {
    // Рабочая очередь для sysfs_notify
	struct work_struct		work;
	struct usb_udc			*udc;  // Наведите указатель на usb_udc
    // Функция аппаратного управления контроллером USB-устройства, не включает операцию ввода-вывода
	const struct usb_gadget_ops	*ops;  
	struct usb_ep *ep0;  // Конечная точка 0, используемая для ответа на запросы управления чтением и записью.
	struct list_head ep_list; // Связанный список всех конечных точек, необходимых драйверу USB-устройства.
	enum usb_device_speed speed;  // Текущая скорость соединения с USB-хостом
	enum usb_device_speed max_speed;  // Максимальная скорость, поддерживаемая драйвером udc
	enum usb_device_state state;  // текущий статус
	const char *name;  // udcИмя водителя,Используйте и подтвердите тип оборудования контроллера
	struct device  dev;
	unsigned out_epnum;  // Последний использованный номер выходной конечной точки
	unsigned in_epnum;   // Последний использованный входной номер конечной точки
	unsigned mA;         // Недавно установленное значение м А
	struct usb_otg_caps *otg_caps; // Возможности OTG
	unsigned sg_supported:1;       // Поддерживать ли совокупный DMA
	unsigned is_otg:1;  // Поддерживать ли OTG, поддержка OTG должна предоставить дескриптор OTG
	unsigned is_a_peripheral:1;    // Обычно неверно, если OTG не поддерживается.
    // Размер буфера запроса выходной конечной точки выравнивается по MaxPacketSize.
	unsigned quirk_ep_out_aligned_size:1;  
	unsigned is_selfpowered:1;  // Это автономное питание?
	unsigned connected:1;       // Соединение успешное?
	unsigned uvc_enabled:1;     // Включена ли функция uvc?
    ......
};
struct usb_gadget_driver {
	char *function;  // Строка, описывающая usb_gadget_driver
	enum usb_device_speed	max_speed;  // Максимальная скорость, с которой может справиться этот водитель
    // Функция обратного вызова, с помощью которой можно привязать гаджет верхнего уровня функциональный драйвер
	int	(*bind)(struct usb_gadget *gadget, struct usb_gadget_driver *driver);
	void (*unbind)(struct usb_gadget *);
    // Вызов запроса управления конечной точкой 0, используемый для управления дескриптором и конфигурацией, обычно вызываемый в прерывании, не может перейти в режим сна.
	int	(*setup)(struct usb_gadget *, const struct usb_ctrlrequest *);
    // Когда хост отключен, он вызывается после остановки всех передач. Он может быть вызван в режиме прерывания и не может перейти в режим ожидания.
	void (*disconnect)(struct usb_gadget *);
	void (*suspend)(struct usb_gadget *);
	void (*resume)(struct usb_gadget *);
    // Вызывается при сбросе шины USB, должен быть реализован, вызывается в прерывании
	void (*reset)(struct usb_gadget *);
	struct device_driver	driver;
};
struct usb_gadget_ops {  // Функция аппаратной работы контроллера USB-устройства, не затрагивающая конечные точки и io
	int	(*get_frame)(struct usb_gadget *);
	int	(*wakeup)(struct usb_gadget *);
	int	(*set_selfpowered) (struct usb_gadget *, int is_selfpowered);
	int	(*vbus_session) (struct usb_gadget *, int is_active);
	int	(*vbus_draw) (struct usb_gadget *, unsigned mA);
    // Потяните вниз, чтобы USB-хост почувствовал, что USB-устройство подключено к USB-шине, и USB-хост перечислит USB-устройство.
	int	(*pullup) (struct usb_gadget *, int is_on);  
	int	(*ioctl)(struct usb_gadget *, unsigned code, unsigned long param);
	void (*get_config_params)(struct usb_dcd_config_params *);
	int	(*udc_start)(struct usb_gadget *, struct usb_gadget_driver *); // начать УДК
	int	(*udc_stop)(struct usb_gadget *);  // остановить УДК
    // Сопоставить конечную точку USB
	struct usb_ep *(*match_ep)(struct usb_gadget *,
		struct usb_endpoint_descriptor *, struct usb_ss_ep_comp_descriptor *);
};
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