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