Re: tm6000 and IR

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hi

This is my summary changes:
1. Add vendor specific keymap for USB TV card (try git add file, but git diff doesn't include this into diff)
2. Spilt ir_config and work with a key to different rc_type
3. When rc_type is NEC get first scancode from a scantable cut address and store it for filtering.
4. When a key is pressed on NEC remote check one byte of address and restore full scancode before return. May
have a some incorrect work when NEC remotes has same as high address bytes. Big thanks to Trident Co.
0x86 0x6B
and
0x86 0xdf
This is need because in other TV cards frontend returned full scancode.
5. temporary removed  usb_set_interface(dev->udev,

This patch for discuss. If all is good I'll made a patch for git.

With my best regards, Dmitry.

> Am 08.12.2010 04:55, schrieb Dmitri Belimov:
> > Hi Stefan
> >
> >> Am 06.12.2010 11:02, schrieb Dmitri Belimov:
> >>>>> Thank you. When I switched to this branch modules is not crash
> >>>>> when USB removed. But disable IR over interrupt after start
> >>>>> video/radio
> >>>>>
> >>>>> With my best regards, Dmitry.
> >>>>>
> >>>> changing the interface configuration by initiation isoc urb can
> >>>> deactivating the interrupt in endpoint
> >>> We configure USB stick when modules is loaded
> >>>
> >>> /* Selects the proper interface */
> >>>    rc = usb_set_interface(usbdev, 0, 1);
> >>>
> >>> The USB controller reserved one half of bandwith for ISOC. Other
> >>> device on USB can work slowely. Much better:
> >>>
> >>> when module loaded
> >>> /* Selects the proper interface */
> >>>    rc = usb_set_interface(usbdev, 0, 2);
> >>>
> >>> when start video/audio/TS
> >>> /* Selects the proper interface */
> >>>    rc = usb_set_interface(usbdev, 0, 1);
> >>>
> >>> when stop video/audio/TS
> >>> /* Selects the proper interface */
> >>>    rc = usb_set_interface(usbdev, 0, 2);
> >>>
> >>> And restart int pipe after each selection. What you mean about it?
> >>> Dynamic bandwith utilization.
> >>>
> >>> With my best regards, Dmitry.
> >>>
> >> No. Here (tm6000_prepare_isoc) is that problem. It resetted the
> >> active interrupt urb pipe and interrupt urb  must reinitialize
> >> after call usb_set_interface, I think.
> >>
> >> static int tm6000_prepare_isoc(struct tm6000_core *dev, unsigned
> >> int framesize)
> >> {
> >>       struct tm6000_dmaqueue *dma_q =&dev->vidq;
> >>       int i, j, sb_size, pipe, size, max_packets, num_bufs = 8;
> >>       struct urb *urb;
> >>
> >>       /* De-allocates all pending stuff */
> >>       tm6000_uninit_isoc(dev);
> >>
> >>       usb_set_interface(dev->udev,
> >>                 dev->isoc_in.bInterfaceNumber,
> >>                 dev->isoc_in.bAlternateSetting);
> >>
> >>
> >>       pipe = usb_rcvisocpipe(dev->udev,
> >>                      dev->isoc_in.endp->desc.bEndpointAddress&
> >>                      USB_ENDPOINT_NUMBER_MASK);
> >>
> >>       size = usb_maxpacket(dev->udev, pipe, usb_pipeout(pipe));
> >>
> >> Can you test without call "usb_set_interface"?
> > Of course. It works. The interrupt pipe is a live after start/stop
> > watch TV. Are you make a patch for this?
> >
> Mauro, what do you think about this?
> > Other point is IR remotes. The tm6010 may be tm5600/tm6000 too
> > returned only two right bytes when received extended nec.
> >
> > Our remotes was send:
> >
> > 0x86 0x6B 0x00 0xFF
> >
> > tm6010 return after decode:
> >
> > 0x86 0x00 0x86 0x00
> >
> > If we use full lenght of key for ir_table
> >
> > 1. need add some code for restore losing byte.
> >
> > if (ir_table.name == OUR_TV_CARD_IR_TABLE)
> >   return to ir core byte1 0x6B byte0
> >
> > Or
> >
> > 2. use only high byte of address for filtering a key.
> >
> > I'll try number 2 as more robust.
> >
> > What you mean about it?
> >
> second once are better, easier and need small code.
> 
> Stefan Ringel
/* behold-wander.h - Keytable for behold_wander Remote Controller
 *
 * keymap imported from ir-keymaps.c
 *
 * Copyright (c) 2010 by Mauro Carvalho Chehab <mchehab@xxxxxxxxxx>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 */

#include <media/rc-map.h>

/* Beholder Intl. Ltd. 2010
 * Dmitry Belimov d.belimov@xxxxxxxxxx
 * Keytable is used by BeholdTV Wander/Voyage
 * The "ascii-art picture" below (in comments, first row
 * is the keycode in hex, and subsequent row(s) shows
 * the button labels (several variants when appropriate)
 * helps to descide which keycodes to assign to the buttons.
 */

static struct rc_map_table behold_wander[] = {

	/*  0x13   0x11   0x1C   0x12  *
	 *  Mute  Source  TV/FM  Power *
	 *                             */

	{ 0x866b13, KEY_MUTE },
	{ 0x866b11, KEY_PROPS },
	{ 0x866b1C, KEY_TUNER },	/* KEY_TV/KEY_RADIO	*/
	{ 0x866b12, KEY_POWER },

	/*  0x01    0x02    0x03  0x0D    *
	 *   1       2       3   Stereo   *
	 *                        	  *
	 *  0x04    0x05    0x06  0x19    *
	 *   4       5       6   Snapshot *
	 *                        	  *
	 *  0x07    0x08    0x09  0x10    *
	 *   7       8       9    Zoom 	  *
	 *                                */
	{ 0x866b01, KEY_1 },
	{ 0x866b02, KEY_2 },
	{ 0x866b03, KEY_3 },
	{ 0x866b0D, KEY_SETUP },	  /* Setup key */
	{ 0x866b04, KEY_4 },
	{ 0x866b05, KEY_5 },
	{ 0x866b06, KEY_6 },
	{ 0x866b19, KEY_CAMERA },	/* Snapshot key */
	{ 0x866b07, KEY_7 },
	{ 0x866b08, KEY_8 },
	{ 0x866b09, KEY_9 },
	{ 0x866b10, KEY_ZOOM },

	/*  0x0A    0x00    0x0B       0x0C   *
	 * RECALL    0    ChannelUp  VolumeUp *
	 *                                    */
	{ 0x866b0A, KEY_AGAIN },
	{ 0x866b00, KEY_0 },
	{ 0x866b0B, KEY_CHANNELUP },
	{ 0x866b0C, KEY_VOLUMEUP },

	/*   0x1B      0x1D      0x15        0x18     *
	 * Timeshift  Record  ChannelDown  VolumeDown *
	 *                                            */

	{ 0x866b1B, KEY_TIME },
	{ 0x866b1D, KEY_RECORD },
	{ 0x866b15, KEY_CHANNELDOWN },
	{ 0x866b18, KEY_VOLUMEDOWN },

	/*   0x0E   0x1E     0x0F     0x1A  *
	 *   Stop   Pause  Previouse  Next  *
	 *                                  */

	{ 0x866b0E, KEY_STOP },
	{ 0x866b1E, KEY_PAUSE },
	{ 0x866b0F, KEY_PREVIOUS },
	{ 0x866b1A, KEY_NEXT },

};

static struct rc_map_list behold_wander_map = {
	.map = {
		.scan    = behold_wander,
		.size    = ARRAY_SIZE(behold_wander),
		.rc_type = RC_TYPE_NEC,	/* Legacy IR type */
		.name    = RC_MAP_BEHOLD_WANDER,
	}
};

static int __init init_rc_map_behold_wander(void)
{
	return rc_map_register(&behold_wander_map);
}

static void __exit exit_rc_map_behold_wander(void)
{
	rc_map_unregister(&behold_wander_map);
}

module_init(init_rc_map_behold_wander)
module_exit(exit_rc_map_behold_wander)

MODULE_LICENSE("GPL");
MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@xxxxxxxxxx>");
diff --git a/drivers/media/rc/keymaps/Makefile b/drivers/media/rc/keymaps/Makefile
index 3194d39..cf7622f 100644
--- a/drivers/media/rc/keymaps/Makefile
+++ b/drivers/media/rc/keymaps/Makefile
@@ -15,6 +15,7 @@ obj-$(CONFIG_RC_MAP) += rc-adstech-dvb-t-pci.o \
 			rc-azurewave-ad-tu700.o \
 			rc-behold.o \
 			rc-behold-columbus.o \
+			rc-behold-wander.o \
 			rc-budget-ci-old.o \
 			rc-cinergy-1400.o \
 			rc-cinergy.o \
diff --git a/drivers/staging/tm6000/tm6000-cards.c b/drivers/staging/tm6000/tm6000-cards.c
index 1c9374a..59ee241 100644
--- a/drivers/staging/tm6000/tm6000-cards.c
+++ b/drivers/staging/tm6000/tm6000-cards.c
@@ -239,6 +239,7 @@ struct tm6000_board tm6000_boards[] = {
 			.demod_reset	= TM6010_GPIO_1,
 			.power_led	= TM6010_GPIO_6,
 		},
+		.ir_codes = RC_MAP_BEHOLD_WANDER,
 	},
 	[TM6010_BOARD_BEHOLD_VOYAGER] = {
 		.name         = "Beholder Voyager TV/FM USB2.0",
@@ -256,6 +257,7 @@ struct tm6000_board tm6000_boards[] = {
 			.tuner_reset	= TM6010_GPIO_0,
 			.power_led	= TM6010_GPIO_6,
 		},
+		.ir_codes = RC_MAP_BEHOLD_WANDER,
 	},
 	[TM6010_BOARD_TERRATEC_CINERGY_HYBRID_XE] = {
 		.name         = "Terratec Cinergy Hybrid XE / Cinergy Hybrid-Stick",
@@ -328,6 +330,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)
 {
diff --git a/drivers/staging/tm6000/tm6000-input.c b/drivers/staging/tm6000/tm6000-input.c
index e02ea67..144c693 100644
--- a/drivers/staging/tm6000/tm6000-input.c
+++ b/drivers/staging/tm6000/tm6000-input.c
@@ -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...) \
@@ -45,7 +49,7 @@ MODULE_PARM_DESC(enable_ir, "enable ir (default is enable)");
 	}
 
 struct tm6000_ir_poll_result {
-	u16 rc_data;
+	u32 rc_data;
 };
 
 struct tm6000_IR {
@@ -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->key_addr << 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,22 @@ 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,7 +289,14 @@ 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 */
@@ -276,6 +338,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);
diff --git a/drivers/staging/tm6000/tm6000-video.c b/drivers/staging/tm6000/tm6000-video.c
index c5690b2..db6c1b2 100644
--- a/drivers/staging/tm6000/tm6000-video.c
+++ b/drivers/staging/tm6000/tm6000-video.c
@@ -545,11 +545,11 @@ static int tm6000_prepare_isoc(struct tm6000_core *dev, unsigned int framesize)
 
 	/* De-allocates all pending stuff */
 	tm6000_uninit_isoc(dev);
-
+#if 0
 	usb_set_interface(dev->udev,
 			  dev->isoc_in.bInterfaceNumber,
 			  dev->isoc_in.bAlternateSetting);
-
+#endif
 	pipe = usb_rcvisocpipe(dev->udev,
 			       dev->isoc_in.endp->desc.bEndpointAddress &
 			       USB_ENDPOINT_NUMBER_MASK);
diff --git a/drivers/staging/tm6000/tm6000.h b/drivers/staging/tm6000/tm6000.h
index 46017b6..38966ac 100644
--- a/drivers/staging/tm6000/tm6000.h
+++ b/drivers/staging/tm6000/tm6000.h
@@ -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 */
 
diff --git a/include/media/rc-map.h b/include/media/rc-map.h
index 1a3d51d..239a309 100644
--- a/include/media/rc-map.h
+++ b/include/media/rc-map.h
@@ -70,6 +70,7 @@ void rc_map_init(void);
 #define RC_MAP_AVERTV_303                "rc-avertv-303"
 #define RC_MAP_AZUREWAVE_AD_TU700        "rc-azurewave-ad-tu700"
 #define RC_MAP_BEHOLD_COLUMBUS           "rc-behold-columbus"
+#define RC_MAP_BEHOLD_WANDER             "rc-behold-wander"
 #define RC_MAP_BEHOLD                    "rc-behold"
 #define RC_MAP_BUDGET_CI_OLD             "rc-budget-ci-old"
 #define RC_MAP_CINERGY_1400              "rc-cinergy-1400"

[Index of Archives]     [Linux Input]     [Video for Linux]     [Gstreamer Embedded]     [Mplayer Users]     [Linux USB Devel]     [Linux Audio Users]     [Linux Kernel]     [Linux SCSI]     [Yosemite Backpacking]
  Powered by Linux