1
/****************************************************************************
2
** hw_awlibusb.c ***********************************************************
3
****************************************************************************
5
* Userspace Lirc plugin for Awox RF/IR usb remote
7
* Copyright (C) 2008 Arif <azeemarif@gmail.com>
8
* Copyright (C) 2008 Awox Pte Ltd <marif@awox.com>
11
* This program is free software; you can redistribute it and/or modify
12
* it under the terms of the GNU General Public License as published by
13
* the Free Software Foundation; either version 2 of the License, or
14
* (at your option) any later version.
16
* This program is distributed in the hope that it will be useful,
17
* but WITHOUT ANY WARRANTY; without even the implied warranty of
18
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19
* GNU Library General Public License for more details.
21
* You should have received a copy of the GNU General Public License
22
* along with this program; if not, write to the Free Software
23
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
25
* July 2008: Created along with corresponding kernel space driver
26
* August 2008: Modified it to work in userspace using libusb.
27
* No kernel driver is needed anymore.
28
* (reference taken from atilibusb)
41
#include <sys/types.h>
47
#include "ir_remote.h"
51
#define AW_MODE_LIRCCODE 1
53
#define AWUSB_RECEIVE_BYTES 5
54
#define USB_TIMEOUT (1000*60)
55
#define AW_VENDOR_THOMSON 0x069b
56
#define AW_DEVICE_THOMSON 0x1111
58
#define AW_KEY_GAP 0 /* Original value=200000. Made it 0 to handle it in userspace */
60
#if !defined(AW_MODE_LIRCCODE)
62
static ir_code code_last;
63
static struct timeval time_current = {0};
64
static struct timeval time_last = {0};
68
static int awlibusb_init();
69
static int awlibusb_deinit();
70
static char *awlibusb_rec(struct ir_remote *remotes);
71
static void usb_read_loop(int fd);
72
static struct usb_device *find_usb_device(void);
73
static int find_device_endpoints(struct usb_device *dev);
75
#ifdef AW_MODE_LIRCCODE
76
struct hardware hw_awlibusb =
78
NULL, /* default device */
80
LIRC_CAN_REC_LIRCCODE, /* features */
82
LIRC_MODE_LIRCCODE, /* rec_mode */
83
(AWUSB_RECEIVE_BYTES-1) * CHAR_BIT, /* code_length */
84
awlibusb_init, /* init_func */
85
NULL, /* config_func */
86
awlibusb_deinit, /* deinit_func */
88
awlibusb_rec, /* rec_func */
89
receive_decode, /* decode_func */
90
NULL, /* ioctl_func */
95
struct hardware hw_awlibusb =
97
NULL, /* default device */
99
LIRC_CAN_REC_CODE, /* features */
101
LIRC_MODE_CODE, /* rec_mode */
102
CHAR_BIT, /* code_length */
103
awlibusb_init, /* init_func */
104
NULL, /* config_func */
105
awlibusb_deinit, /* deinit_func */
106
NULL, /* send_func */
107
awlibusb_rec, /* rec_func */
108
receive_decode, /* decode_func */
109
NULL, /* ioctl_func */
119
/* table of compatible remotes -- from lirc_awusb */
120
static usb_device_id usb_remote_id_table[] = {
121
/* Awox RF/Infrared Transciever */
122
{ AW_VENDOR_THOMSON, AW_DEVICE_THOMSON },
123
/* Terminating entry */
127
static struct usb_dev_handle *dev_handle = NULL;
128
static struct usb_endpoint_descriptor *dev_ep_in = NULL;
129
static pid_t child = -1;
133
/* initialize driver -- returns 1 on success, 0 on error */
134
static int awlibusb_init()
136
struct usb_device *usb_dev;
137
int pipe_fd[2] = { -1, -1 };
139
LOGPRINTF(LOG_INFO, "initializing USB receiver");
143
/* A separate process will be forked to read data from the USB
144
* receiver and write it to a pipe. hw.fd is set to the readable
145
* end of this pipe. */
146
if (pipe(pipe_fd) != 0)
148
logprintf(LOG_ERR, "couldn't open pipe: %s", strerror(errno));
153
usb_dev = find_usb_device();
156
logprintf(LOG_ERR, "couldn't find a compatible USB device");
160
if (!find_device_endpoints(usb_dev))
162
logprintf(LOG_ERR, "couldn't find device endpoints");
166
dev_handle = usb_open(usb_dev);
167
if (dev_handle == NULL)
169
logprintf(LOG_ERR, "couldn't open USB receiver: %s",
174
if (usb_claim_interface(dev_handle, 0) != 0)
176
logprintf(LOG_ERR, "couldn't claim USB interface: %s",
184
logprintf(LOG_ERR, "couldn't fork child process: %s",
190
usb_read_loop(pipe_fd[1]);
193
LOGPRINTF(LOG_INFO, "USB receiver initialized");
199
usb_close(dev_handle);
202
if (pipe_fd[0] >= 0) close(pipe_fd[0]);
203
if (pipe_fd[1] >= 0) close(pipe_fd[1]);
207
/* deinitialize driver -- returns 1 on success, 0 on error */
208
static int awlibusb_deinit()
214
if (usb_close(dev_handle) < 0) err = 1;
220
if (close(hw.fd) < 0) err = 1;
226
if ( (kill(child, SIGTERM) == -1)
227
|| (waitpid(child, NULL, 0) == 0) ) err = 1;
233
static char *awlibusb_rec(struct ir_remote *remotes)
235
if (!clear_rec_buffer()) return NULL;
236
return decode_all(remotes);
239
/* returns 1 if the given device should be used, 0 otherwise */
240
static int is_device_ok(struct usb_device *dev)
242
/* TODO: allow exact device to be specified */
244
/* check if the device ID is in usb_remote_id_table */
245
usb_device_id *dev_id;
246
for (dev_id = usb_remote_id_table; dev_id->vendor; dev_id++)
248
if ( (dev->descriptor.idVendor == dev_id->vendor) &&
249
(dev->descriptor.idProduct == dev_id->product) )
258
/* find a compatible USB receiver and return a usb_device,
259
* or NULL on failure. */
260
static struct usb_device *find_usb_device(void)
262
struct usb_bus *usb_bus;
263
struct usb_device *dev;
269
for (usb_bus = usb_busses; usb_bus; usb_bus = usb_bus->next)
271
for (dev = usb_bus->devices; dev; dev = dev->next)
273
if (is_device_ok(dev)) return dev;
276
return NULL; /* no suitable device found */
279
/* set dev_ep_in and dev_ep_out to the in/out endpoints of the given
280
* device. returns 1 on success, 0 on failure. */
281
static int find_device_endpoints(struct usb_device *dev)
283
struct usb_interface_descriptor *idesc;
285
if (dev->descriptor.bNumConfigurations != 1) return 0;
287
if (dev->config[0].bNumInterfaces != 1) return 0;
289
if (dev->config[0].interface[0].num_altsetting != 1) return 0;
292
idesc = &dev->config[0].interface[0].altsetting[0];
293
// if (idesc->bNumEndpoints != 2) return 0;
296
dev_ep_in = &idesc->endpoint[0];
297
if ((dev_ep_in->bEndpointAddress & USB_ENDPOINT_DIR_MASK)
298
!= USB_ENDPOINT_IN) return 0;
300
if ((dev_ep_in->bmAttributes & USB_ENDPOINT_TYPE_MASK)
301
!= USB_ENDPOINT_TYPE_INTERRUPT) return 0;
306
/* this function is run in a forked process to read data from the USB
307
* receiver and write it to the given fd. it calls exit() with result
308
* code 0 on success, or 1 on failure. */
309
static void usb_read_loop(int fd)
313
#if !defined(AW_MODE_LIRCCODE)
314
long elapsed_seconds = 0; /* diff between seconds counter */
315
long elapsed_useconds = 0; /* diff between microseconds counter */
320
signal(SIGTERM, SIG_DFL);
321
signal(SIGPIPE, SIG_DFL);
322
signal(SIGINT, SIG_DFL);
323
signal(SIGHUP, SIG_IGN);
324
signal(SIGALRM, SIG_IGN);
328
char buf[AWUSB_RECEIVE_BYTES];
329
int bytes_r, bytes_w;
331
/* read from the USB device */
332
bytes_r = usb_interrupt_read(dev_handle,
333
dev_ep_in->bEndpointAddress,
334
&buf[0], sizeof(buf),
338
if (errno == EAGAIN) continue;
339
logprintf(LOG_ERR, "can't read from USB device: %s",
344
/* sometimes the remote sends one byte on startup; ignore it */
348
if (bytes_r == 1) continue;
351
#ifdef AW_MODE_LIRCCODE
352
bytes_w = write(fd, &(buf[1]), (AWUSB_RECEIVE_BYTES-1));
353
/* ignore first byte */
356
logprintf(LOG_ERR, "can't write to pipe: %s",
362
code = buf[AWUSB_RECEIVE_BYTES-2];
364
/* calculate time diff */
365
gettimeofday(&time_current, NULL);
366
elapsed_seconds = time_current.tv_sec - time_last.tv_sec;
367
elapsed_useconds = time_current.tv_usec - time_last.tv_usec;
368
time_diff = (elapsed_seconds) * 1000000 + elapsed_useconds;
369
//printf("time_diff = %d usec\n", time_diff);
371
if ( !((code == code_last) && (time_diff < AW_KEY_GAP)) )
373
bytes_w = write(fd, &code, 1);
376
logprintf(LOG_ERR, "can't write to pipe: %s",
382
memcpy(&time_last, &time_current, sizeof(struct timeval));
389
if (!usb_close(dev_handle)) err = 1;