summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/class/net/net_device.c185
-rw-r--r--src/device/usbd.c40
2 files changed, 144 insertions, 81 deletions
diff --git a/src/class/net/net_device.c b/src/class/net/net_device.c
index 8bbce2305..0f2ccbd44 100644
--- a/src/class/net/net_device.c
+++ b/src/class/net/net_device.c
@@ -40,11 +40,20 @@ void rndis_class_set_handler(uint8_t *data, int size); /* found in ./misc/networ
//--------------------------------------------------------------------+
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;
- bool ecm_mode;
uint8_t ep_in;
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;
#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 -------------//
_netd_itf.itf_num = itf_desc->bInterfaceNumber;
- uint8_t const * p_desc = tu_desc_next( itf_desc );
(*p_length) = sizeof(tusb_desc_interface_t);
+ uint8_t const * p_desc = tu_desc_next( itf_desc );
// Communication Functional Descriptors
while ( TUSB_DESC_CS_INTERFACE == tu_desc_type(p_desc) )
@@ -167,31 +176,44 @@ bool netd_open(uint8_t rhport, tusb_desc_interface_t const * itf_desc, uint16_t
}
//------------- Data Interface -------------//
- // TODO extract Alt Interface 0 & 1
- while ((TUSB_DESC_INTERFACE == tu_desc_type(p_desc)) &&
- (TUSB_CLASS_CDC_DATA == ((tusb_desc_interface_t const *) p_desc)->bInterfaceClass) )
+ // - RNDIS Data followed immediately by a pair of endpoints
+ // - CDC-ECM data interface has 2 alternate settings
+ // - 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_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 )
+ {
+ // 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
+ // 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) );
- (*p_length) += 2*sizeof(tusb_desc_endpoint_t);
- }
+ tud_network_init_cb();
- tud_network_init_cb();
+ // we are ready to transmit a packet
+ can_xmit = true;
- // we are ready to transmit a packet
- can_xmit = true;
-
- // prepare for incoming packets
- tud_network_recv_renew();
+ // prepare for incoming packets
+ tud_network_recv_renew();
+ }
+ (*p_length) += 2*sizeof(tusb_desc_endpoint_t);
return true;
}
@@ -202,14 +224,15 @@ bool netd_control_complete(uint8_t rhport, tusb_control_request_t const * reques
{
(void) rhport;
- // Handle class request only
- TU_VERIFY (request->bmRequestType_bit.type == TUSB_REQ_TYPE_CLASS);
-
- TU_VERIFY (_netd_itf.itf_num == request->wIndex);
-
- if ( !_netd_itf.ecm_mode && (request->bmRequestType_bit.direction == TUSB_DIR_OUT) )
+ // Handle RNDIS class control OUT only
+ if (request->bmRequestType_bit.type == TUSB_REQ_TYPE_CLASS &&
+ request->bmRequestType_bit.direction == TUSB_DIR_OUT &&
+ _netd_itf.itf_num == request->wIndex)
{
- rndis_class_set_handler(notify.rndis_buf, request->wLength);
+ if ( !_netd_itf.ecm_mode )
+ {
+ rndis_class_set_handler(notify.rndis_buf, request->wLength);
+ }
}
return true;
@@ -226,33 +249,95 @@ static void ecm_report(bool nc)
// return false to stall control endpoint (e.g unsupported request)
bool netd_control_request(uint8_t rhport, tusb_control_request_t const * request)
{
- // Handle class request only
- TU_VERIFY(request->bmRequestType_bit.type == TUSB_REQ_TYPE_CLASS);
+ switch ( request->bmRequestType_bit.type )
+ {
+ 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);
- TU_VERIFY (_netd_itf.itf_num == request->wIndex);
+ tud_control_xfer(rhport, request, &_netd_itf.itf_data_alt, 1);
+ }
+ break;
- if (_netd_itf.ecm_mode)
- {
- /* the only required CDC-ECM Management Element Request is SetEthernetPacketFilter */
- if (0x43 /* SET_ETHERNET_PACKET_FILTER */ == request->bRequest)
- {
- tud_control_xfer(rhport, request, NULL, 0);
- ecm_report(true);
- }
- }
- else
- {
- if (request->bmRequestType_bit.direction == TUSB_DIR_IN)
- {
- rndis_generic_msg_t *rndis_msg = (rndis_generic_msg_t *)notify.rndis_buf;
- uint32_t msglen = tu_le32toh(rndis_msg->MessageLength);
- TU_ASSERT(msglen <= sizeof(notify.rndis_buf));
- tud_control_xfer(rhport, request, notify.rndis_buf, msglen);
- }
- else
- {
- tud_control_xfer(rhport, request, notify.rndis_buf, sizeof(notify.rndis_buf));
- }
+ 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);
+
+ if (_netd_itf.ecm_mode)
+ {
+ /* the only required CDC-ECM Management Element Request is SetEthernetPacketFilter */
+ if (0x43 /* SET_ETHERNET_PACKET_FILTER */ == request->bRequest)
+ {
+ tud_control_xfer(rhport, request, NULL, 0);
+ ecm_report(true);
+ }
+ }
+ else
+ {
+ if (request->bmRequestType_bit.direction == TUSB_DIR_IN)
+ {
+ rndis_generic_msg_t *rndis_msg = (rndis_generic_msg_t *)notify.rndis_buf;
+ uint32_t msglen = tu_le32toh(rndis_msg->MessageLength);
+ TU_ASSERT(msglen <= sizeof(notify.rndis_buf));
+ tud_control_xfer(rhport, request, notify.rndis_buf, msglen);
+ }
+ else
+ {
+ tud_control_xfer(rhport, request, notify.rndis_buf, sizeof(notify.rndis_buf));
+ }
+ }
+ break;
+
+ // unsupported request
+ default: return false;
}
return true;
diff --git a/src/device/usbd.c b/src/device/usbd.c
index ad5a32f92..29845ff36 100644
--- a/src/device/usbd.c
+++ b/src/device/usbd.c
@@ -571,39 +571,17 @@ static bool process_control_request(uint8_t rhport, tusb_control_request_t const
uint8_t const drvid = _usbd_dev.itf2drv[itf];
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 )
- {
- case TUSB_REQ_GET_INTERFACE:
- {
- // TODO not support alternate interface yet
- uint8_t alternate = 0;
- 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;
+ // For GET_INTERFACE, it is mandatory to respond even if the class
+ // driver doesn't use alternate settings.
+ TU_VERIFY( TUSB_REQ_TYPE_STANDARD == p_request->bmRequestType_bit.type &&
+ TUSB_REQ_GET_INTERFACE == p_request->bRequest);
- // 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));
+ uint8_t alternate = 0;
+ tud_control_xfer(rhport, p_request, &alternate, 1);
}
}
break;