~ubuntu-branches/ubuntu/precise/lirc/precise

« back to all changes in this revision

Viewing changes to daemons/hw_awlibusb.c

  • Committer: Bazaar Package Importer
  • Author(s): Mario Limonciello
  • Date: 2009-06-18 01:48:20 UTC
  • mfrom: (1.2.8 upstream)
  • Revision ID: james.westby@ubuntu.com-20090618014820-xd3wmu47cd23ejtc
Tags: 0.8.5-0ubuntu1
* New upstream version. (LP: #383446)
  - Fixes imon support (LP: #283317)
* Refresh the following patches for new version:
  - debian/patches/04_man_pages
  - debian/patches/13-warning-cleanup
  - debian/patches/21_atiusb
  - debian/patches/23_pad2keys
  - debian/patches/28_irrecord_resume_support
  - debian/patches/35_general_deviniput
* debian/control:
  - Add build-depends on libftdi-dev to prevent FTBFS.
* debian/copyright:
  - Update to what debian is shipping.
* debian/modules-source/{lirc-modules-source.conf, Makefile}
  - Don't build cmdir anymore.  It's now a userspace module
* debian/rules:
  - Generate dkms.conf using sed instead.
* debian/patches/12_pvr150_transmit_support:
  - Drop.  Upstream didn't like this patch due to questionable
   copyright, and we aren't properly supporting it anyway.
  - Refresh 20_serial_igor
  - Refresh 26_transmitter_lircd
* debian/lirc-modules-source.README.Debian:
  - Drop, inaccurate now.
* debian/lirc.init.d:
  - Cleanup a useless for loop.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/****************************************************************************
 
2
 ** hw_awlibusb.c ***********************************************************
 
3
 ****************************************************************************
 
4
 *
 
5
 *  Userspace Lirc plugin for Awox RF/IR usb remote
 
6
 * 
 
7
 *  Copyright (C) 2008 Arif <azeemarif@gmail.com>
 
8
 *  Copyright (C) 2008 Awox Pte Ltd <marif@awox.com>
 
9
 *
 
10
 *
 
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.
 
15
 *
 
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.
 
20
 *
 
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.
 
24
 *
 
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)
 
29
 */
 
30
 
 
31
 
 
32
#ifdef HAVE_CONFIG_H
 
33
# include <config.h>
 
34
#endif
 
35
 
 
36
#include <errno.h>
 
37
#include <signal.h>
 
38
#include <string.h>
 
39
#include <unistd.h>
 
40
#include <usb.h>
 
41
#include <sys/types.h>
 
42
#include <sys/wait.h>
 
43
#include <time.h>
 
44
 
 
45
 
 
46
#include "hardware.h"
 
47
#include "ir_remote.h"
 
48
#include "lircd.h"
 
49
#include "receive.h"
 
50
 
 
51
#define AW_MODE_LIRCCODE 1
 
52
 
 
53
#define AWUSB_RECEIVE_BYTES 5
 
54
#define USB_TIMEOUT (1000*60)
 
55
#define AW_VENDOR_THOMSON 0x069b
 
56
#define AW_DEVICE_THOMSON 0x1111
 
57
 
 
58
#define AW_KEY_GAP 0 /* Original value=200000. Made it 0 to handle it in userspace */
 
59
 
 
60
#if !defined(AW_MODE_LIRCCODE)
 
61
static ir_code code;
 
62
static ir_code code_last;
 
63
static struct timeval time_current = {0};
 
64
static struct timeval time_last = {0};
 
65
#endif
 
66
 
 
67
 
 
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);
 
74
 
 
75
#ifdef AW_MODE_LIRCCODE
 
76
struct hardware hw_awlibusb =
 
77
{
 
78
        NULL,                       /* default device */
 
79
        -1,                         /* fd */
 
80
        LIRC_CAN_REC_LIRCCODE,      /* features */
 
81
        0,                          /* send_mode */
 
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 */
 
87
        NULL,                       /* send_func */
 
88
        awlibusb_rec,               /* rec_func */
 
89
        receive_decode,             /* decode_func */
 
90
        NULL,                       /* ioctl_func */
 
91
        NULL,                       /* readdata */
 
92
        "awlibusb"
 
93
};
 
94
#else
 
95
struct hardware hw_awlibusb =
 
96
{
 
97
        NULL,                       /* default device */
 
98
        -1,                         /* fd */
 
99
        LIRC_CAN_REC_CODE,          /* features */
 
100
        0,                          /* send_mode */
 
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 */
 
110
        NULL,                       /* readdata */
 
111
        "awlibusb"
 
112
};
 
113
#endif
 
114
typedef struct {
 
115
        u_int16_t vendor;
 
116
        u_int16_t product;
 
117
} usb_device_id;
 
118
 
 
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 */
 
124
        { }
 
125
};
 
