11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 21da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * dvb_ca.c: generic DVB functions for EN50221 CAM interfaces 31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 41da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Copyright (C) 2004 Andrew de Quincey 51da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 61da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Parts of this file were based on sources as follows: 71da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Copyright (C) 2003 Ralph Metzler <rjkm@metzlerbros.de> 91da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * based on code: 111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Copyright (C) 1999-2002 Ralph Metzler 131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * & Marcus Metzler for convergence integrated media GmbH 141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This program is free software; you can redistribute it and/or 161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * modify it under the terms of the GNU General Public License 171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * as published by the Free Software Foundation; either version 2 181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * of the License, or (at your option) any later version. 191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This program is distributed in the hope that it will be useful, 211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * but WITHOUT ANY WARRANTY; without even the implied warranty of 221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * GNU General Public License for more details. 241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * You should have received a copy of the GNU General Public License 261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * along with this program; if not, write to the Free Software 271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Or, point your browser to http://www.gnu.org/copyleft/gpl.html 291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/errno.h> 321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/slab.h> 331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/list.h> 341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/module.h> 351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/vmalloc.h> 361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/delay.h> 37ded928468407c8e08dcb6aedb91aaa97b80d5752Andrew de Quincey#include <linux/spinlock.h> 384e57b6817880946a3a78d5d8cad1ace363f7e449Tim Schmielau#include <linux/sched.h> 399320874a3e6aea7044a4a7eedeab13db990424abChristoph Hellwig#include <linux/kthread.h> 401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "dvb_ca_en50221.h" 421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "dvb_ringbuffer.h" 431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int dvb_ca_en50221_debug; 451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_param_named(cam_debug, dvb_ca_en50221_debug, int, 0644); 471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_PARM_DESC(cam_debug, "enable verbose debug messages"); 481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define dprintk if (dvb_ca_en50221_debug) printk 501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5150b447d5b70dc4021ae3b4eaf8ce98932f61a413Dominique Dumont#define INIT_TIMEOUT_SECS 10 521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define HOST_LINK_BUF_SIZE 0x200 541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define RX_BUFFER_SIZE 65535 561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define MAX_RX_PACKETS_PER_ITERATION 10 581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define CTRLIF_DATA 0 601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define CTRLIF_COMMAND 1 611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define CTRLIF_STATUS 1 621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define CTRLIF_SIZE_LOW 2 631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define CTRLIF_SIZE_HIGH 3 641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define CMDREG_HC 1 /* Host control */ 661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define CMDREG_SW 2 /* Size write */ 671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define CMDREG_SR 4 /* Size read */ 681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define CMDREG_RS 8 /* Reset interface */ 691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define CMDREG_FRIE 0x40 /* Enable FR interrupt */ 701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define CMDREG_DAIE 0x80 /* Enable DA interrupt */ 711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define IRQEN (CMDREG_DAIE) 721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define STATUSREG_RE 1 /* read error */ 741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define STATUSREG_WE 2 /* write error */ 751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define STATUSREG_FR 0x40 /* module free */ 761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define STATUSREG_DA 0x80 /* data available */ 771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define STATUSREG_TXERR (STATUSREG_RE|STATUSREG_WE) /* general transfer error */ 781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define DVB_CA_SLOTSTATE_NONE 0 811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define DVB_CA_SLOTSTATE_UNINITIALISED 1 821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define DVB_CA_SLOTSTATE_RUNNING 2 831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define DVB_CA_SLOTSTATE_INVALID 3 841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define DVB_CA_SLOTSTATE_WAITREADY 4 851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define DVB_CA_SLOTSTATE_VALIDATE 5 861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define DVB_CA_SLOTSTATE_WAITFR 6 871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define DVB_CA_SLOTSTATE_LINKINIT 7 881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Information on a CA slot */ 911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct dvb_ca_slot { 921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* current state of the CAM */ 941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int slot_state; 951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 96d7e43844e40e07cadc48f1733b9738659f83b38cMatthias Dahl /* mutex used for serializing access to one CI slot */ 97d7e43844e40e07cadc48f1733b9738659f83b38cMatthias Dahl struct mutex slot_lock; 98d7e43844e40e07cadc48f1733b9738659f83b38cMatthias Dahl 991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Number of CAMCHANGES that have occurred since last processing */ 1001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds atomic_t camchange_count; 1011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Type of last CAMCHANGE */ 1031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int camchange_type; 1041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* base address of CAM config */ 1061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u32 config_base; 1071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* value to write into Config Control register */ 1091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u8 config_option; 1101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* if 1, the CAM supports DA IRQs */ 1121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u8 da_irq_supported:1; 1131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* size of the buffer to use when talking to the CAM */ 1151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int link_buf_size; 1161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* buffer for incoming packets */ 1181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct dvb_ringbuffer rx_buffer; 1191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* timer used during various states of the slot */ 1211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long timeout; 1221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 1231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Private CA-interface information */ 1251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct dvb_ca_private { 1261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* pointer back to the public data structure */ 1281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct dvb_ca_en50221 *pub; 1291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* the DVB device */ 1311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct dvb_device *dvbdev; 1321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Flags describing the interface (DVB_CA_FLAG_*) */ 1341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u32 flags; 1351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* number of slots supported by this CA interface */ 1371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int slot_count; 1381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* information on each slot */ 1401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct dvb_ca_slot *slot_info; 1411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* wait queues for read() and write() operations */ 1431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds wait_queue_head_t wait_queue; 1441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* PID of the monitoring thread */ 1469320874a3e6aea7044a4a7eedeab13db990424abChristoph Hellwig struct task_struct *thread; 1471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Flag indicating if the CA device is open */ 1491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int open:1; 1501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Flag indicating the thread should wake up now */ 1521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int wakeup:1; 1531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Delay the main thread should use */ 1551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long delay; 1561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Slot to start looking for data to read from in the next user-space read operation */ 1581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int next_read_slot; 1591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 1601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void dvb_ca_en50221_thread_wakeup(struct dvb_ca_private *ca); 1621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int dvb_ca_en50221_read_data(struct dvb_ca_private *ca, int slot, u8 * ebuf, int ecount); 1631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int dvb_ca_en50221_write_data(struct dvb_ca_private *ca, int slot, u8 * ebuf, int ecount); 1641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/** 1671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Safely find needle in haystack. 1681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 1691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @param haystack Buffer to look in. 1701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @param hlen Number of bytes in haystack. 1711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @param needle Buffer to find. 1721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @param nlen Number of bytes in needle. 1731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @return Pointer into haystack needle was found at, or NULL if not found. 1741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 175260f8d7c4cda79b087a182eb03e8574ba41a171eOliver Endrissstatic char *findstr(char * haystack, int hlen, char * needle, int nlen) 1761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i; 1781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (hlen < nlen) 1801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return NULL; 1811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0; i <= hlen - nlen; i++) { 1831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!strncmp(haystack + i, needle, nlen)) 1841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return haystack + i; 1851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return NULL; 1881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* ******************************************************************************** */ 1931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* EN50221 physical interface functions */ 1941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/** 1971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Check CAM status. 1981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 1991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int dvb_ca_en50221_check_camstatus(struct dvb_ca_private *ca, int slot) 2001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int slot_status; 2021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int cam_present_now; 2031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int cam_changed; 2041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* IRQ mode */ 2061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ca->flags & DVB_CA_EN50221_FLAG_IRQ_CAMCHANGE) { 2071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return (atomic_read(&ca->slot_info[slot].camchange_count) != 0); 2081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* poll mode */ 2111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds slot_status = ca->pub->poll_slot_status(ca->pub, slot, ca->open); 2121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cam_present_now = (slot_status & DVB_CA_EN50221_POLL_CAM_PRESENT) ? 1 : 0; 2141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cam_changed = (slot_status & DVB_CA_EN50221_POLL_CAM_CHANGED) ? 1 : 0; 2151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!cam_changed) { 2161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int cam_present_old = (ca->slot_info[slot].slot_state != DVB_CA_SLOTSTATE_NONE); 2171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cam_changed = (cam_present_now != cam_present_old); 2181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (cam_changed) { 2211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!cam_present_now) { 2221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ca->slot_info[slot].camchange_type = DVB_CA_EN50221_CAMCHANGE_REMOVED; 2231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 2241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ca->slot_info[slot].camchange_type = DVB_CA_EN50221_CAMCHANGE_INSERTED; 2251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds atomic_set(&ca->slot_info[slot].camchange_count, 1); 2271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 2281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((ca->slot_info[slot].slot_state == DVB_CA_SLOTSTATE_WAITREADY) && 2291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (slot_status & DVB_CA_EN50221_POLL_CAM_READY)) { 2301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // move to validate state if reset is completed 2311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_VALIDATE; 2321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return cam_changed; 2361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/** 2401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Wait for flags to become set on the STATUS register on a CAM interface, 2411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * checking for errors and timeout. 2421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 2431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @param ca CA instance. 2441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @param slot Slot on interface. 2451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @param waitfor Flags to wait for. 2461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @param timeout_ms Timeout in milliseconds. 2471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 2481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @return 0 on success, nonzero on error. 2491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 2501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int dvb_ca_en50221_wait_if_status(struct dvb_ca_private *ca, int slot, 2511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u8 waitfor, int timeout_hz) 2521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long timeout; 2541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long start; 2551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 25646b4f7c176a2dd4c60ddb7c80bd09ea2f3220674Harvey Harrison dprintk("%s\n", __func__); 2571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* loop until timeout elapsed */ 2591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds start = jiffies; 2601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds timeout = jiffies + timeout_hz; 2611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while (1) { 2621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* read the status and check for error */ 2631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int res = ca->pub->read_cam_control(ca->pub, slot, CTRLIF_STATUS); 2641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (res < 0) 2651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EIO; 2661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* if we got the flags, it was successful! */ 2681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (res & waitfor) { 26946b4f7c176a2dd4c60ddb7c80bd09ea2f3220674Harvey Harrison dprintk("%s succeeded timeout:%lu\n", __func__, jiffies - start); 2701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 2711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* check for timeout */ 2741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (time_after(jiffies, timeout)) { 2751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 2761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* wait for a bit */ 2791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds msleep(1); 2801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 28246b4f7c176a2dd4c60ddb7c80bd09ea2f3220674Harvey Harrison dprintk("%s failed timeout:%lu\n", __func__, jiffies - start); 2831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* if we get here, we've timed out */ 2851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ETIMEDOUT; 2861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/** 2901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Initialise the link layer connection to a CAM. 2911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 2921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @param ca CA instance. 2931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @param slot Slot id. 2941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 2951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @return 0 on success, nonzero on failure. 2961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 2971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int dvb_ca_en50221_link_init(struct dvb_ca_private *ca, int slot) 2981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int ret; 3001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int buf_size; 3011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u8 buf[2]; 3021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 30346b4f7c176a2dd4c60ddb7c80bd09ea2f3220674Harvey Harrison dprintk("%s\n", __func__); 3041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* we'll be determining these during this function */ 3061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ca->slot_info[slot].da_irq_supported = 0; 3071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* set the host link buffer size temporarily. it will be overwritten with the 3091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * real negotiated size later. */ 3101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ca->slot_info[slot].link_buf_size = 2; 3111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* read the buffer size from the CAM */ 3131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((ret = ca->pub->write_cam_control(ca->pub, slot, CTRLIF_COMMAND, IRQEN | CMDREG_SR)) != 0) 3141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return ret; 3151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((ret = dvb_ca_en50221_wait_if_status(ca, slot, STATUSREG_DA, HZ / 10)) != 0) 3161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return ret; 3171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((ret = dvb_ca_en50221_read_data(ca, slot, buf, 2)) != 2) 3181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EIO; 3191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((ret = ca->pub->write_cam_control(ca->pub, slot, CTRLIF_COMMAND, IRQEN)) != 0) 3201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return ret; 3211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* store it, and choose the minimum of our buffer and the CAM's buffer size */ 3231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds buf_size = (buf[0] << 8) | buf[1]; 3241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (buf_size > HOST_LINK_BUF_SIZE) 3251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds buf_size = HOST_LINK_BUF_SIZE; 3261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ca->slot_info[slot].link_buf_size = buf_size; 3271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds buf[0] = buf_size >> 8; 3281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds buf[1] = buf_size & 0xff; 3291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dprintk("Chosen link buffer size of %i\n", buf_size); 3301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* write the buffer size to the CAM */ 3321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((ret = ca->pub->write_cam_control(ca->pub, slot, CTRLIF_COMMAND, IRQEN | CMDREG_SW)) != 0) 3331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return ret; 3341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((ret = dvb_ca_en50221_wait_if_status(ca, slot, STATUSREG_FR, HZ / 10)) != 0) 3351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return ret; 3361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((ret = dvb_ca_en50221_write_data(ca, slot, buf, 2)) != 2) 3371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EIO; 3381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((ret = ca->pub->write_cam_control(ca->pub, slot, CTRLIF_COMMAND, IRQEN)) != 0) 3391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return ret; 3401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* success */ 3421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 3431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/** 3461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Read a tuple from attribute memory. 3471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 3481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @param ca CA instance. 3491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @param slot Slot id. 3501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @param address Address to read from. Updated. 3511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @param tupleType Tuple id byte. Updated. 3521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @param tupleLength Tuple length. Updated. 3531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @param tuple Dest buffer for tuple (must be 256 bytes). Updated. 3541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 3551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @return 0 on success, nonzero on error. 3561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 3571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int dvb_ca_en50221_read_tuple(struct dvb_ca_private *ca, int slot, 3581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int *address, int *tupleType, int *tupleLength, u8 * tuple) 3591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 3601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i; 3611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int _tupleType; 3621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int _tupleLength; 3631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int _address = *address; 3641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* grab the next tuple length and type */ 3661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((_tupleType = ca->pub->read_attribute_mem(ca->pub, slot, _address)) < 0) 3671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return _tupleType; 3681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (_tupleType == 0xff) { 3691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dprintk("END OF CHAIN TUPLE type:0x%x\n", _tupleType); 3701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *address += 2; 3711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *tupleType = _tupleType; 3721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *tupleLength = 0; 3731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 3741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((_tupleLength = ca->pub->read_attribute_mem(ca->pub, slot, _address + 2)) < 0) 3761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return _tupleLength; 3771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds _address += 4; 3781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dprintk("TUPLE type:0x%x length:%i\n", _tupleType, _tupleLength); 3801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* read in the whole tuple */ 3821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0; i < _tupleLength; i++) { 3831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tuple[i] = ca->pub->read_attribute_mem(ca->pub, slot, _address + (i * 2)); 3841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dprintk(" 0x%02x: 0x%02x %c\n", 3851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds i, tuple[i] & 0xff, 3861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ((tuple[i] > 31) && (tuple[i] < 127)) ? tuple[i] : '.'); 3871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds _address += (_tupleLength * 2); 3891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // success 3911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *tupleType = _tupleType; 3921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *tupleLength = _tupleLength; 3931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *address = _address; 3941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 3951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/** 3991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Parse attribute memory of a CAM module, extracting Config register, and checking 4001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * it is a DVB CAM module. 4011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 4021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @param ca CA instance. 4031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @param slot Slot id. 4041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 4051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @return 0 on success, <0 on failure. 4061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 4071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int dvb_ca_en50221_parse_attributes(struct dvb_ca_private *ca, int slot) 4081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 4091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int address = 0; 4101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int tupleLength; 4111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int tupleType; 4121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u8 tuple[257]; 4131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds char *dvb_str; 4141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int rasz; 4151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int status; 4161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int got_cftableentry = 0; 4171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int end_chain = 0; 4181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i; 4191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u16 manfid = 0; 4201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u16 devid = 0; 4211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // CISTPL_DEVICE_0A 4241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((status = 4251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dvb_ca_en50221_read_tuple(ca, slot, &address, &tupleType, &tupleLength, tuple)) < 0) 4261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return status; 4271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (tupleType != 0x1D) 4281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 4291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // CISTPL_DEVICE_0C 4331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((status = 4341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dvb_ca_en50221_read_tuple(ca, slot, &address, &tupleType, &tupleLength, tuple)) < 0) 4351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return status; 4361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (tupleType != 0x1C) 4371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 4381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // CISTPL_VERS_1 4421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((status = 4431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dvb_ca_en50221_read_tuple(ca, slot, &address, &tupleType, &tupleLength, tuple)) < 0) 4441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return status; 4451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (tupleType != 0x15) 4461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 4471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // CISTPL_MANFID 4511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((status = dvb_ca_en50221_read_tuple(ca, slot, &address, &tupleType, 4521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds &tupleLength, tuple)) < 0) 4531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return status; 4541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (tupleType != 0x20) 4551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 4561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (tupleLength != 4) 4571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 4581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds manfid = (tuple[1] << 8) | tuple[0]; 4591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds devid = (tuple[3] << 8) | tuple[2]; 4601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // CISTPL_CONFIG 4641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((status = dvb_ca_en50221_read_tuple(ca, slot, &address, &tupleType, 4651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds &tupleLength, tuple)) < 0) 4661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return status; 4671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (tupleType != 0x1A) 4681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 4691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (tupleLength < 3) 4701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 4711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* extract the configbase */ 4731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rasz = tuple[0] & 3; 4741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (tupleLength < (3 + rasz + 14)) 4751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 4761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ca->slot_info[slot].config_base = 0; 4771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0; i < rasz + 1; i++) { 4781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ca->slot_info[slot].config_base |= (tuple[2 + i] << (8 * i)); 4791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* check it contains the correct DVB string */ 482260f8d7c4cda79b087a182eb03e8574ba41a171eOliver Endriss dvb_str = findstr((char *)tuple, tupleLength, "DVB_CI_V", 8); 4831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (dvb_str == NULL) 4841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 4851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (tupleLength < ((dvb_str - (char *) tuple) + 12)) 4861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 4871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* is it a version we support? */ 4891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (strncmp(dvb_str + 8, "1.00", 4)) { 4901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk("dvb_ca adapter %d: Unsupported DVB CAM module version %c%c%c%c\n", 4911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ca->dvbdev->adapter->num, dvb_str[8], dvb_str[9], dvb_str[10], dvb_str[11]); 4921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 4931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* process the CFTABLE_ENTRY tuples, and any after those */ 4961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while ((!end_chain) && (address < 0x1000)) { 4971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((status = dvb_ca_en50221_read_tuple(ca, slot, &address, &tupleType, 498afd1a0c9ac281eed3b22b293ccd92af7b0d60889Mauro Carvalho Chehab &tupleLength, tuple)) < 0) 4991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return status; 5001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (tupleType) { 5011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case 0x1B: // CISTPL_CFTABLE_ENTRY 5021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (tupleLength < (2 + 11 + 17)) 5031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 5041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* if we've already parsed one, just use it */ 5061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (got_cftableentry) 5071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 5081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* get the config option */ 5101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ca->slot_info[slot].config_option = tuple[0] & 0x3f; 5111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* OK, check it contains the correct strings */ 513260f8d7c4cda79b087a182eb03e8574ba41a171eOliver Endriss if ((findstr((char *)tuple, tupleLength, "DVB_HOST", 8) == NULL) || 514260f8d7c4cda79b087a182eb03e8574ba41a171eOliver Endriss (findstr((char *)tuple, tupleLength, "DVB_CI_MODULE", 13) == NULL)) 5151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 5161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds got_cftableentry = 1; 5181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 5191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case 0x14: // CISTPL_NO_LINK 5211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 5221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case 0xFF: // CISTPL_END 5241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds end_chain = 1; 5251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 5261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds default: /* Unknown tuple type - just skip this tuple and move to the next one */ 5281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dprintk("dvb_ca: Skipping unknown tuple type:0x%x length:0x%x\n", tupleType, 5291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tupleLength); 5301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 5311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 5321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 5331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((address > 0x1000) || (!got_cftableentry)) 5351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 5361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dprintk("Valid DVB CAM detected MANID:%x DEVID:%x CONFIGBASE:0x%x CONFIGOPTION:0x%x\n", 5381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds manfid, devid, ca->slot_info[slot].config_base, ca->slot_info[slot].config_option); 5391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // success! 5411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 5421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 5431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/** 5461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Set CAM's configoption correctly. 5471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 5481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @param ca CA instance. 5491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @param slot Slot containing the CAM. 5501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 5511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int dvb_ca_en50221_set_configoption(struct dvb_ca_private *ca, int slot) 5521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 5531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int configoption; 5541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 55546b4f7c176a2dd4c60ddb7c80bd09ea2f3220674Harvey Harrison dprintk("%s\n", __func__); 5561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* set the config option */ 5581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ca->pub->write_attribute_mem(ca->pub, slot, 5591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ca->slot_info[slot].config_base, 5601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ca->slot_info[slot].config_option); 5611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* check it */ 5631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds configoption = ca->pub->read_attribute_mem(ca->pub, slot, ca->slot_info[slot].config_base); 5641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dprintk("Set configoption 0x%x, read configoption 0x%x\n", 5651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ca->slot_info[slot].config_option, configoption & 0x3f); 5661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* fine! */ 5681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 5691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 5711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/** 5741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This function talks to an EN50221 CAM control interface. It reads a buffer of 5751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * data from the CAM. The data can either be stored in a supplied buffer, or 5761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * automatically be added to the slot's rx_buffer. 5771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 5781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @param ca CA instance. 5791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @param slot Slot to read from. 5801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @param ebuf If non-NULL, the data will be written to this buffer. If NULL, 5811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the data will be added into the buffering system as a normal fragment. 5821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @param ecount Size of ebuf. Ignored if ebuf is NULL. 5831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 5841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @return Number of bytes read, or < 0 on error 5851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 5861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int dvb_ca_en50221_read_data(struct dvb_ca_private *ca, int slot, u8 * ebuf, int ecount) 5871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 5881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int bytes_read; 5891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int status; 5901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u8 buf[HOST_LINK_BUF_SIZE]; 5911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i; 5921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 59346b4f7c176a2dd4c60ddb7c80bd09ea2f3220674Harvey Harrison dprintk("%s\n", __func__); 5941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* check if we have space for a link buf in the rx_buffer */ 5961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ebuf == NULL) { 5971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int buf_free; 5981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ca->slot_info[slot].rx_buffer.data == NULL) { 6001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds status = -EIO; 6011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto exit; 6021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 6031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds buf_free = dvb_ringbuffer_free(&ca->slot_info[slot].rx_buffer); 6041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (buf_free < (ca->slot_info[slot].link_buf_size + DVB_RINGBUFFER_PKTHDRSIZE)) { 6061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds status = -EAGAIN; 6071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto exit; 6081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 6091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 6101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* check if there is data available */ 6121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((status = ca->pub->read_cam_control(ca->pub, slot, CTRLIF_STATUS)) < 0) 6131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto exit; 6141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!(status & STATUSREG_DA)) { 6151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* no data */ 6161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds status = 0; 6171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto exit; 6181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 6191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* read the amount of data */ 6211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((status = ca->pub->read_cam_control(ca->pub, slot, CTRLIF_SIZE_HIGH)) < 0) 6221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto exit; 6231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bytes_read = status << 8; 6241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((status = ca->pub->read_cam_control(ca->pub, slot, CTRLIF_SIZE_LOW)) < 0) 6251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto exit; 6261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bytes_read |= status; 6271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* check it will fit */ 6291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ebuf == NULL) { 6301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (bytes_read > ca->slot_info[slot].link_buf_size) { 6311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk("dvb_ca adapter %d: CAM tried to send a buffer larger than the link buffer size (%i > %i)!\n", 6321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ca->dvbdev->adapter->num, bytes_read, ca->slot_info[slot].link_buf_size); 6331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_LINKINIT; 6341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds status = -EIO; 6351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto exit; 6361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 6371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (bytes_read < 2) { 6381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk("dvb_ca adapter %d: CAM sent a buffer that was less than 2 bytes!\n", 6391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ca->dvbdev->adapter->num); 6401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_LINKINIT; 6411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds status = -EIO; 6421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto exit; 6431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 6441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 6451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (bytes_read > ecount) { 6461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk("dvb_ca adapter %d: CAM tried to send a buffer larger than the ecount size!\n", 6471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ca->dvbdev->adapter->num); 6481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds status = -EIO; 6491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto exit; 6501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 6511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 6521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* fill the buffer */ 6541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0; i < bytes_read; i++) { 6551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* read byte and check */ 6561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((status = ca->pub->read_cam_control(ca->pub, slot, CTRLIF_DATA)) < 0) 6571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto exit; 6581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* OK, store it in the buffer */ 6601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds buf[i] = status; 6611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 6621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* check for read error (RE should now be 0) */ 6641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((status = ca->pub->read_cam_control(ca->pub, slot, CTRLIF_STATUS)) < 0) 6651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto exit; 6661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (status & STATUSREG_RE) { 6671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_LINKINIT; 6681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds status = -EIO; 6691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto exit; 6701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 6711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* OK, add it to the receive buffer, or copy into external buffer if supplied */ 6731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ebuf == NULL) { 6741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ca->slot_info[slot].rx_buffer.data == NULL) { 6751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds status = -EIO; 6761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto exit; 6771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 6781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dvb_ringbuffer_pkt_write(&ca->slot_info[slot].rx_buffer, buf, bytes_read); 6791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 6801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memcpy(ebuf, buf, bytes_read); 6811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 6821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dprintk("Received CA packet for slot %i connection id 0x%x last_frag:%i size:0x%x\n", slot, 6841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds buf[0], (buf[1] & 0x80) == 0, bytes_read); 6851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* wake up readers when a last_fragment is received */ 6871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((buf[1] & 0x80) == 0x00) { 6881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds wake_up_interruptible(&ca->wait_queue); 6891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 6901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds status = bytes_read; 6911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsexit: 6931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return status; 6941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 6951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/** 6981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This function talks to an EN50221 CAM control interface. It writes a buffer of data 6991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * to a CAM. 7001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 7011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @param ca CA instance. 7021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @param slot Slot to write to. 7031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @param ebuf The data in this buffer is treated as a complete link-level packet to 7041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * be written. 7051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @param count Size of ebuf. 7061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 7071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @return Number of bytes written, or < 0 on error. 7081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 7091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int dvb_ca_en50221_write_data(struct dvb_ca_private *ca, int slot, u8 * buf, int bytes_write) 7101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 7111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int status; 7121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i; 7131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 71446b4f7c176a2dd4c60ddb7c80bd09ea2f3220674Harvey Harrison dprintk("%s\n", __func__); 7151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 717d7e43844e40e07cadc48f1733b9738659f83b38cMatthias Dahl /* sanity check */ 7181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (bytes_write > ca->slot_info[slot].link_buf_size) 7191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 7201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 721d7e43844e40e07cadc48f1733b9738659f83b38cMatthias Dahl /* it is possible we are dealing with a single buffer implementation, 722d7e43844e40e07cadc48f1733b9738659f83b38cMatthias Dahl thus if there is data available for read or if there is even a read 723d7e43844e40e07cadc48f1733b9738659f83b38cMatthias Dahl already in progress, we do nothing but awake the kernel thread to 724d7e43844e40e07cadc48f1733b9738659f83b38cMatthias Dahl process the data if necessary. */ 7251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((status = ca->pub->read_cam_control(ca->pub, slot, CTRLIF_STATUS)) < 0) 7261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto exitnowrite; 7271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (status & (STATUSREG_DA | STATUSREG_RE)) { 728d7e43844e40e07cadc48f1733b9738659f83b38cMatthias Dahl if (status & STATUSREG_DA) 729d7e43844e40e07cadc48f1733b9738659f83b38cMatthias Dahl dvb_ca_en50221_thread_wakeup(ca); 730d7e43844e40e07cadc48f1733b9738659f83b38cMatthias Dahl 7311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds status = -EAGAIN; 7321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto exitnowrite; 7331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 7341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* OK, set HC bit */ 7361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((status = ca->pub->write_cam_control(ca->pub, slot, CTRLIF_COMMAND, 7371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds IRQEN | CMDREG_HC)) != 0) 7381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto exit; 7391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* check if interface is still free */ 7411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((status = ca->pub->read_cam_control(ca->pub, slot, CTRLIF_STATUS)) < 0) 7421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto exit; 7431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!(status & STATUSREG_FR)) { 7441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* it wasn't free => try again later */ 7451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds status = -EAGAIN; 7461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto exit; 7471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 7481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* send the amount of data */ 7501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((status = ca->pub->write_cam_control(ca->pub, slot, CTRLIF_SIZE_HIGH, bytes_write >> 8)) != 0) 7511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto exit; 7521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((status = ca->pub->write_cam_control(ca->pub, slot, CTRLIF_SIZE_LOW, 7531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bytes_write & 0xff)) != 0) 7541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto exit; 7551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* send the buffer */ 7571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0; i < bytes_write; i++) { 7581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((status = ca->pub->write_cam_control(ca->pub, slot, CTRLIF_DATA, buf[i])) != 0) 7591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto exit; 7601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 7611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* check for write error (WE should now be 0) */ 7631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((status = ca->pub->read_cam_control(ca->pub, slot, CTRLIF_STATUS)) < 0) 7641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto exit; 7651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (status & STATUSREG_WE) { 7661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_LINKINIT; 7671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds status = -EIO; 7681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto exit; 7691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 7701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds status = bytes_write; 7711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dprintk("Wrote CA packet for slot %i, connection id 0x%x last_frag:%i size:0x%x\n", slot, 7731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds buf[0], (buf[1] & 0x80) == 0, bytes_write); 7741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsexit: 7761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ca->pub->write_cam_control(ca->pub, slot, CTRLIF_COMMAND, IRQEN); 7771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsexitnowrite: 7791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return status; 7801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 7811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsEXPORT_SYMBOL(dvb_ca_en50221_camchange_irq); 7821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* ******************************************************************************** */ 7861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* EN50221 higher level functions */ 7871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/** 7901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * A CAM has been removed => shut it down. 7911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 7921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @param ca CA instance. 7931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @param slot Slot to shut down. 7941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 7951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int dvb_ca_en50221_slot_shutdown(struct dvb_ca_private *ca, int slot) 7961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 79746b4f7c176a2dd4c60ddb7c80bd09ea2f3220674Harvey Harrison dprintk("%s\n", __func__); 7981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ca->pub->slot_shutdown(ca->pub, slot); 8001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_NONE; 8011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* need to wake up all processes to check if they're now 8031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds trying to write to a defunct CAM */ 8041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds wake_up_interruptible(&ca->wait_queue); 8051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dprintk("Slot %i shutdown\n", slot); 8071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* success */ 8091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 8101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 8111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsEXPORT_SYMBOL(dvb_ca_en50221_camready_irq); 8121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/** 8151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * A CAMCHANGE IRQ has occurred. 8161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 8171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @param ca CA instance. 8181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @param slot Slot concerned. 8191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @param change_type One of the DVB_CA_CAMCHANGE_* values. 8201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 8211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid dvb_ca_en50221_camchange_irq(struct dvb_ca_en50221 *pubca, int slot, int change_type) 8221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 8230c53c70f6afa2d3f4d416d8c0e9a219c2f6b7cb6Johannes Stezenbach struct dvb_ca_private *ca = pubca->private; 8241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dprintk("CAMCHANGE IRQ slot:%i change_type:%i\n", slot, change_type); 8261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (change_type) { 8281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case DVB_CA_EN50221_CAMCHANGE_REMOVED: 8291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case DVB_CA_EN50221_CAMCHANGE_INSERTED: 8301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 8311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds default: 8331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 8341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 8351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ca->slot_info[slot].camchange_type = change_type; 8371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds atomic_inc(&ca->slot_info[slot].camchange_count); 8381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dvb_ca_en50221_thread_wakeup(ca); 8391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 8401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsEXPORT_SYMBOL(dvb_ca_en50221_frda_irq); 8411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/** 8441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * A CAMREADY IRQ has occurred. 8451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 8461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @param ca CA instance. 8471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @param slot Slot concerned. 8481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 8491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid dvb_ca_en50221_camready_irq(struct dvb_ca_en50221 *pubca, int slot) 8501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 8510c53c70f6afa2d3f4d416d8c0e9a219c2f6b7cb6Johannes Stezenbach struct dvb_ca_private *ca = pubca->private; 8521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dprintk("CAMREADY IRQ slot:%i\n", slot); 8541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ca->slot_info[slot].slot_state == DVB_CA_SLOTSTATE_WAITREADY) { 8561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_VALIDATE; 8571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dvb_ca_en50221_thread_wakeup(ca); 8581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 8591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 8601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/** 8631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * An FR or DA IRQ has occurred. 8641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 8651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @param ca CA instance. 8661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @param slot Slot concerned. 8671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 8681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid dvb_ca_en50221_frda_irq(struct dvb_ca_en50221 *pubca, int slot) 8691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 8700c53c70f6afa2d3f4d416d8c0e9a219c2f6b7cb6Johannes Stezenbach struct dvb_ca_private *ca = pubca->private; 8711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int flags; 8721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dprintk("FR/DA IRQ slot:%i\n", slot); 8741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (ca->slot_info[slot].slot_state) { 8761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case DVB_CA_SLOTSTATE_LINKINIT: 8771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds flags = ca->pub->read_cam_control(pubca, slot, CTRLIF_STATUS); 8781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (flags & STATUSREG_DA) { 8791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dprintk("CAM supports DA IRQ\n"); 8801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ca->slot_info[slot].da_irq_supported = 1; 8811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 8821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 8831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case DVB_CA_SLOTSTATE_RUNNING: 8851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ca->open) 886ded928468407c8e08dcb6aedb91aaa97b80d5752Andrew de Quincey dvb_ca_en50221_thread_wakeup(ca); 8871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 8881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 8891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 8901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* ******************************************************************************** */ 8941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* EN50221 thread functions */ 8951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/** 8971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Wake up the DVB CA thread 8981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 8991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @param ca CA instance. 9001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 9011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void dvb_ca_en50221_thread_wakeup(struct dvb_ca_private *ca) 9021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 9031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 90446b4f7c176a2dd4c60ddb7c80bd09ea2f3220674Harvey Harrison dprintk("%s\n", __func__); 9051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ca->wakeup = 1; 9071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mb(); 9089320874a3e6aea7044a4a7eedeab13db990424abChristoph Hellwig wake_up_process(ca->thread); 9091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 9101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/** 9121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Update the delay used by the thread. 9131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 9141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @param ca CA instance. 9151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 9161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void dvb_ca_en50221_thread_update_delay(struct dvb_ca_private *ca) 9171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 9181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int delay; 9191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int curdelay = 100000000; 9201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int slot; 9211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 92271a35fe2a345eb3704e1f1b4da65451d3e2b8c2eRobert Schedel /* Beware of too high polling frequency, because one polling 92371a35fe2a345eb3704e1f1b4da65451d3e2b8c2eRobert Schedel * call might take several hundred milliseconds until timeout! 92471a35fe2a345eb3704e1f1b4da65451d3e2b8c2eRobert Schedel */ 9251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (slot = 0; slot < ca->slot_count; slot++) { 9261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (ca->slot_info[slot].slot_state) { 9271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds default: 9281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case DVB_CA_SLOTSTATE_NONE: 92971a35fe2a345eb3704e1f1b4da65451d3e2b8c2eRobert Schedel delay = HZ * 60; /* 60s */ 93071a35fe2a345eb3704e1f1b4da65451d3e2b8c2eRobert Schedel if (!(ca->flags & DVB_CA_EN50221_FLAG_IRQ_CAMCHANGE)) 93171a35fe2a345eb3704e1f1b4da65451d3e2b8c2eRobert Schedel delay = HZ * 5; /* 5s */ 93271a35fe2a345eb3704e1f1b4da65451d3e2b8c2eRobert Schedel break; 9331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case DVB_CA_SLOTSTATE_INVALID: 93471a35fe2a345eb3704e1f1b4da65451d3e2b8c2eRobert Schedel delay = HZ * 60; /* 60s */ 93571a35fe2a345eb3704e1f1b4da65451d3e2b8c2eRobert Schedel if (!(ca->flags & DVB_CA_EN50221_FLAG_IRQ_CAMCHANGE)) 93671a35fe2a345eb3704e1f1b4da65451d3e2b8c2eRobert Schedel delay = HZ / 10; /* 100ms */ 9371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 9381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case DVB_CA_SLOTSTATE_UNINITIALISED: 9401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case DVB_CA_SLOTSTATE_WAITREADY: 9411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case DVB_CA_SLOTSTATE_VALIDATE: 9421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case DVB_CA_SLOTSTATE_WAITFR: 9431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case DVB_CA_SLOTSTATE_LINKINIT: 94471a35fe2a345eb3704e1f1b4da65451d3e2b8c2eRobert Schedel delay = HZ / 10; /* 100ms */ 9451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 9461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case DVB_CA_SLOTSTATE_RUNNING: 94871a35fe2a345eb3704e1f1b4da65451d3e2b8c2eRobert Schedel delay = HZ * 60; /* 60s */ 94971a35fe2a345eb3704e1f1b4da65451d3e2b8c2eRobert Schedel if (!(ca->flags & DVB_CA_EN50221_FLAG_IRQ_CAMCHANGE)) 95071a35fe2a345eb3704e1f1b4da65451d3e2b8c2eRobert Schedel delay = HZ / 10; /* 100ms */ 9511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ca->open) { 9521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((!ca->slot_info[slot].da_irq_supported) || 95371a35fe2a345eb3704e1f1b4da65451d3e2b8c2eRobert Schedel (!(ca->flags & DVB_CA_EN50221_FLAG_IRQ_DA))) 95471a35fe2a345eb3704e1f1b4da65451d3e2b8c2eRobert Schedel delay = HZ / 10; /* 100ms */ 9551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 9561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 9571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 9581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (delay < curdelay) 9601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds curdelay = delay; 9611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 9621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ca->delay = curdelay; 9641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 9651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/** 9691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Kernel thread which monitors CA slots for CAM changes, and performs data transfers. 9701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 9711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int dvb_ca_en50221_thread(void *data) 9721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 9730c53c70f6afa2d3f4d416d8c0e9a219c2f6b7cb6Johannes Stezenbach struct dvb_ca_private *ca = data; 9741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int slot; 9751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int flags; 9761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int status; 9771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int pktcount; 9781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds void *rxbuf; 9791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 98046b4f7c176a2dd4c60ddb7c80bd09ea2f3220674Harvey Harrison dprintk("%s\n", __func__); 9811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* choose the correct initial delay */ 9831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dvb_ca_en50221_thread_update_delay(ca); 9841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* main loop */ 9869320874a3e6aea7044a4a7eedeab13db990424abChristoph Hellwig while (!kthread_should_stop()) { 9871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* sleep for a bit */ 988a39a8ed7beaafe02ce154dfd227f7d734a9f34dcMarco Schluessler if (!ca->wakeup) { 9899320874a3e6aea7044a4a7eedeab13db990424abChristoph Hellwig set_current_state(TASK_INTERRUPTIBLE); 9909320874a3e6aea7044a4a7eedeab13db990424abChristoph Hellwig schedule_timeout(ca->delay); 9919320874a3e6aea7044a4a7eedeab13db990424abChristoph Hellwig if (kthread_should_stop()) 9929320874a3e6aea7044a4a7eedeab13db990424abChristoph Hellwig return 0; 9931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 9941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ca->wakeup = 0; 9951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* go through all the slots processing them */ 9971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (slot = 0; slot < ca->slot_count; slot++) { 9981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 999d7e43844e40e07cadc48f1733b9738659f83b38cMatthias Dahl mutex_lock(&ca->slot_info[slot].slot_lock); 1000d7e43844e40e07cadc48f1733b9738659f83b38cMatthias Dahl 10011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // check the cam status + deal with CAMCHANGEs 10021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while (dvb_ca_en50221_check_camstatus(ca, slot)) { 10031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* clear down an old CI slot if necessary */ 10041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ca->slot_info[slot].slot_state != DVB_CA_SLOTSTATE_NONE) 10051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dvb_ca_en50221_slot_shutdown(ca, slot); 10061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* if a CAM is NOW present, initialise it */ 10081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ca->slot_info[slot].camchange_type == DVB_CA_EN50221_CAMCHANGE_INSERTED) { 10091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_UNINITIALISED; 10101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 10111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* we've handled one CAMCHANGE */ 10131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dvb_ca_en50221_thread_update_delay(ca); 10141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds atomic_dec(&ca->slot_info[slot].camchange_count); 10151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 10161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // CAM state machine 10181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (ca->slot_info[slot].slot_state) { 10191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case DVB_CA_SLOTSTATE_NONE: 10201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case DVB_CA_SLOTSTATE_INVALID: 10211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // no action needed 10221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 10231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case DVB_CA_SLOTSTATE_UNINITIALISED: 10251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_WAITREADY; 10261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ca->pub->slot_reset(ca->pub, slot); 10271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ca->slot_info[slot].timeout = jiffies + (INIT_TIMEOUT_SECS * HZ); 10281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 10291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case DVB_CA_SLOTSTATE_WAITREADY: 10311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (time_after(jiffies, ca->slot_info[slot].timeout)) { 10321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk("dvb_ca adaptor %d: PC card did not respond :(\n", 10331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ca->dvbdev->adapter->num); 10341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_INVALID; 10351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dvb_ca_en50221_thread_update_delay(ca); 10361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 10371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 10381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // no other action needed; will automatically change state when ready 10391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 10401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case DVB_CA_SLOTSTATE_VALIDATE: 10425c1208ba457a1668c81868060c08496a2d053be0Andrew de Quincey if (dvb_ca_en50221_parse_attributes(ca, slot) != 0) { 10435c1208ba457a1668c81868060c08496a2d053be0Andrew de Quincey /* we need this extra check for annoying interfaces like the budget-av */ 10445c1208ba457a1668c81868060c08496a2d053be0Andrew de Quincey if ((!(ca->flags & DVB_CA_EN50221_FLAG_IRQ_CAMCHANGE)) && 10455c1208ba457a1668c81868060c08496a2d053be0Andrew de Quincey (ca->pub->poll_slot_status)) { 1046c6eb8eafdba4ad18b4520a0d28a38bc9e61883eaHans Verkuil status = ca->pub->poll_slot_status(ca->pub, slot, 0); 10475c1208ba457a1668c81868060c08496a2d053be0Andrew de Quincey if (!(status & DVB_CA_EN50221_POLL_CAM_PRESENT)) { 10485c1208ba457a1668c81868060c08496a2d053be0Andrew de Quincey ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_NONE; 10495c1208ba457a1668c81868060c08496a2d053be0Andrew de Quincey dvb_ca_en50221_thread_update_delay(ca); 10505c1208ba457a1668c81868060c08496a2d053be0Andrew de Quincey break; 10515c1208ba457a1668c81868060c08496a2d053be0Andrew de Quincey } 10525c1208ba457a1668c81868060c08496a2d053be0Andrew de Quincey } 10535c1208ba457a1668c81868060c08496a2d053be0Andrew de Quincey 10541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk("dvb_ca adapter %d: Invalid PC card inserted :(\n", 10551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ca->dvbdev->adapter->num); 10561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_INVALID; 10571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dvb_ca_en50221_thread_update_delay(ca); 10581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 10591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 10601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (dvb_ca_en50221_set_configoption(ca, slot) != 0) { 10611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk("dvb_ca adapter %d: Unable to initialise CAM :(\n", 10621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ca->dvbdev->adapter->num); 10631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_INVALID; 10641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dvb_ca_en50221_thread_update_delay(ca); 10651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 10661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 10671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ca->pub->write_cam_control(ca->pub, slot, 10681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds CTRLIF_COMMAND, CMDREG_RS) != 0) { 10691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk("dvb_ca adapter %d: Unable to reset CAM IF\n", 10701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ca->dvbdev->adapter->num); 10711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_INVALID; 10721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dvb_ca_en50221_thread_update_delay(ca); 10731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 10741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 10751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dprintk("DVB CAM validated successfully\n"); 10761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ca->slot_info[slot].timeout = jiffies + (INIT_TIMEOUT_SECS * HZ); 10781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_WAITFR; 10791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ca->wakeup = 1; 10801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 10811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case DVB_CA_SLOTSTATE_WAITFR: 10831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (time_after(jiffies, ca->slot_info[slot].timeout)) { 10841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk("dvb_ca adapter %d: DVB CAM did not respond :(\n", 10851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ca->dvbdev->adapter->num); 10861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_INVALID; 10871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dvb_ca_en50221_thread_update_delay(ca); 10881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 10891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 10901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds flags = ca->pub->read_cam_control(ca->pub, slot, CTRLIF_STATUS); 10921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (flags & STATUSREG_FR) { 10931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_LINKINIT; 10941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ca->wakeup = 1; 10951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 10961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 10971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case DVB_CA_SLOTSTATE_LINKINIT: 10991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (dvb_ca_en50221_link_init(ca, slot) != 0) { 11005c1208ba457a1668c81868060c08496a2d053be0Andrew de Quincey /* we need this extra check for annoying interfaces like the budget-av */ 11015c1208ba457a1668c81868060c08496a2d053be0Andrew de Quincey if ((!(ca->flags & DVB_CA_EN50221_FLAG_IRQ_CAMCHANGE)) && 11025c1208ba457a1668c81868060c08496a2d053be0Andrew de Quincey (ca->pub->poll_slot_status)) { 1103c6eb8eafdba4ad18b4520a0d28a38bc9e61883eaHans Verkuil status = ca->pub->poll_slot_status(ca->pub, slot, 0); 11045c1208ba457a1668c81868060c08496a2d053be0Andrew de Quincey if (!(status & DVB_CA_EN50221_POLL_CAM_PRESENT)) { 11055c1208ba457a1668c81868060c08496a2d053be0Andrew de Quincey ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_NONE; 11065c1208ba457a1668c81868060c08496a2d053be0Andrew de Quincey dvb_ca_en50221_thread_update_delay(ca); 11075c1208ba457a1668c81868060c08496a2d053be0Andrew de Quincey break; 11085c1208ba457a1668c81868060c08496a2d053be0Andrew de Quincey } 11095c1208ba457a1668c81868060c08496a2d053be0Andrew de Quincey } 11105c1208ba457a1668c81868060c08496a2d053be0Andrew de Quincey 11111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk("dvb_ca adapter %d: DVB CAM link initialisation failed :(\n", ca->dvbdev->adapter->num); 11121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_INVALID; 11131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dvb_ca_en50221_thread_update_delay(ca); 11141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 11151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 11161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1117ded928468407c8e08dcb6aedb91aaa97b80d5752Andrew de Quincey if (ca->slot_info[slot].rx_buffer.data == NULL) { 1118ded928468407c8e08dcb6aedb91aaa97b80d5752Andrew de Quincey rxbuf = vmalloc(RX_BUFFER_SIZE); 1119ded928468407c8e08dcb6aedb91aaa97b80d5752Andrew de Quincey if (rxbuf == NULL) { 1120ded928468407c8e08dcb6aedb91aaa97b80d5752Andrew de Quincey printk("dvb_ca adapter %d: Unable to allocate CAM rx buffer :(\n", ca->dvbdev->adapter->num); 1121ded928468407c8e08dcb6aedb91aaa97b80d5752Andrew de Quincey ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_INVALID; 1122ded928468407c8e08dcb6aedb91aaa97b80d5752Andrew de Quincey dvb_ca_en50221_thread_update_delay(ca); 1123ded928468407c8e08dcb6aedb91aaa97b80d5752Andrew de Quincey break; 1124ded928468407c8e08dcb6aedb91aaa97b80d5752Andrew de Quincey } 1125ded928468407c8e08dcb6aedb91aaa97b80d5752Andrew de Quincey dvb_ringbuffer_init(&ca->slot_info[slot].rx_buffer, rxbuf, RX_BUFFER_SIZE); 11261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 11271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ca->pub->slot_ts_enable(ca->pub, slot); 11291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_RUNNING; 11301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dvb_ca_en50221_thread_update_delay(ca); 11311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk("dvb_ca adapter %d: DVB CAM detected and initialised successfully\n", ca->dvbdev->adapter->num); 11321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 11331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case DVB_CA_SLOTSTATE_RUNNING: 11351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!ca->open) 1136d7e43844e40e07cadc48f1733b9738659f83b38cMatthias Dahl break; 11371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1138ded928468407c8e08dcb6aedb91aaa97b80d5752Andrew de Quincey // poll slots for data 11391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pktcount = 0; 11401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while ((status = dvb_ca_en50221_read_data(ca, slot, NULL, 0)) > 0) { 11411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!ca->open) 11421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 11431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* if a CAMCHANGE occurred at some point, do not do any more processing of this slot */ 11451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (dvb_ca_en50221_check_camstatus(ca, slot)) { 11461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // we dont want to sleep on the next iteration so we can handle the cam change 11471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ca->wakeup = 1; 11481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 11491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 11501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* check if we've hit our limit this time */ 11521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (++pktcount >= MAX_RX_PACKETS_PER_ITERATION) { 11531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // dont sleep; there is likely to be more data to read 11541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ca->wakeup = 1; 11551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 11561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 11571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 11581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 11591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1160d7e43844e40e07cadc48f1733b9738659f83b38cMatthias Dahl 1161d7e43844e40e07cadc48f1733b9738659f83b38cMatthias Dahl mutex_unlock(&ca->slot_info[slot].slot_lock); 11621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 11631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 11641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 11661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 11671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* ******************************************************************************** */ 11711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* EN50221 IO interface functions */ 11721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/** 11741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Real ioctl implementation. 11751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * NOTE: CA_SEND_MSG/CA_GET_MSG ioctls have userspace buffers passed to them. 11761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 11771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @param inode Inode concerned. 11781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @param file File concerned. 11791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @param cmd IOCTL command. 11801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @param arg Associated argument. 11811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 11821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @return 0 on success, <0 on error. 11831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 118416ef8def80ea97c3cacdcaa765bdf62b2d94f86dArnd Bergmannstatic int dvb_ca_en50221_io_do_ioctl(struct file *file, 11851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int cmd, void *parg) 11861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 11870c53c70f6afa2d3f4d416d8c0e9a219c2f6b7cb6Johannes Stezenbach struct dvb_device *dvbdev = file->private_data; 11880c53c70f6afa2d3f4d416d8c0e9a219c2f6b7cb6Johannes Stezenbach struct dvb_ca_private *ca = dvbdev->priv; 11891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int err = 0; 11901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int slot; 11911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 119246b4f7c176a2dd4c60ddb7c80bd09ea2f3220674Harvey Harrison dprintk("%s\n", __func__); 11931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (cmd) { 11951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case CA_RESET: 11961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (slot = 0; slot < ca->slot_count; slot++) { 1197d7e43844e40e07cadc48f1733b9738659f83b38cMatthias Dahl mutex_lock(&ca->slot_info[slot].slot_lock); 11981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ca->slot_info[slot].slot_state != DVB_CA_SLOTSTATE_NONE) { 11991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dvb_ca_en50221_slot_shutdown(ca, slot); 12001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ca->flags & DVB_CA_EN50221_FLAG_IRQ_CAMCHANGE) 12011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dvb_ca_en50221_camchange_irq(ca->pub, 12021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds slot, 12031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds DVB_CA_EN50221_CAMCHANGE_INSERTED); 12041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1205d7e43844e40e07cadc48f1733b9738659f83b38cMatthias Dahl mutex_unlock(&ca->slot_info[slot].slot_lock); 12061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 12071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ca->next_read_slot = 0; 12081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dvb_ca_en50221_thread_wakeup(ca); 12091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 12101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case CA_GET_CAP: { 12120c53c70f6afa2d3f4d416d8c0e9a219c2f6b7cb6Johannes Stezenbach struct ca_caps *caps = parg; 12131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds caps->slot_num = ca->slot_count; 12151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds caps->slot_type = CA_CI_LINK; 12161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds caps->descr_num = 0; 12171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds caps->descr_type = 0; 12181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 12191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 12201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case CA_GET_SLOT_INFO: { 12220c53c70f6afa2d3f4d416d8c0e9a219c2f6b7cb6Johannes Stezenbach struct ca_slot_info *info = parg; 12231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((info->num > ca->slot_count) || (info->num < 0)) 12251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 12261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->type = CA_CI_LINK; 12281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->flags = 0; 12291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((ca->slot_info[info->num].slot_state != DVB_CA_SLOTSTATE_NONE) 12301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds && (ca->slot_info[info->num].slot_state != DVB_CA_SLOTSTATE_INVALID)) { 12311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->flags = CA_CI_MODULE_PRESENT; 12321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 12331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ca->slot_info[info->num].slot_state == DVB_CA_SLOTSTATE_RUNNING) { 12341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info->flags |= CA_CI_MODULE_READY; 12351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 12361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 12371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 12381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds default: 12401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds err = -EINVAL; 12411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 12421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 12431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return err; 12451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 12461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/** 12491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Wrapper for ioctl implementation. 12501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 12511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @param inode Inode concerned. 12521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @param file File concerned. 12531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @param cmd IOCTL command. 12541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @param arg Associated argument. 12551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 12561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @return 0 on success, <0 on error. 12571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 125816ef8def80ea97c3cacdcaa765bdf62b2d94f86dArnd Bergmannstatic long dvb_ca_en50221_io_ioctl(struct file *file, 125916ef8def80ea97c3cacdcaa765bdf62b2d94f86dArnd Bergmann unsigned int cmd, unsigned long arg) 12601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 126172024f1ec5164a70d84dd8cf4458fe4064a6b692Arnd Bergmann return dvb_usercopy(file, cmd, arg, dvb_ca_en50221_io_do_ioctl); 12621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 12631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/** 12661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Implementation of write() syscall. 12671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 12681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @param file File structure. 12691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @param buf Source buffer. 12701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @param count Size of source buffer. 12711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @param ppos Position in file (ignored). 12721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 12731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @return Number of bytes read, or <0 on error. 12741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 12751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic ssize_t dvb_ca_en50221_io_write(struct file *file, 12761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds const char __user * buf, size_t count, loff_t * ppos) 12771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 12780c53c70f6afa2d3f4d416d8c0e9a219c2f6b7cb6Johannes Stezenbach struct dvb_device *dvbdev = file->private_data; 12790c53c70f6afa2d3f4d416d8c0e9a219c2f6b7cb6Johannes Stezenbach struct dvb_ca_private *ca = dvbdev->priv; 12801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u8 slot, connection_id; 12811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int status; 1282260f8d7c4cda79b087a182eb03e8574ba41a171eOliver Endriss u8 fragbuf[HOST_LINK_BUF_SIZE]; 12831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int fragpos = 0; 12841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int fraglen; 12851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long timeout; 12861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int written; 12871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 128846b4f7c176a2dd4c60ddb7c80bd09ea2f3220674Harvey Harrison dprintk("%s\n", __func__); 12891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Incoming packet has a 2 byte header. hdr[0] = slot_id, hdr[1] = connection_id */ 12911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (count < 2) 12921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 12931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* extract slot & connection id */ 12951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (copy_from_user(&slot, buf, 1)) 12961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EFAULT; 12971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (copy_from_user(&connection_id, buf + 1, 1)) 12981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EFAULT; 12991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds buf += 2; 13001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds count -= 2; 13011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* check if the slot is actually running */ 13031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ca->slot_info[slot].slot_state != DVB_CA_SLOTSTATE_RUNNING) 13041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 13051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* fragment the packets & store in the buffer */ 13071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while (fragpos < count) { 13081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fraglen = ca->slot_info[slot].link_buf_size - 2; 1309624f0c186978f9cb0ce6582f445922eaaa4a7f4aMauro Carvalho Chehab if (fraglen < 0) 1310624f0c186978f9cb0ce6582f445922eaaa4a7f4aMauro Carvalho Chehab break; 1311624f0c186978f9cb0ce6582f445922eaaa4a7f4aMauro Carvalho Chehab if (fraglen > HOST_LINK_BUF_SIZE - 2) 1312624f0c186978f9cb0ce6582f445922eaaa4a7f4aMauro Carvalho Chehab fraglen = HOST_LINK_BUF_SIZE - 2; 13131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((count - fragpos) < fraglen) 13141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fraglen = count - fragpos; 13151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fragbuf[0] = connection_id; 13171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fragbuf[1] = ((fragpos + fraglen) < count) ? 0x80 : 0x00; 1318e252984c5279dde24fbd6d3efe7fe13dc642e714Dan Carpenter status = copy_from_user(fragbuf + 2, buf + fragpos, fraglen); 1319e252984c5279dde24fbd6d3efe7fe13dc642e714Dan Carpenter if (status) { 1320e252984c5279dde24fbd6d3efe7fe13dc642e714Dan Carpenter status = -EFAULT; 13211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto exit; 1322e252984c5279dde24fbd6d3efe7fe13dc642e714Dan Carpenter } 13231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds timeout = jiffies + HZ / 2; 13251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds written = 0; 13261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while (!time_after(jiffies, timeout)) { 13271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* check the CAM hasn't been removed/reset in the meantime */ 13281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ca->slot_info[slot].slot_state != DVB_CA_SLOTSTATE_RUNNING) { 13291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds status = -EIO; 13301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto exit; 13311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 13321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1333d7e43844e40e07cadc48f1733b9738659f83b38cMatthias Dahl mutex_lock(&ca->slot_info[slot].slot_lock); 13341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds status = dvb_ca_en50221_write_data(ca, slot, fragbuf, fraglen + 2); 1335d7e43844e40e07cadc48f1733b9738659f83b38cMatthias Dahl mutex_unlock(&ca->slot_info[slot].slot_lock); 13361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (status == (fraglen + 2)) { 13371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds written = 1; 13381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 13391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 13401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (status != -EAGAIN) 13411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto exit; 13421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds msleep(1); 13441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 13451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!written) { 13461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds status = -EIO; 13471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto exit; 13481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 13491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fragpos += fraglen; 13511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 13521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds status = count + 2; 13531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsexit: 13551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return status; 13561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 13571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/** 13601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Condition for waking up in dvb_ca_en50221_io_read_condition 13611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 1362ded928468407c8e08dcb6aedb91aaa97b80d5752Andrew de Quinceystatic int dvb_ca_en50221_io_read_condition(struct dvb_ca_private *ca, 1363ded928468407c8e08dcb6aedb91aaa97b80d5752Andrew de Quincey int *result, int *_slot) 13641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 13651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int slot; 13661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int slot_count = 0; 13671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int idx; 1368ded928468407c8e08dcb6aedb91aaa97b80d5752Andrew de Quincey size_t fraglen; 13691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int connection_id = -1; 13701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int found = 0; 13711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u8 hdr[2]; 13721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds slot = ca->next_read_slot; 13741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while ((slot_count < ca->slot_count) && (!found)) { 13751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ca->slot_info[slot].slot_state != DVB_CA_SLOTSTATE_RUNNING) 13761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto nextslot; 13771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ca->slot_info[slot].rx_buffer.data == NULL) { 13791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 13801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 13811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds idx = dvb_ringbuffer_pkt_next(&ca->slot_info[slot].rx_buffer, -1, &fraglen); 13831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while (idx != -1) { 1384b0ba0e3ab6f452321771325b7b5578f9a804f69eAl Viro dvb_ringbuffer_pkt_read(&ca->slot_info[slot].rx_buffer, idx, 0, hdr, 2); 13851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (connection_id == -1) 13861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds connection_id = hdr[0]; 13871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((hdr[0] == connection_id) && ((hdr[1] & 0x80) == 0)) { 13881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *_slot = slot; 13891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds found = 1; 13901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 13911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 13921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds idx = dvb_ringbuffer_pkt_next(&ca->slot_info[slot].rx_buffer, idx, &fraglen); 13941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 13951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1396ded928468407c8e08dcb6aedb91aaa97b80d5752Andrew de Quinceynextslot: 13971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds slot = (slot + 1) % ca->slot_count; 13981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds slot_count++; 13991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 14001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ca->next_read_slot = slot; 14021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return found; 14031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 14041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/** 14071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Implementation of read() syscall. 14081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 14091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @param file File structure. 14101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @param buf Destination buffer. 14111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @param count Size of destination buffer. 14121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @param ppos Position in file (ignored). 14131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 14141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @return Number of bytes read, or <0 on error. 14151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 14161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic ssize_t dvb_ca_en50221_io_read(struct file *file, char __user * buf, 14171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds size_t count, loff_t * ppos) 14181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 14190c53c70f6afa2d3f4d416d8c0e9a219c2f6b7cb6Johannes Stezenbach struct dvb_device *dvbdev = file->private_data; 14200c53c70f6afa2d3f4d416d8c0e9a219c2f6b7cb6Johannes Stezenbach struct dvb_ca_private *ca = dvbdev->priv; 14211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int status; 14221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int result = 0; 14231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u8 hdr[2]; 14241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int slot; 14251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int connection_id = -1; 14261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds size_t idx, idx2; 14271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int last_fragment = 0; 14281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds size_t fraglen; 14291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int pktlen; 14301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int dispose = 0; 14311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 143246b4f7c176a2dd4c60ddb7c80bd09ea2f3220674Harvey Harrison dprintk("%s\n", __func__); 14331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Outgoing packet has a 2 byte header. hdr[0] = slot_id, hdr[1] = connection_id */ 14351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (count < 2) 14361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 14371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* wait for some data */ 14391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((status = dvb_ca_en50221_io_read_condition(ca, &result, &slot)) == 0) { 14401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* if we're in nonblocking mode, exit immediately */ 14421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (file->f_flags & O_NONBLOCK) 14431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EWOULDBLOCK; 14441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* wait for some data */ 14461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds status = wait_event_interruptible(ca->wait_queue, 14471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dvb_ca_en50221_io_read_condition 14481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (ca, &result, &slot)); 14491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 14501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((status < 0) || (result < 0)) { 14511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (result) 14521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return result; 14531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return status; 14541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 14551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds idx = dvb_ringbuffer_pkt_next(&ca->slot_info[slot].rx_buffer, -1, &fraglen); 14571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pktlen = 2; 14581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds do { 14591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (idx == -1) { 14601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk("dvb_ca adapter %d: BUG: read packet ended before last_fragment encountered\n", ca->dvbdev->adapter->num); 14611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds status = -EIO; 14621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto exit; 14631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 14641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1465b0ba0e3ab6f452321771325b7b5578f9a804f69eAl Viro dvb_ringbuffer_pkt_read(&ca->slot_info[slot].rx_buffer, idx, 0, hdr, 2); 14661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (connection_id == -1) 14671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds connection_id = hdr[0]; 14681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (hdr[0] == connection_id) { 14691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (pktlen < count) { 14701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((pktlen + fraglen - 2) > count) { 14711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fraglen = count - pktlen; 14721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 14731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fraglen -= 2; 14741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 14751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1476b0ba0e3ab6f452321771325b7b5578f9a804f69eAl Viro if ((status = dvb_ringbuffer_pkt_read_user(&ca->slot_info[slot].rx_buffer, idx, 2, 1477b0ba0e3ab6f452321771325b7b5578f9a804f69eAl Viro buf + pktlen, fraglen)) < 0) { 14781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto exit; 14791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 14801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pktlen += fraglen; 14811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 14821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((hdr[1] & 0x80) == 0) 14841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds last_fragment = 1; 14851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dispose = 1; 14861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 14871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds idx2 = dvb_ringbuffer_pkt_next(&ca->slot_info[slot].rx_buffer, idx, &fraglen); 14891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (dispose) 14901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dvb_ringbuffer_pkt_dispose(&ca->slot_info[slot].rx_buffer, idx); 14911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds idx = idx2; 14921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dispose = 0; 14931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } while (!last_fragment); 14941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds hdr[0] = slot; 14961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds hdr[1] = connection_id; 1497e252984c5279dde24fbd6d3efe7fe13dc642e714Dan Carpenter status = copy_to_user(buf, hdr, 2); 1498e252984c5279dde24fbd6d3efe7fe13dc642e714Dan Carpenter if (status) { 1499e252984c5279dde24fbd6d3efe7fe13dc642e714Dan Carpenter status = -EFAULT; 15001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto exit; 1501e252984c5279dde24fbd6d3efe7fe13dc642e714Dan Carpenter } 15021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds status = pktlen; 15031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1504ded928468407c8e08dcb6aedb91aaa97b80d5752Andrew de Quinceyexit: 15051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return status; 15061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 15071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/** 15101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Implementation of file open syscall. 15111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 15121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @param inode Inode concerned. 15131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @param file File concerned. 15141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 15151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @return 0 on success, <0 on failure. 15161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 15171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int dvb_ca_en50221_io_open(struct inode *inode, struct file *file) 15181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 15190c53c70f6afa2d3f4d416d8c0e9a219c2f6b7cb6Johannes Stezenbach struct dvb_device *dvbdev = file->private_data; 15200c53c70f6afa2d3f4d416d8c0e9a219c2f6b7cb6Johannes Stezenbach struct dvb_ca_private *ca = dvbdev->priv; 15211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int err; 15221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i; 15231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 152446b4f7c176a2dd4c60ddb7c80bd09ea2f3220674Harvey Harrison dprintk("%s\n", __func__); 15251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!try_module_get(ca->pub->owner)) 15271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EIO; 15281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds err = dvb_generic_open(inode, file); 1530226835d7e0a1136bce2a0b923e0832ab47450a30Marco Schluessler if (err < 0) { 1531226835d7e0a1136bce2a0b923e0832ab47450a30Marco Schluessler module_put(ca->pub->owner); 15321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return err; 1533226835d7e0a1136bce2a0b923e0832ab47450a30Marco Schluessler } 15341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0; i < ca->slot_count; i++) { 15361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ca->slot_info[i].slot_state == DVB_CA_SLOTSTATE_RUNNING) { 15381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ca->slot_info[i].rx_buffer.data != NULL) { 1539ded928468407c8e08dcb6aedb91aaa97b80d5752Andrew de Quincey /* it is safe to call this here without locks because 1540ded928468407c8e08dcb6aedb91aaa97b80d5752Andrew de Quincey * ca->open == 0. Data is not read in this case */ 15411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dvb_ringbuffer_flush(&ca->slot_info[i].rx_buffer); 15421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 15431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 15441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 15451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ca->open = 1; 15471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dvb_ca_en50221_thread_update_delay(ca); 15481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dvb_ca_en50221_thread_wakeup(ca); 15491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 15511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 15521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/** 15551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Implementation of file close syscall. 15561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 15571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @param inode Inode concerned. 15581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @param file File concerned. 15591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 15601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @return 0 on success, <0 on failure. 15611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 15621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int dvb_ca_en50221_io_release(struct inode *inode, struct file *file) 15631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 15640c53c70f6afa2d3f4d416d8c0e9a219c2f6b7cb6Johannes Stezenbach struct dvb_device *dvbdev = file->private_data; 15650c53c70f6afa2d3f4d416d8c0e9a219c2f6b7cb6Johannes Stezenbach struct dvb_ca_private *ca = dvbdev->priv; 15660c12c1bfc432477e38ba76f680be4b3f55112a8eMarco Schluessler int err; 15671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 156846b4f7c176a2dd4c60ddb7c80bd09ea2f3220674Harvey Harrison dprintk("%s\n", __func__); 15691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* mark the CA device as closed */ 15711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ca->open = 0; 15721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dvb_ca_en50221_thread_update_delay(ca); 15731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds err = dvb_generic_release(inode, file); 15751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds module_put(ca->pub->owner); 15771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15780c12c1bfc432477e38ba76f680be4b3f55112a8eMarco Schluessler return err; 15791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 15801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/** 15831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Implementation of poll() syscall. 15841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 15851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @param file File concerned. 15861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @param wait poll wait table. 15871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 15881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @return Standard poll mask. 15891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 15901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic unsigned int dvb_ca_en50221_io_poll(struct file *file, poll_table * wait) 15911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 15920c53c70f6afa2d3f4d416d8c0e9a219c2f6b7cb6Johannes Stezenbach struct dvb_device *dvbdev = file->private_data; 15930c53c70f6afa2d3f4d416d8c0e9a219c2f6b7cb6Johannes Stezenbach struct dvb_ca_private *ca = dvbdev->priv; 15941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int mask = 0; 15951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int slot; 15961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int result = 0; 15971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 159846b4f7c176a2dd4c60ddb7c80bd09ea2f3220674Harvey Harrison dprintk("%s\n", __func__); 15991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 16001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (dvb_ca_en50221_io_read_condition(ca, &result, &slot) == 1) { 16011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mask |= POLLIN; 16021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 16031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 16041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* if there is something, return now */ 16051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (mask) 16061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return mask; 16071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 16081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* wait for something to happen */ 16091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds poll_wait(file, &ca->wait_queue, wait); 16101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 16111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (dvb_ca_en50221_io_read_condition(ca, &result, &slot) == 1) { 16121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mask |= POLLIN; 16131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 16141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 16151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return mask; 16161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 16171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsEXPORT_SYMBOL(dvb_ca_en50221_init); 16181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 16191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1620784e29d2031b535637f65a8b81fb0871c7c51b3fJan Engelhardtstatic const struct file_operations dvb_ca_fops = { 16211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .owner = THIS_MODULE, 16221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .read = dvb_ca_en50221_io_read, 16231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .write = dvb_ca_en50221_io_write, 162416ef8def80ea97c3cacdcaa765bdf62b2d94f86dArnd Bergmann .unlocked_ioctl = dvb_ca_en50221_io_ioctl, 16251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .open = dvb_ca_en50221_io_open, 16261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .release = dvb_ca_en50221_io_release, 16271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .poll = dvb_ca_en50221_io_poll, 16286038f373a3dc1f1c26496e60b6c40b164716f07eArnd Bergmann .llseek = noop_llseek, 16291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 16301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 16311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct dvb_device dvbdev_ca = { 16321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .priv = NULL, 16331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .users = 1, 16341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .readers = 1, 16351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .writers = 1, 16361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .fops = &dvb_ca_fops, 16371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 16381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 16391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 16401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* ******************************************************************************** */ 16411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Initialisation/shutdown functions */ 16421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 16431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 16441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/** 16451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Initialise a new DVB CA EN50221 interface device. 16461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 16471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @param dvb_adapter DVB adapter to attach the new CA device to. 16481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @param ca The dvb_ca instance. 16491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @param flags Flags describing the CA device (DVB_CA_FLAG_*). 16501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @param slot_count Number of slots supported. 16511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 16521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @return 0 on success, nonzero on failure 16531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 16541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint dvb_ca_en50221_init(struct dvb_adapter *dvb_adapter, 16551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct dvb_ca_en50221 *pubca, int flags, int slot_count) 16561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 16571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int ret; 16581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct dvb_ca_private *ca = NULL; 16591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i; 16601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 166146b4f7c176a2dd4c60ddb7c80bd09ea2f3220674Harvey Harrison dprintk("%s\n", __func__); 16621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 16631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (slot_count < 1) 16641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 16651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 16661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* initialise the system data */ 16677408187d223f63d46a13b6a35b8f96b032c2f623Panagiotis Issaris if ((ca = kzalloc(sizeof(struct dvb_ca_private), GFP_KERNEL)) == NULL) { 16681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret = -ENOMEM; 16691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto error; 16701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 16711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ca->pub = pubca; 16721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ca->flags = flags; 16731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ca->slot_count = slot_count; 16747408187d223f63d46a13b6a35b8f96b032c2f623Panagiotis Issaris if ((ca->slot_info = kcalloc(slot_count, sizeof(struct dvb_ca_slot), GFP_KERNEL)) == NULL) { 16751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret = -ENOMEM; 16761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto error; 16771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 16781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds init_waitqueue_head(&ca->wait_queue); 16791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ca->open = 0; 16801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ca->wakeup = 0; 16811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ca->next_read_slot = 0; 16821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pubca->private = ca; 16831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 16841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* register the DVB device */ 16851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret = dvb_register_device(dvb_adapter, &ca->dvbdev, &dvbdev_ca, ca, DVB_DEVICE_CA); 16861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ret) 16871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto error; 16881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 16891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* now initialise each slot */ 16901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0; i < slot_count; i++) { 16911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memset(&ca->slot_info[i], 0, sizeof(struct dvb_ca_slot)); 16921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ca->slot_info[i].slot_state = DVB_CA_SLOTSTATE_NONE; 16931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds atomic_set(&ca->slot_info[i].camchange_count, 0); 16941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ca->slot_info[i].camchange_type = DVB_CA_EN50221_CAMCHANGE_REMOVED; 1695d7e43844e40e07cadc48f1733b9738659f83b38cMatthias Dahl mutex_init(&ca->slot_info[i].slot_lock); 16961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 16971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 16981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (signal_pending(current)) { 16991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret = -EINTR; 17001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto error; 17011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 17021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mb(); 17031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 17041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* create a kthread for monitoring this CA device */ 17059320874a3e6aea7044a4a7eedeab13db990424abChristoph Hellwig ca->thread = kthread_run(dvb_ca_en50221_thread, ca, "kdvb-ca-%i:%i", 17069320874a3e6aea7044a4a7eedeab13db990424abChristoph Hellwig ca->dvbdev->adapter->num, ca->dvbdev->id); 17079320874a3e6aea7044a4a7eedeab13db990424abChristoph Hellwig if (IS_ERR(ca->thread)) { 17089320874a3e6aea7044a4a7eedeab13db990424abChristoph Hellwig ret = PTR_ERR(ca->thread); 17099320874a3e6aea7044a4a7eedeab13db990424abChristoph Hellwig printk("dvb_ca_init: failed to start kernel_thread (%d)\n", 17109320874a3e6aea7044a4a7eedeab13db990424abChristoph Hellwig ret); 17111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto error; 17121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 17131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 17141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1715ded928468407c8e08dcb6aedb91aaa97b80d5752Andrew de Quinceyerror: 17161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ca != NULL) { 17171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ca->dvbdev != NULL) 17181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dvb_unregister_device(ca->dvbdev); 17191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kfree(ca->slot_info); 17201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kfree(ca); 17211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 17221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pubca->private = NULL; 17231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return ret; 17241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 17251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsEXPORT_SYMBOL(dvb_ca_en50221_release); 17261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 17271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 17281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 17291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/** 17301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Release a DVB CA EN50221 interface device. 17311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 17321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @param ca_dev The dvb_device_t instance for the CA device. 17331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @param ca The associated dvb_ca instance. 17341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 17351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid dvb_ca_en50221_release(struct dvb_ca_en50221 *pubca) 17361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 17370c53c70f6afa2d3f4d416d8c0e9a219c2f6b7cb6Johannes Stezenbach struct dvb_ca_private *ca = pubca->private; 17381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i; 17391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 174046b4f7c176a2dd4c60ddb7c80bd09ea2f3220674Harvey Harrison dprintk("%s\n", __func__); 17411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 17421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* shutdown the thread if there was one */ 17439320874a3e6aea7044a4a7eedeab13db990424abChristoph Hellwig kthread_stop(ca->thread); 17441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 17451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0; i < ca->slot_count; i++) { 17461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dvb_ca_en50221_slot_shutdown(ca, i); 174735dc0fefb18eea1b4180a8fafbb83db6a9b7c401Michael Krufky vfree(ca->slot_info[i].rx_buffer.data); 17481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 17491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kfree(ca->slot_info); 17501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dvb_unregister_device(ca->dvbdev); 17511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kfree(ca); 17521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pubca->private = NULL; 17531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1754