diff options
Diffstat (limited to 'drivers/media/dvb/firesat/firesat-ci.c')
-rw-r--r-- | drivers/media/dvb/firesat/firesat-ci.c | 342 |
1 files changed, 300 insertions, 42 deletions
diff --git a/drivers/media/dvb/firesat/firesat-ci.c b/drivers/media/dvb/firesat/firesat-ci.c index 862d9553c5b..821048db283 100644 --- a/drivers/media/dvb/firesat/firesat-ci.c +++ b/drivers/media/dvb/firesat/firesat-ci.c @@ -1,66 +1,303 @@ +/* + * FireSAT DVB driver + * + * Copyright (c) 2008 Henrik Kurelid <henrik@kurelid.se> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + */ + #include "firesat-ci.h" #include "firesat.h" #include "avc_api.h" #include <linux/dvb/ca.h> #include <dvbdev.h> -/* -static int firesat_ca_do_ioctl(struct inode *inode, struct file *file, unsigned int cmd, void *parg) { - //struct firesat *firesat = (struct firesat*)((struct dvb_device*)file->private_data)->priv; - int err; -// printk(KERN_INFO "%s: ioctl %d\n",__func__,cmd); +static unsigned int ca_debug = 0; +module_param(ca_debug, int, 0644); +MODULE_PARM_DESC(ca_debug, "debug logging of ca system, default is 0 (no)"); - switch(cmd) { - case CA_RESET: - // TODO: Needs to be implemented with new AVC Vendor commands +static int firesat_ca_ready(ANTENNA_INPUT_INFO *info) +{ + if (ca_debug != 0) + printk("%s: CaMmi=%d, CaInit=%d, CaError=%d, CaDvb=%d, " + "CaModule=%d, CaAppInfo=%d, CaDateTime=%d, " + "CaPmt=%d\n", __func__, info->CaMmi, + info->CaInitializationStatus, info->CaErrorFlag, + info->CaDvbFlag, info->CaModulePresentStatus, + info->CaApplicationInfo, + info->CaDateTimeRequest, info->CaPmtReply); + return info->CaInitializationStatus == 1 && + info->CaErrorFlag == 0 && + info->CaDvbFlag == 1 && + info->CaModulePresentStatus == 1; +} + +static int firesat_get_ca_flags(ANTENNA_INPUT_INFO *info) +{ + int flags = 0; + if (info->CaModulePresentStatus == 1) + flags |= CA_CI_MODULE_PRESENT; + if (info->CaInitializationStatus == 1 && + info->CaErrorFlag == 0 && + info->CaDvbFlag == 1) + flags |= CA_CI_MODULE_READY; + return flags; +} + +static int firesat_ca_reset(struct firesat *firesat) +{ + if (ca_debug) + printk(KERN_INFO "%s: ioctl CA_RESET\n", __func__); + if (avc_ca_reset(firesat)) + return -EFAULT; + return 0; +} + +static int firesat_ca_get_caps(struct firesat *firesat, void *arg) +{ + struct ca_caps *cap_p = (struct ca_caps*)arg; + int err = 0; + + cap_p->slot_num = 1; + cap_p->slot_type = CA_CI; + cap_p->descr_num = 1; + cap_p->descr_type = CA_ECD; + if (ca_debug) + printk(KERN_INFO "%s: ioctl CA_GET_CAP\n", __func__); + return err; +} + +static int firesat_ca_get_slot_info(struct firesat *firesat, void *arg) +{ + ANTENNA_INPUT_INFO info; + struct ca_slot_info *slot_p = (struct ca_slot_info*)arg; + + if (ca_debug) + printk(KERN_INFO "%s: ioctl CA_GET_SLOT_INFO on slot %d.\n", + __func__, slot_p->num); + if (AVCTunerStatus(firesat, &info)) + return -EFAULT; + + if (slot_p->num == 0) { + slot_p->type = CA_CI; + slot_p->flags = firesat_get_ca_flags(&info); + } + else { + return -EFAULT; + } + return 0; +} + +static int firesat_ca_app_info(struct firesat *firesat, void *arg) +{ + struct ca_msg *reply_p = (struct ca_msg*)arg; + int i; + + if (avc_ca_app_info(firesat, reply_p->msg, &reply_p->length)) + return -EFAULT; + if (ca_debug) { + printk(KERN_INFO "%s: Creating TAG_APP_INFO message:", + __func__); + for (i = 0; i < reply_p->length; i++) + printk("0x%02X, ", (unsigned char)reply_p->msg[i]); + printk("\n"); + } + return 0; +} + +static int firesat_ca_info(struct firesat *firesat, void *arg) +{ + struct ca_msg *reply_p = (struct ca_msg*)arg; + int i; + + if (avc_ca_info(firesat, reply_p->msg, &reply_p->length)) + return -EFAULT; + if (ca_debug) { + printk(KERN_INFO "%s: Creating TAG_CA_INFO message:", + __func__); + for (i = 0; i < reply_p->length; i++) + printk("0x%02X, ", (unsigned char)reply_p->msg[i]); + printk("\n"); + } + return 0; +} + +static int firesat_ca_get_mmi(struct firesat *firesat, void *arg) +{ + struct ca_msg *reply_p = (struct ca_msg*)arg; + int i; + + if (avc_ca_get_mmi(firesat, reply_p->msg, &reply_p->length)) + return -EFAULT; + if (ca_debug) { + printk(KERN_INFO "%s: Creating MMI reply INFO message:", + __func__); + for (i = 0; i < reply_p->length; i++) + printk("0x%02X, ", (unsigned char)reply_p->msg[i]); + printk("\n"); + } + return 0; +} + +static int firesat_ca_get_msg(struct firesat *firesat, void *arg) +{ + int err; + ANTENNA_INPUT_INFO info; + + switch (firesat->ca_last_command) { + case TAG_APP_INFO_ENQUIRY: + err = firesat_ca_app_info(firesat, arg); + break; + case TAG_CA_INFO_ENQUIRY: + err = firesat_ca_info(firesat, arg); break; - case CA_GET_CAP: { - ca_caps_t *cap=(ca_caps_t*)parg; - cap->slot_num = 1; - cap->slot_type = CA_CI_LINK; - cap->descr_num = 1; - cap->descr_type = CA_DSS; + default: + if (AVCTunerStatus(firesat, &info)) + err = -EFAULT; + else if (info.CaMmi == 1) { + err = firesat_ca_get_mmi(firesat, arg); + } + else { + printk(KERN_INFO "%s: Unhandled message 0x%08X\n", + __func__, firesat->ca_last_command); + err = -EFAULT; + } + } + firesat->ca_last_command = 0; + return err; +} +static int firesat_ca_pmt(struct firesat *firesat, void *arg) +{ + struct ca_msg *msg_p = (struct ca_msg*)arg; + int data_pos; + + if (msg_p->msg[3] & 0x80) + data_pos = (msg_p->msg[4] && 0x7F) + 4; + else + data_pos = 4; + if (avc_ca_pmt(firesat, &msg_p->msg[data_pos], + msg_p->length - data_pos)) + return -EFAULT; + return 0; +} + +static int firesat_ca_send_msg(struct firesat *firesat, void *arg) +{ + int err; + struct ca_msg *msg_p = (struct ca_msg*)arg; + + // Do we need a semaphore for this? + firesat->ca_last_command = + (msg_p->msg[0] << 16) + (msg_p->msg[1] << 8) + msg_p->msg[2]; + switch (firesat->ca_last_command) { + case TAG_CA_PMT: + if (ca_debug != 0) + printk(KERN_INFO "%s: Message received: TAG_CA_PMT\n", + __func__); + err = firesat_ca_pmt(firesat, arg); + break; + case TAG_APP_INFO_ENQUIRY: + // This is all handled in ca_get_msg + if (ca_debug != 0) + printk(KERN_INFO "%s: Message received: " + "TAG_APP_INFO_ENQUIRY\n", __func__); err = 0; break; - } - case CA_GET_SLOT_INFO: { - ca_slot_info_t *slot=(ca_slot_info_t*)parg; - if(slot->num == 0) { - slot->type = CA_CI | CA_CI_LINK | CA_DESCR; - slot->flags = CA_CI_MODULE_PRESENT | CA_CI_MODULE_READY; - } else { - slot->type = 0; - slot->flags = 0; - } + case TAG_CA_INFO_ENQUIRY: + // This is all handled in ca_get_msg + if (ca_debug != 0) + printk(KERN_INFO "%s: Message received: " + "TAG_CA_APP_INFO_ENQUIRY\n", __func__); err = 0; break; + case TAG_ENTER_MENU: + if (ca_debug != 0) + printk(KERN_INFO "%s: Entering CA menu.\n", __func__); + err = avc_ca_enter_menu(firesat); + break; + default: + printk(KERN_ERR "%s: Unhandled unknown message 0x%08X\n", + __func__, firesat->ca_last_command); + err = -EFAULT; } + return err; +} + +static int firesat_ca_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, void *arg) +{ + struct dvb_device* dvbdev = (struct dvb_device*) file->private_data; + struct firesat *firesat = dvbdev->priv; + int err; + ANTENNA_INPUT_INFO info; + + switch(cmd) { + case CA_RESET: + err = firesat_ca_reset(firesat); + break; + case CA_GET_CAP: + err = firesat_ca_get_caps(firesat, arg); + break; + case CA_GET_SLOT_INFO: + err = firesat_ca_get_slot_info(firesat, arg); + break; + case CA_GET_MSG: + err = firesat_ca_get_msg(firesat, arg); + break; + case CA_SEND_MSG: + err = firesat_ca_send_msg(firesat, arg); + break; default: - err=-EINVAL; + printk(KERN_INFO "%s: Unhandled ioctl, command: %u\n",__func__, + cmd); + err = -EOPNOTSUPP; } + + if (AVCTunerStatus(firesat, &info)) + return err; + + firesat_ca_ready(&info); + return err; } -*/ -static int firesat_ca_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { - //return dvb_usercopy(inode, file, cmd, arg, firesat_ca_do_ioctl); - return dvb_generic_ioctl(inode, file, cmd, arg); +static int firesat_get_date_time_request(struct firesat *firesat) +{ + if (ca_debug) + printk(KERN_INFO "%s: Retrieving Time/Date request\n", + __func__); + if (avc_ca_get_time_date(firesat, &firesat->ca_time_interval)) + return -EFAULT; + if (ca_debug) + printk(KERN_INFO "%s: Time/Date interval is %d\n", + __func__, firesat->ca_time_interval); + + return 0; } -static int firesat_ca_io_open(struct inode *inode, struct file *file) { - printk(KERN_INFO "%s!\n",__func__); +static int firesat_ca_io_open(struct inode *inode, struct file *file) +{ + if (ca_debug != 0) + printk(KERN_INFO "%s\n",__func__); return dvb_generic_open(inode, file); } -static int firesat_ca_io_release(struct inode *inode, struct file *file) { - printk(KERN_INFO "%s!\n",__func__); +static int firesat_ca_io_release(struct inode *inode, struct file *file) +{ + if (ca_debug != 0) + printk(KERN_INFO "%s\n",__func__); return dvb_generic_release(inode, file); } -static unsigned int firesat_ca_io_poll(struct file *file, poll_table *wait) { -// printk(KERN_INFO "%s!\n",__func__); +static unsigned int firesat_ca_io_poll(struct file *file, poll_table *wait) +{ + if (ca_debug != 0) + printk(KERN_INFO "%s\n",__func__); return POLLIN; } @@ -68,7 +305,7 @@ static struct file_operations firesat_ca_fops = { .owner = THIS_MODULE, .read = NULL, // There is no low level read anymore .write = NULL, // There is no low level write anymore - .ioctl = firesat_ca_ioctl, + .ioctl = dvb_generic_ioctl, .open = firesat_ca_io_open, .release = firesat_ca_io_release, .poll = firesat_ca_io_poll, @@ -80,16 +317,37 @@ static struct dvb_device firesat_ca = { .readers = 1, .writers = 1, .fops = &firesat_ca_fops, + .kernel_ioctl = firesat_ca_ioctl, }; -int firesat_ca_init(struct firesat *firesat) { - int ret = dvb_register_device(firesat->adapter, &firesat->cadev, &firesat_ca, firesat, DVB_DEVICE_CA); - if(ret) return ret; +int firesat_ca_init(struct firesat *firesat) +{ + int err; + ANTENNA_INPUT_INFO info; - // avoid unnecessary delays, we're not talking to the CI yet anyways - return 0; + if (AVCTunerStatus(firesat, &info)) + return -EINVAL; + + if (firesat_ca_ready(&info)) { + err = dvb_register_device(firesat->adapter, + &firesat->cadev, + &firesat_ca, firesat, + DVB_DEVICE_CA); + + if (info.CaApplicationInfo == 0) + printk(KERN_ERR "%s: CaApplicationInfo is not set.\n", + __func__); + if (info.CaDateTimeRequest == 1) + firesat_get_date_time_request(firesat); + } + else + err = -EFAULT; + + return err; } -void firesat_ca_release(struct firesat *firesat) { +void firesat_ca_release(struct firesat *firesat) +{ + if (firesat->cadev) dvb_unregister_device(firesat->cadev); } |