1 | // SPDX-License-Identifier: GPL-2.0-or-later |
2 | /* |
3 | Mantis PCI bridge driver |
4 | |
5 | Copyright (C) Manu Abraham (abraham.manu@gmail.com) |
6 | |
7 | */ |
8 | |
9 | #include <linux/signal.h> |
10 | #include <linux/slab.h> |
11 | #include <linux/sched.h> |
12 | #include <linux/interrupt.h> |
13 | #include <asm/io.h> |
14 | |
15 | #include <media/dmxdev.h> |
16 | #include <media/dvbdev.h> |
17 | #include <media/dvb_demux.h> |
18 | #include <media/dvb_frontend.h> |
19 | #include <media/dvb_net.h> |
20 | |
21 | #include "mantis_common.h" |
22 | #include "mantis_link.h" |
23 | #include "mantis_hif.h" |
24 | #include "mantis_reg.h" |
25 | |
26 | #include "mantis_ca.h" |
27 | |
28 | static int mantis_ca_read_attr_mem(struct dvb_ca_en50221 *en50221, int slot, int addr) |
29 | { |
30 | struct mantis_ca *ca = en50221->data; |
31 | struct mantis_pci *mantis = ca->ca_priv; |
32 | |
33 | dprintk(MANTIS_DEBUG, 1, "Slot(%d): Request Attribute Mem Read" , slot); |
34 | |
35 | if (slot != 0) |
36 | return -EINVAL; |
37 | |
38 | return mantis_hif_read_mem(ca, addr); |
39 | } |
40 | |
41 | static int mantis_ca_write_attr_mem(struct dvb_ca_en50221 *en50221, int slot, int addr, u8 data) |
42 | { |
43 | struct mantis_ca *ca = en50221->data; |
44 | struct mantis_pci *mantis = ca->ca_priv; |
45 | |
46 | dprintk(MANTIS_DEBUG, 1, "Slot(%d): Request Attribute Mem Write" , slot); |
47 | |
48 | if (slot != 0) |
49 | return -EINVAL; |
50 | |
51 | return mantis_hif_write_mem(ca, addr, data); |
52 | } |
53 | |
54 | static int mantis_ca_read_cam_ctl(struct dvb_ca_en50221 *en50221, int slot, u8 addr) |
55 | { |
56 | struct mantis_ca *ca = en50221->data; |
57 | struct mantis_pci *mantis = ca->ca_priv; |
58 | |
59 | dprintk(MANTIS_DEBUG, 1, "Slot(%d): Request CAM control Read" , slot); |
60 | |
61 | if (slot != 0) |
62 | return -EINVAL; |
63 | |
64 | return mantis_hif_read_iom(ca, addr); |
65 | } |
66 | |
67 | static int mantis_ca_write_cam_ctl(struct dvb_ca_en50221 *en50221, int slot, u8 addr, u8 data) |
68 | { |
69 | struct mantis_ca *ca = en50221->data; |
70 | struct mantis_pci *mantis = ca->ca_priv; |
71 | |
72 | dprintk(MANTIS_DEBUG, 1, "Slot(%d): Request CAM control Write" , slot); |
73 | |
74 | if (slot != 0) |
75 | return -EINVAL; |
76 | |
77 | return mantis_hif_write_iom(ca, addr, data); |
78 | } |
79 | |
80 | static int mantis_ca_slot_reset(struct dvb_ca_en50221 *en50221, int slot) |
81 | { |
82 | struct mantis_ca *ca = en50221->data; |
83 | struct mantis_pci *mantis = ca->ca_priv; |
84 | |
85 | dprintk(MANTIS_DEBUG, 1, "Slot(%d): Slot RESET" , slot); |
86 | udelay(500); /* Wait.. */ |
87 | mmwrite(0xda, MANTIS_PCMCIA_RESET); /* Leading edge assert */ |
88 | udelay(500); |
89 | mmwrite(0x00, MANTIS_PCMCIA_RESET); /* Trailing edge deassert */ |
90 | msleep(msecs: 1000); |
91 | dvb_ca_en50221_camready_irq(pubca: &ca->en50221, slot: 0); |
92 | |
93 | return 0; |
94 | } |
95 | |
96 | static int mantis_ca_slot_shutdown(struct dvb_ca_en50221 *en50221, int slot) |
97 | { |
98 | struct mantis_ca *ca = en50221->data; |
99 | struct mantis_pci *mantis = ca->ca_priv; |
100 | |
101 | dprintk(MANTIS_DEBUG, 1, "Slot(%d): Slot shutdown" , slot); |
102 | |
103 | return 0; |
104 | } |
105 | |
106 | static int mantis_ts_control(struct dvb_ca_en50221 *en50221, int slot) |
107 | { |
108 | struct mantis_ca *ca = en50221->data; |
109 | struct mantis_pci *mantis = ca->ca_priv; |
110 | |
111 | dprintk(MANTIS_DEBUG, 1, "Slot(%d): TS control" , slot); |
112 | |
113 | return 0; |
114 | } |
115 | |
116 | static int mantis_slot_status(struct dvb_ca_en50221 *en50221, int slot, int open) |
117 | { |
118 | struct mantis_ca *ca = en50221->data; |
119 | struct mantis_pci *mantis = ca->ca_priv; |
120 | |
121 | dprintk(MANTIS_DEBUG, 1, "Slot(%d): Poll Slot status" , slot); |
122 | |
123 | if (ca->slot_state == MODULE_INSERTED) { |
124 | dprintk(MANTIS_DEBUG, 1, "CA Module present and ready" ); |
125 | return DVB_CA_EN50221_POLL_CAM_PRESENT | DVB_CA_EN50221_POLL_CAM_READY; |
126 | } else { |
127 | dprintk(MANTIS_DEBUG, 1, "CA Module not present or not ready" ); |
128 | } |
129 | |
130 | return 0; |
131 | } |
132 | |
133 | int mantis_ca_init(struct mantis_pci *mantis) |
134 | { |
135 | struct dvb_adapter *dvb_adapter = &mantis->dvb_adapter; |
136 | struct mantis_ca *ca; |
137 | int ca_flags = 0, result; |
138 | |
139 | dprintk(MANTIS_DEBUG, 1, "Initializing Mantis CA" ); |
140 | ca = kzalloc(size: sizeof(struct mantis_ca), GFP_KERNEL); |
141 | if (!ca) { |
142 | dprintk(MANTIS_ERROR, 1, "Out of memory!, exiting .." ); |
143 | result = -ENOMEM; |
144 | goto err; |
145 | } |
146 | |
147 | ca->ca_priv = mantis; |
148 | mantis->mantis_ca = ca; |
149 | ca_flags = DVB_CA_EN50221_FLAG_IRQ_CAMCHANGE; |
150 | /* register CA interface */ |
151 | ca->en50221.owner = THIS_MODULE; |
152 | ca->en50221.read_attribute_mem = mantis_ca_read_attr_mem; |
153 | ca->en50221.write_attribute_mem = mantis_ca_write_attr_mem; |
154 | ca->en50221.read_cam_control = mantis_ca_read_cam_ctl; |
155 | ca->en50221.write_cam_control = mantis_ca_write_cam_ctl; |
156 | ca->en50221.slot_reset = mantis_ca_slot_reset; |
157 | ca->en50221.slot_shutdown = mantis_ca_slot_shutdown; |
158 | ca->en50221.slot_ts_enable = mantis_ts_control; |
159 | ca->en50221.poll_slot_status = mantis_slot_status; |
160 | ca->en50221.data = ca; |
161 | |
162 | mutex_init(&ca->ca_lock); |
163 | |
164 | init_waitqueue_head(&ca->hif_data_wq); |
165 | init_waitqueue_head(&ca->hif_opdone_wq); |
166 | init_waitqueue_head(&ca->hif_write_wq); |
167 | |
168 | dprintk(MANTIS_ERROR, 1, "Registering EN50221 device" ); |
169 | result = dvb_ca_en50221_init(dvb_adapter, ca: &ca->en50221, flags: ca_flags, slot_count: 1); |
170 | if (result != 0) { |
171 | dprintk(MANTIS_ERROR, 1, "EN50221: Initialization failed <%d>" , result); |
172 | goto err; |
173 | } |
174 | dprintk(MANTIS_ERROR, 1, "Registered EN50221 device" ); |
175 | mantis_evmgr_init(ca); |
176 | return 0; |
177 | err: |
178 | kfree(objp: ca); |
179 | return result; |
180 | } |
181 | EXPORT_SYMBOL_GPL(mantis_ca_init); |
182 | |
183 | void mantis_ca_exit(struct mantis_pci *mantis) |
184 | { |
185 | struct mantis_ca *ca = mantis->mantis_ca; |
186 | |
187 | dprintk(MANTIS_DEBUG, 1, "Mantis CA exit" ); |
188 | if (!ca) |
189 | return; |
190 | |
191 | mantis_evmgr_exit(ca); |
192 | dprintk(MANTIS_ERROR, 1, "Unregistering EN50221 device" ); |
193 | dvb_ca_en50221_release(ca: &ca->en50221); |
194 | |
195 | kfree(objp: ca); |
196 | } |
197 | EXPORT_SYMBOL_GPL(mantis_ca_exit); |
198 | |