126
 
 
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;
 
130
 
 
131
/****/
 
132
 
 
133
/* initialize driver -- returns 1 on success, 0 on error */
 
134
static int awlibusb_init()
 
135
{
 
136
        struct usb_device *usb_dev;
 
137
        int pipe_fd[2] = { -1, -1 };
 
138
        
 
139
        LOGPRINTF(LOG_INFO, "initializing USB receiver");
 
140
        
 
141
        init_rec_buffer();
 
142
        
 
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)
 
147
        {
 
148
                logprintf(LOG_ERR, "couldn't open pipe: %s", strerror(errno));
 
149
                return 0;
 
150
        }
 
151
        hw.fd = pipe_fd[0];
 
152
        
 
153
        usb_dev = find_usb_device();
 
154
        if (usb_dev == NULL)
 
155
        {
 
156
                logprintf(LOG_ERR, "couldn't find a compatible USB device");
 
157
                goto fail;
 
158
        }
 
159
 
 
160
        if (!find_device_endpoints(usb_dev))
 
161
        {
 
162
                logprintf(LOG_ERR, "couldn't find device endpoints");
 
163
                goto fail;
 
164
        }
 
165
        
 
166
        dev_handle = usb_open(usb_dev);
 
167
        if (dev_handle == NULL)
 
168
        {
 
169
                logprintf(LOG_ERR, "couldn't open USB receiver: %s",
 
170
                                strerror(errno));
 
171
                goto fail;
 
172
        }
 
173
        
 
174
        if (usb_claim_interface(dev_handle, 0) != 0)
 
175
        {
 
176
                logprintf(LOG_ERR, "couldn't claim USB interface: %s",
 
177
                                strerror(errno));
 
178
                goto fail;
 
179
        }
 
180
        
 
181
        child = fork();
 
182
        if (child == -1)
 
183
        {
 
184
                logprintf(LOG_ERR, "couldn't fork child process: %s",
 
185
                                strerror(errno));
 
186
                goto fail;
 
187
        }
 
188
        else if (child == 0)
 
189
        {
 
190
                usb_read_loop(pipe_fd[1]);
 
191
        }
 
192
        
 
193
        LOGPRINTF(LOG_INFO, "USB receiver initialized");
 
194
        return 1;
 
195
 
 
196
fail:
 
197
        if (dev_handle)
 
198
        {
 
199
                usb_close(dev_handle);
 
200
                dev_handle = NULL;
 
201
        }
 
202
        if (pipe_fd[0] >= 0) close(pipe_fd[0]);
 
203
        if (pipe_fd[1] >= 0) close(pipe_fd[1]);
 
204
        return 0;
 
205
}
 
206
 
 
207
/* deinitialize driver -- returns 1 on success, 0 on error */
 
208
static int awlibusb_deinit()
 
209
{
 
210
        int err = 0;
 
211
        
 
212
        if (dev_handle)
 
213
        {
 
214
                if (usb_close(dev_handle) < 0) err = 1;
 
215
                dev_handle = NULL;
 
216
        }
 
217
        
 
218
        if (hw.fd >= 0)
 
219
        {
 
220
                if (close(hw.fd) < 0) err = 1;
 
221
                hw.fd = -1;
 
222
        }
 
223
        
 
224
        if (child > 1)
 
225
        {
 
226
                if ( (kill(child, SIGTERM) == -1)
 
227
                     || (waitpid(child, NULL, 0) == 0) ) err = 1;
 
228
        }
 
229
        
 
230
        return !err;
 
231
}
 
232
 
 
233
static char *awlibusb_rec(struct ir_remote *remotes)
 
234
{
 
235
        if (!clear_rec_buffer()) return NULL;
 
236
        return decode_all(remotes);
 
237
}
 
238
 
 
239
/* returns 1 if the given device should be used, 0 otherwise */
 
240
static int is_device_ok(struct usb_device *dev)
 
241
{
 
242
        /* TODO: allow exact device to be specified */
 
243
        
 
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++)
 
247
        {
 
248
                if ( (dev->descriptor.idVendor == dev_id->vendor) &&
 
249
                     (dev->descriptor.idProduct == dev_id->product) )
 
250
                {
 
251
                        return 1;
 
252
                }
 
253
        }
 
254
        
 
255
        return 0;
 
256
}
 
