diff options
author | Jarod Wilson <jarod@redhat.com> | 2010-06-16 16:55:52 -0400 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@redhat.com> | 2010-08-02 13:58:58 -0400 |
commit | e23fb9643bd440fee9106e6df76f01a57db2613c (patch) | |
tree | 4bd1858a0a19061646698f6033410750f5738390 /drivers/media/IR | |
parent | 9b7c54d926284c5277cff3ef3cfe29f26568306a (diff) |
V4L/DVB: IR/mceusb: add tx callback functions and wire up
mchehab: merged with IR/mceusb: userspace buffer copy moved out of driver
Userspace buffer copy moved out of driver and into lirc bridge driver
[mchehab@redhat.com: merged the patch to avoid compilation errors with allyesconfig ]
Signed-off-by: Jarod Wilson <jarod@redhat.com>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
Diffstat (limited to 'drivers/media/IR')
-rw-r--r-- | drivers/media/IR/mceusb.c | 148 |
1 files changed, 138 insertions, 10 deletions
diff --git a/drivers/media/IR/mceusb.c b/drivers/media/IR/mceusb.c index 708a71a38443..cc8e2ef28b66 100644 --- a/drivers/media/IR/mceusb.c +++ b/drivers/media/IR/mceusb.c | |||
@@ -15,10 +15,6 @@ | |||
15 | * Jon Smirl, which included enhancements and simplifications to the | 15 | * Jon Smirl, which included enhancements and simplifications to the |
16 | * incoming IR buffer parsing routines. | 16 | * incoming IR buffer parsing routines. |
17 | * | 17 | * |
18 | * TODO: | ||
19 | * - add rc-core transmit support, once available | ||
20 | * - enable support for forthcoming ir-lirc-codec interface | ||
21 | * | ||
22 | * | 18 | * |
23 | * This program is free software; you can redistribute it and/or modify | 19 | * This program is free software; you can redistribute it and/or modify |
24 | * it under the terms of the GNU General Public License as published by | 20 | * it under the terms of the GNU General Public License as published by |
@@ -51,7 +47,6 @@ | |||
51 | #define DRIVER_NAME "mceusb" | 47 | #define DRIVER_NAME "mceusb" |
52 | 48 | ||
53 | #define USB_BUFLEN 32 /* USB reception buffer length */ | 49 | #define USB_BUFLEN 32 /* USB reception buffer length */ |
54 | #define IRBUF_SIZE 256 /* IR work buffer length */ | ||
55 | #define USB_CTRL_MSG_SZ 2 /* Size of usb ctrl msg on gen1 hw */ | 50 | #define USB_CTRL_MSG_SZ 2 /* Size of usb ctrl msg on gen1 hw */ |
56 | #define MCE_G1_INIT_MSGS 40 /* Init messages on gen1 hw to throw out */ | 51 | #define MCE_G1_INIT_MSGS 40 /* Init messages on gen1 hw to throw out */ |
57 | 52 | ||
@@ -263,14 +258,13 @@ struct mceusb_dev { | |||
263 | u32 reserved:28; | 258 | u32 reserved:28; |
264 | } flags; | 259 | } flags; |
265 | 260 | ||
266 | /* handle sending (init strings) */ | 261 | /* transmit support */ |
267 | int send_flags; | 262 | int send_flags; |
268 | int carrier; | 263 | u32 carrier; |
264 | unsigned char tx_mask; | ||
269 | 265 | ||
270 | char name[128]; | 266 | char name[128]; |
271 | char phys[64]; | 267 | char phys[64]; |
272 | |||
273 | unsigned char tx_mask; | ||
274 | }; | 268 | }; |
275 | 269 | ||
276 | /* | 270 | /* |
@@ -520,6 +514,91 @@ static void mce_sync_in(struct mceusb_dev *ir, unsigned char *data, int size) | |||
520 | mce_request_packet(ir, ir->usb_ep_in, data, size, MCEUSB_RX); | 514 | mce_request_packet(ir, ir->usb_ep_in, data, size, MCEUSB_RX); |
521 | } | 515 | } |
522 | 516 | ||
517 | /* Send data out the IR blaster port(s) */ | ||
518 | static int mceusb_tx_ir(void *priv, int *txbuf, u32 n) | ||
519 | { | ||
520 | struct mceusb_dev *ir = priv; | ||
521 | int i, ret = 0; | ||
522 | int count, cmdcount = 0; | ||
523 | unsigned char *cmdbuf; /* MCE command buffer */ | ||
524 | long signal_duration = 0; /* Singnal length in us */ | ||
525 | struct timeval start_time, end_time; | ||
526 | |||
527 | do_gettimeofday(&start_time); | ||
528 | |||
529 | count = n / sizeof(int); | ||
530 | |||
531 | cmdbuf = kzalloc(sizeof(int) * MCE_CMDBUF_SIZE, GFP_KERNEL); | ||
532 | if (!cmdbuf) | ||
533 | return -ENOMEM; | ||
534 | |||
535 | /* MCE tx init header */ | ||
536 | cmdbuf[cmdcount++] = MCE_CONTROL_HEADER; | ||
537 | cmdbuf[cmdcount++] = 0x08; | ||
538 | cmdbuf[cmdcount++] = ir->tx_mask; | ||
539 | |||
540 | /* Generate mce packet data */ | ||
541 | for (i = 0; (i < count) && (cmdcount < MCE_CMDBUF_SIZE); i++) { | ||
542 | signal_duration += txbuf[i]; | ||
543 | txbuf[i] = txbuf[i] / MCE_TIME_UNIT; | ||
544 | |||
545 | do { /* loop to support long pulses/spaces > 127*50us=6.35ms */ | ||
546 | |||
547 | /* Insert mce packet header every 4th entry */ | ||
548 | if ((cmdcount < MCE_CMDBUF_SIZE) && | ||
549 | (cmdcount - MCE_TX_HEADER_LENGTH) % | ||
550 | MCE_CODE_LENGTH == 0) | ||
551 | cmdbuf[cmdcount++] = MCE_PACKET_HEADER; | ||
552 | |||
553 | /* Insert mce packet data */ | ||
554 | if (cmdcount < MCE_CMDBUF_SIZE) | ||
555 | cmdbuf[cmdcount++] = | ||
556 | (txbuf[i] < MCE_PULSE_BIT ? | ||
557 | txbuf[i] : MCE_MAX_PULSE_LENGTH) | | ||
558 | (i & 1 ? 0x00 : MCE_PULSE_BIT); | ||
559 | else { | ||
560 | ret = -EINVAL; | ||
561 | goto out; | ||
562 | } | ||
563 | |||
564 | } while ((txbuf[i] > MCE_MAX_PULSE_LENGTH) && | ||
565 | (txbuf[i] -= MCE_MAX_PULSE_LENGTH)); | ||
566 | } | ||
567 | |||
568 | /* Fix packet length in last header */ | ||
569 | cmdbuf[cmdcount - (cmdcount - MCE_TX_HEADER_LENGTH) % MCE_CODE_LENGTH] = | ||
570 | 0x80 + (cmdcount - MCE_TX_HEADER_LENGTH) % MCE_CODE_LENGTH - 1; | ||
571 | |||
572 | /* Check if we have room for the empty packet at the end */ | ||
573 | if (cmdcount >= MCE_CMDBUF_SIZE) { | ||
574 | ret = -EINVAL; | ||
575 | goto out; | ||
576 | } | ||
577 | |||
578 | /* All mce commands end with an empty packet (0x80) */ | ||
579 | cmdbuf[cmdcount++] = 0x80; | ||
580 | |||
581 | /* Transmit the command to the mce device */ | ||
582 | mce_async_out(ir, cmdbuf, cmdcount); | ||
583 | |||
584 | /* | ||
585 | * The lircd gap calculation expects the write function to | ||
586 | * wait the time it takes for the ircommand to be sent before | ||
587 | * it returns. | ||
588 | */ | ||
589 | do_gettimeofday(&end_time); | ||
590 | signal_duration -= (end_time.tv_usec - start_time.tv_usec) + | ||
591 | (end_time.tv_sec - start_time.tv_sec) * 1000000; | ||
592 | |||
593 | /* delay with the closest number of ticks */ | ||
594 | set_current_state(TASK_INTERRUPTIBLE); | ||
595 | schedule_timeout(usecs_to_jiffies(signal_duration)); | ||
596 | |||
597 | out: | ||
598 | kfree(cmdbuf); | ||
599 | return ret ? ret : n; | ||
600 | } | ||
601 | |||
523 | /* Sets active IR outputs -- mce devices typically (all?) have two */ | 602 | /* Sets active IR outputs -- mce devices typically (all?) have two */ |
524 | static int mceusb_set_tx_mask(void *priv, u32 mask) | 603 | static int mceusb_set_tx_mask(void *priv, u32 mask) |
525 | { | 604 | { |
@@ -533,6 +612,49 @@ static int mceusb_set_tx_mask(void *priv, u32 mask) | |||
533 | return 0; | 612 | return 0; |
534 | } | 613 | } |
535 | 614 | ||
615 | /* Sets the send carrier frequency and mode */ | ||
616 | static int mceusb_set_tx_carrier(void *priv, u32 carrier) | ||
617 | { | ||
618 | struct mceusb_dev *ir = priv; | ||
619 | int clk = 10000000; | ||
620 | int prescaler = 0, divisor = 0; | ||
621 | unsigned char cmdbuf[4] = { 0x9f, 0x06, 0x00, 0x00 }; | ||
622 | |||
623 | /* Carrier has changed */ | ||
624 | if (ir->carrier != carrier) { | ||
625 | |||
626 | if (carrier == 0) { | ||
627 | ir->carrier = carrier; | ||
628 | cmdbuf[2] = 0x01; | ||
629 | cmdbuf[3] = 0x80; | ||
630 | dev_dbg(ir->dev, "%s: disabling carrier " | ||
631 | "modulation\n", __func__); | ||
632 | mce_async_out(ir, cmdbuf, sizeof(cmdbuf)); | ||
633 | return carrier; | ||
634 | } | ||
635 | |||
636 | for (prescaler = 0; prescaler < 4; ++prescaler) { | ||
637 | divisor = (clk >> (2 * prescaler)) / carrier; | ||
638 | if (divisor <= 0xFF) { | ||
639 | ir->carrier = carrier; | ||
640 | cmdbuf[2] = prescaler; | ||
641 | cmdbuf[3] = divisor; | ||
642 | dev_dbg(ir->dev, "%s: requesting %u HZ " | ||
643 | "carrier\n", __func__, carrier); | ||
644 | |||
645 | /* Transmit new carrier to mce device */ | ||
646 | mce_async_out(ir, cmdbuf, sizeof(cmdbuf)); | ||
647 | return carrier; | ||
648 | } | ||
649 | } | ||
650 | |||
651 | return -EINVAL; | ||
652 | |||
653 | } | ||
654 | |||
655 | return carrier; | ||
656 | } | ||
657 | |||
536 | static void mceusb_process_ir_data(struct mceusb_dev *ir, int buf_len) | 658 | static void mceusb_process_ir_data(struct mceusb_dev *ir, int buf_len) |
537 | { | 659 | { |
538 | struct ir_raw_event rawir = { .pulse = false, .duration = 0 }; | 660 | struct ir_raw_event rawir = { .pulse = false, .duration = 0 }; |
@@ -724,6 +846,9 @@ static void mceusb_gen2_init(struct mceusb_dev *ir) | |||
724 | mce_sync_in(ir, NULL, maxp); | 846 | mce_sync_in(ir, NULL, maxp); |
725 | mce_sync_in(ir, NULL, maxp); | 847 | mce_sync_in(ir, NULL, maxp); |
726 | 848 | ||
849 | set_current_state(TASK_INTERRUPTIBLE); | ||
850 | schedule_timeout(msecs_to_jiffies(100)); | ||
851 | |||
727 | /* device reset */ | 852 | /* device reset */ |
728 | mce_async_out(ir, DEVICE_RESET, sizeof(DEVICE_RESET)); | 853 | mce_async_out(ir, DEVICE_RESET, sizeof(DEVICE_RESET)); |
729 | mce_sync_in(ir, NULL, maxp); | 854 | mce_sync_in(ir, NULL, maxp); |
@@ -791,7 +916,7 @@ static struct input_dev *mceusb_init_input_dev(struct mceusb_dev *ir) | |||
791 | goto ir_dev_alloc_failed; | 916 | goto ir_dev_alloc_failed; |
792 | } | 917 | } |
793 | 918 | ||
794 | snprintf(ir->name, sizeof(ir->name), "Media Center Edition eHome " | 919 | snprintf(ir->name, sizeof(ir->name), "Media Center Ed. eHome " |
795 | "Infrared Remote Transceiver (%04x:%04x)", | 920 | "Infrared Remote Transceiver (%04x:%04x)", |
796 | le16_to_cpu(ir->usbdev->descriptor.idVendor), | 921 | le16_to_cpu(ir->usbdev->descriptor.idVendor), |
797 | le16_to_cpu(ir->usbdev->descriptor.idProduct)); | 922 | le16_to_cpu(ir->usbdev->descriptor.idProduct)); |
@@ -804,6 +929,9 @@ static struct input_dev *mceusb_init_input_dev(struct mceusb_dev *ir) | |||
804 | props->priv = ir; | 929 | props->priv = ir; |
805 | props->driver_type = RC_DRIVER_IR_RAW; | 930 | props->driver_type = RC_DRIVER_IR_RAW; |
806 | props->allowed_protos = IR_TYPE_ALL; | 931 | props->allowed_protos = IR_TYPE_ALL; |
932 | props->s_tx_mask = mceusb_set_tx_mask; | ||
933 | props->s_tx_carrier = mceusb_set_tx_carrier; | ||
934 | props->tx_ir = mceusb_tx_ir; | ||
807 | 935 | ||
808 | ir->props = props; | 936 | ir->props = props; |
809 | ir->irdev = irdev; | 937 | ir->irdev = irdev; |