Exemplo n.º 1
0
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;
}
Exemplo n.º 2
0
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;
}