]> git.openfabrics.org - ~shefty/rdma-dev.git/commitdiff
[media] tm6000: rework and fix IR
authorDmitri Belimov <d.belimov@gmail.com>
Wed, 22 Dec 2010 08:57:46 +0000 (05:57 -0300)
committerMauro Carvalho Chehab <mchehab@redhat.com>
Wed, 29 Dec 2010 10:17:15 +0000 (08:17 -0200)
Hi

This patch didn't kill Stefan's remotes and just for upload my good part of code.
1. Add some code for show IR activity
2. Add filter for IR remotes
3. Split remotes to different types.
4. Fix stop interrupt pipe when isoc pipe started.

When we decide general way of IR I'll add support our remotes.
For our customers I'll made custom temporary patch without this part.

Signed-off-by: Beholder Intl. Ltd. Dmitry Belimov <d.belimov@gmail.com>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
drivers/staging/tm6000/TODO
drivers/staging/tm6000/tm6000-cards.c
drivers/staging/tm6000/tm6000-input.c
drivers/staging/tm6000/tm6000-video.c
drivers/staging/tm6000/tm6000.h

index 34780fc17b160debe723c7734bc483330eb42f5c..135d0ea3ad708e976e61af62e6028758b212d4a0 100644 (file)
@@ -1,4 +1,6 @@
 There a few things to do before putting this driver in production:
+       - IR NEC with tm5600/6000 TV cards
+       - IR RC5 with tm5600/6000/6010 TV cards
        - CodingStyle;
        - Fix audio;
        - Fix some panic/OOPS conditions.
index 5a7946c6de50e57bdcf56241c6d537935816117f..455038bdfc9f8d8ced98b36b4f2c3281527e57cd 100644 (file)
@@ -328,6 +328,47 @@ struct usb_device_id tm6000_id_table[] = {
        { },
 };
 
