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