static void *novacom_usb_rx_thread(void *arg) { novacom_usb_handle_t *handle = (novacom_usb_handle_t *)arg; transport_recovery_token_t *rec_token = NULL; ///< recovery token int rc; int packet_type; char *buf; int sniff = 1; buf = platform_calloc(MAX_MTU); platform_assert(buf != NULL); LTRACEF("start, handle %p\n", handle); handle->rx_timeout = novacom_usbll_get_timeout(handle->usbll_handle); while (!novacom_shutdown && !handle->shutdown) { platform_time_t st; int time_used; // read a block from the pmux rc = novacom_usb_read(handle, buf, novacom_usbll_get_mtu(handle->usbll_handle)); platform_get_time(&st); time_used = 0; if (rc <= 0) { platform_time_t et; unsigned int count = 0; TRACEL(LOG_ALWAYS, "%s:%d -- usbll(%08x) error: reading packet, result(%d), errno %d\n", __FUNCTION__, __LINE__, novacom_usbll_getuid(handle->usbll_handle), rc, errno); while (rc <= 0 && !handle->shutdown) { //shutdown asap platform_get_time(&et); if (platform_delta_time_msecs(&st, &et) >= g_usbio_retry_timeout) { handle->shutdown = true; break; } if (g_usbio_retry_delay > 0) { if ((g_usbio_retry_timeout-time_used) >= g_usbio_retry_delay) { usleep(g_usbio_retry_delay * 1000); time_used += g_usbio_retry_delay; } else { usleep((g_usbio_retry_timeout - time_used) * 1000); time_used = g_usbio_retry_timeout; } } rc = novacom_usb_read(handle, buf, novacom_usbll_get_mtu(handle->usbll_handle)); count++; } TRACEL(LOG_ALWAYS, "%s:%d -- usbll(%08x) reading packet, reads(%ld), duration(%dms), result(%d), last_errno %ld\n", __FUNCTION__, __LINE__, novacom_usbll_getuid(handle->usbll_handle), count, platform_delta_time_msecs(&st, &et), rc, errno); count = 0; } /* sniff */ if(sniff) { uint32_t uid = ((handle->busnum & 0x0FFFF) << 16) | (handle->devnum & 0x0FFFF); transport_recovery_token_t sniff_token; int ret; /* generate token from packet */ ret = novacom_usbll_generate_recovery_token(buf, rc, &sniff_token); if(ret == -1) { TRACEL(LOG_ERROR, "%s:%d -- Used out system resouce, exit now !!!\n", __FUNCTION__, __LINE__); abort(); } /* check queue for saved connections */ ret = usbrecords_find(&sniff_token); /* free interface recovery token */ platform_free(sniff_token.token); /* check result: create new handle, or recover */ if(ret) { LTRACEF("Unable to recover(%d)\n", ret); handle->usbll_handle = novacom_usbll_create(handle->devtype, MAX_MTU, 0, USBDEVFS_IOCTL_TIMEOUT); } else { TRACEL(LOG_ERROR, "Recovered record...\n"); handle->usbll_handle = sniff_token.user_data; } /* update uid */ novacom_usbll_setuid(handle->usbll_handle, uid); handle->rx_timeout = novacom_usbll_get_timeout(handle->usbll_handle); handle->tx_timeout = novacom_usbll_get_timeout(handle->usbll_handle); sniff = 0; } /* process */ packet_type = PACKET_TYPE_NULL; if (rc > 0) { // process it packet_type = novacom_usbll_process_packet(handle->usbll_handle, buf, rc); if (packet_type == PACKET_TYPE_BADPACKET) { platform_time_t et; TRACEF("received bad packet\n"); platform_get_time(&et); if (platform_delta_time_msecs(&st, &et) >= g_usbio_retry_timeout) { handle->shutdown = true; break; } if (g_usbio_retry_delay > 0) { if ((g_usbio_retry_timeout-time_used) >= g_usbio_retry_delay) { usleep(g_usbio_retry_delay * 1000); time_used += g_usbio_retry_delay; } else { usleep((g_usbio_retry_timeout - time_used) * 1000); time_used = g_usbio_retry_timeout; } } ///handle->shutdown = true; ///break; } else if(handle->tx_startup_wait) { platform_event_signal(&handle->tx_startup_event); } } else { #if TRACE_ZERO_LEN_PACKETS log_printf(LOG_TRACE, "RX zero len\n"); #endif } } LTRACEF("shutting down handle %p\n", handle); /* wake up tx thread (if still waits for startup) */ if(handle->tx_startup_wait) { LTRACEF("wake up tx thread\n"); platform_event_signal(&handle->tx_startup_event); } /* wait for the tx thread to exit */ LTRACEF("waiting on tx thread\n"); platform_event_wait(&handle->tx_shutdown_event); /* RX thread is responsible for cleaning up */ LTRACEF("cleaning up handle %p\n", handle); /* grab recovery token if available */ if(handle->usbll_handle) { rc = -1; rec_token = platform_calloc(sizeof(transport_recovery_token_t)); if(rec_token) { snprintf(rec_token->nduid, sizeof(rec_token->nduid), "%s", novacom_usbll_get_nduid(handle->usbll_handle)); rc = novacom_usbll_get_recovery_token(handle->usbll_handle, rec_token); if(rc != -1) { rc = usbrecords_add(rec_token); } else { LTRACEF("unable to recovery token!!!\n"); } } /* error: free memory, destroy device */ if(rc == -1) { //we should never go here. novacom_usbll_destroy(handle->usbll_handle); platform_free(rec_token); } } novacom_usb_close(handle); platform_event_destroy(&handle->tx_startup_event); platform_event_destroy(&handle->tx_shutdown_event); platform_free(handle); platform_free(buf); return NULL; }
static int set_usb_online(bool on) { if (on) { if (!usb_online) { /*init */ auth_init(); /* sleep for a second to let things settle down */ sleep(1); platform_event_unsignal(&tx_shutdown_event); platform_event_unsignal(&rx_shutdown_event); usbll_handle = novacom_usbll_create("host", MAX_MTU, 0, 0); ep1in_fd = open(ep1in_name, O_RDWR); LOG_PRINTF("ep1 %d\n", ep1in_fd); if (ep1in_fd < 0) { log_printf(LOG_ERROR, "error opening endpoint 1\n"); return -1; } fcntl(ep1in_fd, F_SETFD, FD_CLOEXEC); ep2out_fd = open(ep2out_name, O_RDWR); LOG_PRINTF("ep2 %d\n", ep2out_fd); if (ep2out_fd < 0) { log_printf(LOG_ERROR, "error opening endpoint 2\n"); close(ep1in_fd); return -1; } fcntl(ep2out_fd, F_SETFD, FD_CLOEXEC); usb_online = true; platform_event_signal(&usb_online_event); /* create the worker threads */ LOG_PRINTF("starting worker threads\n"); platform_create_thread(NULL, &tx_thread_entry, NULL); platform_create_thread(NULL, &rx_thread_entry, NULL); } else if(false == gadgetfs_online) { /* postponed_offline->online */ platform_event_signal(&usb_online_event); } } else { if (usb_online) { //change state before sending out signal! usb_online = false; platform_event_signal(&usb_online_event); /* wait for the existing worker threads to go away */ LOG_PRINTF("waiting for worker threads to go away\n"); platform_event_wait(&tx_shutdown_event); close(ep1in_fd); LOG_PRINTF("closed tx_thread\n"); platform_event_wait(&rx_shutdown_event); close(ep2out_fd); LOG_PRINTF("closed rx_thread\n"); novacom_usbll_destroy(usbll_handle); LOG_PRINTF("destroyed novacom usbll_handle\n"); /* clear auth */ auth_reset(); } } return 0; }