static void *ep0_thread (void *param) { int fd = *(int*) param; struct sigaction action; time_t now, last; struct pollfd ep0_poll; source = sink = ep0 = pthread_self (); pthread_cleanup_push (close_fd, param); /* REVISIT signal handling ... normally one pthread should * be doing sigwait() to handle all async signals. */ action.sa_sigaction = signothing; sigfillset (&action.sa_mask); action.sa_flags = SA_SIGINFO; if (sigaction (SIGINT, &action, NULL) < 0) { perror ("SIGINT"); return 0; } if (sigaction (SIGQUIT, &action, NULL) < 0) { perror ("SIGQUIT"); return 0; } ep0_poll.fd = fd; ep0_poll.events = POLLIN | POLLOUT | POLLHUP; fprintf(stderr,"ep0 thread\n"); /* event loop */ last = 0; for (;;) { int tmp; struct usb_gadgetfs_event event [NEVENT]; int connected = 0; int i, nevent; /* Use poll() to test that mechanism, to generate * activity timestamps, and to make it easier to * tweak this code to work without pthreads. When * AIO is needed without pthreads, ep0 can be driven * instead using SIGIO. */ tmp = poll(&ep0_poll, 1, -1); if (verbose) { time (&now); if ((now - last) > LOGDELAY) { char timebuf[26]; last = now; ctime_r (&now, timebuf); printf ("\n** %s", timebuf); } } if (tmp < 0) { /* exit path includes EINTR exits */ perror("poll"); break; } fprintf(stderr,"ep0 read\n"); tmp = read (fd, &event, sizeof event); if (tmp < 0) { if (errno == EAGAIN) { sleep (1); continue; } perror ("ep0 read after poll"); goto done; } nevent = tmp / sizeof event [0]; if (nevent != 1 && verbose) fprintf (stderr, "read %d ep0 events\n", nevent); for (i = 0; i < nevent; i++) { switch (event [i].type) { case GADGETFS_NOP: if (verbose) fprintf (stderr, "NOP\n"); break; case GADGETFS_CONNECT: connected = 1; current_speed = event [i].u.speed; if (verbose) fprintf (stderr, "CONNECT %s\n", speed (event [i].u.speed)); break; case GADGETFS_SETUP: connected = 1; handle_control (fd, &event [i].u.setup); break; case GADGETFS_DISCONNECT: connected = 0; current_speed = USB_SPEED_UNKNOWN; if (verbose) fprintf(stderr, "DISCONNECT\n"); stop_io (); break; case GADGETFS_SUSPEND: // connected = 1; if (verbose) fprintf (stderr, "SUSPEND\n"); break; default: fprintf (stderr, "* unhandled event %d\n", event [i].type); } } continue; done: fflush (stdout); if (connected) stop_io (); break; } if (verbose) fprintf (stderr, "done\n"); fflush (stdout); pthread_cleanup_pop (1); return 0; }
int usb_device_c::handle_packet(USBPacket *p) { int l, ret = 0; int len = p->len; Bit8u *data = p->data; switch(p->pid) { case USB_MSG_ATTACH: d.state = USB_STATE_ATTACHED; break; case USB_MSG_DETACH: d.state = USB_STATE_NOTATTACHED; break; case USB_MSG_RESET: d.remote_wakeup = 0; d.addr = 0; d.state = USB_STATE_DEFAULT; handle_reset(); break; case USB_TOKEN_SETUP: if (d.state < USB_STATE_DEFAULT || p->devaddr != d.addr) return USB_RET_NODEV; if (len != 8) goto fail; d.stall = 0; memcpy(d.setup_buf, data, 8); d.setup_len = (d.setup_buf[7] << 8) | d.setup_buf[6]; d.setup_index = 0; if (d.setup_buf[0] & USB_DIR_IN) { ret = handle_control((d.setup_buf[0] << 8) | d.setup_buf[1], (d.setup_buf[3] << 8) | d.setup_buf[2], (d.setup_buf[5] << 8) | d.setup_buf[4], d.setup_len, d.data_buf); if (ret < 0) return ret; if (ret < d.setup_len) d.setup_len = ret; d.setup_state = SETUP_STATE_DATA; } else { if (d.setup_len == 0) d.setup_state = SETUP_STATE_ACK; else d.setup_state = SETUP_STATE_DATA; } break; case USB_TOKEN_IN: if (d.state < USB_STATE_DEFAULT || p->devaddr != d.addr) return USB_RET_NODEV; if (d.stall) goto fail; switch(p->devep) { case 0: switch(d.setup_state) { case SETUP_STATE_ACK: if (!(d.setup_buf[0] & USB_DIR_IN)) { d.setup_state = SETUP_STATE_IDLE; ret = handle_control((d.setup_buf[0] << 8) | d.setup_buf[1], (d.setup_buf[3] << 8) | d.setup_buf[2], (d.setup_buf[5] << 8) | d.setup_buf[4], d.setup_len, d.data_buf); if (ret > 0) ret = 0; } else { // return 0 byte } break; case SETUP_STATE_DATA: if (d.setup_buf[0] & USB_DIR_IN) { l = d.setup_len - d.setup_index; if (l > len) l = len; memcpy(data, d.data_buf + d.setup_index, l); d.setup_index += l; if (d.setup_index >= d.setup_len) d.setup_state = SETUP_STATE_ACK; ret = l; } else { d.setup_state = SETUP_STATE_IDLE; goto fail; } break; default: goto fail; } break; default: ret = handle_data(p); break; } break; case USB_TOKEN_OUT: if (d.state < USB_STATE_DEFAULT || p->devaddr != d.addr) return USB_RET_NODEV; if (d.stall) goto fail; switch(p->devep) { case 0: switch(d.setup_state) { case SETUP_STATE_ACK: if (d.setup_buf[0] & USB_DIR_IN) { d.setup_state = SETUP_STATE_IDLE; // transfer OK } else { // ignore additionnal output } break; case SETUP_STATE_DATA: if (!(d.setup_buf[0] & USB_DIR_IN)) { l = d.setup_len - d.setup_index; if (l > len) l = len; memcpy(d.data_buf + d.setup_index, data, l); d.setup_index += l; if (d.setup_index >= d.setup_len) d.setup_state = SETUP_STATE_ACK; ret = l; } else { // it is okay for a host to send an OUT before it reads // all of the expected IN. It is telling the controller // that it doesn't want any more from that particular call. ret = 0; d.setup_state = SETUP_STATE_IDLE; } break; default: goto fail; } break; default: ret = handle_data(p); break; } break; default: fail: d.stall = 1; ret = USB_RET_STALL; break; } return ret; }
int main (int argc, char const *const *argv) { iopause_fd x[2] = { { -1, IOPAUSE_READ, 0 }, { -1, IOPAUSE_READ, 0 } } ; PROG = "s6-svscan" ; { subgetopt_t l = SUBGETOPT_ZERO ; unsigned int t = 5000 ; for (;;) { register int opt = subgetopt_r(argc, argv, "t:c:", &l) ; if (opt == -1) break ; switch (opt) { case 't' : if (uint0_scan(l.arg, &t)) break ; case 'c' : if (uint0_scan(l.arg, &max)) break ; default : strerr_dieusage(100, USAGE) ; } } argc -= l.ind ; argv += l.ind ; if (t) tain_from_millisecs(&defaulttimeout, t) ; else defaulttimeout = tain_infinite_relative ; if (max < 2) max = 2 ; } /* Init phase. If something fails here, we can die, because it means that something is seriously wrong with the system, and we can't run correctly anyway. */ if (argc && (chdir(argv[0]) < 0)) strerr_diefu1sys(111, "chdir") ; x[1].fd = s6_supervise_lock(S6_SVSCAN_CTLDIR) ; x[0].fd = selfpipe_init() ; if (x[0].fd < 0) strerr_diefu1sys(111, "selfpipe_init") ; if (sig_ignore(SIGPIPE) < 0) strerr_diefu1sys(111, "ignore SIGPIPE") ; { sigset_t set ; sigemptyset(&set) ; sigaddset(&set, SIGCHLD) ; sigaddset(&set, SIGALRM) ; sigaddset(&set, SIGTERM) ; sigaddset(&set, SIGHUP) ; sigaddset(&set, SIGQUIT) ; sigaddset(&set, SIGABRT) ; sigaddset(&set, SIGINT) ; sigaddset(&set, SIGUSR1) ; if (selfpipe_trapset(&set) < 0) strerr_diefu1sys(111, "trap signals") ; } { struct svinfo_s blob[max] ; /* careful with that stack, Eugene */ services = blob ; tain_now_g() ; /* Loop phase. From now on, we must not die. Temporize on recoverable errors, and panic on serious ones. */ while (cont) { int r ; tain_add_g(&deadline, &defaulttimeout) ; reap() ; scan() ; killthem() ; r = iopause_g(x, 2, &deadline) ; if (r < 0) panic("iopause") ; else if (!r) wantscan = 1 ; else { if ((x[0].revents | x[1].revents) & IOPAUSE_EXCEPT) { errno = EIO ; panic("check internal pipes") ; } if (x[0].revents & IOPAUSE_READ) handle_signals() ; if (x[1].revents & IOPAUSE_READ) handle_control(x[1].fd) ; } } /* Finish phase. */ selfpipe_finish() ; killthem() ; reap() ; } { char const *eargv[3] = { FINISH_PROG, finish_arg, 0 } ; execve(eargv[0], (char **)eargv, (char *const *)environ) ; } panicnosp("exec finish script " FINISH_PROG) ; }
int main (int argc, char const *const *argv) { iopause_fd x[2] = { { -1, IOPAUSE_READ, 0 }, { -1, IOPAUSE_READ, 0 } } ; PROG = "s6-supervise" ; if (argc < 2) strerr_dieusage(100, USAGE) ; if (chdir(argv[1]) < 0) strerr_diefu2sys(111, "chdir to ", argv[1]) ; { register unsigned int proglen = str_len(PROG) ; register unsigned int namelen = str_len(argv[1]) ; char progname[proglen + namelen + 2] ; byte_copy(progname, proglen, PROG) ; progname[proglen] = ' ' ; byte_copy(progname + proglen + 1, namelen + 1, argv[1]) ; PROG = progname ; if (!fd_sanitize()) strerr_diefu1sys(111, "sanitize stdin and stdout") ; x[1].fd = s6_supervise_lock(S6_SUPERVISE_CTLDIR) ; if (!ftrigw_fifodir_make(S6_SUPERVISE_EVENTDIR, getegid(), 0)) strerr_diefu2sys(111, "mkfifodir ", S6_SUPERVISE_EVENTDIR) ; x[0].fd = selfpipe_init() ; if (x[0].fd == -1) strerr_diefu1sys(111, "init selfpipe") ; if (sig_ignore(SIGPIPE) < 0) strerr_diefu1sys(111, "ignore SIGPIPE") ; { sigset_t set ; sigemptyset(&set) ; sigaddset(&set, SIGTERM) ; sigaddset(&set, SIGHUP) ; sigaddset(&set, SIGQUIT) ; sigaddset(&set, SIGCHLD) ; if (selfpipe_trapset(&set) < 0) strerr_diefu1sys(111, "trap signals") ; } if (!ftrigw_clean(S6_SUPERVISE_EVENTDIR)) strerr_warnwu2sys("ftrigw_clean ", S6_SUPERVISE_EVENTDIR) ; { struct stat st ; if (stat("down", &st) == -1) { if (errno != ENOENT) strerr_diefu1sys(111, "stat down") ; } else status.flagwantup = 0 ; if (stat("nosetsid", &st) == -1) { if (errno != ENOENT) strerr_diefu1sys(111, "stat nosetsid") ; } else flagsetsid = 0 ; } tain_now_g() ; settimeout(0) ; tain_copynow(&status.stamp) ; announce() ; ftrigw_notifyb_nosig(S6_SUPERVISE_EVENTDIR, "s", 1) ; while (cont) { register int r = iopause_g(x, 2, &deadline) ; if (r < 0) strerr_diefu1sys(111, "iopause") ; else if (!r) (*actions[state][V_TIMEOUT])() ; else { if ((x[0].revents | x[1].revents) & IOPAUSE_EXCEPT) strerr_diefu1x(111, "iopause: trouble with pipes") ; if (x[0].revents & IOPAUSE_READ) handle_signals() ; else if (x[1].revents & IOPAUSE_READ) handle_control(x[1].fd) ; } } ftrigw_notifyb_nosig(S6_SUPERVISE_EVENTDIR, "x", 1) ; } return 0 ; }