1 /* $Id: lirc_cmdir.c,v 1.9 2008/01/13 11:13:49 lirc Exp $ */
4 * lirc_cmdir.c - Driver for InnovationOne's COMMANDIR USB Transceiver
6 * This driver requires the COMMANDIR hardware driver, available at
7 * http://www.commandir.com/.
9 * Copyright (C) 2005 InnovationOne - Evelyn Yeung
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 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
31 #include <linux/version.h>
32 #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 2, 18)
33 #error "**********************************************************"
34 #error " Sorry, this driver needs kernel version 2.2.18 or higher "
35 #error "**********************************************************"
38 #include <linux/autoconf.h>
39 #include <linux/module.h>
40 #include <linux/errno.h>
41 #include <linux/signal.h>
42 #include <linux/sched.h>
43 #include <linux/kernel.h>
44 #include <linux/time.h>
45 #include <linux/string.h>
46 #include <linux/delay.h>
47 #include <linux/poll.h>
48 #include "drivers/lirc.h"
49 #include "drivers/lirc_dev/lirc_dev.h"
50 #include "drivers/kcompat.h"
51 #include "lirc_cmdir.h"
54 #define dprintk(fmt, args...) \
57 printk(KERN_DEBUG fmt, ## args); \
64 struct lirc_cmdir hardware
= {
66 /* LIRC_CAN_SET_SEND_DUTY_CYCLE| */
67 LIRC_CAN_SET_SEND_CARRIER
|
69 LIRC_CAN_SET_TRANSMITTER_MASK
|
74 #define LIRC_DRIVER_NAME "lirc_cmdir"
79 static struct lirc_buffer rbuf
;
80 static lirc_t wbuf
[WBUF_LEN
];
81 static unsigned char cmdir_char
[4*WBUF_LEN
];
82 static unsigned char write_control
[MCU_CTRL_SIZE
];
83 static unsigned int last_mc_time
;
84 static int usb_status
= ON
;
85 static unsigned char signal_num
;
88 unsigned int freq
= 38000;
89 /* unsigned int duty_cycle = 50; */
93 #define MAX_UDELAY_US 5000
95 #define MAX_UDELAY_US (MAX_UDELAY_MS*1000)
98 static inline void safe_udelay(unsigned long usecs
)
100 while (usecs
> MAX_UDELAY_US
) {
101 udelay(MAX_UDELAY_US
);
102 usecs
-= MAX_UDELAY_US
;
107 static unsigned int get_time_value(unsigned int firstint
,
108 unsigned int secondint
, unsigned char overflow
)
109 { /* get difference between two timestamps from MCU */
110 unsigned int t_answer
= 0;
112 if (secondint
> firstint
) {
113 t_answer
= secondint
- firstint
+ overflow
*65536;
116 t_answer
= (65536 - firstint
) + secondint
+
117 (overflow
- 1) * 65536;
119 t_answer
= (65536 - firstint
) + secondint
;
122 /* clamp to long signal */
123 if (t_answer
> 16000000)
124 t_answer
= PULSE_MASK
;
130 static int set_use_inc(void *data
)
132 /* Init read buffer. */
133 if (lirc_buffer_init(&rbuf
, sizeof(lirc_t
), RBUF_LEN
) < 0)
140 static void set_use_dec(void *data
)
142 lirc_buffer_free(&rbuf
);
147 static void usb_error_handle(int retval
)
151 /* device has been unplugged */
152 if (usb_status
== ON
) {
154 printk(LIRC_DRIVER_NAME
": device is unplugged\n");
158 printk(LIRC_DRIVER_NAME
": usb error = %d\n", retval
);
163 static int write_to_usb(unsigned char *buffer
, int count
, int time_elapsed
)
167 write_return
= cmdir_write(buffer
, count
, NULL
, time_elapsed
);
168 if (write_return
!= count
) {
169 usb_error_handle(write_return
);
171 if (usb_status
== OFF
) {
172 printk(LIRC_DRIVER_NAME
": device is now plugged in\n");
179 static void set_freq(void)
181 /* float tempfreq = 0.0; */
185 * Can't use floating point in 2.6 kernel!
186 * May be some loss of precision
188 timerval
= (1000000 / freq
) / 2;
189 write_control
[0] = FREQ_HEADER
;
190 write_control
[1] = timerval
;
191 write_control
[2] = 0;
192 write_return
= write_to_usb(write_control
, MCU_CTRL_SIZE
, 0);
193 if (write_return
== MCU_CTRL_SIZE
)
194 printk(LIRC_DRIVER_NAME
": freq set to %dHz\n", freq
);
196 printk(LIRC_DRIVER_NAME
": freq unchanged\n");
200 static int cmdir_convert_RX(unsigned char *orig_rxbuffer
)
202 unsigned char tmp_char_buffer
[80];
203 unsigned int tmp_int_buffer
[20];
204 unsigned int final_data_buffer
[20];
205 unsigned int num_data_values
= 0;
206 unsigned char num_data_bytes
= 0;
207 unsigned int orig_index
= 0;
210 for (i
= 0; i
< 80; i
++)
211 tmp_char_buffer
[i
] = 0;
212 for (i
= 0; i
< 20; i
++)
213 tmp_int_buffer
[i
] = 0;
216 * get number of data bytes that follow the control bytes
217 * (NOT including them)
219 num_data_bytes
= orig_rxbuffer
[1];
221 /* check if num_bytes is multiple of 3; if not, error */
222 if (num_data_bytes
% 3 > 0)
224 if (num_data_bytes
> 60)
226 if (num_data_bytes
< 3)
230 * get number of ints to be returned; num_data_bytes does
231 * NOT include control bytes
233 num_data_values
= num_data_bytes
/3;
235 for (i
= 0; i
< num_data_values
; i
++) {
236 tmp_char_buffer
[i
*4] = orig_rxbuffer
[(i
+1)*3];
237 tmp_char_buffer
[i
*4+1] = orig_rxbuffer
[(i
+1)*3+1];
238 tmp_char_buffer
[i
*4+2] = 0;
239 tmp_char_buffer
[i
*4+3] = 0;
242 /* convert to int array */
243 memcpy((unsigned char *)tmp_int_buffer
, tmp_char_buffer
,
244 (num_data_values
*4));
246 if (orig_rxbuffer
[5] < 255) {
248 final_data_buffer
[0] = get_time_value(last_mc_time
,
251 } else { /* is pulse */
252 final_data_buffer
[0] = get_time_value(last_mc_time
,
255 final_data_buffer
[0] |= PULSE_BIT
;
257 for (i
= 1; i
< num_data_values
; i
++) {
259 * index of orig_rxbuffer that corresponds to
260 * overflow/pulse/space
262 orig_index
= (i
+ 1)*3 + 2;
263 if (orig_rxbuffer
[orig_index
] < 255) {
264 final_data_buffer
[i
] =
265 get_time_value(tmp_int_buffer
[i
- 1],
267 orig_rxbuffer
[orig_index
]);
269 final_data_buffer
[i
] =
270 get_time_value(tmp_int_buffer
[i
- 1],
273 final_data_buffer
[i
] |= PULSE_BIT
;
276 last_mc_time
= tmp_int_buffer
[num_data_values
- 1];
278 if (lirc_buffer_full(&rbuf
)) {
279 printk(KERN_ERR LIRC_DRIVER_NAME
": lirc_buffer is full\n");
282 lirc_buffer_write_n(&rbuf
, (char *)final_data_buffer
, num_data_values
);
288 static int usb_read_once(void)
292 unsigned char read_buffer
[MAX_PACKET
];
294 int tooFull
= 5; /* read up to 5 packets */
296 for (i
= 0; i
< MAX_PACKET
; i
++)
300 read_retval
= cmdir_read(read_buffer
, MAX_PACKET
);
301 /* Loop until we unload the data build-up */
302 if (read_buffer
[1] < 60)
304 if (!(read_retval
== MAX_PACKET
)) {
305 if (read_retval
== -ENODEV
) {
306 if (usb_status
== ON
) {
307 printk(KERN_ALERT LIRC_DRIVER_NAME
308 ": device is unplugged\n");
313 printk(KERN_ALERT LIRC_DRIVER_NAME
314 ": usb error on read = %d\n",
318 dprintk("Error 3\n");
321 if (usb_status
== OFF
) {
323 printk(LIRC_DRIVER_NAME
324 ": device is now plugged in\n");
328 if (read_buffer
[0] & 0x08) {
329 conv_retval
= cmdir_convert_RX(read_buffer
);
330 if (conv_retval
== 0) {
334 dprintk("Looping for more data...\n");
336 dprintk("Error 2: %d\n", (int)conv_retval
);
340 /* There really is no data in their buffer */
341 dprintk("Empty RX Buffer!\n");
348 int add_to_buf(void *data
, struct lirc_buffer
*buf
)
350 return usb_read_once();
354 static ssize_t
lirc_write(struct file
*file
, const char *buf
,
355 size_t n
, loff_t
*ppos
)
358 unsigned int mod_signal_length
= 0;
359 unsigned int time_elapse
= 0;
360 unsigned int total_time_elapsed
= 0;
361 unsigned int num_bytes_already_sent
= 0;
362 unsigned int hibyte
= 0;
363 unsigned int lobyte
= 0;
365 unsigned int wait_this
= 0;
366 struct timeval start_time
;
367 struct timeval end_time
;
368 unsigned int real_time_elapsed
= 0;
370 /* save the time we started the write: */
371 do_gettimeofday(&start_time
);
373 if (n
% sizeof(lirc_t
))
376 count
= n
/sizeof(lirc_t
);
377 if (count
> WBUF_LEN
|| count
% 2 == 0)
379 if (copy_from_user(wbuf
, buf
, n
))
383 * the first time we have to flag that this is the start of a new
384 * signal otherwise COMMANDIR may receive 2 back-to-back pulses &
387 cmdir_char
[0] = TX_HEADER_NEW
;
389 cmdir_char
[1] = signal_num
;
391 for (i
= 0; i
< count
; i
++) {
392 /* conversion to number of modulation frequency pulse edges */
393 mod_signal_length
= wbuf
[i
] >> 3;
395 * account for minor rounding errors -
396 * calculate length from this:
398 time_elapse
+= mod_signal_length
* timerval
;
400 hibyte
= mod_signal_length
/ 256;
401 lobyte
= mod_signal_length
% 256;
402 cmdir_char
[cmdir_cnt
+1] = lobyte
;
403 cmdir_char
[cmdir_cnt
] = hibyte
;
406 /* write data to usb if full packet is collected */
407 if (cmdir_cnt
% MAX_PACKET
== 0) {
408 write_to_usb(cmdir_char
, MAX_PACKET
, time_elapse
);
410 total_time_elapsed
+= time_elapse
;
412 num_bytes_already_sent
+= MAX_PACKET
;
415 if ((i
+ 1) < count
) {
416 /* still more to send: */
417 cmdir_char
[0] = TX_HEADER
; /* Next Packet */
418 cmdir_char
[1] = signal_num
;
419 cmdir_cnt
= 2; /* reset the count */
424 /* send last chunk of data */
426 total_time_elapsed
+= time_elapse
;
427 write_to_usb(cmdir_char
, cmdir_cnt
, time_elapse
);
429 /* XXX ERS remove all this? */
431 * we need to _manually delay ourselves_ to remain backwards
432 * compatible with LIRC and prevent our queue buffer from overflowing.
433 * Queuing in this driver is about instant, and send_start for example
434 * will fill it up quickly and prevent send_stop from taking immediate
437 dprintk("Total elapsed time is: %d. \n", total_time_elapsed
);
438 do_gettimeofday(&end_time
);
440 * udelay for the difference between endtime and
441 * start + total_time_elapsed
443 if (start_time
.tv_usec
< end_time
.tv_usec
)
444 real_time_elapsed
= (end_time
.tv_usec
- start_time
.tv_usec
);
446 real_time_elapsed
= ((end_time
.tv_usec
+ 1000000) -
448 dprintk("Real time elapsed was %u.\n", real_time_elapsed
);
449 if (real_time_elapsed
< (total_time_elapsed
- 1000))
450 wait_this
= total_time_elapsed
- real_time_elapsed
- 1000;
452 #if 0 /* enable this for backwards compatibility */
453 safe_udelay(wait_this
);
460 static int lirc_ioctl(struct inode
*node
, struct file
*filep
, unsigned int cmd
,
466 unsigned int multiplier
= 1;
467 unsigned int mask
= 0;
471 case LIRC_SET_TRANSMITTER_MASK
:
472 if (!(hardware
.features
&LIRC_CAN_SET_TRANSMITTER_MASK
))
474 result
= get_user(ivalue
, (unsigned int *) arg
);
477 for (i
= 0; i
< MAX_CHANNELS
; i
++) {
478 multiplier
= multiplier
* 0x10;
483 set_tx_channels(ivalue
);
487 case LIRC_GET_SEND_MODE
:
488 if (!(hardware
.features
& LIRC_CAN_SEND_MASK
))
491 result
= put_user(LIRC_SEND2MODE
492 (hardware
.features
& LIRC_CAN_SEND_MASK
),
493 (unsigned long *) arg
);
498 case LIRC_SET_SEND_MODE
:
499 if (!(hardware
.features
&LIRC_CAN_SEND_MASK
))
502 result
= get_user(value
, (unsigned long *)arg
);
507 case LIRC_GET_LENGTH
:
511 case LIRC_SET_SEND_DUTY_CYCLE
:
512 dprintk(KERN_WARNING LIRC_DRIVER_NAME
513 ": SET_SEND_DUTY_CYCLE\n");
515 if (!(hardware
.features
&LIRC_CAN_SET_SEND_DUTY_CYCLE
))
518 result
= get_user(ivalue
, (unsigned int *)arg
);
521 if (ivalue
<= 0 || ivalue
> 100)
525 dprintk(LIRC_DRIVER_NAME
526 ": set_send_duty_cycle not yet supported\n");
531 case LIRC_SET_SEND_CARRIER
:
532 dprintk(KERN_WARNING LIRC_DRIVER_NAME
": SET_SEND_CARRIER\n");
534 if (!(hardware
.features
& LIRC_CAN_SET_SEND_CARRIER
))
537 result
= get_user(ivalue
, (unsigned int *)arg
);
540 if (ivalue
> 500000 || ivalue
< 24000)
542 if (ivalue
!= freq
) {
555 static struct file_operations lirc_fops
= {
559 static struct lirc_plugin plugin
= {
560 .name
= LIRC_DRIVER_NAME
,
565 .add_to_buf
= add_to_buf
,
568 .set_use_inc
= set_use_inc
,
569 .set_use_dec
= set_use_dec
,
573 .owner
= THIS_MODULE
,
578 MODULE_AUTHOR("Evelyn Yeung, Matt Bodkin");
579 MODULE_DESCRIPTION("InnovationOne driver for "
580 "CommandIR USB infrared transceiver");
581 #ifdef MODULE_LICENSE
582 MODULE_LICENSE("GPL");
585 module_param(debug
, bool, 0644);
586 MODULE_PARM_DESC(debug
, "Enable debugging messages");
592 int init_module(void)
594 plugin
.features
= hardware
.features
;
595 plugin
.minor
= lirc_register_plugin(&plugin
);
596 if (plugin
.minor
< 0) {
597 printk(KERN_ERR LIRC_DRIVER_NAME
598 ": register_chrdev failed!\n");
605 void cleanup_module(void)
607 lirc_unregister_plugin(plugin
.minor
);
608 printk(KERN_INFO LIRC_DRIVER_NAME
": module removed\n");