/* * SPL - The SPL Programming Language * Copyright (C) 2006 Clifford Wolf * Copyright (C) 2007 Raphael Langerhorst * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * mod_wscons.c: NetBSD Work Station Console Module */ /** * SPL Work Station Console Module * * This Module provides an interface to the NetBSD wscons HID devices. * Currently this is meant to be used with input devices only, like mouse and keyboard. */ #include #include #include #include #include #include #include #include "spl.h" #include "compat.h" // input event structure contains: // type // value // time // seconds // nanoseconds // the following is copied from /usr/include/dev/wscons/wsconsio.h // // /* Event type definitions. Comment for each is information in value. */ // #define WSCONS_EVENT_KEY_UP 1 /* key code */ // #define WSCONS_EVENT_KEY_DOWN 2 /* key code */ // #define WSCONS_EVENT_ALL_KEYS_UP 3 /* void */ // #define WSCONS_EVENT_MOUSE_UP 4 /* button # (leftmost = 0) */ // #define WSCONS_EVENT_MOUSE_DOWN 5 /* button # (leftmost = 0) */ // #define WSCONS_EVENT_MOUSE_DELTA_X 6 /* X delta amount */ // #define WSCONS_EVENT_MOUSE_DELTA_Y 7 /* Y delta amount */ // #define WSCONS_EVENT_MOUSE_ABSOLUTE_X 8 /* X location */ // #define WSCONS_EVENT_MOUSE_ABSOLUTE_Y 9 /* Y location */ // #define WSCONS_EVENT_MOUSE_DELTA_Z 10 /* Z delta amount */ // #define WSCONS_EVENT_MOUSE_ABSOLUTE_Z 11 /* Z location */ // #define WSCONS_EVENT_SCREEN_SWITCH 12 /* New screen number */ // #define WSCONS_EVENT_ASCII 13 /* key code is already ascii */ // #define WSCONS_EVENT_MOUSE_DELTA_W 14 /* W delta amount */ // #define WSCONS_EVENT_MOUSE_ABSOLUTE_W 15 /* W location */ // TODO: parameter sanity checking // TODO: restore! extern void SPL_ABI(spl_mod_wscons_init)(struct spl_vm *vm, struct spl_module *mod, int restore); extern void SPL_ABI(spl_mod_wscons_done)(struct spl_vm *vm, struct spl_module *mod); /** * Opens a wscons device, the device filename should be * provided as parameter. */ //builtin wscons_open(devicefile) static struct spl_node *handler_wscons_open(struct spl_task *task, void UNUSED(*data)) { char* device = spl_clib_get_string(task); int fd = open(device,0,O_RDONLY); if (fd == -1) { spl_report(SPL_REPORT_RUNTIME|SPL_REPORT_WARNING, task,"Could not open wscons device %s, error %d\n",device,errno); return 0; } else { if (fcntl(fd,F_SETOWN,getpid())==-1) spl_report(SPL_REPORT_RUNTIME|SPL_REPORT_WARNING, task,"Could not enable SIGIO signals on process %d, error %d\n",getpid(),errno); if (fcntl(fd,F_SETFL,O_ASYNC)==-1) spl_report(SPL_REPORT_RUNTIME|SPL_REPORT_WARNING, task,"Could not enable SIGIO signals on device %s, error %d\n",device,errno); return SPL_NEW_INT(fd); } } /** * Check if one ore more events can be read from wscons device. * Returns 1 if data is available and undef otherwise. */ // builtin wscons_read() static struct spl_node *handler_wscons_poll(struct spl_task *task, void UNUSED(*data)) { int fd = spl_clib_get_int(task); int timeout = spl_clib_get_int(task); if (timeout < -1) timeout = 0; struct pollfd pfd; pfd.fd = fd; pfd.events = POLLIN; pfd.revents = 0; int bytes_ready = poll(&pfd,1,timeout); if (pfd.revents & (POLLERR | POLLHUP | POLLNVAL)) { spl_report(SPL_REPORT_RUNTIME|SPL_REPORT_WARNING, task,"error polling device %d\n",fd); return 0; } if ((pfd.revents & POLLIN) > 0 && bytes_ready == 1) return SPL_NEW_INT(1); else return 0; } /** * Read an event from the wscons device, the structure is similar * to that of struct wscons_event; found in /dev/wscons/wsconsio.h * * Event time is provided in a time child node containing seconds and nanoseconds. * * On return you should check if the type child node is declared. * * Example: * * var mouse = wscons_open("/dev/wsmouse0"); * //... * if (wscons_poll(mouse) == 1) * { * var event = wscons_read(mouse); * if (declared event.type) * { * debug "event type: " ~ event.type; * debug "event value: " ~ event.value; * debug "event time (seconds): " ~ event.time.seconds; * debug "event time (nanoseconds): " ~ event.time.nanoseconds; * } * else * { * warning "could not read data although wscons_poll() succeeded"; * } * } * else * { * debug "no data available from wscons device"; * } * wscons_close(mouse); * */ // builtin wscons_read() static struct spl_node *handler_wscons_read(struct spl_task *task, void UNUSED(*data)) { int fd = spl_clib_get_int(task); int timeout = spl_clib_get_int(task); if (timeout < -1) timeout = 0; struct wscons_event input; struct pollfd pfd; pfd.fd = fd; pfd.events = POLLIN; pfd.revents = 0; int bytes_ready = poll(&pfd,1,timeout); if ((pfd.revents & POLLIN) > 0 && bytes_ready == 1) { int result = read(fd,&input,sizeof(input)); if (result == -1) { spl_report(SPL_REPORT_RUNTIME|SPL_REPORT_WARNING, task,"Could not read from wscons device %d, error %d\n",fd,errno); return 0; } else { //printf("input event: type = %u, data = %d, seconds = %lu, nanoseconds = %lu\n",input.type,input.value,input.time.tv_sec,input.time.tv_nsec); struct spl_node *event = spl_get(0); spl_create(task, event, "type", SPL_NEW_INT(input.type), SPL_CREATE_LOCAL); spl_create(task, event, "value", SPL_NEW_INT(input.value), SPL_CREATE_LOCAL); struct spl_node *time_node = spl_get(0); spl_create(task, event, "time", time_node, SPL_CREATE_LOCAL); spl_create(task, time_node, "seconds", SPL_NEW_INT(input.time.tv_sec), SPL_CREATE_LOCAL); spl_create(task, time_node, "nanoseconds", SPL_NEW_INT(input.time.tv_nsec), SPL_CREATE_LOCAL); return event; } } return 0; } static struct spl_node *handler_wscons_close(struct spl_task *task, void UNUSED(*data)) { int fd = spl_clib_get_int(task); close(fd); return 0; } // the SIGIO handler doesn't do anything in particular, // it's enough to wake up the process from task_sleep() void wscons_sigio_handler() { //spl_report(SPL_REPORT_RUNTIME, task,"sigio\n"); //printf("sigio\n"); } static struct spl_node *handler_wscons_sigio(struct spl_task *task, void UNUSED(*data)) { struct sigaction sigstruct; sigstruct.sa_sigaction = 0; sigstruct.sa_handler = wscons_sigio_handler; sigstruct.sa_flags = 0; if (sigaction(SIGIO,&sigstruct,0)==-1) { spl_report(SPL_REPORT_RUNTIME|SPL_REPORT_WARNING, task,"Could setup SIGIO handler in wscons module\n"); } return 0; } void SPL_ABI(spl_mod_wscons_init)(struct spl_vm *vm, struct spl_module UNUSED(*mod), int UNUSED(restore)) { spl_clib_reg(vm, "wscons_open", handler_wscons_open, 0); spl_clib_reg(vm, "wscons_poll", handler_wscons_poll, 0); spl_clib_reg(vm, "wscons_read", handler_wscons_read, 0); spl_clib_reg(vm, "wscons_close", handler_wscons_close, 0); spl_clib_reg(vm, "wscons_wake_on_sigio", handler_wscons_sigio, 0); } void SPL_ABI(spl_mod_wscons_done)(struct spl_vm UNUSED(*vm), struct spl_module UNUSED(*mod)) { return; }