Merge pull request #345 from hathach/add-alt-itf
Implement setInterface(alt) for usb net driver
This commit is contained in:
@@ -24,7 +24,6 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "tusb.h"
|
#include "tusb.h"
|
||||||
#include "usb_descriptors.h"
|
|
||||||
|
|
||||||
/* A combination of interfaces must have a unique product id, since PC will save device driver after the first plug.
|
/* A combination of interfaces must have a unique product id, since PC will save device driver after the first plug.
|
||||||
* Same VID/PID with different interface e.g MSC (first), then CDC (later) will possibly cause system error on PC.
|
* Same VID/PID with different interface e.g MSC (first), then CDC (later) will possibly cause system error on PC.
|
||||||
@@ -47,6 +46,20 @@ enum
|
|||||||
STRID_MAC
|
STRID_MAC
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
ITF_NUM_CDC = 0,
|
||||||
|
ITF_NUM_CDC_DATA,
|
||||||
|
ITF_NUM_TOTAL
|
||||||
|
};
|
||||||
|
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
CONFIG_ID_RNDIS = 0,
|
||||||
|
CONFIG_ID_ECM = 1,
|
||||||
|
CONFIG_ID_COUNT
|
||||||
|
};
|
||||||
|
|
||||||
//--------------------------------------------------------------------+
|
//--------------------------------------------------------------------+
|
||||||
// Device Descriptors
|
// Device Descriptors
|
||||||
//--------------------------------------------------------------------+
|
//--------------------------------------------------------------------+
|
||||||
@@ -71,7 +84,7 @@ tusb_desc_device_t const desc_device =
|
|||||||
.iProduct = STRID_PRODUCT,
|
.iProduct = STRID_PRODUCT,
|
||||||
.iSerialNumber = STRID_SERIAL,
|
.iSerialNumber = STRID_SERIAL,
|
||||||
|
|
||||||
.bNumConfigurations = 0x02
|
.bNumConfigurations = CONFIG_ID_COUNT // multiple configurations
|
||||||
};
|
};
|
||||||
|
|
||||||
// Invoked when received GET DEVICE DESCRIPTOR
|
// Invoked when received GET DEVICE DESCRIPTOR
|
||||||
@@ -84,19 +97,6 @@ uint8_t const * tud_descriptor_device_cb(void)
|
|||||||
//--------------------------------------------------------------------+
|
//--------------------------------------------------------------------+
|
||||||
// Configuration Descriptor
|
// Configuration Descriptor
|
||||||
//--------------------------------------------------------------------+
|
//--------------------------------------------------------------------+
|
||||||
enum
|
|
||||||
{
|
|
||||||
ITF_NUM_CDC = 0,
|
|
||||||
ITF_NUM_CDC_DATA,
|
|
||||||
ITF_NUM_TOTAL
|
|
||||||
};
|
|
||||||
|
|
||||||
enum
|
|
||||||
{
|
|
||||||
CONFIG_NUM_DEFAULT = 1,
|
|
||||||
CONFIG_NUM_ALTERNATE = 2,
|
|
||||||
};
|
|
||||||
|
|
||||||
#define MAIN_CONFIG_TOTAL_LEN (TUD_CONFIG_DESC_LEN + TUD_RNDIS_DESC_LEN)
|
#define MAIN_CONFIG_TOTAL_LEN (TUD_CONFIG_DESC_LEN + TUD_RNDIS_DESC_LEN)
|
||||||
#define ALT_CONFIG_TOTAL_LEN (TUD_CONFIG_DESC_LEN + TUD_CDC_ECM_DESC_LEN)
|
#define ALT_CONFIG_TOTAL_LEN (TUD_CONFIG_DESC_LEN + TUD_CDC_ECM_DESC_LEN)
|
||||||
|
|
||||||
@@ -108,30 +108,41 @@ enum
|
|||||||
#define EPNUM_CDC 2
|
#define EPNUM_CDC 2
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static uint8_t const main_configuration[] =
|
static uint8_t const rndis_configuration[] =
|
||||||
{
|
{
|
||||||
// Config number, interface count, string index, total length, attribute, power in mA
|
// Config number (index+1), interface count, string index, total length, attribute, power in mA
|
||||||
TUD_CONFIG_DESCRIPTOR(CONFIG_NUM_DEFAULT, ITF_NUM_TOTAL, 0, MAIN_CONFIG_TOTAL_LEN, 0, 100),
|
TUD_CONFIG_DESCRIPTOR(CONFIG_ID_RNDIS+1, ITF_NUM_TOTAL, 0, MAIN_CONFIG_TOTAL_LEN, 0, 100),
|
||||||
|
|
||||||
// Interface number, string index, EP notification address and size, EP data address (out, in) and size.
|
// Interface number, string index, EP notification address and size, EP data address (out, in) and size.
|
||||||
TUD_RNDIS_DESCRIPTOR(ITF_NUM_CDC, STRID_INTERFACE, 0x81, 8, EPNUM_CDC, 0x80 | EPNUM_CDC, CFG_TUD_NET_ENDPOINT_SIZE),
|
TUD_RNDIS_DESCRIPTOR(ITF_NUM_CDC, STRID_INTERFACE, 0x81, 8, EPNUM_CDC, 0x80 | EPNUM_CDC, CFG_TUD_NET_ENDPOINT_SIZE),
|
||||||
};
|
};
|
||||||
|
|
||||||
static uint8_t const alt_configuration[] =
|
static uint8_t const ecm_configuration[] =
|
||||||
{
|
{
|
||||||
// Config number, interface count, string index, total length, attribute, power in mA
|
// Config number (index+1), interface count, string index, total length, attribute, power in mA
|
||||||
TUD_CONFIG_DESCRIPTOR(CONFIG_NUM_ALTERNATE, ITF_NUM_TOTAL, 0, ALT_CONFIG_TOTAL_LEN, 0, 100),
|
TUD_CONFIG_DESCRIPTOR(CONFIG_ID_ECM+1, ITF_NUM_TOTAL, 0, ALT_CONFIG_TOTAL_LEN, 0, 100),
|
||||||
|
|
||||||
// Interface number, description string index, MAC address string index, EP notification address and size, EP data address (out, in), and size, max segment size.
|
// Interface number, description string index, MAC address string index, EP notification address and size, EP data address (out, in), and size, max segment size.
|
||||||
TUD_CDC_ECM_DESCRIPTOR(ITF_NUM_CDC, STRID_INTERFACE, STRID_MAC, 0x81, 64, EPNUM_CDC, 0x80 | EPNUM_CDC, CFG_TUD_NET_ENDPOINT_SIZE, CFG_TUD_NET_MTU),
|
TUD_CDC_ECM_DESCRIPTOR(ITF_NUM_CDC, STRID_INTERFACE, STRID_MAC, 0x81, 64, EPNUM_CDC, 0x80 | EPNUM_CDC, CFG_TUD_NET_ENDPOINT_SIZE, CFG_TUD_NET_MTU),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Configuration array: RNDIS and CDC-ECM
|
||||||
|
// - Windows only works with RNDIS
|
||||||
|
// - MacOS only works with CDC-ECM
|
||||||
|
// - Linux will work on both
|
||||||
|
// Note index is Num-1x
|
||||||
|
static uint8_t const * const configuration_arr[2] =
|
||||||
|
{
|
||||||
|
[CONFIG_ID_RNDIS] = rndis_configuration,
|
||||||
|
[CONFIG_ID_ECM ] = ecm_configuration
|
||||||
|
};
|
||||||
|
|
||||||
// Invoked when received GET CONFIGURATION DESCRIPTOR
|
// Invoked when received GET CONFIGURATION DESCRIPTOR
|
||||||
// Application return pointer to descriptor
|
// Application return pointer to descriptor
|
||||||
// Descriptor contents must exist long enough for transfer to complete
|
// Descriptor contents must exist long enough for transfer to complete
|
||||||
uint8_t const * tud_descriptor_configuration_cb(uint8_t index)
|
uint8_t const * tud_descriptor_configuration_cb(uint8_t index)
|
||||||
{
|
{
|
||||||
return (0 == index) ? main_configuration : alt_configuration;
|
return (index < CONFIG_ID_COUNT) ? configuration_arr[index] : NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
//--------------------------------------------------------------------+
|
//--------------------------------------------------------------------+
|
||||||
|
@@ -1,28 +0,0 @@
|
|||||||
/*
|
|
||||||
* The MIT License (MIT)
|
|
||||||
*
|
|
||||||
* Copyright (c) 2019 Ha Thach (tinyusb.org)
|
|
||||||
*
|
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
* of this software and associated documentation files (the "Software"), to deal
|
|
||||||
* in the Software without restriction, including without limitation the rights
|
|
||||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
* copies of the Software, and to permit persons to whom the Software is
|
|
||||||
* furnished to do so, subject to the following conditions:
|
|
||||||
*
|
|
||||||
* The above copyright notice and this permission notice shall be included in
|
|
||||||
* all copies or substantial portions of the Software.
|
|
||||||
*
|
|
||||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
||||||
* THE SOFTWARE.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef USB_DESCRIPTORS_H_
|
|
||||||
#define USB_DESCRIPTORS_H_
|
|
||||||
|
|
||||||
#endif /* USB_DESCRIPTORS_H_ */
|
|
@@ -40,11 +40,20 @@ void rndis_class_set_handler(uint8_t *data, int size); /* found in ./misc/networ
|
|||||||
//--------------------------------------------------------------------+
|
//--------------------------------------------------------------------+
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
uint8_t itf_num;
|
uint8_t itf_num; // Index number of Management Interface, +1 for Data Interface
|
||||||
|
uint8_t itf_data_alt; // Alternate setting of Data Interface. 0 : inactive, 1 : active
|
||||||
|
|
||||||
uint8_t ep_notif;
|
uint8_t ep_notif;
|
||||||
bool ecm_mode;
|
|
||||||
uint8_t ep_in;
|
uint8_t ep_in;
|
||||||
uint8_t ep_out;
|
uint8_t ep_out;
|
||||||
|
|
||||||
|
bool ecm_mode;
|
||||||
|
|
||||||
|
// Endpoint descriptor use to open/close when receving SetInterface
|
||||||
|
// TODO since configuration descriptor may not be long-lived memory, we should
|
||||||
|
// keep a copy of endpoint attribute instead
|
||||||
|
uint8_t const * ecm_desc_epdata;
|
||||||
|
|
||||||
} netd_interface_t;
|
} netd_interface_t;
|
||||||
|
|
||||||
#define CFG_TUD_NET_PACKET_PREFIX_LEN sizeof(rndis_data_packet_t)
|
#define CFG_TUD_NET_PACKET_PREFIX_LEN sizeof(rndis_data_packet_t)
|
||||||
@@ -145,8 +154,8 @@ bool netd_open(uint8_t rhport, tusb_desc_interface_t const * itf_desc, uint16_t
|
|||||||
//------------- Management Interface -------------//
|
//------------- Management Interface -------------//
|
||||||
_netd_itf.itf_num = itf_desc->bInterfaceNumber;
|
_netd_itf.itf_num = itf_desc->bInterfaceNumber;
|
||||||
|
|
||||||
uint8_t const * p_desc = tu_desc_next( itf_desc );
|
|
||||||
(*p_length) = sizeof(tusb_desc_interface_t);
|
(*p_length) = sizeof(tusb_desc_interface_t);
|
||||||
|
uint8_t const * p_desc = tu_desc_next( itf_desc );
|
||||||
|
|
||||||
// Communication Functional Descriptors
|
// Communication Functional Descriptors
|
||||||
while ( TUSB_DESC_CS_INTERFACE == tu_desc_type(p_desc) )
|
while ( TUSB_DESC_CS_INTERFACE == tu_desc_type(p_desc) )
|
||||||
@@ -167,23 +176,34 @@ bool netd_open(uint8_t rhport, tusb_desc_interface_t const * itf_desc, uint16_t
|
|||||||
}
|
}
|
||||||
|
|
||||||
//------------- Data Interface -------------//
|
//------------- Data Interface -------------//
|
||||||
// TODO extract Alt Interface 0 & 1
|
// - RNDIS Data followed immediately by a pair of endpoints
|
||||||
while ((TUSB_DESC_INTERFACE == tu_desc_type(p_desc)) &&
|
// - CDC-ECM data interface has 2 alternate settings
|
||||||
(TUSB_CLASS_CDC_DATA == ((tusb_desc_interface_t const *) p_desc)->bInterfaceClass) )
|
// - 0 : zero endpoints for inactive (default)
|
||||||
|
// - 1 : IN & OUT endpoints for active networking
|
||||||
|
TU_ASSERT(TUSB_DESC_INTERFACE == tu_desc_type(p_desc));
|
||||||
|
|
||||||
|
do
|
||||||
{
|
{
|
||||||
// next to endpoint descriptor
|
tusb_desc_interface_t const * data_itf_desc = (tusb_desc_interface_t const *) p_desc;
|
||||||
|
TU_ASSERT(TUSB_CLASS_CDC_DATA == data_itf_desc->bInterfaceClass);
|
||||||
|
|
||||||
(*p_length) += tu_desc_len(p_desc);
|
(*p_length) += tu_desc_len(p_desc);
|
||||||
p_desc = tu_desc_next(p_desc);
|
p_desc = tu_desc_next(p_desc);
|
||||||
}
|
}while( _netd_itf.ecm_mode && (TUSB_DESC_INTERFACE == tu_desc_type(p_desc)) );
|
||||||
|
|
||||||
if (TUSB_DESC_ENDPOINT == tu_desc_type(p_desc))
|
// Pair of endpoints
|
||||||
|
TU_ASSERT(TUSB_DESC_ENDPOINT == tu_desc_type(p_desc));
|
||||||
|
|
||||||
|
if ( _netd_itf.ecm_mode )
|
||||||
{
|
{
|
||||||
// Open endpoint pair
|
// ECM by default is in-active, save the endpoint attribute
|
||||||
|
// to open later when received setInterface
|
||||||
|
_netd_itf.ecm_desc_epdata = p_desc;
|
||||||
|
}else
|
||||||
|
{
|
||||||
|
// Open endpoint pair for RNDIS
|
||||||
TU_ASSERT( usbd_open_edpt_pair(rhport, p_desc, 2, TUSB_XFER_BULK, &_netd_itf.ep_out, &_netd_itf.ep_in) );
|
TU_ASSERT( usbd_open_edpt_pair(rhport, p_desc, 2, TUSB_XFER_BULK, &_netd_itf.ep_out, &_netd_itf.ep_in) );
|
||||||
|
|
||||||
(*p_length) += 2*sizeof(tusb_desc_endpoint_t);
|
|
||||||
}
|
|
||||||
|
|
||||||
tud_network_init_cb();
|
tud_network_init_cb();
|
||||||
|
|
||||||
// we are ready to transmit a packet
|
// we are ready to transmit a packet
|
||||||
@@ -191,7 +211,9 @@ bool netd_open(uint8_t rhport, tusb_desc_interface_t const * itf_desc, uint16_t
|
|||||||
|
|
||||||
// prepare for incoming packets
|
// prepare for incoming packets
|
||||||
tud_network_recv_renew();
|
tud_network_recv_renew();
|
||||||
|
}
|
||||||
|
|
||||||
|
(*p_length) += 2*sizeof(tusb_desc_endpoint_t);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -202,15 +224,16 @@ bool netd_control_complete(uint8_t rhport, tusb_control_request_t const * reques
|
|||||||
{
|
{
|
||||||
(void) rhport;
|
(void) rhport;
|
||||||
|
|
||||||
// Handle class request only
|
// Handle RNDIS class control OUT only
|
||||||
TU_VERIFY (request->bmRequestType_bit.type == TUSB_REQ_TYPE_CLASS);
|
if (request->bmRequestType_bit.type == TUSB_REQ_TYPE_CLASS &&
|
||||||
|
request->bmRequestType_bit.direction == TUSB_DIR_OUT &&
|
||||||
TU_VERIFY (_netd_itf.itf_num == request->wIndex);
|
_netd_itf.itf_num == request->wIndex)
|
||||||
|
{
|
||||||
if ( !_netd_itf.ecm_mode && (request->bmRequestType_bit.direction == TUSB_DIR_OUT) )
|
if ( !_netd_itf.ecm_mode )
|
||||||
{
|
{
|
||||||
rndis_class_set_handler(notify.rndis_buf, request->wLength);
|
rndis_class_set_handler(notify.rndis_buf, request->wLength);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -226,9 +249,66 @@ static void ecm_report(bool nc)
|
|||||||
// return false to stall control endpoint (e.g unsupported request)
|
// return false to stall control endpoint (e.g unsupported request)
|
||||||
bool netd_control_request(uint8_t rhport, tusb_control_request_t const * request)
|
bool netd_control_request(uint8_t rhport, tusb_control_request_t const * request)
|
||||||
{
|
{
|
||||||
// Handle class request only
|
switch ( request->bmRequestType_bit.type )
|
||||||
TU_VERIFY(request->bmRequestType_bit.type == TUSB_REQ_TYPE_CLASS);
|
{
|
||||||
|
case TUSB_REQ_TYPE_STANDARD:
|
||||||
|
switch ( request->bRequest )
|
||||||
|
{
|
||||||
|
case TUSB_REQ_GET_INTERFACE:
|
||||||
|
{
|
||||||
|
uint8_t const req_itfnum = (uint8_t) request->wIndex;
|
||||||
|
TU_VERIFY(_netd_itf.itf_num+1 == req_itfnum);
|
||||||
|
|
||||||
|
tud_control_xfer(rhport, request, &_netd_itf.itf_data_alt, 1);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TUSB_REQ_SET_INTERFACE:
|
||||||
|
{
|
||||||
|
uint8_t const req_itfnum = (uint8_t) request->wIndex;
|
||||||
|
uint8_t const req_alt = (uint8_t) request->wValue;
|
||||||
|
|
||||||
|
// Only valid for Data Interface with Alternate is either 0 or 1
|
||||||
|
TU_VERIFY(_netd_itf.itf_num+1 == req_itfnum && req_alt < 2);
|
||||||
|
|
||||||
|
// ACM-ECM only: qequest to enable/disable network activities
|
||||||
|
TU_VERIFY(_netd_itf.ecm_mode);
|
||||||
|
|
||||||
|
_netd_itf.itf_data_alt = req_alt;
|
||||||
|
|
||||||
|
if ( _netd_itf.itf_data_alt )
|
||||||
|
{
|
||||||
|
// TODO since we don't actually close endpoint
|
||||||
|
// hack here to not re-open it
|
||||||
|
if ( _netd_itf.ep_in == 0 && _netd_itf.ep_out == 0 )
|
||||||
|
{
|
||||||
|
TU_ASSERT(_netd_itf.ecm_desc_epdata);
|
||||||
|
TU_ASSERT( usbd_open_edpt_pair(rhport, _netd_itf.ecm_desc_epdata, 2, TUSB_XFER_BULK, &_netd_itf.ep_out, &_netd_itf.ep_in) );
|
||||||
|
|
||||||
|
// TODO should be merge with RNDIS's after endpoint opened
|
||||||
|
// Also should have opposite callback for application to disable network !!
|
||||||
|
tud_network_init_cb();
|
||||||
|
can_xmit = true; // we are ready to transmit a packet
|
||||||
|
tud_network_recv_renew(); // prepare for incoming packets
|
||||||
|
}
|
||||||
|
}else
|
||||||
|
{
|
||||||
|
// TODO close the endpoint pair
|
||||||
|
// For now pretend that we did, this should have no harm since host won't try to
|
||||||
|
// communicate with the endpoints again
|
||||||
|
// _netd_itf.ep_in = _netd_itf.ep_out = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
tud_control_status(rhport, request);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
// unsupported request
|
||||||
|
default: return false;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TUSB_REQ_TYPE_CLASS:
|
||||||
TU_VERIFY (_netd_itf.itf_num == request->wIndex);
|
TU_VERIFY (_netd_itf.itf_num == request->wIndex);
|
||||||
|
|
||||||
if (_netd_itf.ecm_mode)
|
if (_netd_itf.ecm_mode)
|
||||||
@@ -254,6 +334,11 @@ bool netd_control_request(uint8_t rhport, tusb_control_request_t const * request
|
|||||||
tud_control_xfer(rhport, request, notify.rndis_buf, sizeof(notify.rndis_buf));
|
tud_control_xfer(rhport, request, notify.rndis_buf, sizeof(notify.rndis_buf));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
// unsupported request
|
||||||
|
default: return false;
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@@ -571,40 +571,18 @@ static bool process_control_request(uint8_t rhport, tusb_control_request_t const
|
|||||||
uint8_t const drvid = _usbd_dev.itf2drv[itf];
|
uint8_t const drvid = _usbd_dev.itf2drv[itf];
|
||||||
TU_VERIFY(drvid < USBD_CLASS_DRIVER_COUNT);
|
TU_VERIFY(drvid < USBD_CLASS_DRIVER_COUNT);
|
||||||
|
|
||||||
if (p_request->bmRequestType_bit.type == TUSB_REQ_TYPE_STANDARD)
|
// all requests to Interface (STD or Class) is forwarded to class driver.
|
||||||
|
// notable requests are: GET HID REPORT DESCRIPTOR, SET_INTERFACE, GET_INTERFACE
|
||||||
|
if ( !invoke_class_control(rhport, drvid, p_request) )
|
||||||
{
|
{
|
||||||
switch ( p_request->bRequest )
|
// For GET_INTERFACE, it is mandatory to respond even if the class
|
||||||
{
|
// driver doesn't use alternate settings.
|
||||||
case TUSB_REQ_GET_INTERFACE:
|
TU_VERIFY( TUSB_REQ_TYPE_STANDARD == p_request->bmRequestType_bit.type &&
|
||||||
{
|
TUSB_REQ_GET_INTERFACE == p_request->bRequest);
|
||||||
// TODO not support alternate interface yet
|
|
||||||
uint8_t alternate = 0;
|
uint8_t alternate = 0;
|
||||||
tud_control_xfer(rhport, p_request, &alternate, 1);
|
tud_control_xfer(rhport, p_request, &alternate, 1);
|
||||||
}
|
}
|
||||||
break;
|
|
||||||
|
|
||||||
case TUSB_REQ_SET_INTERFACE:
|
|
||||||
{
|
|
||||||
uint8_t const alternate = (uint8_t) p_request->wValue;
|
|
||||||
(void) alternate;
|
|
||||||
|
|
||||||
// TODO not support alternate interface yet
|
|
||||||
// TU_ASSERT(alternate == 0);
|
|
||||||
tud_control_status(rhport, p_request);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
// forward to class driver: "STD request to Interface"
|
|
||||||
// GET HID REPORT DESCRIPTOR falls into this case
|
|
||||||
TU_VERIFY(invoke_class_control(rhport, drvid, p_request));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}else
|
|
||||||
{
|
|
||||||
// forward to class driver: "non-STD request to Interface"
|
|
||||||
TU_VERIFY(invoke_class_control(rhport, drvid, p_request));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user