--- anysee.c.orig 2010-08-02 00:11:14.000000000 +0200 +++ anysee.c 2010-12-28 09:04:45.000000000 +0100 @@ -32,11 +32,14 @@ */ #include "anysee.h" +#include "anysee_sc.h" #include "tda1002x.h" #include "mt352.h" #include "mt352_priv.h" #include "zl10353.h" +#include + /* debug */ static int dvb_usb_anysee_debug; module_param_named(debug, dvb_usb_anysee_debug, int, 0644); @@ -132,6 +135,273 @@ return anysee_ctrl_msg(d, buf, sizeof(buf), NULL, 0); } +static dev_t sc_dev; +static const unsigned sc_count = 16; +static struct class* sc_class = 0; + +static int anysee_sc_open(struct inode *inode, struct file *filp) +{ + struct anysee_sc_state* sc_state = container_of(inode->i_cdev, struct anysee_sc_state, cdev); + filp->private_data = sc_state; + return 0; +} + +static int anysee_sc_check_presence(struct dvb_usb_device* d) +{ + int ret = 0; + u8 x; + + ret = anysee_read_reg(d, 0x0080, &x); + if (ret!=0) return ret; + + if ((x&0x02)!=0) return 0; + + ret = anysee_write_reg(d, 0xb1, 0xa7); + if (ret!=0) return ret; + + ret = anysee_read_reg(d, 0x0080, &x); + + if (ret!=0) return ret; + else return ((x&0x02)==0) ? -EPIPE : 0; +} + +static int anysee_sc_read_byte(struct dvb_usb_device* d, u8* dest, unsigned int timeout, + u8 last) +{ + static const unsigned read_interval = 20; + + u8 cmd[] = { 0x34, 0x06, 0x01, 0x00 }; + + u8 buf[4]; + unsigned num_cycles = timeout / read_interval, i; + + int ret = 0; + cmd[3] = last; + for(i = 0; i0) { + return -EAGAIN; + } + } + } + + return -ETIMEDOUT; +} + +static ssize_t anysee_sc_read(struct file *filp, char __user *buf, size_t count, loff_t *offp) +{ + struct anysee_sc_state* sc_state = (struct anysee_sc_state*)filp->private_data; + struct dvb_usb_device* d = sc_state->dvb_usb_device; + + int ret = 0; + unsigned index = 0; + u8 read_buf[count]; + + + if (mutex_lock_interruptible(&sc_state->mutex) < 0) + return -EAGAIN; + + if (ret==0) { + ret = anysee_sc_check_presence(d); + } + + while(ret==0 && indexmutex); + + return (ret==0) ? index : ret; +} + +static ssize_t anysee_sc_write(struct file *filp, const char __user *buf, size_t count, loff_t *offp) +{ + struct anysee_sc_state* sc_state = (struct anysee_sc_state*)filp->private_data; + struct dvb_usb_device* d = sc_state->dvb_usb_device; + + u8 cmd[] = { 0x34, 0x08, 0x01, 0x01, 0x00, 0x05 }; + ssize_t ret = 0; + unsigned written = 0; + + if (count>256) { + return -EINVAL; + } + + if (mutex_lock_interruptible(&sc_state->mutex) < 0) + return -EAGAIN; + + if (ret==0) { + ret = anysee_sc_check_presence(d); + } + + if (ret==0) { + cmd[5] = count&0xff; + ret = anysee_ctrl_msg(d, cmd, sizeof(cmd), 0, 0); + } + + while (ret==0 && written48) to_write = 48; + + write_buf[0] = 0x34; + write_buf[1] = 0x07; + write_buf[2] = to_write; + if (copy_from_user(write_buf+3, buf + written, to_write)) { + ret = -EFAULT; + } + + if (ret==0) { + write_buf[to_write+3] = 0x01; + + ret = anysee_ctrl_msg(d, write_buf, to_write + 4, + write_buf, 1); + if (ret==0) { + if (write_buf[0]==to_write) { + written += to_write; + } else { + ret = -EIO; + } + } + } + } + + mutex_unlock(&sc_state->mutex); + + return (ret==0) ? count : ret; +} + +static int anysee_sc_activate(struct anysee_sc_state* sc_state, unsigned long arg) +{ + struct dvb_usb_device* d = sc_state->dvb_usb_device; + struct anysee_sc_activate __user* params = (struct anysee_sc_activate __user*)arg; + int ret = 0; + u8 x; + + if (!access_ok(VERIFY_WRITE, params, sizeof(anysee_sc_activate))) { + ret = -EFAULT; + } + + if (ret==0) { + ret = anysee_sc_check_presence(d); + } + + if (ret==0) { + ret = anysee_read_reg(d, 0x00a0, &x); + } + + if (ret==0) { + ret = anysee_write_reg(d, 0x00a0, x|0x01); + } + + if (ret==0) { + static u8 cmd[] = { 0x34, 0x09, 0x01 }; + ret = anysee_ctrl_msg(d, cmd, sizeof(cmd), 0, 0); + } + + if (ret==0) { + static u8 cmd[] = { 0x34, 0x08, 0x01, 0x02 }; + ret = anysee_ctrl_msg(d, cmd, sizeof(cmd), 0, 0); + } + + if (ret==0) { + unsigned index = 0; + unsigned atr_length = 2; + unsigned fmt_index = 1; + unsigned k = 0; + + while(indexatr) && indexatr[index++] = x; + } + } + params->atr_length = index; + } + + return ret; +} + +static int anysee_sc_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg) +{ + struct anysee_sc_state* sc_state = (struct anysee_sc_state*)filp->private_data; + int ret = -ENODEV; + + if (mutex_lock_interruptible(&sc_state->mutex) < 0) + return -EAGAIN; + + switch(cmd) { + case ANYSEE_SC_ACTIVATE: + ret = anysee_sc_activate(sc_state, arg); + break; + case ANYSEE_SC_PRESENT: + ret = anysee_sc_check_presence(sc_state->dvb_usb_device); + if (ret==-EPIPE) ret = 0; + else if (ret==0) ret = 1; + } + + mutex_unlock(&sc_state->mutex); + + return ret; +} + +static struct file_operations anysee_sc_fops = { + .owner = THIS_MODULE, + .open = anysee_sc_open, + .read = anysee_sc_read, + .write = anysee_sc_write, + .ioctl = anysee_sc_ioctl, +}; + +static int anysee_sc_init(struct dvb_usb_adapter* adap) +{ + struct dvb_usb_device* d = adap->dev; + int ret = 0; + struct anysee_state *state = d->priv; + state->sc_state.dvb_usb_device = d; + + state->sc_state.devnum = MKDEV(MAJOR(sc_dev), d->adapter[0].id); + + cdev_init(&state->sc_state.cdev, &anysee_sc_fops); + state->sc_state.cdev.owner = THIS_MODULE; + + mutex_init(&state->sc_state.mutex); + + ret = cdev_add(&state->sc_state.cdev, state->sc_state.devnum, 1); + if (ret) { + err("%s: cdev_add failed. Error number %d", __func__, ret); + } else { + device_create(sc_class, adap->dvb_adap.device, state->sc_state.devnum, + 0, "anysee_sc%u", d->adapter[0].id); + } + return ret; +} + static int anysee_init(struct dvb_usb_device *d) { int ret; @@ -148,6 +418,17 @@ return 0; } +static void anysee_exit(struct usb_interface *intf) +{ + struct dvb_usb_device *d = usb_get_intfdata(intf); + struct anysee_state *state = d->priv; + + device_destroy(sc_class, state->sc_state.devnum); + cdev_del(&state->sc_state.cdev); + + dvb_usb_device_exit(intf); +} + /* I2C */ static int anysee_master_xfer(struct i2c_adapter *adap, struct i2c_msg *msg, int num) @@ -269,6 +550,10 @@ return ret; deb_info("%s: IO port D:%02x\n", __func__, io_d); + ret = anysee_sc_init(adap); + if (ret) + return ret; + /* Select demod using trial and error method. */ /* Try to attach demodulator in following order: @@ -541,7 +826,7 @@ static struct usb_driver anysee_driver = { .name = "dvb_usb_anysee", .probe = anysee_probe, - .disconnect = dvb_usb_device_exit, + .disconnect = anysee_exit, .id_table = anysee_table, }; @@ -550,10 +835,28 @@ { int ret; - ret = usb_register(&anysee_driver); - if (ret) - err("%s: usb_register failed. Error number %d", __func__, ret); - + ret = alloc_chrdev_region(&sc_dev, 0, sc_count, "anysee_sc"); + if (ret) + err("%s: alloc_chrdev_region failed. Error number %d", __func__, ret); + + if (!ret) { + sc_class = class_create(THIS_MODULE, "anysee_sc"); + if (IS_ERR(sc_class)) { + err("%s: class_simple_create failed.", __func__); + unregister_chrdev_region(sc_dev, sc_count); + ret = -ENODEV; + } + } + + if (!ret) { + ret = usb_register(&anysee_driver); + if (ret) { + err("%s: usb_register failed. Error number %d", __func__, ret); + class_destroy(sc_class); + unregister_chrdev_region(sc_dev, sc_count); + } + } + return ret; } @@ -561,6 +864,11 @@ { /* deregister this driver from the USB subsystem */ usb_deregister(&anysee_driver); + + class_destroy(sc_class); + + unregister_chrdev_region(sc_dev, sc_count); + } module_init(anysee_module_init); --- anysee.h.orig 2010-08-02 00:11:14.000000000 +0200 +++ anysee.h 2010-12-05 19:07:55.000000000 +0100 @@ -34,6 +34,8 @@ #ifndef _DVB_USB_ANYSEE_H_ #define _DVB_USB_ANYSEE_H_ +#include + #define DVB_USB_LOG_PREFIX "anysee" #include "dvb-usb.h" @@ -56,9 +58,17 @@ CMD_SMARTCARD = 0x34, }; +struct anysee_sc_state { + struct dvb_usb_device* dvb_usb_device; + dev_t devnum; + struct cdev cdev; + struct mutex mutex; +}; + struct anysee_state { u8 tuner; u8 seq; + struct anysee_sc_state sc_state; }; #endif