1
2
3
4
5
6
7
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
19
20
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:
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:
41 scancode = ircom & ~0x8000;
42 toggle = ircom & 0x8000;
43 proto = RC_PROTO_RCMM32;
44 break;
45
46 case IR_RC5_EXT:
47
48
49
50
51
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",
63 av7110->ir.ir_config);
64 return;
65 }
66
67 rc_keydown(rcdev, proto, scancode, toggle != 0);
68 }
69}
70
71int av7110_set_ir_config(struct av7110 *av7110)
72{
73 dprintk(4, "ir config = %08x\n", av7110->ir.ir_config);
74
75 return av7110_fw_cmd(av7110, COMTYPE_PIDFILTER, SetIR, 1,
76 av7110->ir.ir_config);
77}
78
79static int change_protocol(struct rc_dev *rcdev, u64 *rc_type)
80{
81 struct av7110 *av7110 = rcdev->priv;
82 u32 ir_config;
83
84 if (*rc_type & RC_PROTO_BIT_RCMM32) {
85 ir_config = IR_RCMM;
86 *rc_type = RC_PROTO_BIT_RCMM32;
87 } else if (*rc_type & RC_PROTO_BIT_RC5) {
88 if (FW_VERSION(av7110->arm_app) >= 0x2620)
89 ir_config = IR_RC5_EXT;
90 else
91 ir_config = IR_RC5;
92 *rc_type = RC_PROTO_BIT_RC5;
93 } else {
94 return -EINVAL;
95 }
96
97 if (ir_config == av7110->ir.ir_config)
98 return 0;
99
100 av7110->ir.ir_config = ir_config;
101
102 return av7110_set_ir_config(av7110);
103}
104
105int av7110_ir_init(struct av7110 *av7110)
106{
107 struct rc_dev *rcdev;
108 struct pci_dev *pci;
109 int ret;
110
111 rcdev = rc_allocate_device(RC_DRIVER_SCANCODE);
112 if (!rcdev)
113 return -ENOMEM;
114
115 pci = av7110->dev->pci;
116
117 snprintf(av7110->ir.input_phys, sizeof(av7110->ir.input_phys),
118 "pci-%s/ir0", pci_name(pci));
119
120 rcdev->device_name = av7110->card_name;
121 rcdev->driver_name = KBUILD_MODNAME;
122 rcdev->input_phys = av7110->ir.input_phys;
123 rcdev->input_id.bustype = BUS_PCI;
124 rcdev->input_id.version = 2;
125 if (pci->subsystem_vendor) {
126 rcdev->input_id.vendor = pci->subsystem_vendor;
127 rcdev->input_id.product = pci->subsystem_device;
128 } else {
129 rcdev->input_id.vendor = pci->vendor;
130 rcdev->input_id.product = pci->device;
131 }
132
133 rcdev->dev.parent = &pci->dev;
134 rcdev->allowed_protocols = RC_PROTO_BIT_RC5 | RC_PROTO_BIT_RCMM32;
135 rcdev->change_protocol = change_protocol;
136 rcdev->map_name = RC_MAP_HAUPPAUGE;
137 rcdev->priv = av7110;
138
139 av7110->ir.rcdev = rcdev;
140 av7110->ir.ir_config = IR_RC5;
141 av7110_set_ir_config(av7110);
142
143 ret = rc_register_device(rcdev);
144 if (ret) {
145 av7110->ir.rcdev = NULL;
146 rc_free_device(rcdev);
147 }
148
149 return ret;
150}
151
152void av7110_ir_exit(struct av7110 *av7110)
153{
154 rc_unregister_device(av7110->ir.rcdev);
155}
156
157
158
159