3ef25cc4bfdbc3e8c8d689e87804e91ab53fb643
[linux-2.6-block.git] / drivers / media / dvb / firesat / firesat-ci.c
1 /*
2  * FireDTV driver (formerly known as FireSAT)
3  *
4  * Copyright (C) 2004 Andreas Monitzer <andy@monitzer.com>
5  * Copyright (C) 2008 Henrik Kurelid <henrik@kurelid.se>
6  *
7  *      This program is free software; you can redistribute it and/or
8  *      modify it under the terms of the GNU General Public License as
9  *      published by the Free Software Foundation; either version 2 of
10  *      the License, or (at your option) any later version.
11  */
12
13 #include <linux/dvb/ca.h>
14 #include <linux/fs.h>
15 #include <linux/module.h>
16
17 #include <dvbdev.h>
18
19 #include "avc_api.h"
20 #include "firesat.h"
21 #include "firesat-ci.h"
22
23 static unsigned int ca_debug = 0;
24 module_param(ca_debug, int, 0644);
25 MODULE_PARM_DESC(ca_debug, "debug logging of ca system, default is 0 (no)");
26
27 static int firesat_ca_ready(ANTENNA_INPUT_INFO *info)
28 {
29         if (ca_debug != 0)
30                 printk("%s: CaMmi=%d, CaInit=%d, CaError=%d, CaDvb=%d, "
31                        "CaModule=%d, CaAppInfo=%d, CaDateTime=%d, "
32                        "CaPmt=%d\n", __func__, info->CaMmi,
33                        info->CaInitializationStatus, info->CaErrorFlag,
34                        info->CaDvbFlag, info->CaModulePresentStatus,
35                        info->CaApplicationInfo,
36                        info->CaDateTimeRequest, info->CaPmtReply);
37         return info->CaInitializationStatus == 1 &&
38                 info->CaErrorFlag == 0 &&
39                 info->CaDvbFlag == 1 &&
40                 info->CaModulePresentStatus == 1;
41 }
42
43 static int firesat_get_ca_flags(ANTENNA_INPUT_INFO *info)
44 {
45         int flags = 0;
46         if (info->CaModulePresentStatus == 1)
47                 flags |= CA_CI_MODULE_PRESENT;
48         if (info->CaInitializationStatus == 1 &&
49             info->CaErrorFlag == 0 &&
50             info->CaDvbFlag == 1)
51                 flags |= CA_CI_MODULE_READY;
52         return flags;
53 }
54
55 static int firesat_ca_reset(struct firesat *firesat)
56 {
57         if (ca_debug)
58                 printk(KERN_INFO "%s: ioctl CA_RESET\n", __func__);
59         if (avc_ca_reset(firesat))
60                 return -EFAULT;
61         return 0;
62 }
63
64 static int firesat_ca_get_caps(struct firesat *firesat, void *arg)
65 {
66         struct ca_caps *cap_p = (struct ca_caps*)arg;
67         int err = 0;
68
69         cap_p->slot_num = 1;
70         cap_p->slot_type = CA_CI;
71         cap_p->descr_num = 1;
72         cap_p->descr_type = CA_ECD;
73         if (ca_debug)
74                 printk(KERN_INFO "%s: ioctl CA_GET_CAP\n", __func__);
75         return err;
76 }
77
78 static int firesat_ca_get_slot_info(struct firesat *firesat, void *arg)
79 {
80         ANTENNA_INPUT_INFO info;
81         struct ca_slot_info *slot_p = (struct ca_slot_info*)arg;
82
83         if (ca_debug)
84                 printk(KERN_INFO "%s: ioctl CA_GET_SLOT_INFO on slot %d.\n",
85                        __func__, slot_p->num);
86         if (AVCTunerStatus(firesat, &info))
87                 return -EFAULT;
88
89         if (slot_p->num == 0) {
90                 slot_p->type = CA_CI;
91                 slot_p->flags = firesat_get_ca_flags(&info);
92         }
93         else {
94                 return -EFAULT;
95         }
96         return 0;
97 }
98
99 static int firesat_ca_app_info(struct firesat *firesat, void *arg)
100 {
101         struct ca_msg *reply_p = (struct ca_msg*)arg;
102         int i;
103
104         if (avc_ca_app_info(firesat, reply_p->msg, &reply_p->length))
105                 return -EFAULT;
106         if (ca_debug) {
107                 printk(KERN_INFO "%s: Creating TAG_APP_INFO message:",
108                        __func__);
109                 for (i = 0; i < reply_p->length; i++)
110                         printk("0x%02X, ", (unsigned char)reply_p->msg[i]);
111                 printk("\n");
112                 }
113         return 0;
114 }
115
116 static int firesat_ca_info(struct firesat *firesat, void *arg)
117 {
118         struct ca_msg *reply_p = (struct ca_msg*)arg;
119         int i;
120
121         if (avc_ca_info(firesat, reply_p->msg, &reply_p->length))
122                 return -EFAULT;
123         if (ca_debug) {
124                 printk(KERN_INFO "%s: Creating TAG_CA_INFO message:",
125                        __func__);
126                 for (i = 0; i < reply_p->length; i++)
127                         printk("0x%02X, ", (unsigned char)reply_p->msg[i]);
128                 printk("\n");
129         }
130         return 0;
131 }
132
133 static int firesat_ca_get_mmi(struct firesat *firesat, void *arg)
134 {
135         struct ca_msg *reply_p = (struct ca_msg*)arg;
136         int i;
137
138         if (avc_ca_get_mmi(firesat, reply_p->msg, &reply_p->length))
139                 return -EFAULT;
140         if (ca_debug) {
141                 printk(KERN_INFO "%s: Creating MMI reply INFO message:",
142                        __func__);
143                 for (i = 0; i < reply_p->length; i++)
144                         printk("0x%02X, ", (unsigned char)reply_p->msg[i]);
145                 printk("\n");
146         }
147         return 0;
148 }
149
150 static int firesat_ca_get_msg(struct firesat *firesat, void *arg)
151 {
152         int err;
153         ANTENNA_INPUT_INFO info;
154
155         switch (firesat->ca_last_command) {
156         case TAG_APP_INFO_ENQUIRY:
157                 err = firesat_ca_app_info(firesat, arg);
158                 break;
159         case TAG_CA_INFO_ENQUIRY:
160                 err = firesat_ca_info(firesat, arg);
161                 break;
162         default:
163                 if (AVCTunerStatus(firesat, &info))
164                         err = -EFAULT;
165                 else if (info.CaMmi == 1) {
166                         err = firesat_ca_get_mmi(firesat, arg);
167                 }
168                 else {
169                         printk(KERN_INFO "%s: Unhandled message 0x%08X\n",
170                                __func__, firesat->ca_last_command);
171                         err = -EFAULT;
172                 }
173         }
174         firesat->ca_last_command = 0;
175         return err;
176 }
177
178 static int firesat_ca_pmt(struct firesat *firesat, void *arg)
179 {
180         struct ca_msg *msg_p = (struct ca_msg*)arg;
181         int data_pos;
182
183         if (msg_p->msg[3] & 0x80)
184                 data_pos = (msg_p->msg[4] && 0x7F) + 4;
185         else
186                 data_pos = 4;
187         if (avc_ca_pmt(firesat, &msg_p->msg[data_pos],
188                        msg_p->length - data_pos))
189                 return -EFAULT;
190         return 0;
191 }
192
193 static int firesat_ca_send_msg(struct firesat *firesat, void *arg)
194 {
195         int err;
196         struct ca_msg *msg_p = (struct ca_msg*)arg;
197
198         // Do we need a semaphore for this?
199         firesat->ca_last_command =
200                 (msg_p->msg[0] << 16) + (msg_p->msg[1] << 8) + msg_p->msg[2];
201         switch (firesat->ca_last_command) {
202         case TAG_CA_PMT:
203                 if (ca_debug != 0)
204                         printk(KERN_INFO "%s: Message received: TAG_CA_PMT\n",
205                                __func__);
206                 err = firesat_ca_pmt(firesat, arg);
207                 break;
208         case TAG_APP_INFO_ENQUIRY:
209                 // This is all handled in ca_get_msg
210                 if (ca_debug != 0)
211                         printk(KERN_INFO "%s: Message received: "
212                                "TAG_APP_INFO_ENQUIRY\n", __func__);
213                 err = 0;
214                 break;
215         case TAG_CA_INFO_ENQUIRY:
216                 // This is all handled in ca_get_msg
217                 if (ca_debug != 0)
218                         printk(KERN_INFO "%s: Message received: "
219                                "TAG_CA_APP_INFO_ENQUIRY\n", __func__);
220                 err = 0;
221                 break;
222         case TAG_ENTER_MENU:
223                 if (ca_debug != 0)
224                         printk(KERN_INFO "%s: Entering CA menu.\n", __func__);
225                 err = avc_ca_enter_menu(firesat);
226                 break;
227         default:
228                 printk(KERN_ERR "%s: Unhandled unknown message 0x%08X\n",
229                        __func__, firesat->ca_last_command);
230                 err = -EFAULT;
231         }
232         return err;
233 }
234
235 static int firesat_ca_ioctl(struct inode *inode, struct file *file,
236                             unsigned int cmd, void *arg)
237 {
238         struct dvb_device* dvbdev = (struct dvb_device*) file->private_data;
239         struct firesat *firesat = dvbdev->priv;
240         int err;
241         ANTENNA_INPUT_INFO info;
242
243         switch(cmd) {
244         case CA_RESET:
245                 err = firesat_ca_reset(firesat);
246                 break;
247         case CA_GET_CAP:
248                 err = firesat_ca_get_caps(firesat, arg);
249                 break;
250         case CA_GET_SLOT_INFO:
251                 err = firesat_ca_get_slot_info(firesat, arg);
252                 break;
253         case CA_GET_MSG:
254                 err = firesat_ca_get_msg(firesat, arg);
255                 break;
256         case CA_SEND_MSG:
257                 err = firesat_ca_send_msg(firesat, arg);
258                 break;
259         default:
260                 printk(KERN_INFO "%s: Unhandled ioctl, command: %u\n",__func__,
261                        cmd);
262                 err = -EOPNOTSUPP;
263         }
264
265         if (AVCTunerStatus(firesat, &info))
266                 return err;
267
268         firesat_ca_ready(&info);
269
270         return err;
271 }
272
273 static int firesat_get_date_time_request(struct firesat *firesat)
274 {
275         if (ca_debug)
276                 printk(KERN_INFO "%s: Retrieving Time/Date request\n",
277                        __func__);
278         if (avc_ca_get_time_date(firesat, &firesat->ca_time_interval))
279                 return -EFAULT;
280         if (ca_debug)
281                 printk(KERN_INFO "%s: Time/Date interval is %d\n",
282                        __func__, firesat->ca_time_interval);
283
284         return 0;
285 }
286
287 static int firesat_ca_io_open(struct inode *inode, struct file *file)
288 {
289         if (ca_debug != 0)
290                 printk(KERN_INFO "%s\n",__func__);
291         return dvb_generic_open(inode, file);
292 }
293
294 static int firesat_ca_io_release(struct inode *inode, struct file *file)
295 {
296         if (ca_debug != 0)
297                 printk(KERN_INFO "%s\n",__func__);
298         return dvb_generic_release(inode, file);
299 }
300
301 static unsigned int firesat_ca_io_poll(struct file *file, poll_table *wait)
302 {
303         if (ca_debug != 0)
304                 printk(KERN_INFO "%s\n",__func__);
305         return POLLIN;
306 }
307
308 static struct file_operations firesat_ca_fops = {
309         .owner = THIS_MODULE,
310         .read = NULL, // There is no low level read anymore
311         .write = NULL, // There is no low level write anymore
312         .ioctl = dvb_generic_ioctl,
313         .open = firesat_ca_io_open,
314         .release = firesat_ca_io_release,
315         .poll = firesat_ca_io_poll,
316 };
317
318 static struct dvb_device firesat_ca = {
319         .priv = NULL,
320         .users = 1,
321         .readers = 1,
322         .writers = 1,
323         .fops = &firesat_ca_fops,
324         .kernel_ioctl = firesat_ca_ioctl,
325 };
326
327 int firesat_ca_init(struct firesat *firesat)
328 {
329         int err;
330         ANTENNA_INPUT_INFO info;
331
332         if (AVCTunerStatus(firesat, &info))
333                 return -EINVAL;
334
335         if (firesat_ca_ready(&info)) {
336                 err = dvb_register_device(firesat->adapter,
337                                               &firesat->cadev,
338                                               &firesat_ca, firesat,
339                                               DVB_DEVICE_CA);
340
341                 if (info.CaApplicationInfo == 0)
342                         printk(KERN_ERR "%s: CaApplicationInfo is not set.\n",
343                                __func__);
344                 if (info.CaDateTimeRequest == 1)
345                         firesat_get_date_time_request(firesat);
346         }
347         else
348                 err = -EFAULT;
349
350         return err;
351 }
352
353 void firesat_ca_release(struct firesat *firesat)
354 {
355         if (firesat->cadev)
356         dvb_unregister_device(firesat->cadev);
357 }