@@ -44,7 +44,7 @@
#include "cxd2820r.h"
/* debug */
-static int dvb_usb_anysee_debug;
+static int dvb_usb_anysee_debug = -1;
module_param_named(debug, dvb_usb_anysee_debug, int, 0644);
MODULE_PARM_DESC(debug, "set debugging level" DVB_USB_DEBUG_STATUS);
static int dvb_usb_anysee_delsys;
@@ -67,6 +67,11 @@ static int anysee_ctrl_msg(struct dvb_usb_device *d, u8 *sbuf, u8 slen,
if (mutex_lock_interruptible(&anysee_usb_mutex) < 0)
return -EAGAIN;
+ if (sbuf[0] == CMD_SMARTCARD) {
+ deb_xfer(">>> ");
+ debug_dump(buf, slen, deb_xfer);
+ }
+
/* We need receive one message more after dvb_usb_generic_rw due
to weird transaction flow, which is 1 x send + 2 x receive. */
ret = dvb_usb_generic_rw(d, buf, sizeof(buf), buf, sizeof(buf), 0);
@@ -79,8 +84,15 @@ static int anysee_ctrl_msg(struct dvb_usb_device *d, u8 *sbuf, u8 slen,
if (ret)
err("%s: recv bulk message failed: %d", __func__, ret);
else {
- deb_xfer("<<< ");
- debug_dump(buf, act_len, deb_xfer);
+// deb_xfer("<<< ");
+// debug_dump(buf, act_len, deb_xfer);
+ if (sbuf[0] == CMD_SMARTCARD) {
+ if (buf[63] != 0x4f)
+ deb_info("%s: packet NOK: %02x\n", __func__, buf[63]);
+
+ deb_xfer("<<< ");
+ debug_dump(buf, 40, deb_xfer);
+ }
}
}
@@ -701,6 +713,8 @@ static int anysee_frontend_attach(struct dvb_usb_adapter *adap)
adap->fe_adap[0].fe = dvb_attach(tda10023_attach,
&anysee_tda10023_config, &adap->dev->i2c_adap, 0x48);
+ state->has_sc = true;
+
break;
case ANYSEE_HW_507SI: /* 11 */
/* E30 S2 Plus */
@@ -1014,6 +1028,7 @@ static int anysee_tuner_attach(struct dvb_usb_adapter *adap)
return ret;
}
+#if 0
static int anysee_rc_query(struct dvb_usb_device *d)
{
u8 buf[] = {CMD_GET_IR_CODE};
@@ -1039,6 +1054,7 @@ static int anysee_rc_query(struct dvb_usb_device *d)
return 0;
}
+#endif
static int anysee_ci_read_attribute_mem(struct dvb_ca_en50221 *ci, int slot,
int addr)
@@ -1208,6 +1224,292 @@ static void anysee_ci_release(struct dvb_usb_device *d)
return;
}
+// stty -aF /dev/ttyUSB0
+// setserial /dev/ttyUSB0
+// statserial /dev/ttyUSB0
+// more /proc/tty/drivers
+// watch head /proc/tty/driver/serial
+// http://www.ibiblio.org/pub/Linux/docs/HOWTO/other-formats/html_single/Serial-HOWTO.html
+
+
+static int anysee_rc_query(struct dvb_usb_device *d)
+{
+ u8 sbuf[] = {CMD_SMARTCARD, 0x06, 0x20};
+ u8 rbuf[60];
+ int ret;
+ u8 *ptr;
+ struct anysee_state *state = d->priv;
+ struct tty_struct *tty = state->sc_tty_driver->ttys[0];
+
+ if (state->sc_poll_count-- <= 0)
+ return 0;
+
+ deb_info("%s:\n", __func__);
+
+ ret = anysee_ctrl_msg(d, sbuf, sizeof(sbuf), rbuf, sizeof(rbuf));
+ if (ret)
+ return -EIO;
+
+ if (rbuf[0] != 0) {
+ ptr = &rbuf[2];
+ deb_info("rece data: ");
+ debug_dump(ptr, rbuf[0], deb_info);
+
+ tty_insert_flip_string(tty, &rbuf[2], rbuf[0]);
+ tty_flip_buffer_push(tty);
+ }
+
+ return 0;
+}
+
+static int anysee_sc_open(struct tty_struct *tty, struct file *filp)
+{
+ struct dvb_usb_device *d = tty->driver_data;
+ struct anysee_state *state = d->priv;
+ int ret, i;
+ u8 sbuf[5] = {CMD_SMARTCARD, 0x03, 1};
+ u8 tab[][2] = {
+ {0x00, 0xaf},
+ {0x10, 0x08},
+ {0x11, 0x4c},
+ };
+
+ deb_info("%s:\n", __func__);
+
+ for (i = 0; i < ARRAY_SIZE(tab); i++) {
+ sbuf[3] = tab[i][0];
+ sbuf[4] = tab[i][1];
+ ret = anysee_ctrl_msg(d, sbuf, sizeof(sbuf), NULL, 0);
+ if (ret)
+ goto err;
+ }
+
+ state->sc_poll_count = 0;
+
+ return 0;
+err:
+ return ret;
+}
+
+static void anysee_sc_close(struct tty_struct *tty, struct file *filp)
+{
+ struct dvb_usb_device *d = tty->driver_data;
+ struct anysee_state *state = d->priv;
+
+ deb_info("%s:\n", __func__);
+
+ state->sc_poll_count = 0;
+
+ msleep(1000);
+
+ return;
+}
+
+static int anysee_sc_tiocmset(struct tty_struct *tty, unsigned int set, unsigned int clear)
+{
+ int ret;
+ struct dvb_usb_device *d = tty->driver_data;
+ struct anysee_state *state = d->priv;
+ u8 sbuf[] = {CMD_SMARTCARD, 0x08, 0x01, 0x02};
+
+ deb_info("%s: set=%x clear=%x set_RTS=%d clear_RTS=%d sc_card_present=%d\n", __func__, set, clear, (set & TIOCM_RTS), (clear & TIOCM_RTS), state->sc_card_present);
+
+ if ((set & TIOCM_RTS) && state->sc_card_present) {
+ deb_info("%s: RESET CARD\n", __func__);
+ ret = anysee_ctrl_msg(d, sbuf, sizeof(sbuf), NULL, 0);
+ if (ret)
+ goto err;
+
+ state->sc_poll_count = 50;
+ }
+
+ return 0;
+err:
+ return ret;
+}
+
+static int anysee_sc_tiocmget(struct tty_struct *tty)
+{
+ struct dvb_usb_device *d = tty->driver_data;
+ struct anysee_state *state = d->priv;
+ int ret;
+ u8 sbuf[] = {CMD_SMARTCARD, 0x02, 0x01, 0x10};
+ u8 rbuf[1];
+ int tio = 0;
+
+ deb_info("%s:\n", __func__);
+ ret = anysee_ctrl_msg(d, sbuf, sizeof(sbuf), rbuf, sizeof(rbuf));
+ if (ret)
+ goto err;
+
+ if (rbuf[0] & (1 << 7)) {
+ tio |= TIOCM_CD;
+ state->sc_card_present = false;
+ } else {
+ tio &= ~TIOCM_CD;
+ state->sc_card_present = true;
+ }
+
+ deb_info("%s: TIO=%x rd:", __func__, tio);
+ debug_dump(rbuf, 1, deb_info);
+
+ return tio;
+err:
+ return ret;
+}
+
+static int anysee_sc_write(struct tty_struct *tty, const u8 *buf, int count)
+{
+ struct dvb_usb_device *d = tty->driver_data;
+ struct anysee_state *state = d->priv;
+ int ret;
+ u8 rbuf[60];
+ u8 sbuf[60] = {CMD_SMARTCARD, 0x08, 0x01, 0x01, 0x00, count};
+
+ deb_info("send data: ");
+ debug_dump(buf, count, deb_info);
+
+ ret = anysee_ctrl_msg(d, sbuf, 7, NULL, 0);
+ if (ret)
+ goto err;
+
+ sbuf[1] = 0x07;
+ sbuf[2] = count;
+ memcpy(&sbuf[3], buf, count);
+
+ ret = anysee_ctrl_msg(d, sbuf, count+3, rbuf, sizeof(rbuf));
+ if (ret)
+ goto err;
+
+ if (rbuf[0]) {
+ /* TODO: can that echo removed ? */
+ tty_insert_flip_string(tty, &sbuf[3], rbuf[0]);
+ tty_flip_buffer_push(tty);
+ }
+
+ state->sc_poll_count = 50;
+
+ return count;
+
+err:
+ return ret;
+}
+
+static int anysee_sc_write_room(struct tty_struct *tty)
+{
+ deb_info("%s:\n", __func__);
+ return 32;
+}
+
+static void anysee_sc_set_termios(struct tty_struct *tty, struct ktermios *old)
+{
+ tty_termios_copy_hw(tty->termios, old);
+ deb_info("%s:\n", __func__);
+ return;
+}
+
+static int anysee_sc_install(struct tty_driver *driver, struct tty_struct *tty)
+{
+ int idx = tty->index;
+
+ deb_info("%s:\n", __func__);
+
+ if (tty_init_termios(tty) == 0) {
+ tty_driver_kref_get(driver);
+ tty->count++;
+ driver->ttys[idx] = tty;
+ tty->driver_data = driver->driver_state;
+ return 0;
+ }
+ return -ENOMEM;
+}
+
+static const struct tty_operations serial_ops = {
+ .open = anysee_sc_open,
+ .close = anysee_sc_close,
+ .write = anysee_sc_write,
+// .hangup = anysee_sc_hangup,
+ .write_room = anysee_sc_write_room,
+// .ioctl = anysee_sc_ioctl,
+ .set_termios = anysee_sc_set_termios,
+// .throttle = anysee_sc_throttle,
+// .unthrottle = anysee_sc_unthrottle,
+// .break_ctl = anysee_sc_break,
+// .chars_in_buffer = anysee_sc_chars_in_buffer,
+ .tiocmget = anysee_sc_tiocmget,
+ .tiocmset = anysee_sc_tiocmset,
+// .get_icount = anysee_sc_get_icount,
+// .cleanup = anysee_sc_cleanup,
+ .install = anysee_sc_install,
+// .proc_fops = &anysee_sc_proc_fops,
+};
+
+#define SERIAL_TTY_MAJOR 188 /* abuse usb-serial... */
+static int anysee_sc_init(struct dvb_usb_device *d)
+{
+ struct anysee_state *state = d->priv;
+ int ret;
+
+ deb_info("%s:\n", __func__);
+
+ state->sc_tty_driver = alloc_tty_driver(1);
+ if (!state->sc_tty_driver) {
+ ret = -ENOMEM;
+ goto err_alloc_tty_driver;
+ }
+
+ state->sc_tty_driver->owner = THIS_MODULE;
+ state->sc_tty_driver->driver_name = "anysee";
+ state->sc_tty_driver->name = "ttyUSB";
+ state->sc_tty_driver->major = SERIAL_TTY_MAJOR;
+ state->sc_tty_driver->minor_start = 0;
+ state->sc_tty_driver->type = TTY_DRIVER_TYPE_SERIAL;
+ state->sc_tty_driver->subtype = SERIAL_TYPE_NORMAL;
+ state->sc_tty_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
+ state->sc_tty_driver->init_termios = tty_std_termios;
+ state->sc_tty_driver->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL;
+ state->sc_tty_driver->init_termios.c_ispeed = 9600;
+ state->sc_tty_driver->init_termios.c_ospeed = 9600;
+ state->sc_tty_driver->driver_state = d;
+ tty_set_operations(state->sc_tty_driver, &serial_ops);
+ ret = tty_register_driver(state->sc_tty_driver);
+ if (ret)
+ goto err_tty_register_driver;
+
+ if (!tty_register_device(state->sc_tty_driver, 0, NULL))
+ goto err_tty_register_device;
+
+ info("serial device registered");
+
+ return 0;
+
+err_tty_register_device:
+ tty_unregister_driver(state->sc_tty_driver);
+
+err_tty_register_driver:
+ put_tty_driver(state->sc_tty_driver);
+
+err_alloc_tty_driver:
+ state->has_sc = false;
+ err("%s: failed=%d", __func__, ret);
+
+ return ret;
+}
+
+
+static void anysee_sc_release(struct dvb_usb_device *d)
+{
+ struct anysee_state *state = d->priv;
+
+ /* detach SmartCard */
+ if (state->has_sc) {
+ tty_unregister_device(state->sc_tty_driver, 0);
+ tty_unregister_driver(state->sc_tty_driver);
+ }
+
+ return;
+}
+
static int anysee_init(struct dvb_usb_device *d)
{
struct anysee_state *state = d->priv;
@@ -1232,6 +1534,15 @@ static int anysee_init(struct dvb_usb_device *d)
}
}
+ /* attach SmartCard */
+ if (state->has_sc) {
+ ret = anysee_sc_init(d);
+ if (ret) {
+ state->has_sc = false;
+ return ret;
+ }
+ }
+
return 0;
}
@@ -1280,6 +1591,7 @@ static void anysee_disconnect(struct usb_interface *intf)
{
struct dvb_usb_device *d = usb_get_intfdata(intf);
+ anysee_sc_release(d);
anysee_ci_release(d);
dvb_usb_device_exit(intf);
@@ -1342,7 +1654,7 @@ static struct dvb_usb_device_properties anysee_properties = {
.protocol = RC_TYPE_OTHER,
.module_name = "anysee",
.rc_query = anysee_rc_query,
- .rc_interval = 250, /* windows driver uses 500ms */
+ .rc_interval = 150, /* windows driver uses 500ms */
},
.i2c_algo = &anysee_i2c_algo,
@@ -38,6 +38,9 @@
#include "dvb-usb.h"
#include "dvb_ca_en50221.h"
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+
#define deb_info(args...) dprintk(dvb_usb_anysee_debug, 0x01, args)
#define deb_xfer(args...) dprintk(dvb_usb_anysee_debug, 0x02, args)
#define deb_rc(args...) dprintk(dvb_usb_anysee_debug, 0x04, args)
@@ -63,8 +66,14 @@ struct anysee_state {
u8 seq;
u8 fe_id:1; /* frondend ID */
u8 has_ci:1;
+ u8 has_sc:1;
+
struct dvb_ca_en50221 ci;
unsigned long ci_cam_ready; /* jiffies */
+
+ struct tty_driver *sc_tty_driver;
+ u8 sc_card_present:1;
+ int sc_poll_count;
};
#define ANYSEE_HW_507T 2 /* E30 */