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 void *novacom_usb_tx_thread(void *arg) { novacom_usb_handle_t *handle = (novacom_usb_handle_t *)arg; int rc; struct novacom_tx_packet packet; char *buf; buf = platform_calloc(MAX_MTU); platform_assert(buf != NULL); LTRACEF("start::wait for startup event: %p\n", handle); platform_event_wait(&handle->tx_startup_event); //why waiting rx for starting ??? handle->tx_startup_wait = 0; //change status to started LTRACEF("start::startup event received, continue: %p\n", handle); handle->tx_timeout = novacom_usbll_get_timeout(handle->usbll_handle); while (!novacom_shutdown && !handle->shutdown) { // see if we have something to send packet.len = novacom_usbll_get_mtu(handle->usbll_handle); packet.buf = buf; if (novacom_usbll_prepare_tx_packet(handle->usbll_handle, &packet, 100) != TX_NO_PACKET) { // write a block back #if FAULTY_TX if (rand() < (RAND_MAX / 10)) { TRACEF("dropped tx packet\n"); } else { #endif rc = novacom_usb_write(handle, packet.buf, packet.len); if (rc < 0) { platform_time_t st; platform_time_t et; int time_used = 0; unsigned int count = 0; TRACEL(LOG_ALWAYS, "usbll(%08x) error writing packet, result(%d), errno %d\n", novacom_usbll_getuid(handle->usbll_handle), rc, errno); platform_get_time(&st); 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_write(handle, packet.buf, packet.len); count++; } TRACEL(LOG_ALWAYS, "usbll(%08x) writing packet, writes(%ld), duration(%dms), result(%d), last_errno %ld\n", novacom_usbll_getuid(handle->usbll_handle), count, platform_delta_time_msecs(&st, &et), rc, errno); count = 0; } if (rc >=0) { TRACEF/*LOG_PRINTF*/("usbll(%08x) wrote tx packet len=%d\n", novacom_usbll_getuid(handle->usbll_handle), rc); } #if FAULTY_TX } #endif } } LTRACEF("shutting down handle %p\n", handle); platform_event_signal(&handle->tx_shutdown_event); 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; }
static void *tx_thread_entry(void *arg) { device_pthread_setaffinity(); int rc; int state; struct novacom_tx_packet packet; const struct aiocb * list[1]; list[0] = &txaio; LOG_PRINTF("entry\n"); while (usb_online) { // see if we have something to send packet.len = novacom_usbll_get_mtu(usbll_handle); packet.buf = tx_buffer; state = novacom_usbll_get_state(usbll_handle); if (novacom_usbll_prepare_tx_packet(usbll_handle, &packet, 100) != TX_NO_PACKET) { #if LOCAL_TRACE_RW // write a block back LTRACEF("going to write packet\n"); #endif #if 0 rc = write(ep1in_fd, packet.buf, packet.len); LTRACEF("rc %d\n", rc); if (rc < 0) { TRACEF("error writing packet\n"); break; } #else rc = queue_tx(ep1in_fd, packet.buf, packet.len); if (rc < 0) { LOG_PRINTF("USB aio_write error, ret=%d, errno=%d\n", rc, errno); usleep(1000*GADGETFS_IO_RETRY_DELAY); novacom_usbll_changeback_state(usbll_handle, state); continue; } struct timespec timeout; rc = suspend(list, 1, &timeout); while (rc < 0 && errno == EAGAIN) { LOG_PRINTF("USB aio_suspend (for write) error, ret=%d, errno=%d\n", rc, errno); rc = suspend(list, 1, &timeout); if (rc >= 0) { LOG_PRINTF("USB aio_suspend (for write) ret=%d, errno=%d\n", rc, errno); } }; #if 0 //do we need it ??? if (rc < 0) { LTRACEF("timeout on tx\n"); rc = aio_suspend(list, 1, NULL); } #endif if (aio_error(&txaio) != EINPROGRESS) { rc = aio_return(&txaio); if (rc < 0) { /* online->offline transition */ LOG_PRINTF("USB aio_return (for write) error, ret=%d, \n", rc); if( (usb_online != gadgetfs_online) && (true == usb_online) ) { int ret = platform_event_wait_timeout(&usb_online_event, TRANSPORT_RECOVERY_TIMEOUT * 1000*2); if (!ret) { LOG_PRINTF("platform_event_wait_timeout for usb_online_event, ret=%d\n", ret); } else { LOG_PRINTF("platform_event_wait_timeout for usb_online_event, ret=%d, ignored\n", ret); } } } } else { LOG_PRINTF("we should never enter here (EINPROGRESS=%d), USB aio write seems to have problem!\n", EINPROGRESS); } if (rc < 0) { novacom_usbll_changeback_state(usbll_handle, state); } else { static platform_time_t prior; static int init = 0; static unsigned int tx_bytes = 0, tx_packets = 0; platform_time_t curr; tx_bytes += packet.len; tx_packets++; if (!init) { platform_get_time(&prior); init = 1; } platform_get_time(&curr); if (platform_delta_time_msecs(&prior, &curr) >= 2800) { //logging for every 3sec platform_get_time(&prior); LOG_PRINTF("wrote %u bytes, %u packets\n",tx_bytes, tx_packets); } } #endif } } LOG_PRINTF("shutting down\n"); platform_event_signal(&tx_shutdown_event); return NULL; }
static void *rx_thread_entry(void *arg) { device_pthread_setaffinity(); int rc; const struct aiocb * list[1]; list[0] = &rxaio; LOG_PRINTF("entry\n"); while (usb_online) { #if LOCAL_TRACE_RW LTRACEF("going to read packet\n"); #endif #if 0 rc = read(ep2out_fd, rx_buffer, sizeof(rx_buffer)); LTRACEF("read rc %d\n", rc); if (rc < 0) { TRACEF("error reading packet\n"); } if (rc > 0) { novacom_usbll_process_packet(usbll_handle, rx_buffer, rc); } #else rc = queue_rx(ep2out_fd, rx_buffer, novacom_usbll_get_mtu(usbll_handle)); if (rc < 0) { LOG_PRINTF("USB aio_read error, ret=%d, errno=%d\n", rc, errno); usleep(1000*GADGETFS_IO_RETRY_DELAY); continue; } struct timespec timeout; rc = suspend(list, 1, &timeout); while (rc < 0 && errno == EAGAIN) { LOG_PRINTF("USB aio_suspend (for read) error, ret=%d, errno=%d\n", rc, errno); rc = suspend(list, 1, &timeout); if (rc >= 0) { LOG_PRINTF("USB aio_suspend (for read), ret=%d, errno=%d\n", rc, errno); } //the gadget_fs event should be the source to notify usb device offline ///novacom_usbll_drop_offline(usbll_handle); // suspend after usbll_drop_offline ????? ///aio_suspend(list, 1, NULL); }; if (aio_error(&rxaio) != EINPROGRESS) { rc = aio_return(&rxaio); #if LOCAL_TRACE_RW LTRACEF("rx successful: nbytes %d\n", rc); #endif if (rc > 0) { rc = novacom_usbll_process_packet(usbll_handle, rx_buffer, rc); if (rc == PACKET_TYPE_BADPACKET) { LOG_PRINTF("Received bad packet, ret=%d, \n", rc); } } else { /* online->offline transition */ LOG_PRINTF("USB aio_return (for read) error, ret=%d, \n", rc); if( (usb_online != gadgetfs_online) && (true == usb_online) ) { int ret = platform_event_wait_timeout(&usb_online_event, TRANSPORT_RECOVERY_TIMEOUT * 1000*2); if (!ret) { LOG_PRINTF("platform_event_wait_timeout for usb_online_event, ret=%d\n", ret); } else { LOG_PRINTF("platform_event_wait_timeout for usb_online_event, ret=%d, ignored\n", ret); } } } } else { LOG_PRINTF("we should never enter here (EINPROGRESS=%d), USB aio read seems to have problem!\n", EINPROGRESS); } #endif } LOG_PRINTF("shutting down\n"); platform_event_signal(&rx_shutdown_event); return NULL; }