File Index
Files and directories
Sign in
FILE

av7110_hw.c

File preview with syntax highlighting.

linux-6.19.14/drivers/staging/media/av7110/av7110_hw.c C
   1// SPDX-License-Identifier: GPL-2.0-or-later
   2/*
   3 * driver for the SAA7146 based AV110 cards
   4 * - av7110 low level hardware access and firmware interface
   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/* for debugging ARM communication: */
  16//#define COM_DEBUG
  17
  18#include <linux/types.h>
  19#include <linux/kernel.h>
  20#include <linux/string.h>
  21#include <linux/delay.h>
  22#include <linux/fs.h>
  23
  24#include "av7110.h"
  25#include "av7110_hw.h"
  26
  27#define _NOHANDSHAKE
  28
  29/*
  30 * Max transfer size done by av7110_fw_cmd()
  31 *
  32 * The maximum size passed to this function is 6 bytes. The buffer also
  33 * uses two additional ones for type and size. So, 8 bytes is enough.
  34 */
  35#define MAX_XFER_SIZE  8
  36
  37/****************************************************************************
  38 * DEBI functions
  39 ****************************************************************************/
  40
  41/* This DEBI code is based on the Stradis driver
  42 * by Nathan Laredo <laredo@gnu.org>
  43 */
  44
  45int av7110_debiwrite(struct av7110 *av7110, u32 config,
  46		     int addr, u32 val, unsigned int count)
  47{
  48	struct saa7146_dev *dev = av7110->dev;
  49
  50	if (count > 32764) {
  51		pr_err("%s(): invalid count %d\n", __func__, count);
  52		return -1;
  53	}
  54	if (saa7146_wait_for_debi_done(av7110->dev, 0) < 0) {
  55		pr_err("%s(): wait_for_debi_done failed\n", __func__);
  56		return -1;
  57	}
  58	saa7146_write(dev, DEBI_CONFIG, config);
  59	if (count <= 4)		/* immediate transfer */
  60		saa7146_write(dev, DEBI_AD, val);
  61	else			/* block transfer */
  62		saa7146_write(dev, DEBI_AD, av7110->debi_bus);
  63	saa7146_write(dev, DEBI_COMMAND, (count << 17) | (addr & 0xffff));
  64	saa7146_write(dev, MC2, (2 << 16) | 2);
  65	return 0;
  66}
  67
  68u32 av7110_debiread(struct av7110 *av7110, u32 config, int addr, unsigned int count)
  69{
  70	struct saa7146_dev *dev = av7110->dev;
  71	u32 result = 0;
  72
  73	if (count > 32764) {
  74		pr_err("%s(): invalid count %d\n", __func__, count);
  75		return 0;
  76	}
  77	if (saa7146_wait_for_debi_done(av7110->dev, 0) < 0) {
  78		pr_err("%s(): wait_for_debi_done #1 failed\n", __func__);
  79		return 0;
  80	}
  81	saa7146_write(dev, DEBI_AD, av7110->debi_bus);
  82	saa7146_write(dev, DEBI_COMMAND, (count << 17) | 0x10000 | (addr & 0xffff));
  83
  84	saa7146_write(dev, DEBI_CONFIG, config);
  85	saa7146_write(dev, MC2, (2 << 16) | 2);
  86	if (count > 4)
  87		return count;
  88	if (saa7146_wait_for_debi_done(av7110->dev, 0) < 0) {
  89		pr_err("%s(): wait_for_debi_done #2 failed\n", __func__);
  90		return 0;
  91	}
  92
  93	result = saa7146_read(dev, DEBI_AD);
  94	result &= (0xffffffffUL >> ((4 - count) * 8));
  95	return result;
  96}
  97
  98/* av7110 ARM core boot stuff */
  99#if 0
 100void av7110_reset_arm(struct av7110 *av7110)
 101{
 102	saa7146_setgpio(av7110->dev, RESET_LINE, SAA7146_GPIO_OUTLO);
 103
 104	/* Disable DEBI and GPIO irq */
 105	SAA7146_IER_DISABLE(av7110->dev, MASK_19 | MASK_03);
 106	SAA7146_ISR_CLEAR(av7110->dev, MASK_19 | MASK_03);
 107
 108	saa7146_setgpio(av7110->dev, RESET_LINE, SAA7146_GPIO_OUTHI);
 109	msleep(30);	/* the firmware needs some time to initialize */
 110
 111	ARM_ResetMailBox(av7110);
 112
 113	SAA7146_ISR_CLEAR(av7110->dev, MASK_19 | MASK_03);
 114	SAA7146_IER_ENABLE(av7110->dev, MASK_03);
 115
 116	av7110->arm_ready = 1;
 117	dprintk(1, "reset ARM\n");
 118}
 119#endif  /*  0  */
 120
 121static int waitdebi(struct av7110 *av7110, int adr, int state)
 122{
 123	int k;
 124
 125	dprintk(4, "%p\n", av7110);
 126
 127	for (k = 0; k < 100; k++) {
 128		if (irdebi(av7110, DEBINOSWAP, adr, 0, 2) == state)
 129			return 0;
 130		udelay(5);
 131	}
 132	return -ETIMEDOUT;
 133}
 134
 135static int load_dram(struct av7110 *av7110, u32 *data, int len)
 136{
 137	int i;
 138	int blocks, rest;
 139	u32 base, bootblock = AV7110_BOOT_BLOCK;
 140
 141	dprintk(4, "%p\n", av7110);
 142
 143	blocks = len / AV7110_BOOT_MAX_SIZE;
 144	rest = len % AV7110_BOOT_MAX_SIZE;
 145	base = DRAM_START_CODE;
 146
 147	for (i = 0; i < blocks; i++) {
 148		if (waitdebi(av7110, AV7110_BOOT_STATE, BOOTSTATE_BUFFER_EMPTY) < 0) {
 149			pr_err("%s(): timeout at block %d\n", __func__, i);
 150			return -ETIMEDOUT;
 151		}
 152		dprintk(4, "writing DRAM block %d\n", i);
 153		mwdebi(av7110, DEBISWAB, bootblock,
 154		       ((u8 *)data) + i * AV7110_BOOT_MAX_SIZE, AV7110_BOOT_MAX_SIZE);
 155		bootblock ^= 0x1400;
 156		iwdebi(av7110, DEBISWAB, AV7110_BOOT_BASE, swab32(base), 4);
 157		iwdebi(av7110, DEBINOSWAP, AV7110_BOOT_SIZE, AV7110_BOOT_MAX_SIZE, 2);
 158		iwdebi(av7110, DEBINOSWAP, AV7110_BOOT_STATE, BOOTSTATE_BUFFER_FULL, 2);
 159		base += AV7110_BOOT_MAX_SIZE;
 160	}
 161
 162	if (rest > 0) {
 163		if (waitdebi(av7110, AV7110_BOOT_STATE, BOOTSTATE_BUFFER_EMPTY) < 0) {
 164			pr_err("%s(): timeout at last block\n", __func__);
 165			return -ETIMEDOUT;
 166		}
 167		if (rest > 4)
 168			mwdebi(av7110, DEBISWAB, bootblock,
 169			       ((u8 *)data) + i * AV7110_BOOT_MAX_SIZE, rest);
 170		else
 171			mwdebi(av7110, DEBISWAB, bootblock,
 172			       ((u8 *)data) + i * AV7110_BOOT_MAX_SIZE - 4, rest + 4);
 173
 174		iwdebi(av7110, DEBISWAB, AV7110_BOOT_BASE, swab32(base), 4);
 175		iwdebi(av7110, DEBINOSWAP, AV7110_BOOT_SIZE, rest, 2);
 176		iwdebi(av7110, DEBINOSWAP, AV7110_BOOT_STATE, BOOTSTATE_BUFFER_FULL, 2);
 177	}
 178	if (waitdebi(av7110, AV7110_BOOT_STATE, BOOTSTATE_BUFFER_EMPTY) < 0) {
 179		pr_err("%s(): timeout after last block\n", __func__);
 180		return -ETIMEDOUT;
 181	}
 182	iwdebi(av7110, DEBINOSWAP, AV7110_BOOT_SIZE, 0, 2);
 183	iwdebi(av7110, DEBINOSWAP, AV7110_BOOT_STATE, BOOTSTATE_BUFFER_FULL, 2);
 184	if (waitdebi(av7110, AV7110_BOOT_STATE, BOOTSTATE_AV7110_BOOT_COMPLETE) < 0) {
 185		pr_err("%s(): final handshake timeout\n", __func__);
 186		return -ETIMEDOUT;
 187	}
 188	return 0;
 189}
 190
 191/* we cannot write av7110 DRAM directly, so load a bootloader into
 192 * the DPRAM which implements a simple boot protocol
 193 */
 194int av7110_bootarm(struct av7110 *av7110)
 195{
 196	const struct firmware *fw;
 197	const char *fw_name = "av7110/bootcode.bin";
 198	struct saa7146_dev *dev = av7110->dev;
 199	u32 ret;
 200	int i;
 201
 202	dprintk(4, "%p\n", av7110);
 203
 204	av7110->arm_ready = 0;
 205
 206	saa7146_setgpio(dev, RESET_LINE, SAA7146_GPIO_OUTLO);
 207
 208	/* Disable DEBI and GPIO irq */
 209	SAA7146_IER_DISABLE(av7110->dev, MASK_03 | MASK_19);
 210	SAA7146_ISR_CLEAR(av7110->dev, MASK_19 | MASK_03);
 211
 212	/* enable DEBI */
 213	saa7146_write(av7110->dev, MC1, 0x08800880);
 214	saa7146_write(av7110->dev, DD1_STREAM_B, 0x00000000);
 215	saa7146_write(av7110->dev, MC2, (MASK_09 | MASK_25 | MASK_10 | MASK_26));
 216
 217	/* test DEBI */
 218	iwdebi(av7110, DEBISWAP, DPRAM_BASE, 0x76543210, 4);
 219	/* FIXME: Why does Nexus CA require 2x iwdebi for first init? */
 220	iwdebi(av7110, DEBISWAP, DPRAM_BASE, 0x76543210, 4);
 221
 222	ret = irdebi(av7110, DEBINOSWAP, DPRAM_BASE, 0, 4);
 223	if (ret != 0x10325476) {
 224		pr_err("debi test in %s() failed: %08x != %08x (check your BIOS 'Plug&Play OS' settings)\n",
 225		       __func__, ret, 0x10325476);
 226		return -1;
 227	}
 228	for (i = 0; i < 8192; i += 4)
 229		iwdebi(av7110, DEBISWAP, DPRAM_BASE + i, 0x00, 4);
 230	dprintk(2, "debi test OK\n");
 231
 232	/* boot */
 233	dprintk(1, "load boot code\n");
 234	saa7146_setgpio(dev, ARM_IRQ_LINE, SAA7146_GPIO_IRQLO);
 235	//saa7146_setgpio(dev, DEBI_DONE_LINE, SAA7146_GPIO_INPUT);
 236	//saa7146_setgpio(dev, 3, SAA7146_GPIO_INPUT);
 237
 238	ret = request_firmware(&fw, fw_name, &dev->pci->dev);
 239	if (ret) {
 240		pr_err("Failed to load firmware \"%s\"\n", fw_name);
 241		return ret;
 242	}
 243
 244	mwdebi(av7110, DEBISWAB, DPRAM_BASE, fw->data, fw->size);
 245	release_firmware(fw);
 246	iwdebi(av7110, DEBINOSWAP, AV7110_BOOT_STATE, BOOTSTATE_BUFFER_FULL, 2);
 247
 248	if (saa7146_wait_for_debi_done(av7110->dev, 1)) {
 249		pr_err("%s(): saa7146_wait_for_debi_done() timed out\n", __func__);
 250		return -ETIMEDOUT;
 251	}
 252	saa7146_setgpio(dev, RESET_LINE, SAA7146_GPIO_OUTHI);
 253	mdelay(1);
 254
 255	dprintk(1, "load dram code\n");
 256	if (load_dram(av7110, (u32 *)av7110->bin_root, av7110->size_root) < 0) {
 257		pr_err("%s(): load_dram() failed\n", __func__);
 258		return -1;
 259	}
 260
 261	saa7146_setgpio(dev, RESET_LINE, SAA7146_GPIO_OUTLO);
 262	mdelay(1);
 263
 264	dprintk(1, "load dpram code\n");
 265	mwdebi(av7110, DEBISWAB, DPRAM_BASE, av7110->bin_dpram, av7110->size_dpram);
 266
 267	if (saa7146_wait_for_debi_done(av7110->dev, 1)) {
 268		pr_err("%s(): saa7146_wait_for_debi_done() timed out after loading DRAM\n", __func__);
 269		return -ETIMEDOUT;
 270	}
 271	saa7146_setgpio(dev, RESET_LINE, SAA7146_GPIO_OUTHI);
 272	msleep(30);	/* the firmware needs some time to initialize */
 273
 274	//ARM_ClearIrq(av7110);
 275	ARM_ResetMailBox(av7110);
 276	SAA7146_ISR_CLEAR(av7110->dev, MASK_19 | MASK_03);
 277	SAA7146_IER_ENABLE(av7110->dev, MASK_03);
 278
 279	av7110->arm_errors = 0;
 280	av7110->arm_ready = 1;
 281	return 0;
 282}
 283MODULE_FIRMWARE("av7110/bootcode.bin");
 284
 285/****************************************************************************
 286 * DEBI command polling
 287 ****************************************************************************/
 288
 289int av7110_wait_msgstate(struct av7110 *av7110, u16 flags)
 290{
 291	unsigned long start;
 292	u32 stat;
 293	int err;
 294
 295	if (FW_VERSION(av7110->arm_app) <= 0x261c) {
 296		/* not supported by old firmware */
 297		msleep(50);
 298		return 0;
 299	}
 300
 301	/* new firmware */
 302	start = jiffies;
 303	for (;;) {
 304		err = time_after(jiffies, start + ARM_WAIT_FREE);
 305		if (mutex_lock_interruptible(&av7110->dcomlock))
 306			return -ERESTARTSYS;
 307		stat = rdebi(av7110, DEBINOSWAP, MSGSTATE, 0, 2);
 308		mutex_unlock(&av7110->dcomlock);
 309		if ((stat & flags) == 0)
 310			break;
 311		if (err) {
 312			pr_err("%s(): timeout waiting for MSGSTATE %04x\n", __func__, stat & flags);
 313			return -ETIMEDOUT;
 314		}
 315		msleep(1);
 316	}
 317	return 0;
 318}
 319
 320static int __av7110_send_fw_cmd(struct av7110 *av7110, u16 *buf, int length)
 321{
 322	int i;
 323	unsigned long start;
 324	char *type = NULL;
 325	u16 flags[2] = {0, 0};
 326	u32 stat;
 327	int err;
 328
 329//	dprintk(4, "%p\n", av7110);
 330
 331	if (!av7110->arm_ready) {
 332		dprintk(1, "arm not ready.\n");
 333		return -ENXIO;
 334	}
 335
 336	start = jiffies;
 337	while (1) {
 338		err = time_after(jiffies, start + ARM_WAIT_FREE);
 339		if (rdebi(av7110, DEBINOSWAP, COMMAND, 0, 2) == 0)
 340			break;
 341		if (err) {
 342			pr_err("%s(): timeout waiting for COMMAND idle\n", __func__);
 343			av7110->arm_errors++;
 344			return -ETIMEDOUT;
 345		}
 346		msleep(1);
 347	}
 348
 349	if (FW_VERSION(av7110->arm_app) <= 0x261f)
 350		wdebi(av7110, DEBINOSWAP, COM_IF_LOCK, 0xffff, 2);
 351
 352#ifndef _NOHANDSHAKE
 353	start = jiffies;
 354	while (1) {
 355		err = time_after(jiffies, start + ARM_WAIT_SHAKE);
 356		if (rdebi(av7110, DEBINOSWAP, HANDSHAKE_REG, 0, 2) == 0)
 357			break;
 358		if (err) {
 359			pr_err("%s(): timeout waiting for HANDSHAKE_REG\n", __func__);
 360			return -ETIMEDOUT;
 361		}
 362		msleep(1);
 363	}
 364#endif
 365
 366	switch ((buf[0] >> 8) & 0xff) {
 367	case COMTYPE_PIDFILTER:
 368	case COMTYPE_ENCODER:
 369	case COMTYPE_REC_PLAY:
 370	case COMTYPE_MPEGDECODER:
 371		type = "MSG";
 372		flags[0] = GPMQOver;
 373		flags[1] = GPMQFull;
 374		break;
 375	case COMTYPE_OSD:
 376		type = "OSD";
 377		flags[0] = OSDQOver;
 378		flags[1] = OSDQFull;
 379		break;
 380	case COMTYPE_MISC:
 381		if (FW_VERSION(av7110->arm_app) >= 0x261d) {
 382			type = "MSG";
 383			flags[0] = GPMQOver;
 384			flags[1] = GPMQBusy;
 385		}
 386		break;
 387	default:
 388		break;
 389	}
 390
 391	if (type) {
 392		/* non-immediate COMMAND type */
 393		start = jiffies;
 394		for (;;) {
 395			err = time_after(jiffies, start + ARM_WAIT_FREE);
 396			stat = rdebi(av7110, DEBINOSWAP, MSGSTATE, 0, 2);
 397			if (stat & flags[0]) {
 398				pr_err("%s(): %s QUEUE overflow\n", __func__, type);
 399				return -1;
 400			}
 401			if ((stat & flags[1]) == 0)
 402				break;
 403			if (err) {
 404				pr_err("%s(): timeout waiting on busy %s QUEUE\n", __func__, type);
 405				av7110->arm_errors++;
 406				return -ETIMEDOUT;
 407			}
 408			msleep(1);
 409		}
 410	}
 411
 412	for (i = 2; i < length; i++)
 413		wdebi(av7110, DEBINOSWAP, COMMAND + 2 * i, (u32)buf[i], 2);
 414
 415	if (length)
 416		wdebi(av7110, DEBINOSWAP, COMMAND + 2, (u32)buf[1], 2);
 417	else
 418		wdebi(av7110, DEBINOSWAP, COMMAND + 2, 0, 2);
 419
 420	wdebi(av7110, DEBINOSWAP, COMMAND, (u32)buf[0], 2);
 421
 422	if (FW_VERSION(av7110->arm_app) <= 0x261f)
 423		wdebi(av7110, DEBINOSWAP, COM_IF_LOCK, 0x0000, 2);
 424
 425#ifdef COM_DEBUG
 426	start = jiffies;
 427	while (1) {
 428		err = time_after(jiffies, start + ARM_WAIT_FREE);
 429		if (rdebi(av7110, DEBINOSWAP, COMMAND, 0, 2) == 0)
 430			break;
 431		if (err) {
 432			pr_err("%s(): timeout waiting for COMMAND %d to complete\n",
 433			       __func__, (buf[0] >> 8) & 0xff);
 434			return -ETIMEDOUT;
 435		}
 436		msleep(1);
 437	}
 438
 439	stat = rdebi(av7110, DEBINOSWAP, MSGSTATE, 0, 2);
 440	if (stat & GPMQOver) {
 441		pr_err("%s(): GPMQOver\n", __func__);
 442		return -ENOSPC;
 443	} else if (stat & OSDQOver) {
 444		pr_err("%s(): OSDQOver\n", __func__);
 445		return -ENOSPC;
 446	}
 447#endif
 448
 449	return 0;
 450}
 451
 452static int av7110_send_fw_cmd(struct av7110 *av7110, u16 *buf, int length)
 453{
 454	int ret;
 455
 456//	dprintk(4, "%p\n", av7110);
 457
 458	if (!av7110->arm_ready) {
 459		dprintk(1, "arm not ready.\n");
 460		return -1;
 461	}
 462	if (mutex_lock_interruptible(&av7110->dcomlock))
 463		return -ERESTARTSYS;
 464
 465	ret = __av7110_send_fw_cmd(av7110, buf, length);
 466	mutex_unlock(&av7110->dcomlock);
 467	if (ret && ret != -ERESTARTSYS)
 468		pr_err("%s(): error %d\n", __func__, ret);
 469	return ret;
 470}
 471
 472int av7110_fw_cmd(struct av7110 *av7110, int type, int com, int num, ...)
 473{
 474	va_list args;
 475	u16 buf[MAX_XFER_SIZE];
 476	int i, ret;
 477
 478//	dprintk(4, "%p\n", av7110);
 479
 480	if (2 + num > ARRAY_SIZE(buf)) {
 481		pr_warn("%s(): len=%d is too big!\n", __func__, num);
 482		return -EINVAL;
 483	}
 484
 485	buf[0] = ((type << 8) | com);
 486	buf[1] = num;
 487
 488	if (num) {
 489		va_start(args, num);
 490		for (i = 0; i < num; i++)
 491			buf[i + 2] = va_arg(args, u32);
 492		va_end(args);
 493	}
 494
 495	ret = av7110_send_fw_cmd(av7110, buf, num + 2);
 496	if (ret && ret != -ERESTARTSYS)
 497		pr_err("%s(): error %d\n", __func__, ret);
 498	return ret;
 499}
 500
 501#if 0
 502int av7110_send_ci_cmd(struct av7110 *av7110, u8 subcom, u8 *buf, u8 len)
 503{
 504	int i, ret;
 505	u16 cmd[18] = { ((COMTYPE_COMMON_IF << 8) + subcom),
 506		16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
 507
 508	dprintk(4, "%p\n", av7110);
 509
 510	for (i = 0; i < len && i < 32; i++) {
 511		if (i % 2 == 0)
 512			cmd[(i / 2) + 2] = (u16)(buf[i]) << 8;
 513		else
 514			cmd[(i / 2) + 2] |= buf[i];
 515	}
 516
 517	ret = av7110_send_fw_cmd(av7110, cmd, 18);
 518	if (ret && ret != -ERESTARTSYS)
 519		pr_err("%s(): error %d\n", __func__, ret);
 520	return ret;
 521}
 522#endif  /*  0  */
 523
 524int av7110_fw_request(struct av7110 *av7110, u16 *request_buf,
 525		      int request_buf_len, u16 *reply_buf, int reply_buf_len)
 526{
 527	int err;
 528	s16 i;
 529	unsigned long start;
 530#ifdef COM_DEBUG
 531	u32 stat;
 532#endif
 533
 534	dprintk(4, "%p\n", av7110);
 535
 536	if (!av7110->arm_ready) {
 537		dprintk(1, "arm not ready.\n");
 538		return -1;
 539	}
 540
 541	if (mutex_lock_interruptible(&av7110->dcomlock))
 542		return -ERESTARTSYS;
 543
 544	err = __av7110_send_fw_cmd(av7110, request_buf, request_buf_len);
 545	if (err < 0) {
 546		mutex_unlock(&av7110->dcomlock);
 547		pr_err("%s(): error %d\n", __func__, err);
 548		return err;
 549	}
 550
 551	start = jiffies;
 552	while (1) {
 553		err = time_after(jiffies, start + ARM_WAIT_FREE);
 554		if (rdebi(av7110, DEBINOSWAP, COMMAND, 0, 2) == 0)
 555			break;
 556		if (err) {
 557			pr_err("%s(): timeout waiting for COMMAND to complete\n", __func__);
 558			mutex_unlock(&av7110->dcomlock);
 559			return -ETIMEDOUT;
 560		}
 561#ifdef _NOHANDSHAKE
 562		msleep(1);
 563#endif
 564	}
 565
 566#ifndef _NOHANDSHAKE
 567	start = jiffies;
 568	while (1) {
 569		err = time_after(jiffies, start + ARM_WAIT_SHAKE);
 570		if (rdebi(av7110, DEBINOSWAP, HANDSHAKE_REG, 0, 2) == 0)
 571			break;
 572		if (err) {
 573			pr_err("%s(): timeout waiting for HANDSHAKE_REG\n", __func__);
 574			mutex_unlock(&av7110->dcomlock);
 575			return -ETIMEDOUT;
 576		}
 577		msleep(1);
 578	}
 579#endif
 580
 581#ifdef COM_DEBUG
 582	stat = rdebi(av7110, DEBINOSWAP, MSGSTATE, 0, 2);
 583	if (stat & GPMQOver) {
 584		pr_err("%s(): GPMQOver\n", __func__);
 585		mutex_unlock(&av7110->dcomlock);
 586		return -1;
 587	} else if (stat & OSDQOver) {
 588		pr_err("%s(): OSDQOver\n", __func__);
 589		mutex_unlock(&av7110->dcomlock);
 590		return -1;
 591	}
 592#endif
 593
 594	for (i = 0; i < reply_buf_len; i++)
 595		reply_buf[i] = rdebi(av7110, DEBINOSWAP, COM_BUFF + 2 * i, 0, 2);
 596
 597	mutex_unlock(&av7110->dcomlock);
 598	return 0;
 599}
 600
 601static int av7110_fw_query(struct av7110 *av7110, u16 tag, u16 *buf, s16 length)
 602{
 603	int ret;
 604
 605	ret = av7110_fw_request(av7110, &tag, 0, buf, length);
 606	if (ret)
 607		pr_err("%s(): error %d\n", __func__, ret);
 608	return ret;
 609}
 610
 611/****************************************************************************
 612 * Firmware commands
 613 ****************************************************************************/
 614
 615/* get version of the firmware ROM, RTSL, video ucode and ARM application  */
 616int av7110_firmversion(struct av7110 *av7110)
 617{
 618	u16 buf[20];
 619	u16 tag = ((COMTYPE_REQUEST << 8) + ReqVersion);
 620
 621	dprintk(4, "%p\n", av7110);
 622
 623	if (av7110_fw_query(av7110, tag, buf, 16)) {
 624		pr_err("failed to boot firmware @ card %d\n", av7110->dvb_adapter.num);
 625		return -EIO;
 626	}
 627
 628	av7110->arm_fw = (buf[0] << 16) + buf[1];
 629	av7110->arm_rtsl = (buf[2] << 16) + buf[3];
 630	av7110->arm_vid = (buf[4] << 16) + buf[5];
 631	av7110->arm_app = (buf[6] << 16) + buf[7];
 632	av7110->avtype = (buf[8] << 16) + buf[9];
 633
 634	pr_info("info @ card %d: firm %08x, rtsl %08x, vid %08x, app %08x\n",
 635		av7110->dvb_adapter.num, av7110->arm_fw,
 636		av7110->arm_rtsl, av7110->arm_vid, av7110->arm_app);
 637
 638	/* print firmware capabilities */
 639	if (FW_CI_LL_SUPPORT(av7110->arm_app))
 640		pr_info("firmware @ card %d supports CI link layer interface\n",
 641			av7110->dvb_adapter.num);
 642	else
 643		pr_info("no firmware support for CI link layer interface @ card %d\n",
 644			av7110->dvb_adapter.num);
 645
 646	return 0;
 647}
 648
 649int av7110_diseqc_send(struct av7110 *av7110, int len, u8 *msg, unsigned long burst)
 650{
 651	int i, ret;
 652	u16 buf[18] = { ((COMTYPE_AUDIODAC << 8) + SendDiSEqC),
 653			16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
 654
 655	dprintk(4, "%p\n", av7110);
 656
 657	if (len > 10)
 658		len = 10;
 659
 660	buf[1] = len + 2;
 661	buf[2] = len;
 662
 663	if (burst != -1)
 664		buf[3] = burst ? 0x01 : 0x00;
 665	else
 666		buf[3] = 0xffff;
 667
 668	for (i = 0; i < len; i++)
 669		buf[i + 4] = msg[i];
 670
 671	ret = av7110_send_fw_cmd(av7110, buf, 18);
 672	if (ret && ret != -ERESTARTSYS)
 673		pr_err("%s(): error %d\n", __func__, ret);
 674	return ret;
 675}
 676
 677#ifdef CONFIG_DVB_AV7110_OSD
 678
 679static inline int SetColorBlend(struct av7110 *av7110, u8 windownr)
 680{
 681	return av7110_fw_cmd(av7110, COMTYPE_OSD, SetCBlend, 1, windownr);
 682}
 683
 684static inline int SetBlend_(struct av7110 *av7110, u8 windownr,
 685			    enum av7110_osd_palette_type colordepth, u16 index, u8 blending)
 686{
 687	return av7110_fw_cmd(av7110, COMTYPE_OSD, SetBlend, 4,
 688			     windownr, colordepth, index, blending);
 689}
 690
 691static inline int SetColor_(struct av7110 *av7110, u8 windownr,
 692			    enum av7110_osd_palette_type colordepth, u16 index, u16 colorhi, u16 colorlo)
 693{
 694	return av7110_fw_cmd(av7110, COMTYPE_OSD, SetColor, 5,
 695			     windownr, colordepth, index, colorhi, colorlo);
 696}
 697
 698static inline int SetFont(struct av7110 *av7110, u8 windownr, u8 fontsize,
 699			  u16 colorfg, u16 colorbg)
 700{
 701	return av7110_fw_cmd(av7110, COMTYPE_OSD, Set_Font, 4,
 702			     windownr, fontsize, colorfg, colorbg);
 703}
 704
 705static int FlushText(struct av7110 *av7110)
 706{
 707	unsigned long start;
 708	int err;
 709
 710	if (mutex_lock_interruptible(&av7110->dcomlock))
 711		return -ERESTARTSYS;
 712	start = jiffies;
 713	while (1) {
 714		err = time_after(jiffies, start + ARM_WAIT_OSD);
 715		if (rdebi(av7110, DEBINOSWAP, BUFF1_BASE, 0, 2) == 0)
 716			break;
 717		if (err) {
 718			pr_err("%s(): timeout waiting for BUFF1_BASE == 0\n", __func__);
 719			mutex_unlock(&av7110->dcomlock);
 720			return -ETIMEDOUT;
 721		}
 722		msleep(1);
 723	}
 724	mutex_unlock(&av7110->dcomlock);
 725	return 0;
 726}
 727
 728static int WriteText(struct av7110 *av7110, u8 win, u16 x, u16 y, char *buf)
 729{
 730	int i, ret;
 731	unsigned long start;
 732	int length = strlen(buf) + 1;
 733	u16 cbuf[5] = { (COMTYPE_OSD << 8) + DText, 3, win, x, y };
 734
 735	if (mutex_lock_interruptible(&av7110->dcomlock))
 736		return -ERESTARTSYS;
 737
 738	start = jiffies;
 739	while (1) {
 740		ret = time_after(jiffies, start + ARM_WAIT_OSD);
 741		if (rdebi(av7110, DEBINOSWAP, BUFF1_BASE, 0, 2) == 0)
 742			break;
 743		if (ret) {
 744			pr_err("%s(): timeout waiting for BUFF1_BASE == 0\n", __func__);
 745			mutex_unlock(&av7110->dcomlock);
 746			return -ETIMEDOUT;
 747		}
 748		msleep(1);
 749	}
 750#ifndef _NOHANDSHAKE
 751	start = jiffies;
 752	while (1) {
 753		ret = time_after(jiffies, start + ARM_WAIT_SHAKE);
 754		if (rdebi(av7110, DEBINOSWAP, HANDSHAKE_REG, 0, 2) == 0)
 755			break;
 756		if (ret) {
 757			pr_err("%s(): timeout waiting for HANDSHAKE_REG\n", __func__);
 758			mutex_unlock(&av7110->dcomlock);
 759			return -ETIMEDOUT;
 760		}
 761		msleep(1);
 762	}
 763#endif
 764	for (i = 0; i < length / 2; i++)
 765		wdebi(av7110, DEBINOSWAP, BUFF1_BASE + i * 2,
 766		      swab16(*(u16 *)(buf + 2 * i)), 2);
 767	if (length & 1)
 768		wdebi(av7110, DEBINOSWAP, BUFF1_BASE + i * 2, 0, 2);
 769	ret = __av7110_send_fw_cmd(av7110, cbuf, 5);
 770	mutex_unlock(&av7110->dcomlock);
 771	if (ret && ret != -ERESTARTSYS)
 772		pr_err("%s(): error %d\n", __func__, ret);
 773	return ret;
 774}
 775
 776static inline int DrawLine(struct av7110 *av7110, u8 windownr,
 777			   u16 x, u16 y, u16 dx, u16 dy, u16 color)
 778{
 779	return av7110_fw_cmd(av7110, COMTYPE_OSD, DLine, 6,
 780			     windownr, x, y, dx, dy, color);
 781}
 782
 783static inline int DrawBlock(struct av7110 *av7110, u8 windownr,
 784			    u16 x, u16 y, u16 dx, u16 dy, u16 color)
 785{
 786	return av7110_fw_cmd(av7110, COMTYPE_OSD, DBox, 6,
 787			     windownr, x, y, dx, dy, color);
 788}
 789
 790static inline int HideWindow(struct av7110 *av7110, u8 windownr)
 791{
 792	return av7110_fw_cmd(av7110, COMTYPE_OSD, WHide, 1, windownr);
 793}
 794
 795static inline int MoveWindowRel(struct av7110 *av7110, u8 windownr, u16 x, u16 y)
 796{
 797	return av7110_fw_cmd(av7110, COMTYPE_OSD, WMoveD, 3, windownr, x, y);
 798}
 799
 800static inline int MoveWindowAbs(struct av7110 *av7110, u8 windownr, u16 x, u16 y)
 801{
 802	return av7110_fw_cmd(av7110, COMTYPE_OSD, WMoveA, 3, windownr, x, y);
 803}
 804
 805static inline int DestroyOSDWindow(struct av7110 *av7110, u8 windownr)
 806{
 807	return av7110_fw_cmd(av7110, COMTYPE_OSD, WDestroy, 1, windownr);
 808}
 809
 810static inline int CreateOSDWindow(struct av7110 *av7110, u8 windownr,
 811				  osd_raw_window_t disptype,
 812				  u16 width, u16 height)
 813{
 814	return av7110_fw_cmd(av7110, COMTYPE_OSD, WCreate, 4,
 815			     windownr, disptype, width, height);
 816}
 817
 818static enum av7110_osd_palette_type bpp2pal[8] = {
 819	Pal1Bit, Pal2Bit, 0, Pal4Bit, 0, 0, 0, Pal8Bit
 820};
 821
 822static osd_raw_window_t bpp2bit[8] = {
 823	OSD_BITMAP1, OSD_BITMAP2, 0, OSD_BITMAP4, 0, 0, 0, OSD_BITMAP8
 824};
 825
 826static inline int WaitUntilBmpLoaded(struct av7110 *av7110)
 827{
 828	int ret = wait_event_timeout(av7110->bmpq,
 829				av7110->bmp_state != BMP_LOADING, 10 * HZ);
 830	if (ret == 0) {
 831		pr_warn("warning: timeout waiting in LoadBitmap: %d, %d\n", ret, av7110->bmp_state);
 832		av7110->bmp_state = BMP_NONE;
 833		return -ETIMEDOUT;
 834	}
 835	return 0;
 836}
 837
 838static inline int LoadBitmap(struct av7110 *av7110,
 839			     u16 dx, u16 dy, int inc, u8 __user *data)
 840{
 841	u16 format;
 842	int bpp;
 843	int i;
 844	int d, delta;
 845	u8 c;
 846	int ret;
 847
 848	dprintk(4, "%p\n", av7110);
 849
 850	format = bpp2bit[av7110->osdbpp[av7110->osdwin]];
 851
 852	av7110->bmp_state = BMP_LOADING;
 853	if	(format == OSD_BITMAP8) {
 854		bpp = 8; delta = 1;
 855	} else if (format == OSD_BITMAP4) {
 856		bpp = 4; delta = 2;
 857	} else if (format == OSD_BITMAP2) {
 858		bpp = 2; delta = 4;
 859	} else if (format == OSD_BITMAP1) {
 860		bpp = 1; delta = 8;
 861	} else {
 862		av7110->bmp_state = BMP_NONE;
 863		return -EINVAL;
 864	}
 865	av7110->bmplen = ((dx * dy * bpp + 7) & ~7) / 8;
 866	av7110->bmpp = 0;
 867	if (av7110->bmplen > 32768) {
 868		av7110->bmp_state = BMP_NONE;
 869		return -EINVAL;
 870	}
 871	for (i = 0; i < dy; i++) {
 872		if (copy_from_user(av7110->bmpbuf + 1024 + i * dx, data + i * inc, dx)) {
 873			av7110->bmp_state = BMP_NONE;
 874			return -EINVAL;
 875		}
 876	}
 877	if (format != OSD_BITMAP8) {
 878		for (i = 0; i < dx * dy / delta; i++) {
 879			c = ((u8 *)av7110->bmpbuf)[1024 + i * delta + delta - 1];
 880			for (d = delta - 2; d >= 0; d--) {
 881				c |= (((u8 *)av7110->bmpbuf)[1024 + i * delta + d]
 882				      << ((delta - d - 1) * bpp));
 883				((u8 *)av7110->bmpbuf)[1024 + i] = c;
 884			}
 885		}
 886	}
 887	av7110->bmplen += 1024;
 888	dprintk(4, "av7110_fw_cmd(): LoadBmp size %d\n", av7110->bmplen);
 889	ret = av7110_fw_cmd(av7110, COMTYPE_OSD, LoadBmp, 3, format, dx, dy);
 890	if (!ret)
 891		ret = WaitUntilBmpLoaded(av7110);
 892	return ret;
 893}
 894
 895static int BlitBitmap(struct av7110 *av7110, u16 x, u16 y)
 896{
 897	dprintk(4, "%p\n", av7110);
 898
 899	return av7110_fw_cmd(av7110, COMTYPE_OSD, BlitBmp, 4, av7110->osdwin, x, y, 0);
 900}
 901
 902static inline int ReleaseBitmap(struct av7110 *av7110)
 903{
 904	dprintk(4, "%p\n", av7110);
 905
 906	if (av7110->bmp_state != BMP_LOADED && FW_VERSION(av7110->arm_app) < 0x261e)
 907		return -1;
 908	if (av7110->bmp_state == BMP_LOADING)
 909		dprintk(1, "%s called while BMP_LOADING\n", __func__);
 910	av7110->bmp_state = BMP_NONE;
 911	return av7110_fw_cmd(av7110, COMTYPE_OSD, ReleaseBmp, 0);
 912}
 913
 914static u32 RGB2YUV(u16 R, u16 G, u16 B)
 915{
 916	u16 y, u, v;
 917	u16 Y, Cr, Cb;
 918
 919	y = R * 77 + G * 150 + B * 29;	/* Luma=0.299R+0.587G+0.114B 0..65535 */
 920	u = 2048 + B * 8 - (y >> 5);	/* Cr 0..4095 */
 921	v = 2048 + R * 8 - (y >> 5);	/* Cb 0..4095 */
 922
 923	Y = y / 256;
 924	Cb = u / 16;
 925	Cr = v / 16;
 926
 927	return Cr | (Cb << 16) | (Y << 8);
 928}
 929
 930static int OSDSetColor(struct av7110 *av7110, u8 color, u8 r, u8 g, u8 b, u8 blend)
 931{
 932	int ret;
 933
 934	u16 ch, cl;
 935	u32 yuv;
 936
 937	yuv = blend ? RGB2YUV(r, g, b) : 0;
 938	cl = (yuv & 0xffff);
 939	ch = ((yuv >> 16) & 0xffff);
 940	ret = SetColor_(av7110, av7110->osdwin, bpp2pal[av7110->osdbpp[av7110->osdwin]],
 941			color, ch, cl);
 942	if (!ret)
 943		ret = SetBlend_(av7110, av7110->osdwin, bpp2pal[av7110->osdbpp[av7110->osdwin]],
 944				color, ((blend >> 4) & 0x0f));
 945	return ret;
 946}
 947
 948static int OSDSetPalette(struct av7110 *av7110, u32 __user *colors, u8 first, u8 last)
 949{
 950	int i;
 951	int length = last - first + 1;
 952
 953	if (length * 4 > DATA_BUFF3_SIZE)
 954		return -EINVAL;
 955
 956	for (i = 0; i < length; i++) {
 957		u32 color, blend, yuv;
 958
 959		if (get_user(color, colors + i))
 960			return -EFAULT;
 961		blend = (color & 0xF0000000) >> 4;
 962		yuv = blend ? RGB2YUV(color & 0xFF, (color >> 8) & 0xFF,
 963				     (color >> 16) & 0xFF) | blend : 0;
 964		yuv = ((yuv & 0xFFFF0000) >> 16) | ((yuv & 0x0000FFFF) << 16);
 965		wdebi(av7110, DEBINOSWAP, DATA_BUFF3_BASE + i * 4, yuv, 4);
 966	}
 967	return av7110_fw_cmd(av7110, COMTYPE_OSD, Set_Palette, 4,
 968			    av7110->osdwin,
 969			    bpp2pal[av7110->osdbpp[av7110->osdwin]],
 970			    first, last);
 971}
 972
 973static int OSDSetBlock(struct av7110 *av7110, int x0, int y0,
 974		       int x1, int y1, int inc, u8 __user *data)
 975{
 976	uint w, h, bpp, bpl, size, lpb, bnum, brest;
 977	int i;
 978	int rc, release_rc;
 979
 980	w = x1 - x0 + 1;
 981	h = y1 - y0 + 1;
 982	if (inc <= 0)
 983		inc = w;
 984	if (w <= 0 || w > 720 || h <= 0 || h > 576)
 985		return -EINVAL;
 986	bpp = av7110->osdbpp[av7110->osdwin] + 1;
 987	bpl = ((w * bpp + 7) & ~7) / 8;
 988	size = h * bpl;
 989	lpb = (32 * 1024) / bpl;
 990	bnum = size / (lpb * bpl);
 991	brest = size - bnum * lpb * bpl;
 992
 993	if (av7110->bmp_state == BMP_LOADING) {
 994		/* possible if syscall is repeated by -ERESTARTSYS and if firmware cannot abort */
 995		if (WARN_ON(FW_VERSION(av7110->arm_app) >= 0x261e))
 996			return -EIO;
 997		rc = WaitUntilBmpLoaded(av7110);
 998		if (rc)
 999			return rc;
1000		/* just continue. This should work for all fw versions
1001		 * if bnum==1 && !brest && LoadBitmap was successful
1002		 */
1003	}
1004
1005	rc = 0;
1006	for (i = 0; i < bnum; i++) {
1007		rc = LoadBitmap(av7110, w, lpb, inc, data);
1008		if (rc)
1009			break;
1010		rc = BlitBitmap(av7110, x0, y0 + i * lpb);
1011		if (rc)
1012			break;
1013		data += lpb * inc;
1014	}
1015	if (!rc && brest) {
1016		rc = LoadBitmap(av7110, w, brest / bpl, inc, data);
1017		if (!rc)
1018			rc = BlitBitmap(av7110, x0, y0 + bnum * lpb);
1019	}
1020	release_rc = ReleaseBitmap(av7110);
1021	if (!rc)
1022		rc = release_rc;
1023	if (rc)
1024		dprintk(1, "returns %d\n", rc);
1025	return rc;
1026}
1027
1028int av7110_osd_cmd(struct av7110 *av7110, osd_cmd_t *dc)
1029{
1030	int ret;
1031
1032	if (mutex_lock_interruptible(&av7110->osd_mutex))
1033		return -ERESTARTSYS;
1034
1035	switch (dc->cmd) {
1036	case OSD_Close:
1037		ret = DestroyOSDWindow(av7110, av7110->osdwin);
1038		break;
1039	case OSD_Open:
1040		av7110->osdbpp[av7110->osdwin] = (dc->color - 1) & 7;
1041		ret = CreateOSDWindow(av7110, av7110->osdwin,
1042				      bpp2bit[av7110->osdbpp[av7110->osdwin]],
1043				dc->x1 - dc->x0 + 1, dc->y1 - dc->y0 + 1);
1044		if (ret)
1045			break;
1046		if (!dc->data) {
1047			ret = MoveWindowAbs(av7110, av7110->osdwin, dc->x0, dc->y0);
1048			if (ret)
1049				break;
1050			ret = SetColorBlend(av7110, av7110->osdwin);
1051		}
1052		break;
1053	case OSD_Show:
1054		ret = MoveWindowRel(av7110, av7110->osdwin, 0, 0);
1055		break;
1056	case OSD_Hide:
1057		ret = HideWindow(av7110, av7110->osdwin);
1058		break;
1059	case OSD_Clear:
1060		ret = DrawBlock(av7110, av7110->osdwin, 0, 0, 720, 576, 0);
1061		break;
1062	case OSD_Fill:
1063		ret = DrawBlock(av7110, av7110->osdwin, 0, 0, 720, 576, dc->color);
1064		break;
1065	case OSD_SetColor:
1066		ret = OSDSetColor(av7110, dc->color, dc->x0, dc->y0, dc->x1, dc->y1);
1067		break;
1068	case OSD_SetPalette:
1069		if (FW_VERSION(av7110->arm_app) >= 0x2618) {
1070			ret = OSDSetPalette(av7110, dc->data, dc->color, dc->x0);
1071		} else {
1072			int i, len = dc->x0 - dc->color + 1;
1073			u8 __user *colors = (u8 __user *)dc->data;
1074			u8 r, g = 0, b = 0, blend = 0;
1075
1076			ret = 0;
1077			for (i = 0; i < len; i++) {
1078				if (get_user(r, colors + i * 4) ||
1079				    get_user(g, colors + i * 4 + 1) ||
1080				    get_user(b, colors + i * 4 + 2) ||
1081				    get_user(blend, colors + i * 4 + 3)) {
1082					ret = -EFAULT;
1083					break;
1084				}
1085				ret = OSDSetColor(av7110, dc->color + i, r, g, b, blend);
1086				if (ret)
1087					break;
1088			}
1089		}
1090		break;
1091	case OSD_SetPixel:
1092		ret = DrawLine(av7110, av7110->osdwin,
1093			       dc->x0, dc->y0, 0, 0, dc->color);
1094		break;
1095	case OSD_SetRow:
1096		dc->y1 = dc->y0;
1097		fallthrough;
1098	case OSD_SetBlock:
1099		ret = OSDSetBlock(av7110, dc->x0, dc->y0, dc->x1, dc->y1, dc->color, dc->data);
1100		break;
1101	case OSD_FillRow:
1102		ret = DrawBlock(av7110, av7110->osdwin, dc->x0, dc->y0,
1103				dc->x1 - dc->x0 + 1, dc->y1, dc->color);
1104		break;
1105	case OSD_FillBlock:
1106		ret = DrawBlock(av7110, av7110->osdwin, dc->x0, dc->y0,
1107				dc->x1 - dc->x0 + 1, dc->y1 - dc->y0 + 1, dc->color);
1108		break;
1109	case OSD_Line:
1110		ret = DrawLine(av7110, av7110->osdwin,
1111			       dc->x0, dc->y0, dc->x1 - dc->x0, dc->y1 - dc->y0, dc->color);
1112		break;
1113	case OSD_Text:
1114	{
1115		char textbuf[240];
1116
1117		if (strncpy_from_user(textbuf, dc->data, 240) < 0) {
1118			ret = -EFAULT;
1119			break;
1120		}
1121		textbuf[239] = 0;
1122		if (dc->x1 > 3)
1123			dc->x1 = 3;
1124		ret = SetFont(av7110, av7110->osdwin, dc->x1,
1125			      (u16)(dc->color & 0xffff), (u16)(dc->color >> 16));
1126		if (!ret)
1127			ret = FlushText(av7110);
1128		if (!ret)
1129			ret = WriteText(av7110, av7110->osdwin, dc->x0, dc->y0, textbuf);
1130		break;
1131	}
1132	case OSD_SetWindow:
1133		if (dc->x0 < 1 || dc->x0 > 7) {
1134			ret = -EINVAL;
1135		} else {
1136			av7110->osdwin = dc->x0;
1137			ret = 0;
1138		}
1139		break;
1140	case OSD_MoveWindow:
1141		ret = MoveWindowAbs(av7110, av7110->osdwin, dc->x0, dc->y0);
1142		if (!ret)
1143			ret = SetColorBlend(av7110, av7110->osdwin);
1144		break;
1145	case OSD_OpenRaw:
1146		if (dc->color < OSD_BITMAP1 || dc->color > OSD_CURSOR) {
1147			ret = -EINVAL;
1148			break;
1149		}
1150		if (dc->color >= OSD_BITMAP1 && dc->color <= OSD_BITMAP8HR)
1151			av7110->osdbpp[av7110->osdwin] = (1 << (dc->color & 3)) - 1;
1152		else
1153			av7110->osdbpp[av7110->osdwin] = 0;
1154		ret = CreateOSDWindow(av7110, av7110->osdwin, (osd_raw_window_t)dc->color,
1155				      dc->x1 - dc->x0 + 1, dc->y1 - dc->y0 + 1);
1156		if (ret)
1157			break;
1158		if (!dc->data) {
1159			ret = MoveWindowAbs(av7110, av7110->osdwin, dc->x0, dc->y0);
1160			if (!ret)
1161				ret = SetColorBlend(av7110, av7110->osdwin);
1162		}
1163		break;
1164	default:
1165		ret = -EINVAL;
1166		break;
1167	}
1168
1169	mutex_unlock(&av7110->osd_mutex);
1170	if (ret == -ERESTARTSYS)
1171		dprintk(1, "%s(%d) returns with -ERESTARTSYS\n", __func__, dc->cmd);
1172	else if (ret)
1173		dprintk(1, "%s(%d) returns with %d\n", __func__, dc->cmd, ret);
1174
1175	return ret;
1176}
1177
1178int av7110_osd_capability(struct av7110 *av7110, osd_cap_t *cap)
1179{
1180	switch (cap->cmd) {
1181	case OSD_CAP_MEMSIZE:
1182		if (FW_4M_SDRAM(av7110->arm_app))
1183			cap->val = 1000000;
1184		else
1185			cap->val = 92000;
1186		return 0;
1187	default:
1188		return -EINVAL;
1189	}
1190}
1191#endif /* CONFIG_DVB_AV7110_OSD */
~/ Read-only file preview.