diff -Naurp lirc-0.8.4a.orig/daemons/hw_devinput.c lirc-0.8.4a.upd/daemons/hw_devinput.c --- lirc-0.8.4a.orig/daemons/hw_devinput.c 2008-03-02 14:16:30.000000000 -0500 +++ lirc-0.8.4a.upd/daemons/hw_devinput.c 2008-12-08 17:10:05.072745094 -0500 @@ -220,7 +220,7 @@ int devinput_init() if (ioctl(hw.fd, EVIOCGRAB, 1) == -1) { logprintf(LOG_WARNING, "can't get exclusive access to events " - "comming from `%s' interface", + "coming from `%s' interface", hw.device); } #endif diff -Naurp lirc-0.8.4a.orig/daemons/irrecord.c lirc-0.8.4a.upd/daemons/irrecord.c --- lirc-0.8.4a.orig/daemons/irrecord.c 2008-12-08 16:47:25.358745194 -0500 +++ lirc-0.8.4a.upd/daemons/irrecord.c 2008-12-08 16:55:26.208557409 -0500 @@ -1395,6 +1395,7 @@ void analyse_remote(struct ir_remote *ra next_code = NULL; current_code = NULL; current_index = 0; + memset(&remote, 0, sizeof(remote)); get_lengths(&remote, 0, 0 /* not interactive */ ); if(is_rc6(&remote)) diff -Naurp lirc-0.8.4a.orig/daemons/lircd.c lirc-0.8.4a.upd/daemons/lircd.c --- lirc-0.8.4a.orig/daemons/lircd.c 2008-10-04 17:48:43.000000000 -0400 +++ lirc-0.8.4a.upd/daemons/lircd.c 2008-12-08 17:06:32.108557638 -0500 @@ -1,4 +1,4 @@ -/* $Id: lircd.c,v 5.80 2008/10/04 21:48:43 lirc Exp $ */ +/* $Id: lircd.c,v 5.82 2008/12/06 20:00:03 lirc Exp $ */ /**************************************************************************** ** lircd.c ***************************************************************** @@ -57,6 +57,12 @@ #include #include +#if defined(__linux__) +#include +#include +#include "input_map.h" +#endif + #if defined __APPLE__ #include #endif @@ -151,31 +157,40 @@ FILE *lf=NULL; /* quite arbitrary limits */ #define MAX_PEERS 100 -/* substract one for lirc, sockfd, sockinet, logfile, pidfile */ -#define MAX_CLIENTS (FD_SETSIZE-5-MAX_PEERS) +/* substract one for lirc, sockfd, sockinet, logfile, pidfile, uinput */ +#define MAX_CLIENTS (FD_SETSIZE-6-MAX_PEERS) int sockfd, sockinet; +static int uinputfd = -1; int clis[MAX_CLIENTS]; #define CT_LOCAL 1 #define CT_REMOTE 2 -int cli_type[MAX_CLIENTS]; -int clin=0; +static int cli_type[MAX_CLIENTS]; +static int clin=0; int listen_tcpip=0; unsigned short int port=LIRC_INET_PORT; +struct in_addr address; struct peer_connection *peers[MAX_PEERS]; int peern = 0; int debug=0; -int daemonized=0; -int allow_simulate=0; +static int daemonized=0; +static int allow_simulate=0; +static int userelease=0; +static int useuinput=0; static sig_atomic_t term=0,hup=0,alrm=0; static int termsig; +inline int use_hw() +{ + return (clin>0 || (useuinput && uinputfd != -1) || repeat_remote != NULL); +} + /* set_transmitters only supports 32 bit int */ #define MAX_TX (CHAR_BIT*sizeof(unsigned long)) @@ -303,6 +318,7 @@ void dosigterm(int sig) free_config(free_remotes); } free_config(remotes); + repeat_remote = NULL; logprintf(LOG_NOTICE,"caught signal"); for (i=0; i0 && hw.deinit_func) hw.deinit_func(); + if(use_hw() && hw.deinit_func) hw.deinit_func(); #ifdef USE_SYSLOG closelog(); #else @@ -387,6 +410,52 @@ void dosighup(int sig) } } +int setup_uinputfd(const char *name) +{ +#if defined(__linux__) + int fd; + int key; + struct uinput_user_dev dev; + + fd = open("/dev/input/uinput", O_RDWR); + if(fd == -1) + { + fprintf(stderr, "could not open %s\n", "uinput"); + perror(NULL); + return -1; + } + memset(&dev, 0, sizeof(dev)); + strncpy(dev.name, name, sizeof(dev.name)); + dev.name[sizeof(dev.name)-1] = 0; + if(write(fd, &dev, sizeof(dev)) != sizeof(dev) || + ioctl(fd, UI_SET_EVBIT, EV_KEY) != 0 || + ioctl(fd, UI_SET_EVBIT, EV_REP) != 0) + { + goto setup_error; + } + + for(key = KEY_RESERVED; key <= KEY_UNKNOWN; key++) + { + if(ioctl(fd, UI_SET_KEYBIT, key) != 0) + { + goto setup_error; + } + } + + if(ioctl(fd, UI_DEV_CREATE) != 0) + { + goto setup_error; + } + return fd; + + setup_error: + fprintf(stderr, "could not setup %s\n", "uinput"); + perror(NULL); + close(fd); +#endif + return -1; +} + void config(void) { FILE *fd; @@ -448,9 +517,7 @@ void remove_client(int fd) logprintf(LOG_INFO,"removed client"); clin--; - if(clin==0 && - repeat_remote==NULL && - hw.deinit_func) + if(!use_hw() && hw.deinit_func) { hw.deinit_func(); } @@ -508,8 +575,8 @@ void add_client(int sock) { cli_type[clin]=0; /* what? */ } - clis[clin++]=fd; - if(clin==1 && repeat_remote==NULL) + clis[clin]=fd; + if(!use_hw()) { if(hw.init_func) { @@ -525,6 +592,7 @@ void add_client(int sock) } } } + clin++; } int add_peer_connection(char *server) @@ -799,6 +867,10 @@ void start_server(mode_t permission,int listen(sockfd,3); nolinger(sockfd); + if(useuinput) + { + uinputfd = setup_uinputfd(progname); + } if(listen_tcpip) { int enable=1; @@ -815,7 +887,7 @@ void start_server(mode_t permission,int (void) setsockopt(sockinet,SOL_SOCKET,SO_REUSEADDR, &enable,sizeof(enable)); serv_addr_in.sin_family=AF_INET; - serv_addr_in.sin_addr.s_addr=htonl(INADDR_ANY); + serv_addr_in.sin_addr=address; serv_addr_in.sin_port=htons(port); if(bind(sockinet,(struct sockaddr *) &serv_addr_in, @@ -995,7 +1067,7 @@ void dosigalrm(int sig) free(repeat_message); repeat_message=NULL; } - if(clin==0 && repeat_remote==NULL && hw.deinit_func) + if(!use_hw() && hw.deinit_func) { hw.deinit_func(); } @@ -1025,7 +1097,7 @@ void dosigalrm(int sig) repeat_message=NULL; repeat_fd=-1; } - if(clin==0 && repeat_remote==NULL && hw.deinit_func) + if(!use_hw() && hw.deinit_func) { hw.deinit_func(); } @@ -1645,13 +1717,21 @@ void free_old_remotes() struct ir_remote *scan_remotes,*found; struct ir_ncode *code; const char *release_event; + const char *release_remote_name; + const char *release_button_name; if(decoding ==free_remotes) return; - release_event = release_map_remotes(free_remotes, remotes); + release_event = release_map_remotes(free_remotes, remotes, + &release_remote_name, + &release_button_name); if(release_event != NULL) { - broadcast_message(release_event); + input_message(release_event, + release_remote_name, + release_button_name, + 0, + 1); } if(last_remote!=NULL) { @@ -1741,19 +1821,56 @@ void free_old_remotes() } } -void broadcast_message(const char *message) +void input_message(const char *message, const char *remote_name, + const char *button_name, int reps, int release) { - int len,i; const char *release_message; + const char *release_remote_name; + const char *release_button_name; - release_message = check_release_event(); + release_message = check_release_event(&release_remote_name, + &release_button_name); if(release_message) { - broadcast_message(release_message); + input_message(release_message, release_remote_name, + release_button_name, 0, 1); + } + + if(!release || userelease) + { + broadcast_message(message); } + +#ifdef __linux__ + if(uinputfd != -1) + { + linux_input_code input_code; + + if(reps < 2 && + get_input_code(button_name, &input_code) != -1) + { + struct input_event event; + + memset(&event, 0, sizeof(event)); + event.type = EV_KEY; + event.code = input_code; + event.value = release ? 0 : (reps>0 ? 2:1); + if(write(uinputfd, &event, sizeof(event)) != sizeof(event)) + { + logprintf(LOG_ERR, "writing to uinput failed"); + logperror(LOG_ERR, NULL); + } + } + } +#endif +} +void broadcast_message(const char *message) +{ + int len,i; + len=strlen(message); - + for (i=0; i0 && hw.rec_mode!=0 && hw.fd!=-1) + if(use_hw() && hw.rec_mode!=0 && hw.fd!=-1) { FD_SET(hw.fd,&fds); maxfd=max(maxfd,hw.fd); @@ -1915,10 +2032,19 @@ int waitfordata(long maxusec) timercmp(&now, &release_time, >)) { const char *release_message; - release_message = trigger_release_event(); + const char *release_remote_name; + const char *release_button_name; + + release_message = trigger_release_event + (&release_remote_name, + &release_button_name); if(release_message) { - broadcast_message(release_message); + input_message(release_message, + release_remote_name, + release_button_name, + 0, + 1); } } if(free_remotes!=NULL) @@ -1948,7 +2074,9 @@ int waitfordata(long maxusec) } while(ret==-1 && errno==EINTR); - if(hw.fd == -1 && clin > 0 && hw.init_func) + if(hw.fd == -1 && + use_hw() && + hw.init_func) { log_enable(0); hw.init_func(); @@ -1993,7 +2121,7 @@ int waitfordata(long maxusec) LOGPRINTF(1,"registering inet client"); add_client(sockinet); } - if(clin>0 && hw.rec_mode!=0 && hw.fd!=-1 && + if(use_hw() && hw.rec_mode!=0 && hw.fd!=-1 && FD_ISSET(hw.fd,&fds)) { register_input(); @@ -2016,13 +2144,20 @@ void loop() if(message!=NULL) { + const char *remote_name; + const char *button_name; + int reps; + if(hw.ioctl_func && (hw.features&LIRC_CAN_NOTIFY_DECODE)) { hw.ioctl_func(LIRC_NOTIFY_DECODE, NULL); } - broadcast_message(message); + get_release_data(&remote_name, &button_name, &reps); + + input_message(message, remote_name, button_name, + reps, 0); } } } @@ -2034,6 +2169,7 @@ int main(int argc,char **argv) mode_t permission=S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH; char *device=NULL; + address.s_addr = htonl(INADDR_ANY); hw_choose_driver(NULL); while(1) { @@ -2058,9 +2194,15 @@ int main(int argc,char **argv) # endif {"release",optional_argument,NULL,'r'}, {"allow-simulate",no_argument,NULL,'a'}, +# if defined(__linux__) + {"uinput",no_argument,NULL,'u'}, +# endif {0, 0, 0, 0} }; c = getopt_long(argc,argv,"hvnp:H:d:o:P:l::c:r::a" +# if defined(__linux__) + "u" +# endif # ifndef USE_SYSLOG "L:" # endif @@ -2080,7 +2222,7 @@ int main(int argc,char **argv) printf("\t -p --permission=mode\t\tfile permissions for " LIRCD "\n"); printf("\t -H --driver=driver\t\tuse given driver\n"); printf("\t -d --device=device\t\tread from given device\n"); - printf("\t -l --listen[=port]\t\tlisten for network connections on port\n"); + printf("\t -l --listen[=[addresss:]port]\t\tlisten for network connections\n"); printf("\t -c --connect=host[:port]\tconnect to remote lircd server\n"); printf("\t -o --output=socket\t\toutput socket filename\n"); printf("\t -P --pidfile=file\t\tdaemon pid file\n"); @@ -2092,6 +2234,9 @@ int main(int argc,char **argv) # endif printf("\t -r --release[=suffix]\t\tauto-generate release events\n"); printf("\t -a --allow-simulate\t\taccept SIMULATE command\n"); +# if defined(__linux__) + printf("\t -u --uinput\t\tgenerate Linux input events\n"); +# endif return(EXIT_SUCCESS); case 'v': printf("%s %s\n",progname,VERSION); @@ -2135,16 +2280,28 @@ int main(int argc,char **argv) { long p; char *endptr; - - p=strtol(optarg,&endptr,10); + char *sep = strchr(optarg, ':'); + char *port_str = sep ? sep + 1 : optarg; + p=strtol(port_str,&endptr,10); if(!*optarg || *endptr || p<1 || p>USHRT_MAX) { fprintf(stderr, "%s: bad port number \"%s\"\n", - progname,optarg); + progname,port_str); return(EXIT_FAILURE); } port=(unsigned short int) p; + if (sep) + { + *sep = 0; + if(!inet_aton(optarg, &address)) + { + fprintf(stderr, + "%s: bad address \"%s\"\n", + progname,optarg); + return(EXIT_FAILURE); + } + } } else { @@ -2174,10 +2331,16 @@ int main(int argc,char **argv) { set_release_suffix(LIRC_RELEASE_SUFFIX); } + userelease=1; break; case 'a': allow_simulate=1; break; +# if defined(__linux__) + case 'u': + useuinput=1; + break; +# endif default: printf("Usage: %s [options] [config-file]\n",progname); return(EXIT_FAILURE); diff -Naurp lirc-0.8.4a.orig/daemons/lircd.h lirc-0.8.4a.upd/daemons/lircd.h --- lirc-0.8.4a.orig/daemons/lircd.h 2007-09-29 13:13:14.000000000 -0400 +++ lirc-0.8.4a.upd/daemons/lircd.h 2008-12-08 16:54:04.374682209 -0500 @@ -32,6 +32,7 @@ void sigterm(int sig); void dosigterm(int sig); void sighup(int sig); void dosighup(int sig); +int setup_uinput(const char *name); void config(void); void nolinger(int sock); void remove_client(int fd); @@ -76,6 +77,8 @@ int send_core(int fd,char *message,char int version(int fd,char *message,char *arguments); int get_pid(int fd,char *message,char *arguments); int get_command(int fd); +void input_message(const char *message, const char *remote_name, + const char *button_name, int reps, int release); void broadcast_message(const char *message); int waitfordata(long maxusec); void loop(void); diff -Naurp lirc-0.8.4a.orig/daemons/Makefile.am lirc-0.8.4a.upd/daemons/Makefile.am --- lirc-0.8.4a.orig/daemons/Makefile.am 2008-09-21 14:33:19.000000000 -0400 +++ lirc-0.8.4a.upd/daemons/Makefile.am 2008-12-08 16:50:31.050433540 -0500 @@ -59,7 +59,8 @@ libhw_module_a_DEPENDENCIES = @hw_module sbin_PROGRAMS = lircd lircmd lircd_SOURCES = lircd.c lircd.h \ - config_file.c config_file.h + config_file.c config_file.h \ + input_map.c input_map.h lircd_LDADD = @daemon@ libhw_module.a @hw_module_libs@ lircmd_SOURCES = lircmd.c @@ -79,6 +80,7 @@ EXTRA_PROGRAMS = lircd.simsend lircd.sim noinst_PROGRAMS = @maintmode_daemons_extra@ lircd_simsend_SOURCES = lircd.c ir_remote.c config_file.c \ lircd.h ir_remote.h ir_remote_types.h config_file.h \ + input_map.c input_map.h \ hw-types.c hw-types.h hardware.h \ hw_default.c hw_default.h \ receive.c receive.h \ @@ -87,6 +89,7 @@ lircd_simsend_SOURCES = lircd.c ir_remot lircd_simsend_CFLAGS = -DSIM_SEND lircd_simrec_SOURCES = lircd.c ir_remote.c config_file.c \ lircd.h ir_remote.h ir_remote_types.h config_file.h \ + input_map.c input_map.h \ hw-types.c hw-types.h hardware.h \ hw_default.c hw_default.h \ receive.c receive.h \ diff -Naurp lirc-0.8.4a.orig/daemons/release.c lirc-0.8.4a.upd/daemons/release.c --- lirc-0.8.4a.orig/daemons/release.c 2008-02-06 08:43:07.000000000 -0500 +++ lirc-0.8.4a.upd/daemons/release.c 2008-12-08 16:59:03.799472804 -0500 @@ -1,4 +1,4 @@ -/* $Id: release.c,v 1.3 2008/02/06 13:43:07 lirc Exp $ */ +/* $Id: release.c,v 1.4 2008/12/06 20:00:03 lirc Exp $ */ /**************************************************************************** ** release.c *************************************************************** @@ -25,24 +25,23 @@ static struct timeval release_time; static struct ir_remote *release_remote; static struct ir_ncode *release_ncode; static ir_code release_code; +static int release_reps; static lirc_t release_gap; static struct ir_remote *release_remote2; static struct ir_ncode *release_ncode2; static ir_code release_code2; -static const char *release_suffix = NULL; +static const char *release_suffix = LIRC_RELEASE_SUFFIX; static char message[PACKET_SIZE+1]; void register_input(void) { struct timeval gap; - if(release_suffix == NULL) return; - if(release_remote == NULL) return; timerclear(&gap); - gap.tv_usec = 2*release_gap; + gap.tv_usec = 3*release_gap; gettimeofday(&release_time,NULL); timeradd(&release_time, &gap, &release_time); @@ -51,8 +50,6 @@ void register_input(void) void register_button_press(struct ir_remote *remote, struct ir_ncode *ncode, ir_code code, int reps) { - if(release_suffix == NULL) return; - if(reps == 0 && release_remote != NULL) { release_remote2 = release_remote; @@ -63,11 +60,21 @@ void register_button_press(struct ir_rem release_remote = remote; release_ncode = ncode; release_code = code; + release_reps = reps; release_gap = remote->max_remaining_gap; register_input(); } +void get_release_data(const char **remote_name, + const char **button_name, + int *reps) +{ + *remote_name = release_remote->name; + *button_name = release_ncode->name; + *reps = release_reps; +} + void set_release_suffix(const char *s) { release_suffix = s; @@ -78,12 +85,15 @@ void get_release_time(struct timeval *tv *tv = release_time; } -const char *check_release_event(void) +const char *check_release_event(const char **remote_name, + const char **button_name) { int len = 0; if(release_remote2 != NULL) { + *remote_name = release_remote2->name; + *button_name = release_ncode2->name; len = write_message(message, PACKET_SIZE+1, release_remote2->name, release_ncode2->name, release_suffix, @@ -98,18 +108,21 @@ const char *check_release_event(void) return(NULL); } - logprintf(LOG_INFO, "check"); + LOGPRINTF(3, "check"); return message; } return NULL; } -const char *trigger_release_event(void) +const char *trigger_release_event(const char **remote_name, + const char **button_name) { int len = 0; if(release_remote != NULL) { + *remote_name = release_remote->name; + *button_name = release_ncode->name; len = write_message(message, PACKET_SIZE+1, release_remote->name, release_ncode->name, release_suffix, release_code, 0); @@ -123,13 +136,15 @@ const char *trigger_release_event(void) logprintf(LOG_ERR,"message buffer overflow"); return(NULL); } - logprintf(LOG_INFO, "trigger"); + LOGPRINTF(3, "trigger"); return message; } return NULL; } -const char *release_map_remotes(struct ir_remote *old, struct ir_remote *new) +const char *release_map_remotes(struct ir_remote *old, struct ir_remote *new, + const char **remote_name, + const char **button_name) { struct ir_remote *remote; struct ir_ncode *ncode; @@ -150,7 +165,7 @@ const char *release_map_remotes(struct i } else { - return trigger_release_event(); + return trigger_release_event(remote_name, button_name); } } return NULL; diff -Naurp lirc-0.8.4a.orig/daemons/release.h lirc-0.8.4a.upd/daemons/release.h --- lirc-0.8.4a.orig/daemons/release.h 2007-05-06 07:54:02.000000000 -0400 +++ lirc-0.8.4a.upd/daemons/release.h 2008-12-08 16:58:00.938502877 -0500 @@ -1,4 +1,4 @@ -/* $Id: release.h,v 1.1 2007/05/06 11:54:02 lirc Exp $ */ +/* $Id: release.h,v 1.2 2008/12/06 20:00:03 lirc Exp $ */ /**************************************************************************** ** release.h *************************************************************** @@ -18,10 +18,17 @@ void register_input(void); void register_button_press(struct ir_remote *remote, struct ir_ncode *ncode, ir_code code, int reps); +void get_release_data(const char **remote_name, + const char **button_name, + int *reps); void set_release_suffix(const char *s); void get_release_time(struct timeval *tv); -const char *check_release_event(void); -const char *trigger_release_event(void); -const char *release_map_remotes(struct ir_remote *old, struct ir_remote *new); +const char *check_release_event(const char **remote_name, + const char **button_name); +const char *trigger_release_event(const char **remote_name, + const char **button_name); +const char *release_map_remotes(struct ir_remote *old, struct ir_remote *new + const char **remote_name, + const char **button_name); #endif /* RELEASE_H */ diff -Naurp lirc-0.8.4a.orig/doc/man/lircd.8 lirc-0.8.4a.upd/doc/man/lircd.8 --- lirc-0.8.4a.orig/doc/man/lircd.8 2008-10-26 10:15:37.000000000 -0400 +++ lirc-0.8.4a.upd/doc/man/lircd.8 2008-12-08 17:14:44.574433177 -0500 @@ -70,8 +70,9 @@ the device name isn't fixed. \fISTRING\f wildcards and '\\' to mark them as literal. With the --listen option you can let lircd listen for network -connections on the given port. The default port is 8765. No security -checks are currently implemented. +connections on the given address/port. The default address is 0.0.0.0, +which means that connections on all network interfaces will be accepted. +The default port is 8765. No security checks are currently implemented. The --connect option allows you to connect to other lircd servers that provide a network socket at the given host and port number. The number @@ -99,6 +100,14 @@ users with access to the lircd socket wi E.g. if you have configured your system to shut down by a button press on your remote control, everybody will be able to shut down your system from the command line. + +On Linux systems the --uinput option will enable automatic generation +of Linux input events. lircd will open /dev/input/uinput and inject +key events to the Linux kernel. The key code depends on the name that +was given a button in the lircd config file, e.g. if the button is +named KEY_1, the '1' key code will be generated. You will find a +complete list of possible button names in /usr/include/linux/input.h. + .SH FILES The config file for lircd is located in /etc/lircd.conf. lircd diff -Naurp lirc-0.8.4a.orig/NEWS lirc-0.8.4a.upd/NEWS --- lirc-0.8.4a.orig/NEWS 2008-12-08 16:47:25.391622403 -0500 +++ lirc-0.8.4a.upd/NEWS 2008-12-08 17:40:05.345432825 -0500 @@ -1,3 +1,7 @@ +0.8.5-CVS: future + * Linux input event generation using uinput + * standardised namespace following Linux input conventions + 0.8.4a: 10/26/08 * fixed show-stopper bug in irrecord for drivers using MODE2 diff -Naurp lirc-0.8.4a.orig/TODO lirc-0.8.4a.upd/TODO --- lirc-0.8.4a.orig/TODO 2008-07-31 07:17:53.000000000 -0400 +++ lirc-0.8.4a.upd/TODO 2008-12-08 17:40:51.546432812 -0500 @@ -2,8 +2,6 @@ * __init, __exit -* uinput - * namespace * GUI for irrecord