// SPDX-License-Identifier: GPL-2.0-or-later /* * dvb_ca.c: generic DVB functions for EN50221 CAM interfaces * * Copyright (C) 2004 Andrew de Quincey * * Parts of this file were based on sources as follows: * * Copyright (C) 2003 Ralph Metzler <[email protected]> * * based on code: * * Copyright (C) 1999-2002 Ralph Metzler * & Marcus Metzler for convergence integrated media GmbH */ #define pr_fmt(fmt) … #include <linux/errno.h> #include <linux/slab.h> #include <linux/list.h> #include <linux/module.h> #include <linux/nospec.h> #include <linux/vmalloc.h> #include <linux/delay.h> #include <linux/spinlock.h> #include <linux/sched/signal.h> #include <linux/kthread.h> #include <media/dvb_ca_en50221.h> #include <media/dvb_ringbuffer.h> static int dvb_ca_en50221_debug; module_param_named(cam_debug, dvb_ca_en50221_debug, int, 0644); MODULE_PARM_DESC(…) …; #define dprintk(fmt, arg...) … #define INIT_TIMEOUT_SECS … #define HOST_LINK_BUF_SIZE … #define RX_BUFFER_SIZE … #define MAX_RX_PACKETS_PER_ITERATION … #define CTRLIF_DATA … #define CTRLIF_COMMAND … #define CTRLIF_STATUS … #define CTRLIF_SIZE_LOW … #define CTRLIF_SIZE_HIGH … #define CMDREG_HC … #define CMDREG_SW … #define CMDREG_SR … #define CMDREG_RS … #define CMDREG_FRIE … #define CMDREG_DAIE … #define IRQEN … #define STATUSREG_RE … #define STATUSREG_WE … #define STATUSREG_FR … #define STATUSREG_DA … #define DVB_CA_SLOTSTATE_NONE … #define DVB_CA_SLOTSTATE_UNINITIALISED … #define DVB_CA_SLOTSTATE_RUNNING … #define DVB_CA_SLOTSTATE_INVALID … #define DVB_CA_SLOTSTATE_WAITREADY … #define DVB_CA_SLOTSTATE_VALIDATE … #define DVB_CA_SLOTSTATE_WAITFR … #define DVB_CA_SLOTSTATE_LINKINIT … /* Information on a CA slot */ struct dvb_ca_slot { … }; /* Private CA-interface information */ struct dvb_ca_private { … }; static void dvb_ca_private_free(struct dvb_ca_private *ca) { … } static void dvb_ca_private_release(struct kref *ref) { … } static void dvb_ca_private_get(struct dvb_ca_private *ca) { … } static void dvb_ca_private_put(struct dvb_ca_private *ca) { … } static void dvb_ca_en50221_thread_wakeup(struct dvb_ca_private *ca); static int dvb_ca_en50221_read_data(struct dvb_ca_private *ca, int slot, u8 *ebuf, int ecount); static int dvb_ca_en50221_write_data(struct dvb_ca_private *ca, int slot, u8 *ebuf, int ecount, int size_write_flag); /** * findstr - Safely find needle in haystack. * * @haystack: Buffer to look in. * @hlen: Number of bytes in haystack. * @needle: Buffer to find. * @nlen: Number of bytes in needle. * return: Pointer into haystack needle was found at, or NULL if not found. */ static char *findstr(char *haystack, int hlen, char *needle, int nlen) { … } /* ************************************************************************** */ /* EN50221 physical interface functions */ /* * dvb_ca_en50221_check_camstatus - Check CAM status. */ static int dvb_ca_en50221_check_camstatus(struct dvb_ca_private *ca, int slot) { … } /** * dvb_ca_en50221_wait_if_status - Wait for flags to become set on the STATUS * register on a CAM interface, checking for errors and timeout. * * @ca: CA instance. * @slot: Slot on interface. * @waitfor: Flags to wait for. * @timeout_hz: Timeout in milliseconds. * * return: 0 on success, nonzero on error. */ static int dvb_ca_en50221_wait_if_status(struct dvb_ca_private *ca, int slot, u8 waitfor, int timeout_hz) { … } /** * dvb_ca_en50221_link_init - Initialise the link layer connection to a CAM. * * @ca: CA instance. * @slot: Slot id. * * return: 0 on success, nonzero on failure. */ static int dvb_ca_en50221_link_init(struct dvb_ca_private *ca, int slot) { … } /** * dvb_ca_en50221_read_tuple - Read a tuple from attribute memory. * * @ca: CA instance. * @slot: Slot id. * @address: Address to read from. Updated. * @tuple_type: Tuple id byte. Updated. * @tuple_length: Tuple length. Updated. * @tuple: Dest buffer for tuple (must be 256 bytes). Updated. * * return: 0 on success, nonzero on error. */ static int dvb_ca_en50221_read_tuple(struct dvb_ca_private *ca, int slot, int *address, int *tuple_type, int *tuple_length, u8 *tuple) { … } /** * dvb_ca_en50221_parse_attributes - Parse attribute memory of a CAM module, * extracting Config register, and checking it is a DVB CAM module. * * @ca: CA instance. * @slot: Slot id. * * return: 0 on success, <0 on failure. */ static int dvb_ca_en50221_parse_attributes(struct dvb_ca_private *ca, int slot) { … } /** * dvb_ca_en50221_set_configoption - Set CAM's configoption correctly. * * @ca: CA instance. * @slot: Slot containing the CAM. */ static int dvb_ca_en50221_set_configoption(struct dvb_ca_private *ca, int slot) { … } /** * dvb_ca_en50221_read_data - This function talks to an EN50221 CAM control * interface. It reads a buffer of data from the CAM. The data can either * be stored in a supplied buffer, or automatically be added to the slot's * rx_buffer. * * @ca: CA instance. * @slot: Slot to read from. * @ebuf: If non-NULL, the data will be written to this buffer. If NULL, * the data will be added into the buffering system as a normal * fragment. * @ecount: Size of ebuf. Ignored if ebuf is NULL. * * return: Number of bytes read, or < 0 on error */ static int dvb_ca_en50221_read_data(struct dvb_ca_private *ca, int slot, u8 *ebuf, int ecount) { … } /** * dvb_ca_en50221_write_data - This function talks to an EN50221 CAM control * interface. It writes a buffer of data to a CAM. * * @ca: CA instance. * @slot: Slot to write to. * @buf: The data in this buffer is treated as a complete link-level packet to * be written. * @bytes_write: Size of ebuf. * @size_write_flag: A flag on Command Register which says whether the link size * information will be writen or not. * * return: Number of bytes written, or < 0 on error. */ static int dvb_ca_en50221_write_data(struct dvb_ca_private *ca, int slot, u8 *buf, int bytes_write, int size_write_flag) { … } /* ************************************************************************** */ /* EN50221 higher level functions */ /** * dvb_ca_en50221_slot_shutdown - A CAM has been removed => shut it down. * * @ca: CA instance. * @slot: Slot to shut down. */ static int dvb_ca_en50221_slot_shutdown(struct dvb_ca_private *ca, int slot) { … } /** * dvb_ca_en50221_camchange_irq - A CAMCHANGE IRQ has occurred. * * @pubca: CA instance. * @slot: Slot concerned. * @change_type: One of the DVB_CA_CAMCHANGE_* values. */ void dvb_ca_en50221_camchange_irq(struct dvb_ca_en50221 *pubca, int slot, int change_type) { … } EXPORT_SYMBOL(…); /** * dvb_ca_en50221_camready_irq - A CAMREADY IRQ has occurred. * * @pubca: CA instance. * @slot: Slot concerned. */ void dvb_ca_en50221_camready_irq(struct dvb_ca_en50221 *pubca, int slot) { … } EXPORT_SYMBOL(…); /** * dvb_ca_en50221_frda_irq - An FR or DA IRQ has occurred. * * @pubca: CA instance. * @slot: Slot concerned. */ void dvb_ca_en50221_frda_irq(struct dvb_ca_en50221 *pubca, int slot) { … } EXPORT_SYMBOL(…); /* ************************************************************************** */ /* EN50221 thread functions */ /** * dvb_ca_en50221_thread_wakeup - Wake up the DVB CA thread * * @ca: CA instance. */ static void dvb_ca_en50221_thread_wakeup(struct dvb_ca_private *ca) { … } /** * dvb_ca_en50221_thread_update_delay - Update the delay used by the thread. * * @ca: CA instance. */ static void dvb_ca_en50221_thread_update_delay(struct dvb_ca_private *ca) { … } /** * dvb_ca_en50221_poll_cam_gone - Poll if the CAM is gone. * * @ca: CA instance. * @slot: Slot to process. * return:: 0 .. no change * 1 .. CAM state changed */ static int dvb_ca_en50221_poll_cam_gone(struct dvb_ca_private *ca, int slot) { … } /** * dvb_ca_en50221_thread_state_machine - Thread state machine for one CA slot * to perform the data transfer. * * @ca: CA instance. * @slot: Slot to process. */ static void dvb_ca_en50221_thread_state_machine(struct dvb_ca_private *ca, int slot) { … } /* * Kernel thread which monitors CA slots for CAM changes, and performs data * transfers. */ static int dvb_ca_en50221_thread(void *data) { … } /* ************************************************************************** */ /* EN50221 IO interface functions */ /** * dvb_ca_en50221_io_do_ioctl - Real ioctl implementation. * * @file: File concerned. * @cmd: IOCTL command. * @parg: Associated argument. * * NOTE: CA_SEND_MSG/CA_GET_MSG ioctls have userspace buffers passed to them. * * return: 0 on success, <0 on error. */ static int dvb_ca_en50221_io_do_ioctl(struct file *file, unsigned int cmd, void *parg) { … } /** * dvb_ca_en50221_io_ioctl - Wrapper for ioctl implementation. * * @file: File concerned. * @cmd: IOCTL command. * @arg: Associated argument. * * return: 0 on success, <0 on error. */ static long dvb_ca_en50221_io_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { … } /** * dvb_ca_en50221_io_write - Implementation of write() syscall. * * @file: File structure. * @buf: Source buffer. * @count: Size of source buffer. * @ppos: Position in file (ignored). * * return: Number of bytes read, or <0 on error. */ static ssize_t dvb_ca_en50221_io_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) { … } /* * Condition for waking up in dvb_ca_en50221_io_read_condition */ static int dvb_ca_en50221_io_read_condition(struct dvb_ca_private *ca, int *result, int *_slot) { … } /** * dvb_ca_en50221_io_read - Implementation of read() syscall. * * @file: File structure. * @buf: Destination buffer. * @count: Size of destination buffer. * @ppos: Position in file (ignored). * * return: Number of bytes read, or <0 on error. */ static ssize_t dvb_ca_en50221_io_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) { … } /** * dvb_ca_en50221_io_open - Implementation of file open syscall. * * @inode: Inode concerned. * @file: File concerned. * * return: 0 on success, <0 on failure. */ static int dvb_ca_en50221_io_open(struct inode *inode, struct file *file) { … } /** * dvb_ca_en50221_io_release - Implementation of file close syscall. * * @inode: Inode concerned. * @file: File concerned. * * return: 0 on success, <0 on failure. */ static int dvb_ca_en50221_io_release(struct inode *inode, struct file *file) { … } /** * dvb_ca_en50221_io_poll - Implementation of poll() syscall. * * @file: File concerned. * @wait: poll wait table. * * return: Standard poll mask. */ static __poll_t dvb_ca_en50221_io_poll(struct file *file, poll_table *wait) { … } static const struct file_operations dvb_ca_fops = …; static const struct dvb_device dvbdev_ca = …; /* ************************************************************************** */ /* Initialisation/shutdown functions */ /** * dvb_ca_en50221_init - Initialise a new DVB CA EN50221 interface device. * * @dvb_adapter: DVB adapter to attach the new CA device to. * @pubca: The dvb_ca instance. * @flags: Flags describing the CA device (DVB_CA_FLAG_*). * @slot_count: Number of slots supported. * * return: 0 on success, nonzero on failure */ int dvb_ca_en50221_init(struct dvb_adapter *dvb_adapter, struct dvb_ca_en50221 *pubca, int flags, int slot_count) { … } EXPORT_SYMBOL(…); /** * dvb_ca_en50221_release - Release a DVB CA EN50221 interface device. * * @pubca: The associated dvb_ca instance. */ void dvb_ca_en50221_release(struct dvb_ca_en50221 *pubca) { … } EXPORT_SYMBOL(…);