static unsigned char add_switch_cap(dterm_t* dt, int fd) { dterm_mark_t prop; dterm_mark_t c_list; #ifndef SW_CNT #define SW_CNT SW_MAX #endif unsigned char bitmask[SW_CNT / 8 + 1]; int i = 0; if (ioctl(fd, EVIOCGBIT(EV_SW, sizeof(bitmask)), bitmask) < 0) { return IEDRV_RES_IO_ERROR; } dterm_tuple_begin(dt, &prop); dterm_atom(dt, ie_switch); dterm_list_begin(dt, &c_list); // Add all capabilities present for(i = 0; i < sizeof(sw_cap_map) / sizeof(sw_cap_map[0]); ++i) { if (t_bit(bitmask, sw_cap_map[i].bit)) { dterm_mark_t cap_tuple; dterm_tuple_begin(dt, &cap_tuple); dterm_atom(dt, sw_cap_map[i].atom); dterm_tuple_end(dt, &cap_tuple); } } dterm_list_end(dt, &c_list); dterm_tuple_end(dt, &prop); return IEDRV_RES_OK; }
static unsigned char add_sync_cap(dterm_t* dt, int fd) { dterm_mark_t prop; dterm_mark_t c_list; unsigned char bitmask[1]; // 4 SYN events. int i = 0; if (ioctl(fd, EVIOCGBIT(EV_SYN, sizeof(bitmask)), bitmask) < 0) { return IEDRV_RES_IO_ERROR; } dterm_tuple_begin(dt, &prop); dterm_atom(dt, ie_sync); dterm_list_begin(dt, &c_list); // Add all capabilities present for(i = 0; i < sizeof(sync_cap_map) / sizeof(sync_cap_map[0]); ++i) { if (t_bit(bitmask, sync_cap_map[i].bit)) { dterm_mark_t cap_tuple; dterm_tuple_begin(dt, &cap_tuple); dterm_atom(dt, sync_cap_map[i].atom); dterm_tuple_end(dt, &cap_tuple); } } dterm_list_end(dt, &c_list); dterm_tuple_end(dt, &prop); return IEDRV_RES_OK; }
static unsigned char add_key_cap(dterm_t* dt, int fd) { dterm_mark_t prop; dterm_mark_t c_list; #ifndef KEY_CNT #define KEY_CNT KEY_UNKNOWN #endif unsigned char bitmask[KEY_CNT / 8 + 1]; int i = 0; if (ioctl(fd, EVIOCGBIT(EV_KEY, sizeof(bitmask)), bitmask) < 0) { return IEDRV_RES_IO_ERROR; } dterm_tuple_begin(dt, &prop); dterm_atom(dt, ie_key); dterm_list_begin(dt, &c_list); // Add all capabilities present for(i = 0; i < sizeof(key_cap_map) / sizeof(key_cap_map[0]); ++i) if (t_bit(bitmask, key_cap_map[i].bit)) { dterm_mark_t cap_tuple; dterm_tuple_begin(dt, &cap_tuple); dterm_atom(dt, key_cap_map[i].atom); dterm_int(dt, key_cap_map[i].bit); dterm_tuple_end(dt, &cap_tuple); } dterm_list_end(dt, &c_list); dterm_tuple_end(dt, &prop); return IEDRV_RES_OK; }
static unsigned char add_abs_cap(dterm_t* dt, int fd) { dterm_mark_t prop; dterm_mark_t c_list; unsigned char bitmask[KEY_CNT / 8 + 1]; int i = 0; if (ioctl(fd, EVIOCGBIT(EV_ABS, sizeof(bitmask)), bitmask) < 0) { return IEDRV_RES_IO_ERROR; } dterm_tuple_begin(dt, &prop); dterm_atom(dt, ie_abs); dterm_list_begin(dt, &c_list); // Add all capabilities present. // Each element will have the format // { Cap (abs_x), { CurrentVal, Min, Max, Fuzz, Flat, Resolution }} for(i = 0; i < sizeof(abs_cap_map) / sizeof(abs_cap_map[0]); ++i) { struct input_absinfo abs_info; dterm_mark_t a_prop; if (!t_bit(bitmask, abs_cap_map[i].bit)) continue; if (ioctl(fd, EVIOCGABS(abs_cap_map[i].bit), &abs_info) < 0) { continue; } dterm_tuple_begin(dt, &a_prop);{ dterm_mark_t cap_tuple; dterm_tuple_begin(dt, &cap_tuple); dterm_atom(dt, abs_cap_map[i].atom); dterm_atom(dt, ie_absinfo); dterm_int(dt, abs_info.value); dterm_int(dt, abs_info.minimum); dterm_int(dt, abs_info.maximum); dterm_int(dt, abs_info.fuzz); dterm_int(dt, abs_info.flat); // dterm_int(dt, abs_info.resolution); // Not available in ARM7 dterm_tuple_end(dt, &cap_tuple); } dterm_tuple_end(dt, &a_prop); } dterm_list_end(dt, &c_list); dterm_tuple_end(dt, &prop); return IEDRV_RES_OK; }
void dterm_kv_bool(dterm_t* t,ErlDrvTermData key, int value) { dterm_mark_t m; dterm_tuple_begin(t, &m); { dterm_atom(t, key); dterm_atom(t, value ? am_true : am_false); } dterm_tuple_end(t, &m); }
void dterm_kv_atom(dterm_t* t,ErlDrvTermData key, ErlDrvTermData value) { dterm_mark_t m; dterm_tuple_begin(t, &m); { dterm_atom(t, key); dterm_atom(t, value); } dterm_tuple_end(t, &m); }
void dterm_kv_string(dterm_t* t,ErlDrvTermData key, char* value) { dterm_mark_t m; size_t len = strlen(value); char* dst = (char*) dterm_link_copy_data(t, value, len); dterm_tuple_begin(t, &m); { dterm_atom(t, key); dterm_string(t, dst, len); } dterm_tuple_end(t, &m); }
// send {Ref, {error,Reason}} int dthread_port_send_error(dthread_t* thr, dthread_t* source, ErlDrvTermData target, ErlDrvTermData ref, int error) { dterm_t t; dterm_mark_t m,e; int r; dterm_init(&t); dterm_tuple_begin(&t, &m); { dterm_int(&t, ref); dterm_tuple_begin(&t, &e); { dterm_atom(&t, am_error); dterm_atom(&t, error_atom(error)); } dterm_tuple_end(&t,&e); } dterm_tuple_end(&t,&m); r = dthread_port_send_term(thr, source, target, dterm_data(&t), dterm_used_size(&t)); dterm_finish(&t); return r; }
static void inpevt_ready_input(ErlDrvData drv_data, ErlDrvEvent event) { IEContext* ctx = 0; struct input_event buf[32]; ssize_t rd_res = 0; ctx = (IEContext*) drv_data; if (ctx->mDescriptor == -1) { return; } while((rd_res = read(ctx->mDescriptor, (char*) buf, sizeof(buf))) > 0) { int i = 0; for (i = 0; i < rd_res / sizeof(buf[0]); ++i) { dterm_t dt; dterm_mark_t ev_mark; dterm_init(&dt); dterm_tuple_begin(&dt, &ev_mark); dterm_atom(&dt, ie_input_event); dterm_port(&dt, ctx->mDport); dterm_int(&dt, buf[i].time.tv_sec); dterm_int(&dt, buf[i].time.tv_usec); dterm_atom(&dt, *type_atoms[buf[i].type].atom); if (type_atoms[buf[i].type].code) dterm_atom(&dt, *type_atoms[buf[i].type].code[buf[i].code]); else dterm_atom(&dt, ie_unknown); dterm_int(&dt, buf[i].code); dterm_int(&dt, buf[i].value); dterm_tuple_end(&dt, &ev_mark); driver_output_term(ctx->mPort, dterm_data(&dt), dterm_used_size(&dt)); dterm_finish(&dt); } } return; }
static unsigned char send_device_info(IEContext* ctx, unsigned int reply_id) { dterm_mark_t msg; dterm_t dt; int len = 0; char name[256]; char topology[256]; char uniq_id[256]; struct input_id id; // Get device id. if (ioctl(ctx->mDescriptor, EVIOCGID, &id) < 0) { return IEDRV_RES_IO_ERROR; } if ((len = ioctl(ctx->mDescriptor, EVIOCGNAME(sizeof(name) - 1), name)) < 0) { return IEDRV_RES_IO_ERROR; } name[len] = 0; if ((len = ioctl(ctx->mDescriptor, EVIOCGPHYS(sizeof(topology) - 1), topology)) < 0) { return IEDRV_RES_IO_ERROR; } topology[len] = 0; if ((len = ioctl(ctx->mDescriptor, EVIOCGUNIQ(sizeof(uniq_id) - 1), uniq_id)) < 0) uniq_id[0] = 0; uniq_id[len] = 0; dterm_init(&dt); dterm_tuple_begin(&dt, &msg); { dterm_mark_t prop; dterm_atom(&dt, ie_device_info); dterm_port(&dt, ctx->mDport); dterm_int(&dt, reply_id); // // Setup { id, Bustype, Vendor, Product, Version, Name} // dterm_tuple_begin(&dt, &prop); { dterm_atom(&dt, ie_drv_dev_id); dterm_string(&dt, uniq_id, strlen(uniq_id)); dterm_string(&dt, name, strlen(name)); dterm_atom(&dt, *bus_atoms[id.bustype]); dterm_int(&dt, id.vendor); dterm_int(&dt, id.product); dterm_int(&dt, id.version); dterm_string(&dt, topology, strlen(topology)); // // Setup [{ capability, [ { Cap, [X] }, { Cap, [Y] }, ...}, ...] // add_cap(&dt, ctx->mDescriptor); dterm_tuple_end(&dt, &prop); } } dterm_tuple_end(&dt, &msg); driver_output_term(ctx->mPort, dterm_data(&dt), dterm_used_size(&dt)); dterm_finish(&dt); return IEDRV_RES_OK; }
// thread main! int uart_unix_main(void* arg) { dthread_t* self = (dthread_t*) arg; dthread_t* other = (dthread_t*) self->arg; dmessage_t* mp = NULL; dthread_poll_event_t ev, *evp; size_t nev; dterm_t term; uart_ctx_t ctx; ErlDrvTermData mp_from; ErlDrvTermData mp_ref; dthread_t* mp_source; int tmo; int r; DEBUGF("uart_unix: thread started"); uart_init(&ctx, self, other); dterm_init(&term); again_tmo: tmo = next_timeout(&ctx); again: nev = 0; evp = NULL; if (ctx.fd >= 0) { ev.event = (ErlDrvEvent) ((long)ctx.fd); ev.events = 0; if ((ctx.option.active != UART_PASSIVE) || ctx.recv) { ev.events |= ERL_DRV_READ; if (ctx.option.ptypkt && (ctx.fd != ctx.tty_fd)) ev.events |= ERL_DRV_EXCEP; } if (ctx.oq.mesg) ev.events |= ERL_DRV_WRITE; if (ev.events) { evp = &ev; nev = 1; } DEBUGF("ctx.fd=%d, ev.events=%d", ctx.fd, ev.events); } DEBUGF("uart_unix_main: nev=%d, events=%x, timeout = %d", nev, ev.events, tmo); r = dthread_poll(self, evp, &nev, tmo); if (r < 0) { DEBUGF("uart_unix_main: dthread_poll failed=%d", r); goto again_tmo; } else { DEBUGF("uart_unix_main: nev=%d, r=%d", nev, r); if (evp && (nev == 1)) { if (evp->revents & ERL_DRV_WRITE) process_output(&ctx, self); if (evp->revents & (ERL_DRV_READ|ERL_DRV_EXCEP)) { while((process_input(&ctx, self, 0) == 1) && (ctx.option.active != UART_PASSIVE)) ; } } tmo = next_timeout(&ctx); DEBUGF("uart_unix_main: timeout = %d", tmo); if (ctx.recv) { if (tmo == 0) { uart_async_error_am(&ctx, ctx.dport, ctx.caller, am_timeout); clear_timeout(&ctx); ctx.remain = 0; } } if (r == 0) goto again; // r>0 (number of messages) DEBUGF("about to receive message r=%d", r); if ((mp = dthread_recv(self, NULL)) == NULL) { DEBUGF("uart_unix_main: message was NULL"); goto again; } mp_from = mp->from; mp_ref = mp->ref; mp_source = mp->source; switch (mp->cmd) { case DTHREAD_STOP: DEBUGF("uart_unix_main: STOP"); close_device(&ctx); uart_final(&ctx); dmessage_free(mp); DEBUGF("uart_unix_main: EXIT"); dthread_exit(0); break; case DTHREAD_OUTPUT: // async send! DEBUGF("uart_unix_main: OUTPUT"); if (ctx.fd < 0) { dmessage_free(mp); goto again; } if (enq_output(&ctx, self, mp, 0) < 0) { mp = NULL; goto error; } goto again; case UART_CMD_CONNECT: { ErlDrvTermData owner; if (mp->used != 0) goto badarg; owner = driver_connected(self->port); self->owner = owner; other->owner = owner; goto ok; } case UART_CMD_CLOSE: DEBUGF("uart_unix_main: CLOSE"); close_device(&ctx); goto ok; case UART_CMD_SEND: // sync send DEBUGF("uart_unix_main: SEND"); if (ctx.fd < 0) goto ebadf; if (enq_output(&ctx, self, mp, mp_from) < 0) { mp = NULL; goto error; } goto again; case UART_CMD_SENDCHAR: // sync send DEBUGF("uart_unix_main: SENDCHAR"); if (ctx.fd < 0) goto ebadf; if (enq_output(&ctx, self, mp, mp_from) < 0) { mp = NULL; goto error; } goto again; case UART_CMD_RECV: { // <<Time:32, Length:32>> Time=0xffffffff=inf uint32_t tm; int len; DEBUGF("uart_unix_main: RECV"); if (ctx.fd < 0) goto ebadf; if (ctx.recv) goto ealready; if (mp->used != 8) goto badarg; if (ctx.option.active != UART_PASSIVE) goto badarg; tm = get_uint32((uint8_t*) mp->buffer); len = (int) get_uint32((uint8_t*) (mp->buffer+4)); if ((len < 0) || (len > UART_MAX_PACKET_SIZE)) goto badarg; ctx.ref = mp_ref; ctx.caller = mp_from; set_timeout(&ctx, tm); ctx.recv = 1; DEBUGF("recv timeout %lu", tm); process_input(&ctx, self, len); dmessage_free(mp); goto again_tmo; } case UART_CMD_UNRECV: { // argument is data to push back uart_buf_push(&ctx.ib, mp->buffer, mp->used); DEBUGF("unrecived %d bytes", ctx.ib.ptr - ctx.ib.ptr_start); if (ctx.option.active != UART_PASSIVE) { while((process_input(&ctx, self, 0) == 1) && (ctx.option.active != UART_PASSIVE)) ; } goto ok; } case UART_CMD_SETOPTS: { uart_com_state_t state = ctx.state; uart_opt_t option = ctx.option; uint32_t sflags = ctx.sflags; // parse & update options in state,option and sflag if (uart_parse_opts(mp->buffer, mp->used, &state, &option, &sflags) < 0) goto badarg; // apply the changed values if ((r=apply_opts(&ctx, &state, &option, sflags)) < 0) goto error; if (r == 1) { while((process_input(&ctx, self, 0) == 1) && (ctx.option.active != UART_PASSIVE)) ; } goto ok; } case UART_CMD_GETOPTS: { dterm_mark_t m1; dterm_mark_t m2; // {Ref, {ok,List}} || {Ref, {error,Reason}} dterm_tuple_begin(&term, &m1); { dterm_uint(&term, mp_ref); dterm_tuple_begin(&term, &m2); { dterm_atom(&term, am_ok); if (uart_get_opts(&term, &ctx,(uint8_t*)mp->buffer,mp->used) < 0) { dterm_reset(&term); goto badarg; } } dterm_tuple_end(&term, &m2); } dterm_tuple_end(&term, &m1); dthread_port_send_dterm(mp_source, self, mp_from, &term); dterm_reset(&term); dmessage_free(mp); goto again; } case UART_CMD_GET_MODEM: { dterm_mark_t m1; dterm_mark_t m2; uart_modem_state_t mstate; if (ctx.tty_fd < 0) goto ebadf; if (get_modem_state(ctx.tty_fd, &mstate) < 0) goto error; dterm_tuple_begin(&term, &m1); { dterm_uint(&term, mp_ref); dterm_tuple_begin(&term, &m2); { dterm_atom(&term, am_ok); modem_state_dterm(&term, mstate); } dterm_tuple_end(&term, &m2); } dterm_tuple_end(&term, &m1); dthread_port_send_dterm(mp_source, self, mp_from, &term); dterm_reset(&term); dmessage_free(mp); goto again; } case UART_CMD_SET_MODEM: { uart_modem_state_t mstate; if (ctx.tty_fd < 0) goto ebadf; if (mp->used != 4) goto badarg; mstate = (uart_modem_state_t) get_uint32((uint8_t*) mp->buffer); if (set_modem_state(ctx.tty_fd, mstate, 1) < 0) goto error; goto ok; } case UART_CMD_CLR_MODEM: { uart_modem_state_t mstate; if (ctx.tty_fd < 0) goto ebadf; if (mp->used != 4) goto badarg; mstate = (uart_modem_state_t) get_uint32((uint8_t*) mp->buffer); if (set_modem_state(ctx.tty_fd, mstate, 0) < 0) goto error; goto ok; } case UART_CMD_HANGUP: { struct termios tio; int r; if (ctx.tty_fd < 0) goto ebadf; if (mp->used != 0) goto badarg; if ((r = tcgetattr(ctx.tty_fd, &tio)) < 0) { INFOF("tcgetattr: error=%s\n", strerror(errno)); goto badarg; } cfsetispeed(&tio, B0); cfsetospeed(&tio, B0); if ((r = tcsetattr(ctx.tty_fd, TCSANOW, &tio)) < 0) { INFOF("tcsetattr: error=%s\n", strerror(errno)); goto badarg; } goto ok; } case UART_CMD_BREAK: { int duration; if (ctx.tty_fd < 0) goto ebadf; if (mp->used != 4) goto badarg; duration = (int) get_uint32((uint8_t*) mp->buffer); if (tcsendbreak(ctx.tty_fd, duration) < 0) goto error; goto ok; } case UART_CMD_FLOW: if (ctx.tty_fd < 0) goto ebadf; if (mp->used != 1) goto badarg; switch(mp->buffer[0]) { case 0: r = tcflow(ctx.tty_fd, TCIOFF); break; case 1: r = tcflow(ctx.tty_fd, TCION); break; case 2: r = tcflow(ctx.tty_fd, TCOOFF); break; case 3: r = tcflow(ctx.tty_fd, TCOON); break; default: goto badarg; break; } if (r < 0) goto error; goto ok; default: goto badarg; } } ok: dthread_port_send_ok(mp_source, self, mp_from, mp_ref); if (mp) dmessage_free(mp); goto again; ebadf: errno = EBADF; goto error; badarg: errno = EINVAL; goto error; ealready: errno = EALREADY; goto error; error: dthread_port_send_error(mp_source, self, mp_from, mp_ref, uart_errno(&ctx)); if (mp) dmessage_free(mp); goto again; }
// thread main! int uart_win32_main(void* arg) { dthread_t* self = (dthread_t*) arg; dthread_t* other = (dthread_t*) self->arg; dmessage_t* mp = NULL; dthread_poll_event_t ev[3]; dthread_poll_event_t* evp; size_t nev; dterm_t term; uart_ctx_t ctx; ErlDrvTermData mp_from; ErlDrvTermData mp_ref; dthread_t* mp_source; int tmo; int r; DEBUGF("uart_win32: thread started"); uart_init(&ctx, self, other); dterm_init(&term); again_tmo: tmo = next_timeout(&ctx); again: nev = 0; if (ctx.writing) { ev[nev].event = (ErlDrvEvent) ctx.out.hEvent; ev[nev].events = ERL_DRV_READ; // yepp, even for write nev++; } while(!ctx.reading && (ctx.recv || (ctx.option.active != UART_PASSIVE))) process_input(&ctx, self, 0); if (ctx.reading) { ev[nev].event = (ErlDrvEvent) ctx.in.hEvent; ev[nev].events = ERL_DRV_READ; nev++; } evp = nev ? &ev[0] : NULL; DEBUGF("uart_win32_main: ctx.fh=%d, nev=%u, timeout = %d", ctx.fh, nev, tmo); r = dthread_poll(self, evp, &nev, tmo); if (r < 0) { DEBUGF("uart_win32_main: dthread_poll failed=%d", r); goto again_tmo; } else { DWORD i; DEBUGF("uart_win32_main: nev=%u, r=%d", nev, r); for (i = 0; i < nev; i++) { if (ev[i].revents & ERL_DRV_READ) { if (ev[i].event == (ErlDrvEvent) ctx.in.hEvent) { while((process_input(&ctx, self, 0) == 1) && (ctx.option.active != UART_PASSIVE)) ; } else if (ev[i].event == (ErlDrvEvent) ctx.out.hEvent) { process_output(&ctx, self); } } } tmo = next_timeout(&ctx); DEBUGF("uart_win32_main: timeout = %d", tmo); if (ctx.recv) { if (tmo == 0) { uart_async_error_am(&ctx, ctx.dport, ctx.caller, am_timeout); clear_timeout(&ctx); ctx.remain = 0; } } if (r == 0) goto again; // r>0 (number of messages) DEBUGF("about to receive message r=%d", r); if ((mp = dthread_recv(self, NULL)) == NULL) { DEBUGF("uart_win32_main: message was NULL"); goto again; } mp_from = mp->from; mp_ref = mp->ref; mp_source = mp->source; switch (mp->cmd) { case DTHREAD_STOP: DEBUGF("uart_win32_main: STOP"); close_device(&ctx); uart_final(&ctx); dmessage_free(mp); DEBUGF("uart_win32_main: EXIT"); dthread_exit(0); break; case DTHREAD_OUTPUT: // async send! DEBUGF("uart_win32_main: OUTPUT"); if (ctx.fh == INVALID_HANDLE_VALUE) { dmessage_free(mp); goto again; } if (enq_output(&ctx, self, mp, 0) < 0) { mp = NULL; goto error; } goto again; case UART_CMD_CONNECT: { ErlDrvTermData owner; if (mp->used != 0) goto badarg; owner = driver_connected(self->port); self->owner = owner; other->owner = owner; goto ok; } case UART_CMD_CLOSE: DEBUGF("uart_win32_main: CLOSE"); close_device(&ctx); goto ok; case UART_CMD_SEND: // sync send DEBUGF("uart_win32_main: SEND"); if (ctx.fh == INVALID_HANDLE_VALUE) goto ebadf; if (enq_output(&ctx, self, mp, mp_from) < 0) { mp = NULL; goto error; } goto again; case UART_CMD_SENDCHAR: // sync send DEBUGF("uart_win32_main: SENDCHAR"); if (ctx.fh == INVALID_HANDLE_VALUE) goto ebadf; if (enq_output(&ctx, self, mp, mp_from) < 0) { mp = NULL; goto error; } goto again; case UART_CMD_RECV: { // <<Time:32, Length:32>> Time=0xffffffff=inf uint32_t tm; int len; DEBUGF("uart_win32_main: RECV"); if (ctx.fh == INVALID_HANDLE_VALUE) goto ebadf; if (ctx.recv) goto ealready; if (mp->used != 8) goto badarg; if (ctx.option.active != UART_PASSIVE) goto badarg; tm = get_uint32((uint8_t*) mp->buffer); len = (int) get_uint32((uint8_t*) (mp->buffer+4)); if ((len < 0) || (len > UART_MAX_PACKET_SIZE)) goto badarg; ctx.ref = mp_ref; ctx.caller = mp_from; set_timeout(&ctx, tm); ctx.recv = 1; DEBUGF("recv timeout %lu", tm); process_input(&ctx, self, len); dmessage_free(mp); goto again_tmo; } case UART_CMD_UNRECV: { // argument is data to push back uart_buf_push(&ctx.ib, mp->buffer, mp->used); DEBUGF("unrecived %d bytes", ctx.ib.ptr - ctx.ib.ptr_start); if (ctx.option.active != UART_PASSIVE) { while((process_input(&ctx, self, 0) == 1) && (ctx.option.active != UART_PASSIVE)) ; } goto ok; } case UART_CMD_SETOPTS: { uart_com_state_t state = ctx.state; uart_opt_t option = ctx.option; uint32_t sflags = ctx.sflags; // parse & update options in state,option and sflag if (uart_parse_opts(mp->buffer, mp->used, &state, &option, &sflags) < 0) goto badarg; // apply the changed values if ((r=apply_opts(&ctx, &state, &option, sflags)) < 0) { goto error; } goto ok; } case UART_CMD_GETOPTS: { dterm_mark_t m1; dterm_mark_t m2; // {Ref, {ok,List}} || {Ref, {error,Reason}} dterm_tuple_begin(&term, &m1); { dterm_uint(&term, mp_ref); dterm_tuple_begin(&term, &m2); { dterm_atom(&term, am_ok); if (uart_get_opts(&term, &ctx,(uint8_t*)mp->buffer,mp->used) < 0) { dterm_reset(&term); goto badarg; } } dterm_tuple_end(&term, &m2); } dterm_tuple_end(&term, &m1); dthread_port_send_dterm(mp_source, self, mp_from, &term); dterm_reset(&term); dmessage_free(mp); goto again; } case UART_CMD_GET_MODEM: { dterm_mark_t m1; dterm_mark_t m2; uart_modem_state_t mstate; if (ctx.fh == INVALID_HANDLE_VALUE) goto ebadf; if (get_modem_state(ctx.fh, &mstate) < 0) goto error; dterm_tuple_begin(&term, &m1); { dterm_uint(&term, mp_ref); dterm_tuple_begin(&term, &m2); { dterm_atom(&term, am_ok); modem_state_dterm(&term, mstate); } dterm_tuple_end(&term, &m2); } dterm_tuple_end(&term, &m1); dthread_port_send_dterm(mp_source, self, mp_from, &term); dterm_reset(&term); dmessage_free(mp); goto again; } case UART_CMD_SET_MODEM: { uart_modem_state_t mstate; if (ctx.fh == INVALID_HANDLE_VALUE) goto ebadf; if (mp->used != 4) goto badarg; mstate = (uart_modem_state_t) get_uint32((uint8_t*) mp->buffer); if (set_modem_state(ctx.fh, mstate, 1) < 0) goto error; goto ok; } case UART_CMD_CLR_MODEM: { uart_modem_state_t mstate; if (ctx.fh == INVALID_HANDLE_VALUE) goto ebadf; if (mp->used != 4) goto badarg; mstate = (uart_modem_state_t) get_uint32((uint8_t*) mp->buffer); if (set_modem_state(ctx.fh, mstate, 0) < 0) goto error; goto ok; } case UART_CMD_HANGUP: { if (ctx.fh == INVALID_HANDLE_VALUE) goto ebadf; if (mp->used != 0) goto badarg; // FIXME? goto ok; } case UART_CMD_BREAK: { int duration; if (ctx.fh == INVALID_HANDLE_VALUE) goto ebadf; if (mp->used != 4) goto badarg; duration = (int) get_uint32((uint8_t*) mp->buffer); if (!EscapeCommFunction(ctx.fh, SETBREAK)) { DEBUG_ERROR("EscapeCommFunction: error %d", GetLastError()); goto error; } Sleep(duration); if (!EscapeCommFunction(ctx.fh, CLRBREAK)) { DEBUG_ERROR("EscapeCommFunction: error %d", GetLastError()); goto error; } goto ok; } case UART_CMD_FLOW: if (ctx.fh == INVALID_HANDLE_VALUE) goto ebadf; if (mp->used != 1) goto badarg; switch(mp->buffer[0]) { case 0: if (!EscapeCommFunction(ctx.fh, SETXOFF)) { DEBUG_ERROR("EscapeCommFunction: error %d", GetLastError()); goto error; } break; case 1: if (!EscapeCommFunction(ctx.fh, SETXON)) { DEBUG_ERROR("EscapeCommFunction: error %d", GetLastError()); goto error; } break; case 2: // TransmitCommChar(ctx.fh, XOFF); break; case 3: // TransmitCommChar(ctx.fh, XON); break; default: goto badarg; } goto ok; default: goto badarg; } } ok: dthread_port_send_ok(mp_source, self, mp_from, mp_ref); if (mp) dmessage_free(mp); goto again; ebadf: errno = EBADF; goto error; badarg: errno = EINVAL; goto error; ealready: errno = EBUSY; goto error; error: dthread_port_send_error(mp_source, self, mp_from, mp_ref, uart_errno(&ctx)); if (mp) dmessage_free(mp); goto again; }