+/* Control power led for show some activity */
+void tm6000_flash_led(struct tm6000_core *dev, u8 state)
+{
+       /* Power LED unconfigured */
+       if (!dev->gpio.power_led)
+               return;
+
+       /* ON Power LED */
+       if (state) {
+               switch (dev->model) {
+               case TM6010_BOARD_HAUPPAUGE_900H:
+               case TM6010_BOARD_TERRATEC_CINERGY_HYBRID_XE:
+               case TM6010_BOARD_TWINHAN_TU501:
+                       tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
+                               dev->gpio.power_led, 0x00);
+                       break;
+               case TM6010_BOARD_BEHOLD_WANDER:
+               case TM6010_BOARD_BEHOLD_VOYAGER:
+                       tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
+                               dev->gpio.power_led, 0x01);
+                       break;
+               }
+       }
+       /* OFF Power LED */
+       else {
+               switch (dev->model) {
+               case TM6010_BOARD_HAUPPAUGE_900H:
+               case TM6010_BOARD_TERRATEC_CINERGY_HYBRID_XE:
+               case TM6010_BOARD_TWINHAN_TU501:
+                       tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
+                               dev->gpio.power_led, 0x01);
+                       break;
+               case TM6010_BOARD_BEHOLD_WANDER:
+               case TM6010_BOARD_BEHOLD_VOYAGER:
+                       tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
+                               dev->gpio.power_led, 0x00);
+                       break;
+               }
+       }
+}
+
 /* Tuner callback to provide the proper gpio changes needed for xc5000 */
 int tm6000_xc5000_callback(void *ptr, int component, int command, int arg)
 {
index e02ea6720380e306d7591874cc9237a873d2b661..21e7da40f049c2824c289b9da1e41913620fc458 100644 (file)
@@ -37,6 +37,10 @@ static unsigned int enable_ir = 1;
 module_param(enable_ir, int, 0644);
 MODULE_PARM_DESC(enable_ir, "enable ir (default is enable)");
 
+/* number of 50ms for ON-OFF-ON power led */
+/* show IR activity */
+#define PWLED_OFF 2
+
 #undef dprintk
 
 #define dprintk(fmt, arg...) \
@@ -59,6 +63,9 @@ struct tm6000_IR {
        struct delayed_work     work;
        u8                      wait:1;
        u8                      key:1;
+       u8                      pwled:1;
+       u8                      pwledcnt;
+       u16                     key_addr;
        struct urb              *int_urb;
        u8                      *urb_data;
 
@@ -89,26 +96,49 @@ static int tm6000_ir_config(struct tm6000_IR *ir)
        u8 buf[10];
        int rc;
 
-       /* hack */
-       buf[0] = 0xff;
-       buf[1] = 0xff;
-       buf[2] = 0xf2;
-       buf[3] = 0x2b;
-       buf[4] = 0x20;
-       buf[5] = 0x35;
-       buf[6] = 0x60;
-       buf[7] = 0x04;
-       buf[8] = 0xc0;
-       buf[9] = 0x08;
-
-       rc = tm6000_read_write_usb(dev, USB_DIR_OUT | USB_TYPE_VENDOR |
-               USB_RECIP_DEVICE, REQ_00_SET_IR_VALUE, 0, 0, buf, 0x0a);
-       msleep(100);
-
-       if (rc < 0) {
-               printk(KERN_INFO "IR configuration failed");
-               return rc;
+       switch (ir->rc_type) {
+       case RC_TYPE_NEC:
+               /* Setup IR decoder for NEC standard 12MHz system clock */
+               /* IR_LEADER_CNT = 0.9ms             */
+               tm6000_set_reg(dev, TM6010_REQ07_RD8_IR_LEADER1, 0xaa);
+               tm6000_set_reg(dev, TM6010_REQ07_RD8_IR_LEADER0, 0x30);
+               /* IR_PULSE_CNT = 0.7ms              */
+               tm6000_set_reg(dev, TM6010_REQ07_RD8_IR_PULSE_CNT1, 0x20);
+               tm6000_set_reg(dev, TM6010_REQ07_RD8_IR_PULSE_CNT0, 0xd0);
+               /* Remote WAKEUP = enable */
+               tm6000_set_reg(dev, TM6010_REQ07_RE5_REMOTE_WAKEUP, 0xfe);
+               /* IR_WKUP_SEL = Low byte in decoded IR data */
+               tm6000_set_reg(dev, TM6010_REQ07_RD8_IR_WAKEUP_SEL, 0xff);
+               /* IR_WKU_ADD code */
+               tm6000_set_reg(dev, TM6010_REQ07_RD8_IR_WAKEUP_ADD, 0xff);
+               tm6000_flash_led(dev, 0);
+               msleep(100);
+               tm6000_flash_led(dev, 1);
+               break;
+       default:
+               /* hack */
+               buf[0] = 0xff;
+               buf[1] = 0xff;
+               buf[2] = 0xf2;
+               buf[3] = 0x2b;
+               buf[4] = 0x20;
+               buf[5] = 0x35;
+               buf[6] = 0x60;
+               buf[7] = 0x04;
+               buf[8] = 0xc0;
+               buf[9] = 0x08;
+
+               rc = tm6000_read_write_usb(dev, USB_DIR_OUT | USB_TYPE_VENDOR |
+                       USB_RECIP_DEVICE, REQ_00_SET_IR_VALUE, 0, 0, buf, 0x0a);
+               msleep(100);
+
+               if (rc < 0) {
+                       printk(KERN_INFO "IR configuration failed");
+                       return rc;
+               }
+               break;
        }
+
        return 0;
 }
 
@@ -143,10 +173,21 @@ static int default_polling_getkey(struct tm6000_IR *ir,
                return 0;
 
        if (&dev->int_in) {
-               if (ir->rc_type == RC_TYPE_RC5)
+               switch (ir->rc_type) {
+               case RC_TYPE_RC5:
                        poll_result->rc_data = ir->urb_data[0];
-               else
-                       poll_result->rc_data = ir->urb_data[0] | ir->urb_data[1] << 8;
+                       break;
+               case RC_TYPE_NEC:
+                       if (ir->urb_data[1] == ((ir->key_addr >> 8) & 0xff)) {
+                               poll_result->rc_data = ir->urb_data[0]
+                                                       | ir->urb_data[1] << 8;
+                       }
+                       break;
+               default:
+                       poll_result->rc_data = ir->urb_data[0]
+                                       | ir->urb_data[1] << 8;
+                       break;
+               }
        } else {
                tm6000_set_reg(dev, REQ_04_EN_DISABLE_MCU_INT, 2, 0);
                msleep(10);
@@ -186,6 +227,7 @@ static int default_polling_getkey(struct tm6000_IR *ir,
 
 static void tm6000_ir_handle_key(struct tm6000_IR *ir)
 {
+       struct tm6000_core *dev = ir->dev;
        int result;
        struct tm6000_ir_poll_result poll_result;
 
@@ -198,9 +240,21 @@ static void tm6000_ir_handle_key(struct tm6000_IR *ir)
 
        dprintk("ir->get_key result data=%04x\n", poll_result.rc_data);
 
+       if (ir->pwled) {
+               if (ir->pwledcnt >= PWLED_OFF) {
+                       ir->pwled = 0;
+                       ir->pwledcnt = 0;
+                       tm6000_flash_led(dev, 1);
+               } else
+                       ir->pwledcnt += 1;
+       }
+
        if (ir->key) {
                rc_keydown(ir->rc, poll_result.rc_data, 0);
                ir->key = 0;
+               ir->pwled = 1;
+               ir->pwledcnt = 0;
+               tm6000_flash_led(dev, 0);
        }
        return;
 }
@@ -234,19 +288,80 @@ int tm6000_ir_change_protocol(struct rc_dev *rc, u64 rc_type)
 {
        struct tm6000_IR *ir = rc->priv;
 
+       if (!ir)
+               return 0;
+
+       if ((rc->rc_map.scan) && (rc_type == RC_TYPE_NEC))
+               ir->key_addr = ((rc->rc_map.scan[0].scancode >> 8) & 0xffff);
+
        ir->get_key = default_polling_getkey;
+       ir->rc_type = rc_type;
 
        tm6000_ir_config(ir);
        /* TODO */
        return 0;
 }
 
+int tm6000_ir_int_start(struct tm6000_core *dev)
+{
+       struct tm6000_IR *ir = dev->ir;
+       int pipe, size;
+       int err = -ENOMEM;
+
+
+       if (!ir)
+               return -ENODEV;
+
+       ir->int_urb = usb_alloc_urb(0, GFP_KERNEL);
+
+       pipe = usb_rcvintpipe(dev->udev,
+               dev->int_in.endp->desc.bEndpointAddress
+               & USB_ENDPOINT_NUMBER_MASK);
+
+       size = usb_maxpacket(dev->udev, pipe, usb_pipeout(pipe));
+       dprintk("IR max size: %d\n", size);
+
+       ir->int_urb->transfer_buffer = kzalloc(size, GFP_KERNEL);
+       if (ir->int_urb->transfer_buffer == NULL) {
+               usb_free_urb(ir->int_urb);
+               return err;
+       }
+       dprintk("int interval: %d\n", dev->int_in.endp->desc.bInterval);
+       usb_fill_int_urb(ir->int_urb, dev->udev, pipe,
+               ir->int_urb->transfer_buffer, size,
+               tm6000_ir_urb_received, dev,
+               dev->int_in.endp->desc.bInterval);
+       err = usb_submit_urb(ir->int_urb, GFP_KERNEL);
+       if (err) {
+               kfree(ir->int_urb->transfer_buffer);
+               usb_free_urb(ir->int_urb);
+               return err;
+       }
+       ir->urb_data = kzalloc(size, GFP_KERNEL);
+
+       return 0;
+}
+
+void tm6000_ir_int_stop(struct tm6000_core *dev)
+{
+       struct tm6000_IR *ir = dev->ir;
+
+       if (!ir)
+               return;
+
+       usb_kill_urb(ir->int_urb);
+       kfree(ir->int_urb->transfer_buffer);
+       usb_free_urb(ir->int_urb);
+       ir->int_urb = NULL;
+       kfree(ir->urb_data);
+       ir->urb_data = NULL;
+}
+
 int tm6000_ir_init(struct tm6000_core *dev)
 {
        struct tm6000_IR *ir;
        struct rc_dev *rc;
        int err = -ENOMEM;
-       int pipe, size;
 
        if (!enable_ir)
                return -ENODEV;
@@ -276,6 +391,9 @@ int tm6000_ir_init(struct tm6000_core *dev)
        rc->driver_type = RC_DRIVER_SCANCODE;
 
        ir->polling = 50;
+       ir->pwled = 0;
+       ir->pwledcnt = 0;
+
 
        snprintf(ir->name, sizeof(ir->name), "tm5600/60x0 IR (%s)",
                                                dev->name);
@@ -298,32 +416,10 @@ int tm6000_ir_init(struct tm6000_core *dev)
        if (&dev->int_in) {
                dprintk("IR over int\n");
 
-               ir->int_urb = usb_alloc_urb(0, GFP_KERNEL);
-
-               pipe = usb_rcvintpipe(dev->udev,
-                       dev->int_in.endp->desc.bEndpointAddress
-                       & USB_ENDPOINT_NUMBER_MASK);
+               err = tm6000_ir_int_start(dev);
 
-               size = usb_maxpacket(dev->udev, pipe, usb_pipeout(pipe));
-               dprintk("IR max size: %d\n", size);
-
-               ir->int_urb->transfer_buffer = kzalloc(size, GFP_KERNEL);
-               if (ir->int_urb->transfer_buffer == NULL) {
-                       usb_free_urb(ir->int_urb);
-                       goto out;
-               }
-               dprintk("int interval: %d\n", dev->int_in.endp->desc.bInterval);
-               usb_fill_int_urb(ir->int_urb, dev->udev, pipe,
-                       ir->int_urb->transfer_buffer, size,
-                       tm6000_ir_urb_received, dev,
-                       dev->int_in.endp->desc.bInterval);
-               err = usb_submit_urb(ir->int_urb, GFP_KERNEL);
-               if (err) {
-                       kfree(ir->int_urb->transfer_buffer);
-                       usb_free_urb(ir->int_urb);
+               if (err)
                        goto out;
-               }
-               ir->urb_data = kzalloc(size, GFP_KERNEL);
        }
 
        /* ir register */
@@ -352,12 +448,7 @@ int tm6000_ir_fini(struct tm6000_core *dev)
        rc_unregister_device(ir->rc);
 
        if (ir->int_urb) {
-               usb_kill_urb(ir->int_urb);
-               kfree(ir->int_urb->transfer_buffer);
-               usb_free_urb(ir->int_urb);
-               ir->int_urb = NULL;
-               kfree(ir->urb_data);
-               ir->urb_data = NULL;
+               tm6000_ir_int_stop(dev);
        }
 
        kfree(ir);
index 0dae427a21ec7dcf7daef514d1e1be0c6eb65bf3..8fe017c3721fbb7415a8270059492fe83e47dd2f 100644 (file)
@@ -545,11 +545,16 @@ static int tm6000_prepare_isoc(struct tm6000_core *dev, unsigned int framesize)
 
        /* De-allocates all pending stuff */
        tm6000_uninit_isoc(dev);
+       /* Stop interrupt USB pipe */
+       tm6000_ir_int_stop(dev);
 
        usb_set_interface(dev->udev,
                          dev->isoc_in.bInterfaceNumber,
                          dev->isoc_in.bAlternateSetting);
 
+       /* Start interrupt USB pipe */
+       tm6000_ir_int_start(dev);
+
        pipe = usb_rcvisocpipe(dev->udev,
                               dev->isoc_in.endp->desc.bEndpointAddress &
                               USB_ENDPOINT_NUMBER_MASK);
index 46017b60319096f2698d87df1b14cb3f12d9120d..bf11eeec92c7fa8421afb962ce671403580a03fc 100644 (file)
@@ -266,6 +266,7 @@ struct tm6000_fh {
 int tm6000_tuner_callback(void *ptr, int component, int command, int arg);
 int tm6000_xc5000_callback(void *ptr, int component, int command, int arg);
 int tm6000_cards_setup(struct tm6000_core *dev);
+void tm6000_flash_led(struct tm6000_core *dev, u8 state);
 
 /* In tm6000-core.c */
 
@@ -332,6 +333,8 @@ int tm6000_queue_init(struct tm6000_core *dev);
 int tm6000_ir_init(struct tm6000_core *dev);
 int tm6000_ir_fini(struct tm6000_core *dev);
 void tm6000_ir_wait(struct tm6000_core *dev, u8 state);
+int tm6000_ir_int_start(struct tm6000_core *dev);
+void tm6000_ir_int_stop(struct tm6000_core *dev);
 
 /* Debug stuff */