257
 
 
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)
 
261
{
 
262
        struct usb_bus *usb_bus;
 
263
        struct usb_device *dev;
 
264
        
 
265
        usb_init();
 
266
        usb_find_busses();
 
267
        usb_find_devices();
 
268
        
 
269
        for (usb_bus = usb_busses; usb_bus; usb_bus = usb_bus->next)
 
270
        {
 
271
                for (dev = usb_bus->devices; dev; dev = dev->next)
 
272
                {
 
273
                        if (is_device_ok(dev)) return dev;
 
274
                }
 
275
        }
 
276
        return NULL;  /* no suitable device found */
 
277
}
 
278
 
 
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)
 
282
{
 
283
        struct usb_interface_descriptor *idesc;
 
284
 
 
285
        if (dev->descriptor.bNumConfigurations != 1) return 0;
 
286
 
 
287
        if (dev->config[0].bNumInterfaces != 1) return 0;
 
288
 
 
289
        if (dev->config[0].interface[0].num_altsetting != 1) return 0;
 
290
 
 
291
        
 
292
        idesc = &dev->config[0].interface[0].altsetting[0];
 
293
//      if (idesc->bNumEndpoints != 2) return 0;
 
294
 
 
295
        
 
296
        dev_ep_in = &idesc->endpoint[0];
 
297
        if ((dev_ep_in->bEndpointAddress & USB_ENDPOINT_DIR_MASK)
 
298
                        != USB_ENDPOINT_IN) return 0;
 
299
 
 
300
        if ((dev_ep_in->bmAttributes & USB_ENDPOINT_TYPE_MASK)
 
301
                        != USB_ENDPOINT_TYPE_INTERRUPT) return 0;
 
302
 
 
303
        return 1;
 
304
}
 
305
 
 
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)
 
310
{
 
311
        int inited = 0;
 
312
        int err = 0;
 
313
#if !defined(AW_MODE_LIRCCODE)
 
314
        long elapsed_seconds = 0;  /* diff between seconds counter */
 
315
        long elapsed_useconds = 0; /* diff between microseconds counter */
 
316
        long time_diff = 0;
 
317
#endif
 
318
        
 
319
        alarm(0);
 
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);
 
325
        
 
326
        for(;;)
 
327
        {
 
328
                char buf[AWUSB_RECEIVE_BYTES];
 
329
                int bytes_r, bytes_w;
 
330
                
 
331
                /* read from the USB device */
 
332
                bytes_r = usb_interrupt_read(dev_handle,
 
333
                                             dev_ep_in->bEndpointAddress,
 
334
                                             &buf[0], sizeof(buf),
 
335
                                             USB_TIMEOUT);
 
336
                if (bytes_r < 0)
 
337
                {
 
338
                        if (errno == EAGAIN) continue;
 
339
                        logprintf(LOG_ERR, "can't read from USB device: %s",
 
340
                                  strerror(errno));
 
341
                        err = 1; goto done;
 
342
                }
 
343
                
 
344
                /* sometimes the remote sends one byte on startup; ignore it */
 
345
                if (!inited)
 
346
                {
 
347
                        inited = 1;
 
348
                        if (bytes_r == 1) continue;
 
349
                }
 
350
                
 
351
#ifdef AW_MODE_LIRCCODE
 
352
                bytes_w = write(fd, &(buf[1]), (AWUSB_RECEIVE_BYTES-1));
 
353
                /* ignore first byte */
 
354
                if (bytes_w < 0)
 
355
                {
 
356
                        logprintf(LOG_ERR, "can't write to pipe: %s",
 
357
                                  strerror(errno));
 
358
                        err = 1;
 
359
                        goto done;
 
360
                }
 
361
#else
 
362
                code = buf[AWUSB_RECEIVE_BYTES-2];
 
363
 
 
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);
 
370
 
 
371
                if ( !((code == code_last) && (time_diff < AW_KEY_GAP)) )
 
372
                { 
 
373
                        bytes_w = write(fd, &code, 1);
 
374
                        if (bytes_w < 0)
 
375
                        {
 
376
                                logprintf(LOG_ERR, "can't write to pipe: %s",
 
377
                                          strerror(errno));
 
378
                                err = 1;
 
379
                                goto done;
 
380
                        }
 
381
                        code_last = code;
 
382
                        memcpy(&time_last, &time_current, sizeof(struct timeval));
 
383
                }
 
384
#endif
 
385
                
 
386
        }
 
387
        
 
388
 done:
 
389
        if (!usb_close(dev_handle)) err = 1;
 
390
        _exit(err);
 
391
}