File Index
Files and directories
Sign in
FILE

av7110_ir.c

File preview with syntax highlighting.

linux-6.19.14/drivers/staging/media/av7110/av7110_ir.c C
  1// SPDX-License-Identifier: GPL-2.0-or-later
  2/*
  3 * Driver for the remote control of SAA7146 based AV7110 cards
  4 *
  5 * Copyright (C) 1999-2003 Holger Waechtler <holger@convergence.de>
  6 * Copyright (C) 2003-2007 Oliver Endriss <o.endriss@gmx.de>
  7 * Copyright (C) 2019 Sean Young <sean@mess.org>
  8 */
  9
 10#include <linux/kernel.h>
 11#include <media/rc-core.h>
 12
 13#include "av7110.h"
 14#include "av7110_hw.h"
 15
 16#define IR_RC5		0
 17#define IR_RCMM		1
 18#define IR_RC5_EXT	2 /* internal only */
 19
 20/* interrupt handler */
 21void av7110_ir_handler(struct av7110 *av7110, u32 ircom)
 22{
 23	struct rc_dev *rcdev = av7110->ir.rcdev;
 24	enum rc_proto proto;
 25	u32 command, addr, scancode;
 26	u32 toggle;
 27
 28	dprintk(4, "ir command = %08x\n", ircom);
 29
 30	if (rcdev) {
 31		switch (av7110->ir.ir_config) {
 32		case IR_RC5: /* RC5: 5 bits device address, 6 bits command */
 33			command = ircom & 0x3f;
 34			addr = (ircom >> 6) & 0x1f;
 35			scancode = RC_SCANCODE_RC5(addr, command);
 36			toggle = ircom & 0x0800;
 37			proto = RC_PROTO_RC5;
 38			break;
 39
 40		case IR_RCMM: /* RCMM: 32 bits scancode */
 41			scancode = ircom & ~0x8000;
 42			toggle = ircom & 0x8000;
 43			proto = RC_PROTO_RCMM32;
 44			break;
 45
 46		case IR_RC5_EXT:
 47			/*
 48			 * extended RC5: 5 bits device address, 7 bits command
 49			 *
 50			 * Extended RC5 uses only one start bit. The second
 51			 * start bit is re-assigned bit 6 of the command bit.
 52			 */
 53			command = ircom & 0x3f;
 54			addr = (ircom >> 6) & 0x1f;
 55			if (!(ircom & 0x1000))
 56				command |= 0x40;
 57			scancode = RC_SCANCODE_RC5(addr, command);
 58			toggle = ircom & 0x0800;
 59			proto = RC_PROTO_RC5;
 60			break;
 61		default:
 62			dprintk(2, "unknown ir config %d\n", av7110->ir.ir_config);
 63			return;
 64		}
 65
 66		rc_keydown(rcdev, proto, scancode, toggle != 0);
 67	}
 68}
 69
 70int av7110_set_ir_config(struct av7110 *av7110)
 71{
 72	dprintk(4, "ir config = %08x\n", av7110->ir.ir_config);
 73
 74	return av7110_fw_cmd(av7110, COMTYPE_PIDFILTER, SetIR, 1,
 75			     av7110->ir.ir_config);
 76}
 77
 78static int change_protocol(struct rc_dev *rcdev, u64 *rc_type)
 79{
 80	struct av7110 *av7110 = rcdev->priv;
 81	u32 ir_config;
 82
 83	if (*rc_type & RC_PROTO_BIT_RCMM32) {
 84		ir_config = IR_RCMM;
 85		*rc_type = RC_PROTO_BIT_RCMM32;
 86	} else if (*rc_type & RC_PROTO_BIT_RC5) {
 87		if (FW_VERSION(av7110->arm_app) >= 0x2620)
 88			ir_config = IR_RC5_EXT;
 89		else
 90			ir_config = IR_RC5;
 91		*rc_type = RC_PROTO_BIT_RC5;
 92	} else {
 93		return -EINVAL;
 94	}
 95
 96	if (ir_config == av7110->ir.ir_config)
 97		return 0;
 98
 99	av7110->ir.ir_config = ir_config;
100
101	return av7110_set_ir_config(av7110);
102}
103
104int av7110_ir_init(struct av7110 *av7110)
105{
106	struct rc_dev *rcdev;
107	struct pci_dev *pci;
108	int ret;
109
110	rcdev = rc_allocate_device(RC_DRIVER_SCANCODE);
111	if (!rcdev)
112		return -ENOMEM;
113
114	pci = av7110->dev->pci;
115
116	snprintf(av7110->ir.input_phys, sizeof(av7110->ir.input_phys),
117		 "pci-%s/ir0", pci_name(pci));
118
119	rcdev->device_name = av7110->card_name;
120	rcdev->driver_name = KBUILD_MODNAME;
121	rcdev->input_phys = av7110->ir.input_phys;
122	rcdev->input_id.bustype = BUS_PCI;
123	rcdev->input_id.version = 2;
124	if (pci->subsystem_vendor) {
125		rcdev->input_id.vendor	= pci->subsystem_vendor;
126		rcdev->input_id.product = pci->subsystem_device;
127	} else {
128		rcdev->input_id.vendor	= pci->vendor;
129		rcdev->input_id.product = pci->device;
130	}
131
132	rcdev->dev.parent = &pci->dev;
133	rcdev->allowed_protocols = RC_PROTO_BIT_RC5 | RC_PROTO_BIT_RCMM32;
134	rcdev->change_protocol = change_protocol;
135	rcdev->map_name = RC_MAP_HAUPPAUGE;
136	rcdev->priv = av7110;
137
138	av7110->ir.rcdev = rcdev;
139	av7110->ir.ir_config = IR_RC5;
140	av7110_set_ir_config(av7110);
141
142	ret = rc_register_device(rcdev);
143	if (ret) {
144		av7110->ir.rcdev = NULL;
145		rc_free_device(rcdev);
146	}
147
148	return ret;
149}
150
151void av7110_ir_exit(struct av7110 *av7110)
152{
153	rc_unregister_device(av7110->ir.rcdev);
154}
155
156//MODULE_AUTHOR("Holger Waechtler <holger@convergence.de>, Oliver Endriss <o.endriss@gmx.de>");
157//MODULE_LICENSE("GPL");
~/ Read-only file preview.