All of lore.kernel.org
 help / color / mirror / Atom feed
From: Antti Palosaari <crope@iki.fi>
To: "Bjørn Mork" <bjorn@mork.no>, "István Váradi" <ivaradi@gmail.com>
Cc: linux-media@vger.kernel.org
Subject: Re: Smart card reader support for Anysee DVB devices
Date: Wed, 28 Sep 2011 17:32:06 +0300	[thread overview]
Message-ID: <4E832FE6.7020103@iki.fi> (raw)
In-Reply-To: <4E60DB09.1060304@iki.fi>

[-- Attachment #1: Type: text/plain, Size: 1677 bytes --]

On 09/02/2011 04:32 PM, Antti Palosaari wrote:
> On 09/02/2011 02:04 PM, Bjørn Mork wrote:
>> Antti Palosaari<crope@iki.fi> writes:
>>
>>> Since Anysee device itself does not have CCID interface it is needed
>>> to make virtual USB device in order to get CCID support. I have never
>>> seen virtual USB devices like that, but there is VHCI in current
>>> kernel staging that actually does something like that over IP.
>>
>> Don't know if you have seen this already, but there's a virtual CCID
>> device implementation in QEMU. See
>> http://wiki.qemu.org/Features/Smartcard
>> Should be a good starting point. Combine it withe the VHCI driver from
>> USBIP and you have your CCID device.
>
> It is first time I hear about QEMU virtual CCID. Now we have all parts
> needed for USBIP VHCI and QEMU virtual CCID, just glue those together.
>
> I wonder if it is wise to even create virtual CCID "core" to Kernel.
> There is few other readers that can use that too, actually I think all
> USB readers that have unique USB ID (blocking out those which uses
> USB-serial converters with common IDs).
>
> As I see that CCID still more complex as serial device I will still look
> implementing it as serial as now.

Here it is, patch attached. Implemented as serial device. Anysee uses 
two different smart card interfaces, CST56I01 and TDA8024. That one is 
old CST56I01, I will try to add TDA8024 later, maybe even tonight.

Anyhow, it is something like proof-of-concept currently, missing locks 
and abusing ttyUSB. Have you any idea if I should reserve own major 
device numbers for Anysee or should I reserve one like DVB common?

Any other ideas?

Antti
-- 
http://palosaari.fi/

[-- Attachment #2: anysee_smartcard_sniper2.patch --]
[-- Type: text/plain, Size: 10932 bytes --]

diff --git a/drivers/media/dvb/dvb-usb/anysee.c b/drivers/media/dvb/dvb-usb/anysee.c
index 0bc1372..79497f3 100644
--- a/drivers/media/dvb/dvb-usb/anysee.c
+++ b/drivers/media/dvb/dvb-usb/anysee.c
@@ -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,
diff --git a/drivers/media/dvb/dvb-usb/anysee.h b/drivers/media/dvb/dvb-usb/anysee.h
index 8ac8794..1026717 100644
--- a/drivers/media/dvb/dvb-usb/anysee.h
+++ b/drivers/media/dvb/dvb-usb/anysee.h
@@ -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 */

  reply	other threads:[~2011-09-28 14:32 UTC|newest]

Thread overview: 16+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2011-07-17 14:18 Smart card reader support for Anysee DVB devices István Váradi
2011-08-14 23:51 ` Antti Palosaari
2011-08-15 11:14   ` Antti Palosaari
2011-08-17 20:41     ` Antti Palosaari
2011-08-29 14:44       ` István Váradi
2011-08-29 14:50         ` Antti Palosaari
2011-08-29 15:13           ` István Váradi
2011-08-29 15:23             ` Antti Palosaari
2011-09-02 11:04               ` Bjørn Mork
2011-09-02 13:32                 ` Antti Palosaari
2011-09-28 14:32                   ` Antti Palosaari [this message]
2011-09-30 15:36                     ` Antti Palosaari
2011-10-02 21:06                       ` HoP
2011-10-03 17:56                       ` Bjørn Mork
2011-10-03 12:36           ` James Courtier-Dutton
2011-10-03 12:50             ` Antti Palosaari

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=4E832FE6.7020103@iki.fi \
    --to=crope@iki.fi \
    --cc=bjorn@mork.no \
    --cc=ivaradi@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.