linux/drivers/media/firewire/firedtv-ci.c
<<
>>
Prefs
   1/*
   2 * FireDTV driver (formerly known as FireSAT)
   3 *
   4 * Copyright (C) 2004 Andreas Monitzer <andy@monitzer.com>
   5 * Copyright (C) 2008 Henrik Kurelid <henrik@kurelid.se>
   6 *
   7 *      This program is free software; you can redistribute it and/or
   8 *      modify it under the terms of the GNU General Public License as
   9 *      published by the Free Software Foundation; either version 2 of
  10 *      the License, or (at your option) any later version.
  11 */
  12
  13#include <linux/device.h>
  14#include <linux/dvb/ca.h>
  15#include <linux/fs.h>
  16#include <linux/module.h>
  17
  18#include <dvbdev.h>
  19
  20#include "firedtv.h"
  21
  22#define EN50221_TAG_APP_INFO_ENQUIRY    0x9f8020
  23#define EN50221_TAG_CA_INFO_ENQUIRY     0x9f8030
  24#define EN50221_TAG_CA_PMT              0x9f8032
  25#define EN50221_TAG_ENTER_MENU          0x9f8022
  26
  27static int fdtv_ca_ready(struct firedtv_tuner_status *stat)
  28{
  29        return stat->ca_initialization_status   == 1 &&
  30               stat->ca_error_flag              == 0 &&
  31               stat->ca_dvb_flag                == 1 &&
  32               stat->ca_module_present_status   == 1;
  33}
  34
  35static int fdtv_get_ca_flags(struct firedtv_tuner_status *stat)
  36{
  37        int flags = 0;
  38
  39        if (stat->ca_module_present_status == 1)
  40                flags |= CA_CI_MODULE_PRESENT;
  41        if (stat->ca_initialization_status == 1 &&
  42            stat->ca_error_flag            == 0 &&
  43            stat->ca_dvb_flag              == 1)
  44                flags |= CA_CI_MODULE_READY;
  45        return flags;
  46}
  47
  48static int fdtv_ca_get_caps(void *arg)
  49{
  50        struct ca_caps *cap = arg;
  51
  52        cap->slot_num = 1;
  53        cap->slot_type = CA_CI;
  54        cap->descr_num = 1;
  55        cap->descr_type = CA_ECD;
  56        return 0;
  57}
  58
  59static int fdtv_ca_get_slot_info(struct firedtv *fdtv, void *arg)
  60{
  61        struct firedtv_tuner_status stat;
  62        struct ca_slot_info *slot = arg;
  63        int err;
  64
  65        err = avc_tuner_status(fdtv, &stat);
  66        if (err)
  67                return err;
  68
  69        if (slot->num != 0)
  70                return -EACCES;
  71
  72        slot->type = CA_CI;
  73        slot->flags = fdtv_get_ca_flags(&stat);
  74        return 0;
  75}
  76
  77static int fdtv_ca_app_info(struct firedtv *fdtv, void *arg)
  78{
  79        struct ca_msg *reply = arg;
  80
  81        return avc_ca_app_info(fdtv, reply->msg, &reply->length);
  82}
  83
  84static int fdtv_ca_info(struct firedtv *fdtv, void *arg)
  85{
  86        struct ca_msg *reply = arg;
  87
  88        return avc_ca_info(fdtv, reply->msg, &reply->length);
  89}
  90
  91static int fdtv_ca_get_mmi(struct firedtv *fdtv, void *arg)
  92{
  93        struct ca_msg *reply = arg;
  94
  95        return avc_ca_get_mmi(fdtv, reply->msg, &reply->length);
  96}
  97
  98static int fdtv_ca_get_msg(struct firedtv *fdtv, void *arg)
  99{
 100        struct firedtv_tuner_status stat;
 101        int err;
 102
 103        switch (fdtv->ca_last_command) {
 104        case EN50221_TAG_APP_INFO_ENQUIRY:
 105                err = fdtv_ca_app_info(fdtv, arg);
 106                break;
 107        case EN50221_TAG_CA_INFO_ENQUIRY:
 108                err = fdtv_ca_info(fdtv, arg);
 109                break;
 110        default:
 111                err = avc_tuner_status(fdtv, &stat);
 112                if (err)
 113                        break;
 114                if (stat.ca_mmi == 1)
 115                        err = fdtv_ca_get_mmi(fdtv, arg);
 116                else {
 117                        dev_info(fdtv->device, "unhandled CA message 0x%08x\n",
 118                                 fdtv->ca_last_command);
 119                        err = -EACCES;
 120                }
 121        }
 122        fdtv->ca_last_command = 0;
 123        return err;
 124}
 125
 126static int fdtv_ca_pmt(struct firedtv *fdtv, void *arg)
 127{
 128        struct ca_msg *msg = arg;
 129        int data_pos;
 130        int data_length;
 131        int i;
 132
 133        data_pos = 4;
 134        if (msg->msg[3] & 0x80) {
 135                data_length = 0;
 136                for (i = 0; i < (msg->msg[3] & 0x7f); i++)
 137                        data_length = (data_length << 8) + msg->msg[data_pos++];
 138        } else {
 139                data_length = msg->msg[3];
 140        }
 141
 142        return avc_ca_pmt(fdtv, &msg->msg[data_pos], data_length);
 143}
 144
 145static int fdtv_ca_send_msg(struct firedtv *fdtv, void *arg)
 146{
 147        struct ca_msg *msg = arg;
 148        int err;
 149
 150        /* Do we need a semaphore for this? */
 151        fdtv->ca_last_command =
 152                (msg->msg[0] << 16) + (msg->msg[1] << 8) + msg->msg[2];
 153        switch (fdtv->ca_last_command) {
 154        case EN50221_TAG_CA_PMT:
 155                err = fdtv_ca_pmt(fdtv, arg);
 156                break;
 157        case EN50221_TAG_APP_INFO_ENQUIRY:
 158                /* handled in ca_get_msg */
 159                err = 0;
 160                break;
 161        case EN50221_TAG_CA_INFO_ENQUIRY:
 162                /* handled in ca_get_msg */
 163                err = 0;
 164                break;
 165        case EN50221_TAG_ENTER_MENU:
 166                err = avc_ca_enter_menu(fdtv);
 167                break;
 168        default:
 169                dev_err(fdtv->device, "unhandled CA message 0x%08x\n",
 170                        fdtv->ca_last_command);
 171                err = -EACCES;
 172        }
 173        return err;
 174}
 175
 176static int fdtv_ca_ioctl(struct file *file, unsigned int cmd, void *arg)
 177{
 178        struct dvb_device *dvbdev = file->private_data;
 179        struct firedtv *fdtv = dvbdev->priv;
 180        struct firedtv_tuner_status stat;
 181        int err;
 182
 183        switch (cmd) {
 184        case CA_RESET:
 185                err = avc_ca_reset(fdtv);
 186                break;
 187        case CA_GET_CAP:
 188                err = fdtv_ca_get_caps(arg);
 189                break;
 190        case CA_GET_SLOT_INFO:
 191                err = fdtv_ca_get_slot_info(fdtv, arg);
 192                break;
 193        case CA_GET_MSG:
 194                err = fdtv_ca_get_msg(fdtv, arg);
 195                break;
 196        case CA_SEND_MSG:
 197                err = fdtv_ca_send_msg(fdtv, arg);
 198                break;
 199        default:
 200                dev_info(fdtv->device, "unhandled CA ioctl %u\n", cmd);
 201                err = -EOPNOTSUPP;
 202        }
 203
 204        /* FIXME Is this necessary? */
 205        avc_tuner_status(fdtv, &stat);
 206
 207        return err;
 208}
 209
 210static unsigned int fdtv_ca_io_poll(struct file *file, poll_table *wait)
 211{
 212        return POLLIN;
 213}
 214
 215static const struct file_operations fdtv_ca_fops = {
 216        .owner          = THIS_MODULE,
 217        .unlocked_ioctl = dvb_generic_ioctl,
 218        .open           = dvb_generic_open,
 219        .release        = dvb_generic_release,
 220        .poll           = fdtv_ca_io_poll,
 221        .llseek         = noop_llseek,
 222};
 223
 224static struct dvb_device fdtv_ca = {
 225        .users          = 1,
 226        .readers        = 1,
 227        .writers        = 1,
 228        .fops           = &fdtv_ca_fops,
 229        .kernel_ioctl   = fdtv_ca_ioctl,
 230};
 231
 232int fdtv_ca_register(struct firedtv *fdtv)
 233{
 234        struct firedtv_tuner_status stat;
 235        int err;
 236
 237        if (avc_tuner_status(fdtv, &stat))
 238                return -EINVAL;
 239
 240        if (!fdtv_ca_ready(&stat))
 241                return -EFAULT;
 242
 243        err = dvb_register_device(&fdtv->adapter, &fdtv->cadev,
 244                                  &fdtv_ca, fdtv, DVB_DEVICE_CA, 0);
 245
 246        if (stat.ca_application_info == 0)
 247                dev_err(fdtv->device, "CaApplicationInfo is not set\n");
 248        if (stat.ca_date_time_request == 1)
 249                avc_ca_get_time_date(fdtv, &fdtv->ca_time_interval);
 250
 251        return err;
 252}
 253
 254void fdtv_ca_release(struct firedtv *fdtv)
 255{
 256        dvb_unregister_device(fdtv->cadev);
 257}
 258