linux/drivers/media/pci/ttpci/av7110_ca.c
<<
>>
Prefs
   1/*
   2 * av7110_ca.c: CA and CI stuff
   3 *
   4 * Copyright (C) 1999-2002 Ralph  Metzler
   5 *                       & Marcus Metzler for convergence integrated media GmbH
   6 *
   7 * originally based on code by:
   8 * Copyright (C) 1998,1999 Christian Theiss <mistert@rz.fh-augsburg.de>
   9 *
  10 * This program is free software; you can redistribute it and/or
  11 * modify it under the terms of the GNU General Public License
  12 * as published by the Free Software Foundation; either version 2
  13 * of the License, or (at your option) any later version.
  14 *
  15 *
  16 * This program is distributed in the hope that it will be useful,
  17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  19 * GNU General Public License for more details.
  20 *
  21 *
  22 * You should have received a copy of the GNU General Public License
  23 * along with this program; if not, write to the Free Software
  24 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  25 * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
  26 *
  27 *
  28 * the project's page is at http://www.linuxtv.org/ 
  29 */
  30
  31#include <linux/kernel.h>
  32#include <linux/types.h>
  33#include <linux/delay.h>
  34#include <linux/fs.h>
  35#include <linux/timer.h>
  36#include <linux/poll.h>
  37#include <linux/gfp.h>
  38
  39#include "av7110.h"
  40#include "av7110_hw.h"
  41#include "av7110_ca.h"
  42
  43
  44void CI_handle(struct av7110 *av7110, u8 *data, u16 len)
  45{
  46        dprintk(8, "av7110:%p\n",av7110);
  47
  48        if (len < 3)
  49                return;
  50        switch (data[0]) {
  51        case CI_MSG_CI_INFO:
  52                if (data[2] != 1 && data[2] != 2)
  53                        break;
  54                switch (data[1]) {
  55                case 0:
  56                        av7110->ci_slot[data[2] - 1].flags = 0;
  57                        break;
  58                case 1:
  59                        av7110->ci_slot[data[2] - 1].flags |= CA_CI_MODULE_PRESENT;
  60                        break;
  61                case 2:
  62                        av7110->ci_slot[data[2] - 1].flags |= CA_CI_MODULE_READY;
  63                        break;
  64                }
  65                break;
  66        case CI_SWITCH_PRG_REPLY:
  67                //av7110->ci_stat=data[1];
  68                break;
  69        default:
  70                break;
  71        }
  72}
  73
  74
  75void ci_get_data(struct dvb_ringbuffer *cibuf, u8 *data, int len)
  76{
  77        if (dvb_ringbuffer_free(cibuf) < len + 2)
  78                return;
  79
  80        DVB_RINGBUFFER_WRITE_BYTE(cibuf, len >> 8);
  81        DVB_RINGBUFFER_WRITE_BYTE(cibuf, len & 0xff);
  82        dvb_ringbuffer_write(cibuf, data, len);
  83        wake_up_interruptible(&cibuf->queue);
  84}
  85
  86
  87/******************************************************************************
  88 * CI link layer file ops
  89 ******************************************************************************/
  90
  91static int ci_ll_init(struct dvb_ringbuffer *cirbuf, struct dvb_ringbuffer *ciwbuf, int size)
  92{
  93        struct dvb_ringbuffer *tab[] = { cirbuf, ciwbuf, NULL }, **p;
  94        void *data;
  95
  96        for (p = tab; *p; p++) {
  97                data = vmalloc(size);
  98                if (!data) {
  99                        while (p-- != tab) {
 100                                vfree(p[0]->data);
 101                                p[0]->data = NULL;
 102                        }
 103                        return -ENOMEM;
 104                }
 105                dvb_ringbuffer_init(*p, data, size);
 106        }
 107        return 0;
 108}
 109
 110static void ci_ll_flush(struct dvb_ringbuffer *cirbuf, struct dvb_ringbuffer *ciwbuf)
 111{
 112        dvb_ringbuffer_flush_spinlock_wakeup(cirbuf);
 113        dvb_ringbuffer_flush_spinlock_wakeup(ciwbuf);
 114}
 115
 116static void ci_ll_release(struct dvb_ringbuffer *cirbuf, struct dvb_ringbuffer *ciwbuf)
 117{
 118        vfree(cirbuf->data);
 119        cirbuf->data = NULL;
 120        vfree(ciwbuf->data);
 121        ciwbuf->data = NULL;
 122}
 123
 124static int ci_ll_reset(struct dvb_ringbuffer *cibuf, struct file *file,
 125                       int slots, ca_slot_info_t *slot)
 126{
 127        int i;
 128        int len = 0;
 129        u8 msg[8] = { 0x00, 0x06, 0x00, 0x00, 0xff, 0x02, 0x00, 0x00 };
 130
 131        for (i = 0; i < 2; i++) {
 132                if (slots & (1 << i))
 133                        len += 8;
 134        }
 135
 136        if (dvb_ringbuffer_free(cibuf) < len)
 137                return -EBUSY;
 138
 139        for (i = 0; i < 2; i++) {
 140                if (slots & (1 << i)) {
 141                        msg[2] = i;
 142                        dvb_ringbuffer_write(cibuf, msg, 8);
 143                        slot[i].flags = 0;
 144                }
 145        }
 146
 147        return 0;
 148}
 149
 150static ssize_t ci_ll_write(struct dvb_ringbuffer *cibuf, struct file *file,
 151                           const char __user *buf, size_t count, loff_t *ppos)
 152{
 153        int free;
 154        int non_blocking = file->f_flags & O_NONBLOCK;
 155        u8 *page = (u8 *)__get_free_page(GFP_USER);
 156        int res;
 157
 158        if (!page)
 159                return -ENOMEM;
 160
 161        res = -EINVAL;
 162        if (count > 2048)
 163                goto out;
 164
 165        res = -EFAULT;
 166        if (copy_from_user(page, buf, count))
 167                goto out;
 168
 169        free = dvb_ringbuffer_free(cibuf);
 170        if (count + 2 > free) {
 171                res = -EWOULDBLOCK;
 172                if (non_blocking)
 173                        goto out;
 174                res = -ERESTARTSYS;
 175                if (wait_event_interruptible(cibuf->queue,
 176                                             (dvb_ringbuffer_free(cibuf) >= count + 2)))
 177                        goto out;
 178        }
 179
 180        DVB_RINGBUFFER_WRITE_BYTE(cibuf, count >> 8);
 181        DVB_RINGBUFFER_WRITE_BYTE(cibuf, count & 0xff);
 182
 183        res = dvb_ringbuffer_write(cibuf, page, count);
 184out:
 185        free_page((unsigned long)page);
 186        return res;
 187}
 188
 189static ssize_t ci_ll_read(struct dvb_ringbuffer *cibuf, struct file *file,
 190                          char __user *buf, size_t count, loff_t *ppos)
 191{
 192        int avail;
 193        int non_blocking = file->f_flags & O_NONBLOCK;
 194        ssize_t len;
 195
 196        if (!cibuf->data || !count)
 197                return 0;
 198        if (non_blocking && (dvb_ringbuffer_empty(cibuf)))
 199                return -EWOULDBLOCK;
 200        if (wait_event_interruptible(cibuf->queue,
 201                                     !dvb_ringbuffer_empty(cibuf)))
 202                return -ERESTARTSYS;
 203        avail = dvb_ringbuffer_avail(cibuf);
 204        if (avail < 4)
 205                return 0;
 206        len = DVB_RINGBUFFER_PEEK(cibuf, 0) << 8;
 207        len |= DVB_RINGBUFFER_PEEK(cibuf, 1);
 208        if (avail < len + 2 || count < len)
 209                return -EINVAL;
 210        DVB_RINGBUFFER_SKIP(cibuf, 2);
 211
 212        return dvb_ringbuffer_read_user(cibuf, buf, len);
 213}
 214
 215static int dvb_ca_open(struct inode *inode, struct file *file)
 216{
 217        struct dvb_device *dvbdev = file->private_data;
 218        struct av7110 *av7110 = dvbdev->priv;
 219        int err = dvb_generic_open(inode, file);
 220
 221        dprintk(8, "av7110:%p\n",av7110);
 222
 223        if (err < 0)
 224                return err;
 225        ci_ll_flush(&av7110->ci_rbuffer, &av7110->ci_wbuffer);
 226        return 0;
 227}
 228
 229static unsigned int dvb_ca_poll (struct file *file, poll_table *wait)
 230{
 231        struct dvb_device *dvbdev = file->private_data;
 232        struct av7110 *av7110 = dvbdev->priv;
 233        struct dvb_ringbuffer *rbuf = &av7110->ci_rbuffer;
 234        struct dvb_ringbuffer *wbuf = &av7110->ci_wbuffer;
 235        unsigned int mask = 0;
 236
 237        dprintk(8, "av7110:%p\n",av7110);
 238
 239        poll_wait(file, &rbuf->queue, wait);
 240        poll_wait(file, &wbuf->queue, wait);
 241
 242        if (!dvb_ringbuffer_empty(rbuf))
 243                mask |= (POLLIN | POLLRDNORM);
 244
 245        if (dvb_ringbuffer_free(wbuf) > 1024)
 246                mask |= (POLLOUT | POLLWRNORM);
 247
 248        return mask;
 249}
 250
 251static int dvb_ca_ioctl(struct file *file, unsigned int cmd, void *parg)
 252{
 253        struct dvb_device *dvbdev = file->private_data;
 254        struct av7110 *av7110 = dvbdev->priv;
 255        unsigned long arg = (unsigned long) parg;
 256        int ret = 0;
 257
 258        dprintk(8, "av7110:%p\n",av7110);
 259
 260        if (mutex_lock_interruptible(&av7110->ioctl_mutex))
 261                return -ERESTARTSYS;
 262
 263        switch (cmd) {
 264        case CA_RESET:
 265                ret = ci_ll_reset(&av7110->ci_wbuffer, file, arg,
 266                                  &av7110->ci_slot[0]);
 267                break;
 268        case CA_GET_CAP:
 269        {
 270                ca_caps_t cap;
 271
 272                cap.slot_num = 2;
 273                cap.slot_type = (FW_CI_LL_SUPPORT(av7110->arm_app) ?
 274                                 CA_CI_LINK : CA_CI) | CA_DESCR;
 275                cap.descr_num = 16;
 276                cap.descr_type = CA_ECD;
 277                memcpy(parg, &cap, sizeof(cap));
 278                break;
 279        }
 280
 281        case CA_GET_SLOT_INFO:
 282        {
 283                ca_slot_info_t *info=(ca_slot_info_t *)parg;
 284
 285                if (info->num < 0 || info->num > 1) {
 286                        mutex_unlock(&av7110->ioctl_mutex);
 287                        return -EINVAL;
 288                }
 289                av7110->ci_slot[info->num].num = info->num;
 290                av7110->ci_slot[info->num].type = FW_CI_LL_SUPPORT(av7110->arm_app) ?
 291                                                        CA_CI_LINK : CA_CI;
 292                memcpy(info, &av7110->ci_slot[info->num], sizeof(ca_slot_info_t));
 293                break;
 294        }
 295
 296        case CA_GET_MSG:
 297                break;
 298
 299        case CA_SEND_MSG:
 300                break;
 301
 302        case CA_GET_DESCR_INFO:
 303        {
 304                ca_descr_info_t info;
 305
 306                info.num = 16;
 307                info.type = CA_ECD;
 308                memcpy(parg, &info, sizeof (info));
 309                break;
 310        }
 311
 312        case CA_SET_DESCR:
 313        {
 314                ca_descr_t *descr = (ca_descr_t*) parg;
 315
 316                if (descr->index >= 16 || descr->parity > 1) {
 317                        mutex_unlock(&av7110->ioctl_mutex);
 318                        return -EINVAL;
 319                }
 320                av7110_fw_cmd(av7110, COMTYPE_PIDFILTER, SetDescr, 5,
 321                              (descr->index<<8)|descr->parity,
 322                              (descr->cw[0]<<8)|descr->cw[1],
 323                              (descr->cw[2]<<8)|descr->cw[3],
 324                              (descr->cw[4]<<8)|descr->cw[5],
 325                              (descr->cw[6]<<8)|descr->cw[7]);
 326                break;
 327        }
 328
 329        default:
 330                ret = -EINVAL;
 331                break;
 332        }
 333
 334        mutex_unlock(&av7110->ioctl_mutex);
 335        return ret;
 336}
 337
 338static ssize_t dvb_ca_write(struct file *file, const char __user *buf,
 339                            size_t count, loff_t *ppos)
 340{
 341        struct dvb_device *dvbdev = file->private_data;
 342        struct av7110 *av7110 = dvbdev->priv;
 343
 344        dprintk(8, "av7110:%p\n",av7110);
 345        return ci_ll_write(&av7110->ci_wbuffer, file, buf, count, ppos);
 346}
 347
 348static ssize_t dvb_ca_read(struct file *file, char __user *buf,
 349                           size_t count, loff_t *ppos)
 350{
 351        struct dvb_device *dvbdev = file->private_data;
 352        struct av7110 *av7110 = dvbdev->priv;
 353
 354        dprintk(8, "av7110:%p\n",av7110);
 355        return ci_ll_read(&av7110->ci_rbuffer, file, buf, count, ppos);
 356}
 357
 358static const struct file_operations dvb_ca_fops = {
 359        .owner          = THIS_MODULE,
 360        .read           = dvb_ca_read,
 361        .write          = dvb_ca_write,
 362        .unlocked_ioctl = dvb_generic_ioctl,
 363        .open           = dvb_ca_open,
 364        .release        = dvb_generic_release,
 365        .poll           = dvb_ca_poll,
 366        .llseek         = default_llseek,
 367};
 368
 369static struct dvb_device dvbdev_ca = {
 370        .priv           = NULL,
 371        .users          = 1,
 372        .writers        = 1,
 373        .fops           = &dvb_ca_fops,
 374        .kernel_ioctl   = dvb_ca_ioctl,
 375};
 376
 377
 378int av7110_ca_register(struct av7110 *av7110)
 379{
 380        return dvb_register_device(&av7110->dvb_adapter, &av7110->ca_dev,
 381                                   &dvbdev_ca, av7110, DVB_DEVICE_CA);
 382}
 383
 384void av7110_ca_unregister(struct av7110 *av7110)
 385{
 386        dvb_unregister_device(av7110->ca_dev);
 387}
 388
 389int av7110_ca_init(struct av7110* av7110)
 390{
 391        return ci_ll_init(&av7110->ci_rbuffer, &av7110->ci_wbuffer, 8192);
 392}
 393
 394void av7110_ca_exit(struct av7110* av7110)
 395{
 396        ci_ll_release(&av7110->ci_rbuffer, &av7110->ci_wbuffer);
 397}
 398