Merge pull request #3135 from andrewleech/ncm-link-state-control
Add USB NCM link state control support
This commit is contained in:
@@ -58,6 +58,7 @@
|
|||||||
#define LWIP_HTTPD_SSI_INCLUDE_TAG 0
|
#define LWIP_HTTPD_SSI_INCLUDE_TAG 0
|
||||||
|
|
||||||
#define LWIP_SINGLE_NETIF 1
|
#define LWIP_SINGLE_NETIF 1
|
||||||
|
#define LWIP_NETIF_LINK_CALLBACK 1
|
||||||
|
|
||||||
#define PBUF_POOL_SIZE 4
|
#define PBUF_POOL_SIZE 4
|
||||||
|
|
||||||
|
@@ -31,6 +31,12 @@ this appears as either a RNDIS or CDC-ECM USB virtual network adapter; the OS pi
|
|||||||
RNDIS should be valid on Linux and Windows hosts, and CDC-ECM should be valid on Linux and macOS hosts
|
RNDIS should be valid on Linux and Windows hosts, and CDC-ECM should be valid on Linux and macOS hosts
|
||||||
|
|
||||||
The MCU appears to the host as IP address 192.168.7.1, and provides a DHCP server, DNS server, and web server.
|
The MCU appears to the host as IP address 192.168.7.1, and provides a DHCP server, DNS server, and web server.
|
||||||
|
|
||||||
|
Link State Control:
|
||||||
|
- Press the user button to toggle the network link state (UP/DOWN)
|
||||||
|
- This simulates "ethernet cable unplugged/plugged" events
|
||||||
|
- The host OS will see the network interface as disconnected/connected accordingly
|
||||||
|
- Use this to test network error handling and recovery in host applications
|
||||||
*/
|
*/
|
||||||
/*
|
/*
|
||||||
Some smartphones *may* work with this implementation as well, but likely have limited (broken) drivers,
|
Some smartphones *may* work with this implementation as well, but likely have limited (broken) drivers,
|
||||||
@@ -63,9 +69,6 @@ try changing the first byte of tud_network_mac_address[] below from 0x02 to 0x00
|
|||||||
/* lwip context */
|
/* lwip context */
|
||||||
static struct netif netif_data;
|
static struct netif netif_data;
|
||||||
|
|
||||||
/* shared between tud_network_recv_cb() and service_traffic() */
|
|
||||||
static struct pbuf *received_frame;
|
|
||||||
|
|
||||||
/* this is used by this code, ./class/net/net_driver.c, and usb_descriptors.c */
|
/* this is used by this code, ./class/net/net_driver.c, and usb_descriptors.c */
|
||||||
/* ideally speaking, this should be generated from the hardware's unique ID (if available) */
|
/* ideally speaking, this should be generated from the hardware's unique ID (if available) */
|
||||||
/* it is suggested that the first byte is 0x02 to indicate a link-local address */
|
/* it is suggested that the first byte is 0x02 to indicate a link-local address */
|
||||||
@@ -137,6 +140,12 @@ static err_t netif_init_cb(struct netif *netif) {
|
|||||||
return ERR_OK;
|
return ERR_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* notifies the USB host about the link state change. */
|
||||||
|
static void usbnet_netif_link_callback(struct netif *netif) {
|
||||||
|
bool link_up = netif_is_link_up(netif);
|
||||||
|
tud_network_link_state(BOARD_TUD_RHPORT, link_up);
|
||||||
|
}
|
||||||
|
|
||||||
static void init_lwip(void) {
|
static void init_lwip(void) {
|
||||||
struct netif *netif = &netif_data;
|
struct netif *netif = &netif_data;
|
||||||
|
|
||||||
@@ -147,11 +156,19 @@ static void init_lwip(void) {
|
|||||||
memcpy(netif->hwaddr, tud_network_mac_address, sizeof(tud_network_mac_address));
|
memcpy(netif->hwaddr, tud_network_mac_address, sizeof(tud_network_mac_address));
|
||||||
netif->hwaddr[5] ^= 0x01;
|
netif->hwaddr[5] ^= 0x01;
|
||||||
|
|
||||||
netif = netif_add(netif, &ipaddr, &netmask, &gateway, NULL, netif_init_cb, ip_input);
|
netif = netif_add(netif, &ipaddr, &netmask, &gateway, NULL, netif_init_cb, ethernet_input);
|
||||||
#if LWIP_IPV6
|
#if LWIP_IPV6
|
||||||
netif_create_ip6_linklocal_address(netif, 1);
|
netif_create_ip6_linklocal_address(netif, 1);
|
||||||
#endif
|
#endif
|
||||||
netif_set_default(netif);
|
netif_set_default(netif);
|
||||||
|
|
||||||
|
#if LWIP_NETIF_LINK_CALLBACK
|
||||||
|
// Set the link callback to notify USB host about link state changes
|
||||||
|
netif_set_link_callback(netif, usbnet_netif_link_callback);
|
||||||
|
netif_set_link_up(netif);
|
||||||
|
#else
|
||||||
|
tud_network_link_state(BOARD_TUD_RHPORT, true);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
/* handle any DNS requests from dns-server */
|
/* handle any DNS requests from dns-server */
|
||||||
@@ -164,20 +181,29 @@ bool dns_query_proc(const char *name, ip4_addr_t *addr) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool tud_network_recv_cb(const uint8_t *src, uint16_t size) {
|
bool tud_network_recv_cb(const uint8_t *src, uint16_t size) {
|
||||||
/* this shouldn't happen, but if we get another packet before
|
struct netif *netif = &netif_data;
|
||||||
parsing the previous, we must signal our inability to accept it */
|
|
||||||
if (received_frame) return false;
|
|
||||||
|
|
||||||
if (size) {
|
if (size) {
|
||||||
struct pbuf *p = pbuf_alloc(PBUF_RAW, size, PBUF_POOL);
|
struct pbuf *p = pbuf_alloc(PBUF_RAW, size, PBUF_POOL);
|
||||||
|
|
||||||
if (p) {
|
if (p == NULL) {
|
||||||
/* pbuf_alloc() has already initialized struct; all we need to do is copy the data */
|
printf("ERROR: Failed to allocate pbuf of size %d\n", size);
|
||||||
memcpy(p->payload, src, size);
|
return false;
|
||||||
|
|
||||||
/* store away the pointer for service_traffic() to later handle */
|
|
||||||
received_frame = p;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Copy buf to pbuf */
|
||||||
|
pbuf_take(p, src, size);
|
||||||
|
|
||||||
|
// Surrender ownership of our pbuf unless there was an error
|
||||||
|
// Only call pbuf_free if not Ok else it will panic with "pbuf_free: p->ref > 0"
|
||||||
|
// or steal it from whatever took ownership of it with undefined consequences.
|
||||||
|
// See: https://savannah.nongnu.org/patch/index.php?10121
|
||||||
|
if (netif->input(p, netif) != ERR_OK) {
|
||||||
|
printf("ERROR: netif input failed\n");
|
||||||
|
pbuf_free(p);
|
||||||
|
}
|
||||||
|
// Signal tinyusb that the current frame has been processed.
|
||||||
|
tud_network_recv_renew();
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@@ -191,29 +217,26 @@ uint16_t tud_network_xmit_cb(uint8_t *dst, void *ref, uint16_t arg) {
|
|||||||
return pbuf_copy_partial(p, dst, p->tot_len, 0);
|
return pbuf_copy_partial(p, dst, p->tot_len, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void service_traffic(void) {
|
static void handle_link_state_switch(void) {
|
||||||
/* handle any packet received by tud_network_recv_cb() */
|
/* Check for button press to toggle link state */
|
||||||
if (received_frame) {
|
static bool last_link_state = true;
|
||||||
// Surrender ownership of our pbuf unless there was an error
|
static bool last_button_state = false;
|
||||||
// Only call pbuf_free if not Ok else it will panic with "pbuf_free: p->ref > 0"
|
bool current_button_state = board_button_read();
|
||||||
// or steal it from whatever took ownership of it with undefined consequences.
|
|
||||||
// See: https://savannah.nongnu.org/patch/index.php?10121
|
|
||||||
if (ethernet_input(received_frame, &netif_data)!=ERR_OK) {
|
|
||||||
pbuf_free(received_frame);
|
|
||||||
}
|
|
||||||
received_frame = NULL;
|
|
||||||
tud_network_recv_renew();
|
|
||||||
}
|
|
||||||
|
|
||||||
sys_check_timeouts();
|
if (current_button_state && !last_button_state) {
|
||||||
|
/* Button pressed - toggle link state */
|
||||||
|
last_link_state = !last_link_state;
|
||||||
|
if (last_link_state) {
|
||||||
|
printf("Link state: UP\n");
|
||||||
|
netif_set_link_up(&netif_data);
|
||||||
|
} else {
|
||||||
|
printf("Link state: DOWN\n");
|
||||||
|
netif_set_link_down(&netif_data);
|
||||||
}
|
}
|
||||||
|
/* LWIP callback will notify USB host about the change */
|
||||||
|
}
|
||||||
|
last_button_state = current_button_state;
|
||||||
|
|
||||||
void tud_network_init_cb(void) {
|
|
||||||
/* if the network is re-initializing and we have a leftover packet, we must do a cleanup */
|
|
||||||
if (received_frame) {
|
|
||||||
pbuf_free(received_frame);
|
|
||||||
received_frame = NULL;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(void) {
|
int main(void) {
|
||||||
@@ -243,15 +266,23 @@ int main(void) {
|
|||||||
lwiperf_start_tcp_server_default(NULL, NULL);
|
lwiperf_start_tcp_server_default(NULL, NULL);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if CFG_TUD_NCM
|
||||||
|
printf("USB NCM network interface initialized\n");
|
||||||
|
#elif CFG_TUD_ECM_RNDIS
|
||||||
|
printf("USB RNDIS/ECM network interface initialized\n");
|
||||||
|
#endif
|
||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
tud_task();
|
tud_task();
|
||||||
service_traffic();
|
sys_check_timeouts(); // service lwip
|
||||||
|
handle_link_state_switch();
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* lwip has provision for using a mutex, when applicable */
|
/* lwip has provision for using a mutex, when applicable */
|
||||||
|
/* This implementation is for single-threaded use only */
|
||||||
sys_prot_t sys_arch_protect(void) {
|
sys_prot_t sys_arch_protect(void) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@@ -85,6 +85,7 @@ extern "C" {
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Use different configurations to test all net devices (also due to resource limitations)
|
// Use different configurations to test all net devices (also due to resource limitations)
|
||||||
|
#ifndef USE_ECM
|
||||||
#if TU_CHECK_MCU(OPT_MCU_LPC15XX, OPT_MCU_LPC40XX, OPT_MCU_LPC51UXX, OPT_MCU_LPC54)
|
#if TU_CHECK_MCU(OPT_MCU_LPC15XX, OPT_MCU_LPC40XX, OPT_MCU_LPC51UXX, OPT_MCU_LPC54)
|
||||||
#define USE_ECM 1
|
#define USE_ECM 1
|
||||||
#elif TU_CHECK_MCU(OPT_MCU_SAMD21, OPT_MCU_SAML21, OPT_MCU_SAML22)
|
#elif TU_CHECK_MCU(OPT_MCU_SAMD21, OPT_MCU_SAML21, OPT_MCU_SAML22)
|
||||||
@@ -97,6 +98,7 @@ extern "C" {
|
|||||||
#define USE_ECM 0
|
#define USE_ECM 0
|
||||||
#define INCLUDE_IPERF
|
#define INCLUDE_IPERF
|
||||||
#endif
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
//--------------------------------------------------------------------
|
//--------------------------------------------------------------------
|
||||||
// NCM CLASS CONFIGURATION, SEE "ncm.h" FOR PERFORMANCE TUNING
|
// NCM CLASS CONFIGURATION, SEE "ncm.h" FOR PERFORMANCE TUNING
|
||||||
|
@@ -81,6 +81,7 @@ typedef struct {
|
|||||||
static netd_interface_t _netd_itf;
|
static netd_interface_t _netd_itf;
|
||||||
CFG_TUD_MEM_SECTION static netd_epbuf_t _netd_epbuf;
|
CFG_TUD_MEM_SECTION static netd_epbuf_t _netd_epbuf;
|
||||||
static bool can_xmit;
|
static bool can_xmit;
|
||||||
|
static bool ecm_link_is_up = true; // Store link state for ECM mode
|
||||||
|
|
||||||
void tud_network_recv_renew(void) {
|
void tud_network_recv_renew(void) {
|
||||||
usbd_edpt_xfer(0, _netd_itf.ep_out, _netd_epbuf.rx, NETD_PACKET_SIZE);
|
usbd_edpt_xfer(0, _netd_itf.ep_out, _netd_epbuf.rx, NETD_PACKET_SIZE);
|
||||||
@@ -95,7 +96,11 @@ void netd_report(uint8_t *buf, uint16_t len) {
|
|||||||
const uint8_t rhport = 0;
|
const uint8_t rhport = 0;
|
||||||
len = tu_min16(len, sizeof(ecm_notify_t));
|
len = tu_min16(len, sizeof(ecm_notify_t));
|
||||||
|
|
||||||
TU_VERIFY(usbd_edpt_claim(rhport, _netd_itf.ep_notif), );
|
if (!usbd_edpt_claim(rhport, _netd_itf.ep_notif)) {
|
||||||
|
TU_LOG1("ECM: Failed to claim notification endpoint\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
memcpy(_netd_epbuf.notify, buf, len);
|
memcpy(_netd_epbuf.notify, buf, len);
|
||||||
usbd_edpt_xfer(rhport, _netd_itf.ep_notif, _netd_epbuf.notify, len);
|
usbd_edpt_xfer(rhport, _netd_itf.ep_notif, _netd_epbuf.notify, len);
|
||||||
}
|
}
|
||||||
@@ -181,8 +186,6 @@ uint16_t netd_open(uint8_t rhport, tusb_desc_interface_t const * itf_desc, uint1
|
|||||||
// Open endpoint pair for RNDIS
|
// 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), 0);
|
TU_ASSERT(usbd_open_edpt_pair(rhport, p_desc, 2, TUSB_XFER_BULK, &_netd_itf.ep_out, &_netd_itf.ep_in), 0);
|
||||||
|
|
||||||
tud_network_init_cb();
|
|
||||||
|
|
||||||
// we are ready to transmit a packet
|
// we are ready to transmit a packet
|
||||||
can_xmit = true;
|
can_xmit = true;
|
||||||
|
|
||||||
@@ -196,11 +199,11 @@ uint16_t netd_open(uint8_t rhport, tusb_desc_interface_t const * itf_desc, uint1
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void ecm_report(bool nc) {
|
static void ecm_report(bool nc) {
|
||||||
const ecm_notify_t ecm_notify_nc = {
|
ecm_notify_t ecm_notify_nc = {
|
||||||
.header = {
|
.header = {
|
||||||
.bmRequestType = 0xA1,
|
.bmRequestType = 0xA1,
|
||||||
.bRequest = 0, /* NETWORK_CONNECTION aka NetworkConnection */
|
.bRequest = 0, /* NETWORK_CONNECTION aka NetworkConnection */
|
||||||
.wValue = 1, /* Connected */
|
.wValue = ecm_link_is_up ? 1 : 0, /* Use current link state */
|
||||||
.wLength = 0,
|
.wLength = 0,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
@@ -259,7 +262,6 @@ bool netd_control_xfer_cb (uint8_t rhport, uint8_t stage, tusb_control_request_t
|
|||||||
|
|
||||||
// TODO should be merge with RNDIS's after endpoint opened
|
// TODO should be merge with RNDIS's after endpoint opened
|
||||||
// Also should have opposite callback for application to disable network !!
|
// Also should have opposite callback for application to disable network !!
|
||||||
tud_network_init_cb();
|
|
||||||
can_xmit = true; // we are ready to transmit a packet
|
can_xmit = true; // we are ready to transmit a packet
|
||||||
tud_network_recv_renew(); // prepare for incoming packets
|
tud_network_recv_renew(); // prepare for incoming packets
|
||||||
}
|
}
|
||||||
@@ -286,8 +288,11 @@ bool netd_control_xfer_cb (uint8_t rhport, uint8_t stage, tusb_control_request_t
|
|||||||
/* the only required CDC-ECM Management Element Request is SetEthernetPacketFilter */
|
/* the only required CDC-ECM Management Element Request is SetEthernetPacketFilter */
|
||||||
if (0x43 /* SET_ETHERNET_PACKET_FILTER */ == request->bRequest) {
|
if (0x43 /* SET_ETHERNET_PACKET_FILTER */ == request->bRequest) {
|
||||||
tud_control_xfer(rhport, request, NULL, 0);
|
tud_control_xfer(rhport, request, NULL, 0);
|
||||||
|
// Only send connection notification if link is up
|
||||||
|
if (ecm_link_is_up) {
|
||||||
ecm_report(true);
|
ecm_report(true);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
if (request->bmRequestType_bit.direction == TUSB_DIR_IN) {
|
if (request->bmRequestType_bit.direction == TUSB_DIR_IN) {
|
||||||
rndis_generic_msg_t* rndis_msg = (rndis_generic_msg_t*)((void*)_netd_epbuf.ctrl);
|
rndis_generic_msg_t* rndis_msg = (rndis_generic_msg_t*)((void*)_netd_epbuf.ctrl);
|
||||||
@@ -363,9 +368,8 @@ bool netd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (_netd_itf.ecm_mode && (ep_addr == _netd_itf.ep_notif)) {
|
if (_netd_itf.ecm_mode && (ep_addr == _netd_itf.ep_notif)) {
|
||||||
if (sizeof(tusb_control_request_t) == xferred_bytes) {
|
// Notification transfer complete - endpoint is now free
|
||||||
ecm_report(false);
|
// Don't automatically send speed change notification after link state changes
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@@ -398,4 +402,31 @@ void tud_network_xmit(void *ref, uint16_t arg) {
|
|||||||
do_in_xfer(_netd_epbuf.tx, len);
|
do_in_xfer(_netd_epbuf.tx, len);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Set the network link state (up/down) and notify the host
|
||||||
|
void tud_network_link_state(uint8_t rhport, bool is_up) {
|
||||||
|
(void)rhport;
|
||||||
|
|
||||||
|
if (_netd_itf.ecm_mode) {
|
||||||
|
ecm_link_is_up = is_up;
|
||||||
|
|
||||||
|
// For ECM mode, send network connection notification only
|
||||||
|
// Don't trigger speed change notification for link state changes
|
||||||
|
ecm_notify_t notify = {
|
||||||
|
.header = {
|
||||||
|
.bmRequestType = 0xA1,
|
||||||
|
.bRequest = 0, /* NETWORK_CONNECTION */
|
||||||
|
.wValue = is_up ? 1 : 0, /* 0 = disconnected, 1 = connected */
|
||||||
|
.wLength = 0,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
notify.header.wIndex = _netd_itf.itf_num;
|
||||||
|
netd_report((uint8_t *)¬ify, sizeof(notify.header));
|
||||||
|
} else {
|
||||||
|
// For RNDIS mode, we would need to implement RNDIS status indication
|
||||||
|
// This is more complex and requires RNDIS_INDICATE_STATUS_MSG
|
||||||
|
// For now, RNDIS doesn't support dynamic link state changes
|
||||||
|
(void)is_up;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@@ -110,6 +110,7 @@ typedef struct {
|
|||||||
NOTIFICATION_DONE
|
NOTIFICATION_DONE
|
||||||
} notification_xmit_state; // state of notification transmission
|
} notification_xmit_state; // state of notification transmission
|
||||||
bool notification_xmit_is_running; // notification is currently transmitted
|
bool notification_xmit_is_running; // notification is currently transmitted
|
||||||
|
bool link_is_up; // current link state
|
||||||
|
|
||||||
// misc
|
// misc
|
||||||
bool tud_network_recv_renew_active; // tud_network_recv_renew() is active (avoid recursive invocations)
|
bool tud_network_recv_renew_active; // tud_network_recv_renew() is active (avoid recursive invocations)
|
||||||
@@ -218,7 +219,7 @@ static void notification_xmit(uint8_t rhport, bool force_next) {
|
|||||||
.direction = TUSB_DIR_IN
|
.direction = TUSB_DIR_IN
|
||||||
},
|
},
|
||||||
.bRequest = CDC_NOTIF_NETWORK_CONNECTION,
|
.bRequest = CDC_NOTIF_NETWORK_CONNECTION,
|
||||||
.wValue = 1 /* Connected */,
|
.wValue = ncm_interface.link_is_up ? 1 : 0, /* Dynamic link state */
|
||||||
.wIndex = ncm_interface.itf_num,
|
.wIndex = ncm_interface.itf_num,
|
||||||
.wLength = 0,
|
.wLength = 0,
|
||||||
},
|
},
|
||||||
@@ -232,6 +233,7 @@ static void notification_xmit(uint8_t rhport, bool force_next) {
|
|||||||
ncm_interface.notification_xmit_is_running = true;
|
ncm_interface.notification_xmit_is_running = true;
|
||||||
} else {
|
} else {
|
||||||
TU_LOG_DRV(" NOTIFICATION_FINISHED\n");
|
TU_LOG_DRV(" NOTIFICATION_FINISHED\n");
|
||||||
|
ncm_interface.notification_xmit_is_running = false;
|
||||||
}
|
}
|
||||||
} // notification_xmit
|
} // notification_xmit
|
||||||
|
|
||||||
@@ -755,6 +757,32 @@ static void tud_network_recv_renew_r(uint8_t rhport) {
|
|||||||
tud_network_recv_renew();
|
tud_network_recv_renew();
|
||||||
} // tud_network_recv_renew
|
} // tud_network_recv_renew
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the link state and send notification to host
|
||||||
|
*/
|
||||||
|
void tud_network_link_state(uint8_t rhport, bool is_up) {
|
||||||
|
TU_LOG_DRV("tud_network_link_state(%d, %d)\n", rhport, is_up);
|
||||||
|
|
||||||
|
if (ncm_interface.link_is_up == is_up) {
|
||||||
|
// No change in link state
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ncm_interface.link_is_up = is_up;
|
||||||
|
|
||||||
|
// Only send notification if we have an active data interface
|
||||||
|
if (ncm_interface.itf_data_alt != 1) {
|
||||||
|
TU_LOG_DRV(" link state notification skipped (interface not active)\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reset notification state to send link state update
|
||||||
|
ncm_interface.notification_xmit_state = NOTIFICATION_CONNECTED;
|
||||||
|
|
||||||
|
// Trigger notification transmission
|
||||||
|
notification_xmit(rhport, false);
|
||||||
|
}
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
//
|
//
|
||||||
// all the netd_*() stuff (interface TinyUSB -> driver)
|
// all the netd_*() stuff (interface TinyUSB -> driver)
|
||||||
@@ -774,6 +802,12 @@ void netd_init(void) {
|
|||||||
for (int i = 0; i < RECV_NTB_N; ++i) {
|
for (int i = 0; i < RECV_NTB_N; ++i) {
|
||||||
ncm_interface.recv_free_ntb[i] = &ncm_epbuf.recv[i].ntb;
|
ncm_interface.recv_free_ntb[i] = &ncm_epbuf.recv[i].ntb;
|
||||||
}
|
}
|
||||||
|
// Default link state - can be configured via CFG_TUD_NCM_DEFAULT_LINK_UP
|
||||||
|
#ifdef CFG_TUD_NCM_DEFAULT_LINK_UP
|
||||||
|
ncm_interface.link_is_up = CFG_TUD_NCM_DEFAULT_LINK_UP;
|
||||||
|
#else
|
||||||
|
ncm_interface.link_is_up = true; // Default to link up if not set.
|
||||||
|
#endif
|
||||||
} // netd_init
|
} // netd_init
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@@ -87,6 +87,11 @@ void tud_network_init_cb(void);
|
|||||||
// TODO removed later since it is not part of tinyusb stack
|
// TODO removed later since it is not part of tinyusb stack
|
||||||
extern uint8_t tud_network_mac_address[6];
|
extern uint8_t tud_network_mac_address[6];
|
||||||
|
|
||||||
|
//------------- NCM -------------//
|
||||||
|
|
||||||
|
// Set the network link state (up/down) and notify the host
|
||||||
|
void tud_network_link_state(uint8_t rhport, bool is_up);
|
||||||
|
|
||||||
//--------------------------------------------------------------------+
|
//--------------------------------------------------------------------+
|
||||||
// INTERNAL USBD-CLASS DRIVER API
|
// INTERNAL USBD-CLASS DRIVER API
|
||||||
//--------------------------------------------------------------------+
|
//--------------------------------------------------------------------+
|
||||||
|
Reference in New Issue
Block a user