Beispiel #1
0
int novacom_usb_transport_start(void)
{

	/*clear auth */
	auth_reset();

	/* create an event to drive the io worker thread */
	platform_event_create(&usb_online_event);
	platform_event_unsignal(&usb_online_event);

	/* create a set of events to track the status of the io threads */
	platform_event_create(&rx_shutdown_event);
	platform_event_unsignal(&rx_shutdown_event);
	platform_event_create(&tx_shutdown_event);
	platform_event_unsignal(&tx_shutdown_event);

	/* create a thread to run the control endpoint */
	platform_create_thread(NULL, &ep0_thread, NULL);

	return 0;
}
Beispiel #2
0
/* main worker thread */
static void *novacom_usb_findandattach_thread(void *arg)
{
	novacom_usb_handle_t *usb;

	/* init records */
	usbrecords_init();

	/* initialize records queue */
	TAILQ_INIT(&t_recovery_queue);

	/* device discovery */
	while (!novacom_shutdown) {

		usb = novacom_usb_open();
		if (usb ) {
			usb->shutdown = false;
			TRACEF("usb_handle 0x%08x, bus=%03d dev=%03d\n", usb->usbll_handle, usb->busnum, usb->devnum);
			platform_event_create(&usb->tx_startup_event);
			platform_event_unsignal(&usb->tx_startup_event);
			usb->tx_startup_wait = 1;
			platform_event_create(&usb->tx_shutdown_event);
			platform_event_unsignal(&usb->tx_shutdown_event);
	
			platform_create_thread(NULL, &novacom_usb_rx_thread, (void *)usb);
			platform_create_thread(NULL, &novacom_usb_tx_thread, (void *)usb);
		}
	
		if (!novacom_shutdown) {
			sleep(1); // dont peg the cpu waiting for usb
			/* check recovery records, shutdown interface if timeout expired */
			(void) usbrecords_update( 1 );	/* assume 1sec delay */
		}
	}

	/* update records: forcing shutdown of all records */
	usbrecords_update(TRANSPORT_RECOVERY_TIMEOUT);

	return NULL;
}
Beispiel #3
0
static void *ep0_thread(void *arg)
{
	device_pthread_setaffinity();

	char buf[sizeof(struct usb_gadgetfs_event)*10]; /* store up to 10 events */
	fd_set fds;
	struct timeval tv;
	int rc;

	LOG_PRINTF("entry: self %ld\n", syscall(SYS_gettid));
	rc = 0; 	// re-use rc as a loop counter
retry:
	/* novacom_ep0 */
	ep0_fd = open("/dev/novacom_ep0", O_RDWR);
	if (ep0_fd >= 0) {
		ep1in_name = "/dev/novacom_ep_in";
		ep2out_name = "/dev/novacom_ep_out";
		goto opened;
	}

	/* try the omap3's usb port first */
	ep0_fd = open("/dev/gadget/musb_hdrc", O_RDWR);
	if (ep0_fd >= 0) {
		struct stat stbuf;
		if (stat("/dev/gadget/ep4in", &stbuf) == 0) {
			ep1in_name = "/dev/gadget/ep4in";
			ep2out_name = "/dev/gadget/ep3out";
		} else {
			ep1in_name = "/dev/gadget/ep2in";
			ep2out_name = "/dev/gadget/ep2out";
		}
		goto opened;
	}

	/* omap2 */
	ep0_fd = open("/dev/gadget/omap_udc", O_RDWR);
	if (ep0_fd >= 0) {
		ep1in_name = "/dev/gadget/ep7in-bulk";
		ep2out_name = "/dev/gadget/ep8out-bulk";
		goto opened;
	}

	/* msm */
	ep0_fd = open("/dev/gadget/msm_hsusb", O_RDWR);
	if (ep0_fd >= 0) {
		struct stat stbuf;
		if (stat("/dev/gadget/ep4in", &stbuf) == 0) {
			ep1in_name = "/dev/gadget/ep4in";
			ep2out_name = "/dev/gadget/ep3out";
		} else {
			ep1in_name = "/dev/gadget/ep2in";
			ep2out_name = "/dev/gadget/ep2out";
		}
		goto opened;
	}

	/* fail */
	rc++;
	if (rc >= GADGET_RETRY_COUNT) {
		log_printf(LOG_ERROR, "failed to open gadgetfs %d times - giving up on usb\n", rc);
		return (NULL);
	}

	log_printf(LOG_ERROR, "failed to open gadgetfs ep0 node - retry\n");
	sleep(1);
	goto retry;

opened:
	fcntl(ep0_fd, F_SETFD, FD_CLOEXEC);

	/* main loop */
	for (;;) {
		struct timeval *ptrtv = NULL;
		/* we use timeout only when required:: usb_online && gadgetfs disconnect event*/
		if( (gadgetfs_online == false) && usb_online) {
			ptrtv = &tv;
			tv.tv_sec = TRANSPORT_RECOVERY_TIMEOUT;
			tv.tv_usec = 0;
			/* about to trigger wait timer: clear event */
			platform_event_unsignal(&usb_online_event);
		}
		/* select */
		FD_ZERO(&fds);
		FD_SET(ep0_fd, &fds);
		rc = select(ep0_fd + 1, &fds, NULL, NULL, ptrtv);
		/* error */
		if(-1 == rc) {
			if((EAGAIN == errno) || (EINTR == errno)) {
				continue;
			} else {
				break;
			}
		}

		/* timeout */
		if(rc == 0) {
			/* gadgetfs reported disconnect */
			if( (gadgetfs_online == false) && usb_online) {
				LOG_PRINTF("Postponed going offline...\n");
				set_usb_online(false);
			}
			else {
				LOG_PRINTF("Timeout, usb is in online state, to continue...\n");
			}
			continue;
		}

		/*normal flow */
		if ( !(FD_ISSET(ep0_fd, &fds)) ) {
			continue;
		}
		int err = read(ep0_fd, buf, sizeof(buf));
		LOG_PRINTF("ep0 err %d\n", err);
		if (err < 0)
			break;

		struct usb_gadgetfs_event *event = (struct usb_gadgetfs_event *)buf;
		int nevents = err / sizeof(struct usb_gadgetfs_event);
		for (; nevents > 0; nevents--) {
			LOG_PRINTF("got usb event type %d: ", event->type);
			switch (event->type) {
				case GADGETFS_NOP:
					LOG_PRINTF("NOP\n");
					break;
				case GADGETFS_CONNECT:
					LOG_PRINTF("CONNECT\n");
					LOG_PRINTF("speed %d\n", event->u.speed);
					break;
				case GADGETFS_DISCONNECT:
					LOG_PRINTF("DISCONNECT\n");
					gadgetfs_online = false;
					break;
				case GADGETFS_SETUP:
					LOG_PRINTF("SETUP: requesttype 0x%x, request 0x%x, value 0x%x, index 0x%x, length 0x%x", event->u.setup.bRequestType, event->u.setup.bRequest, event->u.setup.wValue, event->u.setup.wIndex, event->u.setup.wLength);
					switch (event->u.setup.bRequest) {
						case USB_REQ_SET_INTERFACE:
							LOG_PRINTF("USB_REQ_SET_INTERFACE: %d\n", event->u.setup.wValue);

							// setting interface to 0 seems to be a disconnect
//								if (event->u.setup.wValue == 0) {
//									stop_io();
//								}
							break;
						case USB_REQ_SET_CONFIGURATION:
							LOG_PRINTF("USB_REQ_SET_CONFIGURATION: config %d\n", event->u.setup.wValue);
							if (event->u.setup.wValue > 0) {
								if(set_usb_online(true) < 0) {
									close(ep0_fd);
									goto retry;
								}
								gadgetfs_online = true;
							} else {
								gadgetfs_online = false;
							}
							break;
						default:
							LOG_PRINTF("unhandled request\n");
					}
					break;
				case GADGETFS_SUSPEND:
					LOG_PRINTF("SUSPEND\n");
					break;
				default:
					LOG_PRINTF("UNKNOWN\n");
					break;
			}

			event++;
		}
	}

	LOG_PRINTF("closing ep0\n");
	set_usb_online(false);
	close(ep0_fd);

	return NULL;
}
Beispiel #4
0
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;
}