static void ps2_command(uint port, uchar cmd, uchar * buf, int sz) { int i; if (port) outb(PS2_CMND, 0xD4); do_assert(wait_write()); outb(PS2_DATA, cmd); do_assert(wait_read()); if (inb(PS2_DATA) != 0xFA) { assert(0); } if (buf != NULL) { for (i = 0; wait_read() && i < sz; i++) { buf[i] = inb(PS2_DATA); } } }
// device should be disabled static void detect_device(uint port, uchar enable, uchar test, uchar mask) { ps2_device * ps2d; uchar check = 0; ushort type = 0; if (get_config() & mask) { outb(PS2_CMND, enable); if (!(get_config() & mask)) { outb(PS2_CMND, test); do_assert(wait_read()); if (!inb(PS2_DATA)) { ps2_command(port, 0xFF, &check, 1); if (check == 0xAA) { ps2_command(port, 0xF5, NULL, 0); ps2_command(port, 0xF2, (uchar *)(&type), 2); if (type == PS2_NO_DEVICE) { type = PS2_KB_NORMAL; } if (type == PS2_KB_NORMAL || type == PS2_KB_MF2) { ps2_devs[port] = create_stream( sizeof(unsigned), ps2_kb_enable, ps2_kb_disable, ps2_kb_read, NULL ); ps2d = kalloc(sizeof(ps2_device)); ps2d->type = type; ps2d->port = port; ps2_devs[port]->data = ps2d; reg_dev(DEVICE_INPUT, ps2_devs[port]->hndl); enable_device(ps2_devs[port]); } else { ps2_devs[port] = NULL; //TODO: implement } kprintf("PS/2 Device %x detected.\n", type); } } else { outb(PS2_CMND, enable - 1); } } } }
static ssize_t mailstream_low_ssl_read(mailstream_low * s, void * buf, size_t count) { struct mailstream_ssl_data * ssl_data; int r; ssl_data = (struct mailstream_ssl_data *) s->data; if (mailstream_cancel_cancelled(ssl_data->cancel)) return -1; while (1) { int ssl_r; r = SSL_read(ssl_data->ssl_conn, buf, count); if (r > 0) return r; ssl_r = SSL_get_error(ssl_data->ssl_conn, r); switch (ssl_r) { case SSL_ERROR_NONE: return r; case SSL_ERROR_ZERO_RETURN: return r; case SSL_ERROR_WANT_READ: r = wait_read(s); if (r < 0) return r; break; default: return -1; } } }
static ssize_t mailstream_low_ssl_read(mailstream_low * s, void * buf, size_t count) { struct mailstream_ssl_data * ssl_data; int r; ssl_data = (struct mailstream_ssl_data *) s->data; if (mailstream_cancel_cancelled(ssl_data->cancel)) return -1; while (1) { r = gnutls_record_recv(ssl_data->session, buf, count); if (r > 0) return r; switch (r) { case 0: /* closed connection */ return -1; case GNUTLS_E_REHANDSHAKE: do { r = gnutls_handshake(ssl_data->session); } while (r == GNUTLS_E_AGAIN || r == GNUTLS_E_INTERRUPTED); break; /* re-receive */ case GNUTLS_E_AGAIN: case GNUTLS_E_INTERRUPTED: r = wait_read(s); if (r < 0) return r; break; default: return -1; } } }
void detect_ps2(void) { // disable ps/2 devices outb(PS2_CMND, 0xAD); outb(PS2_CMND, 0xA7); flush_output(); // disable interrupts and translation chg_config(0x43, 0); // ps/2 controller self test outb(PS2_CMND, 0xAA); do_assert(wait_read()); if (inb(PS2_DATA) != 0x55) { kputs("PS/2 Controller self test failed.\n"); return; } // individual device detection detect_device(0, 0xAE, 0xAB, 0x10); detect_device(1, 0xA8, 0xA9, 0x20); }
int main() { /* using NAME_MAX prevents EINVAL on read() (twice for UTF-16 on NTFS) */ char buf[sizeof(struct inotify_event) + NAME_MAX*2 + 1]; char *crtpath, *qpath, *rqpath, *looppath, *lsthost, *lstport; int sz, offset, rereg, evqok, retryid; struct inotify_event *iev; double retrytmout, lastclock; /* init logging */ syslog_init(); /* extract environment */ crtpath = alloc_env(CABLE_CERTS, "/" CERTS_NAME); qpath = alloc_env(CABLE_QUEUES, "/" QUEUE_NAME); rqpath = alloc_env(CABLE_QUEUES, "/" RQUEUE_NAME); looppath = alloc_env(CABLE_HOME, "/" LOOP_NAME); lsthost = alloc_env(CABLE_HOST, ""); lstport = alloc_env(CABLE_PORT, ""); /* initialize rng */ if (!rand_init()) warning("failed to initialize RNG"); /* initialize process accounting */ if (!init_process_acc()) warning("failed to initialize process accounting"); /* initialize webserver */ if (!init_server(crtpath, qpath, rqpath, lsthost, lstport)) { flog(LOG_ERR, "failed to initialize webserver"); return EXIT_FAILURE; } /* try to reregister watches as long as no signal caught */ for (lastclock = getmontime(), retryid = 0; !stop_requested(); ) { /* support empty CABLE_NOLOOP when testing, to act as pure server */ #ifdef TESTING if (getenv("CABLE_NOLOOP")) { sleepsec(RETRY_TMOUT); continue; } #endif wait_reg_watches(qpath, rqpath); /* read events as long as no signal caught and no unmount / move_self / etc. events read */ for (rereg = evqok = 0; !stop_requested() && !rereg; ) { /* wait for an event, or timeout (later blocking read() results in error) */ retrytmout = RETRY_TMOUT + RETRY_TMOUT * (rand_shift() / 2); if (wait_read(inotfd, retrytmout - (getmontime() - lastclock))) { /* read events (non-blocking), taking care to handle interrupts due to signals */ if ((sz = read(inotfd, buf, sizeof(buf))) == -1 && errno != EINTR) { /* happens buffer is too small (e.g., NTFS + 255 unicode chars) */ warning("error while reading from inotify queue"); rereg = 1; } /* process all events in buffer, sz = -1 and 0 are automatically ignored */ for (offset = 0; offset < sz && !stop_requested() && !rereg; evqok = 1) { /* get handler to next event in read buffer, and update offset */ iev = (struct inotify_event*) (buf + offset); offset += sizeof(struct inotify_event) + iev->len; /* IN_IGNORED is triggered by watched directory removal / fs unmount IN_MOVE_SELF is only triggered by move of actual watched directory (i.e., not its parent) */ if ((iev->mask & (IN_IGNORED | IN_UNMOUNT | IN_Q_OVERFLOW | IN_MOVE_SELF))) rereg = 1; /* ignore non-subdirectory events, and events with incorrect name */ else if (iev->len > 0 && (iev->mask & IN_ISDIR) && is_msgdir(iev->name)) { assert(iev->wd == inotqwd || iev->wd == inotrqwd); if (iev->wd == inotqwd || iev->wd == inotrqwd) { /* stop can be indicated here (while waiting for less processes) */ const char *qtype = (iev->wd == inotqwd) ? QUEUE_NAME : RQUEUE_NAME; run_loop(qtype, iev->name, looppath); } else flog(LOG_WARNING, "unknown watch descriptor"); } } } /* if sufficient time passed since last retries, retry again */ if (!stop_requested() && getmontime() - lastclock >= retrytmout) { /* alternate between queue dirs to prevent lock starvation on self-send */ if ((retryid ^= 1)) retry_dir(QUEUE_NAME, qpath, looppath); else retry_dir(RQUEUE_NAME, rqpath, looppath); lastclock = getmontime(); /* inotify is apparently unreliable on fuse, so reregister when no events */ if (!evqok) rereg = 1; evqok = 0; } } } unreg_watches(); if (!shutdown_server()) flog(LOG_WARNING, "failed to shutdown webserver"); dealloc_env(lstport); dealloc_env(lsthost); dealloc_env(looppath); dealloc_env(rqpath); dealloc_env(qpath); dealloc_env(crtpath); flog(LOG_INFO, "exiting"); closelog(); return EXIT_SUCCESS; }
static uchar get_config(void) { outb(PS2_CMND, 0x20); do_assert(wait_read()); return inb(PS2_DATA); }