1/*
2	Mantis PCI bridge driver
3
4	Copyright (C) Manu Abraham (abraham.manu@gmail.com)
5
6	This program is free software; you can redistribute it and/or modify
7	it under the terms of the GNU General Public License as published by
8	the Free Software Foundation; either version 2 of the License, or
9	(at your option) any later version.
10
11	This program is distributed in the hope that it will be useful,
12	but WITHOUT ANY WARRANTY; without even the implied warranty of
13	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14	GNU General Public License for more details.
15
16	You should have received a copy of the GNU General Public License
17	along with this program; if not, write to the Free Software
18	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19*/
20
21#include <linux/signal.h>
22#include <linux/slab.h>
23#include <linux/sched.h>
24#include <linux/interrupt.h>
25#include <asm/io.h>
26
27#include "dmxdev.h"
28#include "dvbdev.h"
29#include "dvb_demux.h"
30#include "dvb_frontend.h"
31#include "dvb_net.h"
32
33#include "mantis_common.h"
34#include "mantis_link.h"
35#include "mantis_hif.h"
36#include "mantis_reg.h"
37
38#include "mantis_ca.h"
39
40static int mantis_ca_read_attr_mem(struct dvb_ca_en50221 *en50221, int slot, int addr)
41{
42	struct mantis_ca *ca = en50221->data;
43	struct mantis_pci *mantis = ca->ca_priv;
44
45	dprintk(MANTIS_DEBUG, 1, "Slot(%d): Request Attribute Mem Read", slot);
46
47	if (slot != 0)
48		return -EINVAL;
49
50	return mantis_hif_read_mem(ca, addr);
51}
52
53static int mantis_ca_write_attr_mem(struct dvb_ca_en50221 *en50221, int slot, int addr, u8 data)
54{
55	struct mantis_ca *ca = en50221->data;
56	struct mantis_pci *mantis = ca->ca_priv;
57
58	dprintk(MANTIS_DEBUG, 1, "Slot(%d): Request Attribute Mem Write", slot);
59
60	if (slot != 0)
61		return -EINVAL;
62
63	return mantis_hif_write_mem(ca, addr, data);
64}
65
66static int mantis_ca_read_cam_ctl(struct dvb_ca_en50221 *en50221, int slot, u8 addr)
67{
68	struct mantis_ca *ca = en50221->data;
69	struct mantis_pci *mantis = ca->ca_priv;
70
71	dprintk(MANTIS_DEBUG, 1, "Slot(%d): Request CAM control Read", slot);
72
73	if (slot != 0)
74		return -EINVAL;
75
76	return mantis_hif_read_iom(ca, addr);
77}
78
79static int mantis_ca_write_cam_ctl(struct dvb_ca_en50221 *en50221, int slot, u8 addr, u8 data)
80{
81	struct mantis_ca *ca = en50221->data;
82	struct mantis_pci *mantis = ca->ca_priv;
83
84	dprintk(MANTIS_DEBUG, 1, "Slot(%d): Request CAM control Write", slot);
85
86	if (slot != 0)
87		return -EINVAL;
88
89	return mantis_hif_write_iom(ca, addr, data);
90}
91
92static int mantis_ca_slot_reset(struct dvb_ca_en50221 *en50221, int slot)
93{
94	struct mantis_ca *ca = en50221->data;
95	struct mantis_pci *mantis = ca->ca_priv;
96
97	dprintk(MANTIS_DEBUG, 1, "Slot(%d): Slot RESET", slot);
98	udelay(500); /* Wait.. */
99	mmwrite(0xda, MANTIS_PCMCIA_RESET); /* Leading edge assert */
100	udelay(500);
101	mmwrite(0x00, MANTIS_PCMCIA_RESET); /* Trailing edge deassert */
102	msleep(1000);
103	dvb_ca_en50221_camready_irq(&ca->en50221, 0);
104
105	return 0;
106}
107
108static int mantis_ca_slot_shutdown(struct dvb_ca_en50221 *en50221, int slot)
109{
110	struct mantis_ca *ca = en50221->data;
111	struct mantis_pci *mantis = ca->ca_priv;
112
113	dprintk(MANTIS_DEBUG, 1, "Slot(%d): Slot shutdown", slot);
114
115	return 0;
116}
117
118static int mantis_ts_control(struct dvb_ca_en50221 *en50221, int slot)
119{
120	struct mantis_ca *ca = en50221->data;
121	struct mantis_pci *mantis = ca->ca_priv;
122
123	dprintk(MANTIS_DEBUG, 1, "Slot(%d): TS control", slot);
124/*	mantis_set_direction(mantis, 1); */ /* Enable TS through CAM */
125
126	return 0;
127}
128
129static int mantis_slot_status(struct dvb_ca_en50221 *en50221, int slot, int open)
130{
131	struct mantis_ca *ca = en50221->data;
132	struct mantis_pci *mantis = ca->ca_priv;
133
134	dprintk(MANTIS_DEBUG, 1, "Slot(%d): Poll Slot status", slot);
135
136	if (ca->slot_state == MODULE_INSERTED) {
137		dprintk(MANTIS_DEBUG, 1, "CA Module present and ready");
138		return DVB_CA_EN50221_POLL_CAM_PRESENT | DVB_CA_EN50221_POLL_CAM_READY;
139	} else {
140		dprintk(MANTIS_DEBUG, 1, "CA Module not present or not ready");
141	}
142
143	return 0;
144}
145
146int mantis_ca_init(struct mantis_pci *mantis)
147{
148	struct dvb_adapter *dvb_adapter	= &mantis->dvb_adapter;
149	struct mantis_ca *ca;
150	int ca_flags = 0, result;
151
152	dprintk(MANTIS_DEBUG, 1, "Initializing Mantis CA");
153	ca = kzalloc(sizeof(struct mantis_ca), GFP_KERNEL);
154	if (!ca) {
155		dprintk(MANTIS_ERROR, 1, "Out of memory!, exiting ..");
156		result = -ENOMEM;
157		goto err;
158	}
159
160	ca->ca_priv		= mantis;
161	mantis->mantis_ca	= ca;
162	ca_flags		= DVB_CA_EN50221_FLAG_IRQ_CAMCHANGE;
163	/* register CA interface */
164	ca->en50221.owner		= THIS_MODULE;
165	ca->en50221.read_attribute_mem	= mantis_ca_read_attr_mem;
166	ca->en50221.write_attribute_mem	= mantis_ca_write_attr_mem;
167	ca->en50221.read_cam_control	= mantis_ca_read_cam_ctl;
168	ca->en50221.write_cam_control	= mantis_ca_write_cam_ctl;
169	ca->en50221.slot_reset		= mantis_ca_slot_reset;
170	ca->en50221.slot_shutdown	= mantis_ca_slot_shutdown;
171	ca->en50221.slot_ts_enable	= mantis_ts_control;
172	ca->en50221.poll_slot_status	= mantis_slot_status;
173	ca->en50221.data		= ca;
174
175	mutex_init(&ca->ca_lock);
176
177	init_waitqueue_head(&ca->hif_data_wq);
178	init_waitqueue_head(&ca->hif_opdone_wq);
179	init_waitqueue_head(&ca->hif_write_wq);
180
181	dprintk(MANTIS_ERROR, 1, "Registering EN50221 device");
182	result = dvb_ca_en50221_init(dvb_adapter, &ca->en50221, ca_flags, 1);
183	if (result != 0) {
184		dprintk(MANTIS_ERROR, 1, "EN50221: Initialization failed <%d>", result);
185		goto err;
186	}
187	dprintk(MANTIS_ERROR, 1, "Registered EN50221 device");
188	mantis_evmgr_init(ca);
189	return 0;
190err:
191	kfree(ca);
192	return result;
193}
194EXPORT_SYMBOL_GPL(mantis_ca_init);
195
196void mantis_ca_exit(struct mantis_pci *mantis)
197{
198	struct mantis_ca *ca = mantis->mantis_ca;
199
200	dprintk(MANTIS_DEBUG, 1, "Mantis CA exit");
201	if (!ca)
202		return;
203
204	mantis_evmgr_exit(ca);
205	dprintk(MANTIS_ERROR, 1, "Unregistering EN50221 device");
206	dvb_ca_en50221_release(&ca->en50221);
207
208	kfree(ca);
209}
210EXPORT_SYMBOL_GPL(mantis_ca_exit);
211