From: gcembed <gcembed@gmail.com>
To: linux-media@vger.kernel.org
Subject: Re: [PATCH] TT CT-3650 IR and CI support
Date: Mon, 28 Jun 2010 10:46:27 +0200 [thread overview]
Message-ID: <4C286163.6080909@gmail.com> (raw)
In-Reply-To: <4C21A349.3070104@gmail.com>
Hi,
I did some tests and my tests with CAM were unsuccessful.
* On Debian Lenny (5) with kernel 2.6.32-5 (from repo) + last hg clone
v4l-dvb + this patch + Kaffeine 0.8.8 : compile is working, CT-3650 is
detected, ca0 node is created but CT-3650 was unable to tune and CAM is
not detected by Kaffeine.
I have to note that even without this patch, CT-3650 can't tune.
I also have a PCI card Technotrend C-2300 + CI and it works with last hg
clone of v4l-dvb (CAM is detected and working). So I don't know why
ttusb2 driver stops working in this configuration. I have to boot with
previous version of kernel (2.6.31) and an old v4l-dvb repo (before
CT-3650 was implemented) + patch to support CT-3650 to have everything
working.
If I have time, I will compile a newer kernel manually and try this
patch again.
* On Slackware 13.0 with kernel 2.6.33 (manually compiled) + last hg
clone v4l-dvb + this patch + Kaffeine 1.0 (tar.gz from official website)
: compile is working, CT-3650 is detected, ca0 node is created, CT-3650
tuned correctly but CAM is not detected by Kaffeine (!! I don't know if
CAM is already implemented in this new version that seems to miss a lot
of feature).
So unfortunately, my tests were not successful but I will try again next
week-end. And hope to be so lucky than Martin.
Best regards,
Gaëtan
On 06/23/2010 08:01 AM, gcembed wrote:
> Thanks a lot Waling,
> I often tried to write the support for CT-3650 but it was never
> successful (due to leak of time). I will try your patch this week-end.
> Gaëtan.
>
> On 06/23/2010 12:48 AM, Waling Dijkstra wrote:
>> Hi linux-media,
>>
>> adding support for IR and CI on the TT CT-3650.
>> CI code was mainly copied from pctv452e (PCTV 452e DVB driver).
>> IR support is same as on TT-S1500 (and 452e).
>>
>> Signed-off-by: Waling Dijkstra<walingdijkstra@hotmail.com>
>>
>> rgrds,
>>
>>
>> Waling
>>
>> diff --git a/drivers/media/dvb/dvb-usb/ttusb2.c
>> b/drivers/media/dvb/dvb-usb/ttusb2.c
>> index a6de489..5ce6a51 100644
>> --- a/drivers/media/dvb/dvb-usb/ttusb2.c
>> +++ b/drivers/media/dvb/dvb-usb/ttusb2.c
>> @@ -32,6 +32,8 @@
>> #include "tda1002x.h"
>> #include "tda827x.h"
>> #include "lnbp21.h"
>> +/* CA */
>> +#include "dvb_ca_en50221.h"
>>
>> /* debug */
>> static int dvb_usb_ttusb2_debug;
>> @@ -41,7 +43,26 @@ MODULE_PARM_DESC(debug, "set debugging level
>> (1=info (or-able))." DVB_USB_DEBUG_
>>
>> DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
>>
>> +#define ci_dbg(format, arg...) \
>> +do { \
>> + if (0) \
>> + printk (KERN_DEBUG DVB_USB_LOG_PREFIX \
>> + ": " format "\n" , ## arg); \
>> +} while (0)
>> +
>> +enum {
>> + TT3650_CMD_CI_TEST = 0x40,
>> + TT3650_CMD_CI_RD_CTRL,
>> + TT3650_CMD_CI_WR_CTRL,
>> + TT3650_CMD_CI_RD_ATTR,
>> + TT3650_CMD_CI_WR_ATTR,
>> + TT3650_CMD_CI_RESET,
>> + TT3650_CMD_CI_SET_VIDEO_PORT
>> +};
>> +
>> struct ttusb2_state {
>> + struct dvb_ca_en50221 ca;
>> + struct mutex ca_mutex;
>> u8 id;
>> };
>>
>> @@ -128,6 +149,333 @@ static struct i2c_algorithm ttusb2_i2c_algo = {
>> .functionality = ttusb2_i2c_func,
>> };
>>
>> +/* IR */
>> +/* Remote Control Stuff for CT-3650 (copied from TT-S1500): */
>> +static struct dvb_usb_rc_key tt_connect_CT_3650_rc_key[] = {
>> + {0x1501, KEY_POWER},
>> + {0x1502, KEY_SHUFFLE}, /* ? double-arrow key */
>> + {0x1503, KEY_1},
>> + {0x1504, KEY_2},
>> + {0x1505, KEY_3},
>> + {0x1506, KEY_4},
>> + {0x1507, KEY_5},
>> + {0x1508, KEY_6},
>> + {0x1509, KEY_7},
>> + {0x150a, KEY_8},
>> + {0x150b, KEY_9},
>> + {0x150c, KEY_0},
>> + {0x150d, KEY_UP},
>> + {0x150e, KEY_LEFT},
>> + {0x150f, KEY_OK},
>> + {0x1510, KEY_RIGHT},
>> + {0x1511, KEY_DOWN},
>> + {0x1512, KEY_INFO},
>> + {0x1513, KEY_EXIT},
>> + {0x1514, KEY_RED},
>> + {0x1515, KEY_GREEN},
>> + {0x1516, KEY_YELLOW},
>> + {0x1517, KEY_BLUE},
>> + {0x1518, KEY_MUTE},
>> + {0x1519, KEY_TEXT},
>> + {0x151a, KEY_MODE}, /* ? TV/Radio */
>> + {0x1521, KEY_OPTION},
>> + {0x1522, KEY_EPG},
>> + {0x1523, KEY_CHANNELUP},
>> + {0x1524, KEY_CHANNELDOWN},
>> + {0x1525, KEY_VOLUMEUP},
>> + {0x1526, KEY_VOLUMEDOWN},
>> + {0x1527, KEY_SETUP},
>> + {0x153a, KEY_RECORD},/* these keys are only in the black remote */
>> + {0x153b, KEY_PLAY},
>> + {0x153c, KEY_STOP},
>> + {0x153d, KEY_REWIND},
>> + {0x153e, KEY_PAUSE},
>> + {0x153f, KEY_FORWARD}
>> +};
>> +
>> +static int tt3650_rc_query(struct dvb_usb_device *d, u32 *keyevent,
>> int *keystate)
>> +{
>> + u8 keybuf[5];
>> + int ret;
>> + u8 b[36];/* this was (CMD_BUFFER_SIZE) u8 b[0x28] -
>> dvb_usb_generic_rw adds another 4 */
>> + u8 rx[60];/* same (64 -4) */
>> + ret = ttusb2_msg(d, CMD_GET_IR_CODE, b, 0, rx, 9);
>> + if (ret != 0)
>> + return ret;
>> +
>> + if (rx[8]& 0x01) {
>> + /* got a "press" event */
>> +/* if (debug> 2) {
>> + printk("%s: cmd=0x%02x sys=0x%02x\n", __func__, rx[2], rx[3]);
>> + }
>> +*/
>> + keybuf[0] = 0x01;/* DVB_USB_RC_NEC_KEY_PRESSED; why is this
>> #define'd privately? */
>> + keybuf[1] = rx[3];
>> + keybuf[2] = ~keybuf[1]; /* fake checksum */
>> + keybuf[3] = rx[2];
>> + keybuf[4] = ~keybuf[3]; /* fake checksum */
>> + dvb_usb_nec_rc_key_to_event(d, keybuf, keyevent, keystate);
>> + }
>> + return 0;
>> +}
>> +
>> +/* ci */
>> +static int tt3650_ci_msg (struct dvb_usb_device *d, u8 cmd, u8 *data,
>> + unsigned int write_len, unsigned int read_len)
>> +{
>> + int ret;
>> + u8 rx[60];/* (64 -4) */
>> + ret = ttusb2_msg(d, cmd, data, write_len, rx, read_len);
>> + if (ret == 0)
>> + memcpy (data, rx, read_len);
>> + return ret;
>> +}
>> +
>> +static int tt3650_ci_msg_locked(struct dvb_ca_en50221 *ca,
>> + u8 cmd, u8 *data, unsigned int write_len, unsigned int read_len)
>> +{
>> + struct dvb_usb_device *d = (struct dvb_usb_device *)ca->data;
>> + struct ttusb2_state *state = (struct ttusb2_state *)d->priv;
>> + int ret;
>> +
>> + mutex_lock(&state->ca_mutex);
>> + ret = tt3650_ci_msg(d, cmd, data, write_len, read_len);
>> + mutex_unlock(&state->ca_mutex);
>> +
>> + return ret;
>> +}
>> +
>> +static int tt3650_ci_read_attribute_mem(struct dvb_ca_en50221 *ca,
>> int slot, int address)
>> +{
>> + u8 buf[3];
>> + int ret;
>> +
>> + if (0 != slot)
>> + return -EINVAL;
>> +
>> + buf[0] = (address>> 8)& 0x0F;
>> + buf[1] = address;
>> +
>> + ret = tt3650_ci_msg_locked(ca, TT3650_CMD_CI_RD_ATTR, buf, 2, 3);
>> +
>> + ci_dbg ("%s %04x -> %d 0x%02x",
>> + __func__, address, ret, buf[2]);
>> +
>> + if (ret< 0)
>> + return ret;
>> +
>> + return buf[2];
>> +}
>> +
>> +static int tt3650_ci_write_attribute_mem(struct dvb_ca_en50221 *ca,
>> int slot, int address, u8 value)
>> +{
>> + u8 buf[3];
>> +
>> + ci_dbg("%s %d 0x%04x 0x%02x",
>> + __func__, slot, address, value);
>> +
>> + if (0 != slot)
>> + return -EINVAL;
>> +
>> + buf[0] = (address>> 8)& 0x0F;
>> + buf[1] = address;
>> + buf[2] = value;
>> +
>> + return tt3650_ci_msg_locked(ca, TT3650_CMD_CI_WR_ATTR, buf, 3, 3);
>> +}
>> +
>> +static int tt3650_ci_read_cam_control(struct dvb_ca_en50221 *ca, int
>> slot, u8 address)
>> +{
>> + u8 buf[2];
>> + int ret;
>> +
>> + if (0 != slot)
>> + return -EINVAL;
>> +
>> + buf[0] = address& 3;
>> +
>> + ret = tt3650_ci_msg_locked(ca, TT3650_CMD_CI_RD_CTRL, buf, 1, 2);
>> +
>> + ci_dbg("%s 0x%02x -> %d 0x%02x",
>> + __func__, address, ret, buf[1]);
>> +
>> + if (ret< 0)
>> + return ret;
>> +
>> + return buf[1];
>> +}
>> +
>> +static int tt3650_ci_write_cam_control(struct dvb_ca_en50221 *ca, int
>> slot, u8 address, u8 value)
>> +{
>> + u8 buf[2];
>> +
>> + ci_dbg("%s %d 0x%02x 0x%02x",
>> + __func__, slot, address, value);
>> +
>> + if (0 != slot)
>> + return -EINVAL;
>> +
>> + buf[0] = address;
>> + buf[1] = value;
>> +
>> + return tt3650_ci_msg_locked(ca, TT3650_CMD_CI_WR_CTRL, buf, 2, 2);
>> +}
>> +
>> +static int tt3650_ci_set_video_port(struct dvb_ca_en50221 *ca, int
>> slot, int enable)
>> +{
>> + u8 buf[1];
>> + int ret;
>> +
>> + ci_dbg("%s %d %d", __func__, slot, enable);
>> +
>> + if (0 != slot)
>> + return -EINVAL;
>> +
>> + enable = !!enable;
>> + buf[0] = enable;
>> +
>> + ret = tt3650_ci_msg_locked(ca, TT3650_CMD_CI_SET_VIDEO_PORT, buf, 1,
>> 1);
>> + if (ret< 0)
>> + return ret;
>> +
>> + if (enable != buf[0]) {
>> + err("CI not %sabled.", enable ? "en" : "dis");
>> + return -EIO;
>> + }
>> +
>> + return 0;
>> +}
>> +
>> +static int tt3650_ci_slot_shutdown(struct dvb_ca_en50221 *ca, int slot)
>> +{
>> + return tt3650_ci_set_video_port(ca, slot, /* enable */ 0);
>> +}
>> +
>> +static int tt3650_ci_slot_ts_enable(struct dvb_ca_en50221 *ca, int slot)
>> +{
>> + return tt3650_ci_set_video_port(ca, slot, /* enable */ 1);
>> +}
>> +
>> +static int tt3650_ci_slot_reset(struct dvb_ca_en50221 *ca, int slot)
>> +{
>> + struct dvb_usb_device *d = (struct dvb_usb_device *)ca->data;
>> + struct ttusb2_state *state = (struct ttusb2_state *)d->priv;
>> + u8 buf[1];
>> + int ret;
>> +
>> + ci_dbg ("%s %d", __func__, slot);
>> +
>> + if (0 != slot)
>> + return -EINVAL;
>> +
>> + buf[0] = 0;
>> +
>> + mutex_lock (&state->ca_mutex);
>> +
>> + ret = tt3650_ci_msg(d, TT3650_CMD_CI_RESET, buf, 1, 1);
>> + if (0 != ret)
>> + goto failed;
>> +
>> + msleep (500);
>> +
>> + buf[0] = 1;
>> +
>> + ret = tt3650_ci_msg(d, TT3650_CMD_CI_RESET, buf, 1, 1);
>> + if (0 != ret)
>> + goto failed;
>> +
>> + msleep (500);
>> +
>> + buf[0] = 0; /* FTA */
>> +
>> + ret = tt3650_ci_msg(d, TT3650_CMD_CI_SET_VIDEO_PORT, buf, 1, 1);
>> +
>> + failed:
>> + mutex_unlock (&state->ca_mutex);
>> +
>> + return ret;
>> +}
>> +
>> +static int tt3650_ci_poll_slot_status(struct dvb_ca_en50221 *ca, int
>> slot, int open)
>> +{
>> + u8 buf[1];
>> + int ret;
>> +
>> + if (0 != slot)
>> + return -EINVAL;
>> +
>> + ret = tt3650_ci_msg_locked(ca, TT3650_CMD_CI_TEST, buf, 0, 1);
>> + if (0 != ret)
>> + return ret;
>> +
>> + if (1 == buf[0]) {
>> + return DVB_CA_EN50221_POLL_CAM_PRESENT |
>> + DVB_CA_EN50221_POLL_CAM_READY;
>> + } else {
>> + return 0;
>> + }
>> +}
>> +
>> +static void tt3650_ci_uninit(struct dvb_usb_device *d)
>> +{
>> + struct ttusb2_state *state;
>> +
>> + ci_dbg("%s", __func__);
>> +
>> + if (NULL == d)
>> + return;
>> +
>> + state = (struct ttusb2_state *)d->priv;
>> + if (NULL == state)
>> + return;
>> +
>> + if (NULL == state->ca.data)
>> + return;
>> +
>> + /* Error ignored. */
>> + tt3650_ci_set_video_port(&state->ca, /* slot */ 0, /* enable */ 0);
>> +
>> + dvb_ca_en50221_release(&state->ca);
>> +
>> + memset(&state->ca, 0, sizeof(state->ca));
>> +}
>> +
>> +static int tt3650_ci_init(struct dvb_usb_adapter *a)
>> +{
>> + struct dvb_usb_device *d = a->dev;
>> + struct ttusb2_state *state = (struct ttusb2_state *)d->priv;
>> + int ret;
>> +
>> + ci_dbg ("%s", __func__);
>> +
>> + mutex_init(&state->ca_mutex);
>> +
>> + state->ca.owner = THIS_MODULE;
>> + state->ca.read_attribute_mem = tt3650_ci_read_attribute_mem;
>> + state->ca.write_attribute_mem = tt3650_ci_write_attribute_mem;
>> + state->ca.read_cam_control = tt3650_ci_read_cam_control;
>> + state->ca.write_cam_control = tt3650_ci_write_cam_control;
>> + state->ca.slot_reset = tt3650_ci_slot_reset;
>> + state->ca.slot_shutdown = tt3650_ci_slot_shutdown;
>> + state->ca.slot_ts_enable = tt3650_ci_slot_ts_enable;
>> + state->ca.poll_slot_status = tt3650_ci_poll_slot_status;
>> + state->ca.data = d;
>> +
>> + ret = dvb_ca_en50221_init (&a->dvb_adap,
>> + &state->ca,
>> + /* flags */ 0,
>> + /* n_slots */ 1);
>> + if (0 != ret) {
>> + err ("Cannot initialize CI: Error %d.", ret);
>> + memset (&state->ca, 0, sizeof (state->ca));
>> + return ret;
>> + }
>> +
>> + info ("CI initialized.");
>> +
>> + return 0;
>> +}
>> +
>> /* Callbacks for DVB USB */
>> static int ttusb2_identify_state (struct usb_device *udev, struct
>> dvb_usb_device_properties *props, struct dvb_usb_device_description
>> **desc,
>> @@ -177,12 +525,19 @@ static int
>> ttusb2_frontend_tda10086_attach(struct dvb_usb_adapter *adap)
>>
>> static int ttusb2_frontend_tda10023_attach(struct dvb_usb_adapter *adap)
>> {
>> + struct usb_device_id *id;
>> if (usb_set_interface(adap->dev->udev, 0, 3)< 0)
>> err("set interface to alts=3 failed");
>> if ((adap->fe =
>> dvb_attach(tda10023_attach,&tda10023_config,&adap->dev->i2c_adap,
>> 0x48)) == NULL) {
>> deb_info("TDA10023 attach failed\n");
>> return -ENODEV;
>> }
>> + id = adap->dev->desc->warm_ids[0];
>> + if (USB_VID_TECHNOTREND == id->idVendor
>> + && USB_PID_TECHNOTREND_CONNECT_CT3650 == id->idProduct) {
>> + /* Error ignored. */
>> + tt3650_ci_init (adap);
>> + }
>> return 0;
>> }
>>
>> @@ -214,6 +569,14 @@ static struct dvb_usb_device_properties
>> ttusb2_properties;
>> static struct dvb_usb_device_properties ttusb2_properties_s2400;
>> static struct dvb_usb_device_properties ttusb2_properties_ct3650;
>>
>> +static void ttusb2_usb_disconnect (struct usb_interface *intf)
>> +{
>> + struct dvb_usb_device *d = usb_get_intfdata (intf);
>> +
>> + tt3650_ci_uninit (d);
>> + dvb_usb_device_exit (intf);
>> +}
>> +
>> static int ttusb2_probe(struct usb_interface *intf,
>> const struct usb_device_id *id)
>> {
>> @@ -345,6 +708,11 @@ static struct dvb_usb_device_properties
>> ttusb2_properties_ct3650 = {
>>
>> .size_of_priv = sizeof(struct ttusb2_state),
>>
>> + .rc_key_map = tt_connect_CT_3650_rc_key,
>> + .rc_key_map_size = ARRAY_SIZE(tt_connect_CT_3650_rc_key),
>> + .rc_query = tt3650_rc_query,
>> + .rc_interval = 500,
>> +
>> .num_adapters = 1,
>> .adapter = {
>> {
>> @@ -387,7 +755,7 @@ static struct dvb_usb_device_properties
>> ttusb2_properties_ct3650 = {
>> static struct usb_driver ttusb2_driver = {
>> .name = "dvb_usb_ttusb2",
>> .probe = ttusb2_probe,
>> - .disconnect = dvb_usb_device_exit,
>> + .disconnect = ttusb2_usb_disconnect,
>> .id_table = ttusb2_table,
>> };
>>
>> diff --git a/drivers/media/dvb/dvb-usb/ttusb2.h
>> b/drivers/media/dvb/dvb-usb/ttusb2.h
>> index 52a63af..1bd5d54 100644
>> --- a/drivers/media/dvb/dvb-usb/ttusb2.h
>> +++ b/drivers/media/dvb/dvb-usb/ttusb2.h
>> @@ -45,6 +45,9 @@
>> #define CMD_DISEQC 0x18
>> /* out data:<master=0xff/burst=??> <cmdlen> <cmdbytes>[cmdlen] */
>>
>> +/* command to poll IR receiver (copied from pctv452e.c) */
>> +#define CMD_GET_IR_CODE 0x1b
>> +
>> #define CMD_PID_ENABLE 0x22
>> /* out data:<index> <type: ts=1/sec=2> <pid msb> <pid lsb> */
>>
>>
>>
>>
>> --
>> To unsubscribe from this list: send the line "unsubscribe linux-media" in
>> the body of a message to majordomo@vger.kernel.org
>> More majordomo info at http://vger.kernel.org/majordomo-info.html
>
next prev parent reply other threads:[~2010-06-28 8:46 UTC|newest]
Thread overview: 6+ messages / expand[flat|nested] mbox.gz Atom feed top
2010-06-22 22:48 [PATCH] TT CT-3650 IR and CI support Waling Dijkstra
2010-06-23 6:01 ` gcembed
2010-06-28 8:46 ` gcembed [this message]
2010-07-06 1:45 ` Mauro Carvalho Chehab
-- strict thread matches above, loose matches on Subject: below --
2010-06-26 12:09 Martin Dauskardt
2010-06-22 22:10 Waling Dijkstra
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=4C286163.6080909@gmail.com \
--to=gcembed@gmail.com \
--cc=linux-media@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.