2 * av7110_ca.c: CA and CI stuff
4 * Copyright (C) 1999-2002 Ralph Metzler
5 * & Marcus Metzler for convergence integrated media GmbH
7 * originally based on code by:
8 * Copyright (C) 1998,1999 Christian Theiss <mistert@rz.fh-augsburg.de>
10 * This program is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU General Public License
12 * as published by the Free Software Foundation; either version 2
13 * of the License, or (at your option) any later version.
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, write to the Free Software
24 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
25 * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
28 * the project's page is at http://www.linuxtv.org/dvb/
31 #include <linux/kernel.h>
32 #include <linux/sched.h>
33 #include <linux/types.h>
34 #include <linux/delay.h>
36 #include <linux/timer.h>
37 #include <linux/poll.h>
38 #include <linux/byteorder/swabb.h>
39 #include <linux/smp_lock.h>
42 #include "av7110_hw.h"
45 void CI_handle(struct av7110
*av7110
, u8
*data
, u16 len
)
47 dprintk(8, "av7110:%p\n",av7110
);
53 if (data
[2] != 1 && data
[2] != 2)
57 av7110
->ci_slot
[data
[2] - 1].flags
= 0;
60 av7110
->ci_slot
[data
[2] - 1].flags
|= CA_CI_MODULE_PRESENT
;
63 av7110
->ci_slot
[data
[2] - 1].flags
|= CA_CI_MODULE_READY
;
67 case CI_SWITCH_PRG_REPLY
:
68 //av7110->ci_stat=data[1];
76 void ci_get_data(struct dvb_ringbuffer
*cibuf
, u8
*data
, int len
)
78 if (dvb_ringbuffer_free(cibuf
) < len
+ 2)
81 DVB_RINGBUFFER_WRITE_BYTE(cibuf
, len
>> 8);
82 DVB_RINGBUFFER_WRITE_BYTE(cibuf
, len
& 0xff);
83 dvb_ringbuffer_write(cibuf
, data
, len
);
84 wake_up_interruptible(&cibuf
->queue
);
88 /******************************************************************************
89 * CI link layer file ops
90 ******************************************************************************/
92 static int ci_ll_init(struct dvb_ringbuffer
*cirbuf
, struct dvb_ringbuffer
*ciwbuf
, int size
)
94 struct dvb_ringbuffer
*tab
[] = { cirbuf
, ciwbuf
, NULL
}, **p
;
97 for (p
= tab
; *p
; p
++) {
106 dvb_ringbuffer_init(*p
, data
, size
);
111 static void ci_ll_flush(struct dvb_ringbuffer
*cirbuf
, struct dvb_ringbuffer
*ciwbuf
)
113 dvb_ringbuffer_flush_spinlock_wakeup(cirbuf
);
114 dvb_ringbuffer_flush_spinlock_wakeup(ciwbuf
);
117 static void ci_ll_release(struct dvb_ringbuffer
*cirbuf
, struct dvb_ringbuffer
*ciwbuf
)
125 static int ci_ll_reset(struct dvb_ringbuffer
*cibuf
, struct file
*file
,
126 int slots
, ca_slot_info_t
*slot
)
130 u8 msg
[8] = { 0x00, 0x06, 0x00, 0x00, 0xff, 0x02, 0x00, 0x00 };
132 for (i
= 0; i
< 2; i
++) {
133 if (slots
& (1 << i
))
137 if (dvb_ringbuffer_free(cibuf
) < len
)
140 for (i
= 0; i
< 2; i
++) {
141 if (slots
& (1 << i
)) {
143 dvb_ringbuffer_write(cibuf
, msg
, 8);
151 static ssize_t
ci_ll_write(struct dvb_ringbuffer
*cibuf
, struct file
*file
,
152 const char __user
*buf
, size_t count
, loff_t
*ppos
)
155 int non_blocking
= file
->f_flags
& O_NONBLOCK
;
156 char *page
= (char *)__get_free_page(GFP_USER
);
167 if (copy_from_user(page
, buf
, count
))
170 free
= dvb_ringbuffer_free(cibuf
);
171 if (count
+ 2 > free
) {
176 if (wait_event_interruptible(cibuf
->queue
,
177 (dvb_ringbuffer_free(cibuf
) >= count
+ 2)))
181 DVB_RINGBUFFER_WRITE_BYTE(cibuf
, count
>> 8);
182 DVB_RINGBUFFER_WRITE_BYTE(cibuf
, count
& 0xff);
184 res
= dvb_ringbuffer_write(cibuf
, page
, count
);
186 free_page((unsigned long)page
);
190 static ssize_t
ci_ll_read(struct dvb_ringbuffer
*cibuf
, struct file
*file
,
191 char __user
*buf
, size_t count
, loff_t
*ppos
)
194 int non_blocking
= file
->f_flags
& O_NONBLOCK
;
197 if (!cibuf
->data
|| !count
)
199 if (non_blocking
&& (dvb_ringbuffer_empty(cibuf
)))
201 if (wait_event_interruptible(cibuf
->queue
,
202 !dvb_ringbuffer_empty(cibuf
)))
204 avail
= dvb_ringbuffer_avail(cibuf
);
207 len
= DVB_RINGBUFFER_PEEK(cibuf
, 0) << 8;
208 len
|= DVB_RINGBUFFER_PEEK(cibuf
, 1);
209 if (avail
< len
+ 2 || count
< len
)
211 DVB_RINGBUFFER_SKIP(cibuf
, 2);
213 return dvb_ringbuffer_read(cibuf
, buf
, len
, 1);
216 static int dvb_ca_open(struct inode
*inode
, struct file
*file
)
218 struct dvb_device
*dvbdev
= (struct dvb_device
*) file
->private_data
;
219 struct av7110
*av7110
= (struct av7110
*) dvbdev
->priv
;
220 int err
= dvb_generic_open(inode
, file
);
222 dprintk(8, "av7110:%p\n",av7110
);
226 ci_ll_flush(&av7110
->ci_rbuffer
, &av7110
->ci_wbuffer
);
230 static unsigned int dvb_ca_poll (struct file
*file
, poll_table
*wait
)
232 struct dvb_device
*dvbdev
= (struct dvb_device
*) file
->private_data
;
233 struct av7110
*av7110
= (struct av7110
*) dvbdev
->priv
;
234 struct dvb_ringbuffer
*rbuf
= &av7110
->ci_rbuffer
;
235 struct dvb_ringbuffer
*wbuf
= &av7110
->ci_wbuffer
;
236 unsigned int mask
= 0;
238 dprintk(8, "av7110:%p\n",av7110
);
240 poll_wait(file
, &rbuf
->queue
, wait
);
241 poll_wait(file
, &wbuf
->queue
, wait
);
243 if (!dvb_ringbuffer_empty(rbuf
))
244 mask
|= (POLLIN
| POLLRDNORM
);
246 if (dvb_ringbuffer_free(wbuf
) > 1024)
247 mask
|= (POLLOUT
| POLLWRNORM
);
252 static int dvb_ca_ioctl(struct inode
*inode
, struct file
*file
,
253 unsigned int cmd
, void *parg
)
255 struct dvb_device
*dvbdev
= (struct dvb_device
*) file
->private_data
;
256 struct av7110
*av7110
= (struct av7110
*) dvbdev
->priv
;
257 unsigned long arg
= (unsigned long) parg
;
259 dprintk(8, "av7110:%p\n",av7110
);
263 return ci_ll_reset(&av7110
->ci_wbuffer
, file
, arg
, &av7110
->ci_slot
[0]);
270 cap
.slot_type
= (FW_CI_LL_SUPPORT(av7110
->arm_app
) ?
271 CA_CI_LINK
: CA_CI
) | CA_DESCR
;
273 cap
.descr_type
= CA_ECD
;
274 memcpy(parg
, &cap
, sizeof(cap
));
278 case CA_GET_SLOT_INFO
:
280 ca_slot_info_t
*info
=(ca_slot_info_t
*)parg
;
284 av7110
->ci_slot
[info
->num
].num
= info
->num
;
285 av7110
->ci_slot
[info
->num
].type
= FW_CI_LL_SUPPORT(av7110
->arm_app
) ?
287 memcpy(info
, &av7110
->ci_slot
[info
->num
], sizeof(ca_slot_info_t
));
297 case CA_GET_DESCR_INFO
:
299 ca_descr_info_t info
;
303 memcpy(parg
, &info
, sizeof (info
));
309 ca_descr_t
*descr
= (ca_descr_t
*) parg
;
311 if (descr
->index
>= 16)
313 if (descr
->parity
> 1)
315 av7110_fw_cmd(av7110
, COMTYPE_PIDFILTER
, SetDescr
, 5,
316 (descr
->index
<<8)|descr
->parity
,
317 (descr
->cw
[0]<<8)|descr
->cw
[1],
318 (descr
->cw
[2]<<8)|descr
->cw
[3],
319 (descr
->cw
[4]<<8)|descr
->cw
[5],
320 (descr
->cw
[6]<<8)|descr
->cw
[7]);
330 static ssize_t
dvb_ca_write(struct file
*file
, const char __user
*buf
,
331 size_t count
, loff_t
*ppos
)
333 struct dvb_device
*dvbdev
= (struct dvb_device
*) file
->private_data
;
334 struct av7110
*av7110
= (struct av7110
*) dvbdev
->priv
;
336 dprintk(8, "av7110:%p\n",av7110
);
337 return ci_ll_write(&av7110
->ci_wbuffer
, file
, buf
, count
, ppos
);
340 static ssize_t
dvb_ca_read(struct file
*file
, char __user
*buf
,
341 size_t count
, loff_t
*ppos
)
343 struct dvb_device
*dvbdev
= (struct dvb_device
*) file
->private_data
;
344 struct av7110
*av7110
= (struct av7110
*) dvbdev
->priv
;
346 dprintk(8, "av7110:%p\n",av7110
);
347 return ci_ll_read(&av7110
->ci_rbuffer
, file
, buf
, count
, ppos
);
352 static struct file_operations dvb_ca_fops
= {
353 .owner
= THIS_MODULE
,
355 .write
= dvb_ca_write
,
356 .ioctl
= dvb_generic_ioctl
,
358 .release
= dvb_generic_release
,
362 static struct dvb_device dvbdev_ca
= {
366 .fops
= &dvb_ca_fops
,
367 .kernel_ioctl
= dvb_ca_ioctl
,
371 int av7110_ca_register(struct av7110
*av7110
)
373 return dvb_register_device(&av7110
->dvb_adapter
, &av7110
->ca_dev
,
374 &dvbdev_ca
, av7110
, DVB_DEVICE_CA
);
377 void av7110_ca_unregister(struct av7110
*av7110
)
379 dvb_unregister_device(av7110
->ca_dev
);
382 int av7110_ca_init(struct av7110
* av7110
)
384 return ci_ll_init(&av7110
->ci_rbuffer
, &av7110
->ci_wbuffer
, 8192);
387 void av7110_ca_exit(struct av7110
* av7110
)
389 ci_ll_release(&av7110
->ci_rbuffer
, &av7110
->ci_wbuffer
);