Commit 7679ba7b authored by Michael Hunold's avatar Michael Hunold Committed by Linus Torvalds

[PATCH] DVB: Add EN50221 cam support to dvb-core

 - [DVB] add generic functions for EN50221 CAM interfaces
parent 2b7f4a04
...@@ -3,6 +3,7 @@ ...@@ -3,6 +3,7 @@
# #
dvb-core-objs = dvbdev.o dmxdev.o dvb_demux.o dvb_filter.o \ dvb-core-objs = dvbdev.o dmxdev.o dvb_demux.o dvb_filter.o \
dvb_functions.o dvb_frontend.o dvb_i2c.o dvb_net.o dvb_ksyms.o dvb_ringbuffer.o dvb_ca_en50221.o dvb_functions.o dvb_frontend.o \
dvb_i2c.o dvb_net.o dvb_ksyms.o dvb_ringbuffer.o
obj-$(CONFIG_DVB_CORE) += dvb-core.o obj-$(CONFIG_DVB_CORE) += dvb-core.o
This diff is collapsed.
/*
* dvb_ca.h: generic DVB functions for EN50221 CA interfaces
*
* Copyright (C) 2004 Andrew de Quincey
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2.1
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#ifndef _DVB_CA_EN50221_H_
#define _DVB_CA_EN50221_H_
#include <linux/list.h>
#include <linux/dvb/ca.h>
#include "dvbdev.h"
#define DVB_CA_EN50221_POLL_CAM_PRESENT 1
#define DVB_CA_EN50221_POLL_CAM_CHANGED 2
#define DVB_CA_EN50221_POLL_CAM_READY 4
#define DVB_CA_EN50221_FLAG_IRQ_CAMCHANGE 1
#define DVB_CA_EN50221_FLAG_IRQ_FR 2
#define DVB_CA_EN50221_FLAG_IRQ_DA 4
#define DVB_CA_EN50221_CAMCHANGE_REMOVED 0
#define DVB_CA_EN50221_CAMCHANGE_INSERTED 1
/* Structure describing a CA interface */
struct dvb_ca_en50221 {
/* functions for accessing attribute memory on the CAM */
int (*read_attribute_mem)(struct dvb_ca_en50221* ca, int slot, int address);
int (*write_attribute_mem)(struct dvb_ca_en50221* ca, int slot, int address, u8 value);
/* functions for accessing the control interface on the CAM */
int (*read_cam_control)(struct dvb_ca_en50221* ca, int slot, u8 address);
int (*write_cam_control)(struct dvb_ca_en50221* ca, int slot, u8 address, u8 value);
/* Functions for controlling slots */
int (*slot_reset)(struct dvb_ca_en50221* ca, int slot);
int (*slot_shutdown)(struct dvb_ca_en50221* ca, int slot);
int (*slot_ts_enable)(struct dvb_ca_en50221* ca, int slot);
/*
* Poll slot status.
* Only necessary if DVB_CA_FLAG_EN50221_IRQ_CAMCHANGE is not set
*/
int (*poll_slot_status)(struct dvb_ca_en50221* ca, int slot);
/* private data, used by caller */
void* data;
/* Opaque data used by the dvb_ca core. Do not modify! */
void* private;
};
/* ******************************************************************************** */
/* Functions for reporting IRQ events */
/**
* A CAMCHANGE IRQ has occurred.
*
* @param ca CA instance.
* @param slot Slot concerned.
* @param change_type One of the DVB_CA_CAMCHANGE_* values
*/
void dvb_ca_en50221_camchange_irq(struct dvb_ca_en50221* pubca, int slot, int change_type);
/**
* A CAMREADY IRQ has occurred.
*
* @param ca CA instance.
* @param slot Slot concerned.
*/
void dvb_ca_en50221_camready_irq(struct dvb_ca_en50221* pubca, int slot);
/**
* An FR or a DA IRQ has occurred.
*
* @param ca CA instance.
* @param slot Slot concerned.
*/
void dvb_ca_en50221_frda_irq(struct dvb_ca_en50221* ca, int slot);
/* ******************************************************************************** */
/* Initialisation/shutdown functions */
/**
* Initialise a new DVB CA device.
*
* @param dvb_adapter DVB adapter to attach the new CA device to.
* @param ca The dvb_ca instance.
* @param flags Flags describing the CA device (DVB_CA_EN50221_FLAG_*).
* @param slot_count Number of slots supported.
*
* @return 0 on success, nonzero on failure
*/
extern int dvb_ca_en50221_init(struct dvb_adapter *dvb_adapter, struct dvb_ca_en50221* ca, int flags, int slot_count);
/**
* Release a DVB CA device.
*
* @param ca The associated dvb_ca instance.
*/
extern void dvb_ca_en50221_release(struct dvb_ca_en50221* ca);
#endif
...@@ -10,6 +10,7 @@ ...@@ -10,6 +10,7 @@
#include "dvb_frontend.h" #include "dvb_frontend.h"
#include "dvb_net.h" #include "dvb_net.h"
#include "dvb_filter.h" #include "dvb_filter.h"
#include "dvb_ca_en50221.h"
EXPORT_SYMBOL(dvb_dmxdev_init); EXPORT_SYMBOL(dvb_dmxdev_init);
EXPORT_SYMBOL(dvb_dmxdev_release); EXPORT_SYMBOL(dvb_dmxdev_release);
...@@ -49,3 +50,8 @@ EXPORT_SYMBOL(dvb_filter_pes2ts_init); ...@@ -49,3 +50,8 @@ EXPORT_SYMBOL(dvb_filter_pes2ts_init);
EXPORT_SYMBOL(dvb_filter_pes2ts); EXPORT_SYMBOL(dvb_filter_pes2ts);
EXPORT_SYMBOL(dvb_filter_get_ac3info); EXPORT_SYMBOL(dvb_filter_get_ac3info);
EXPORT_SYMBOL(dvb_ca_en50221_init);
EXPORT_SYMBOL(dvb_ca_en50221_release);
EXPORT_SYMBOL(dvb_ca_en50221_frda_irq);
EXPORT_SYMBOL(dvb_ca_en50221_camchange_irq);
EXPORT_SYMBOL(dvb_ca_en50221_camready_irq);
...@@ -3,9 +3,10 @@ ...@@ -3,9 +3,10 @@
* dvb_ringbuffer.c: ring buffer implementation for the dvb driver * dvb_ringbuffer.c: ring buffer implementation for the dvb driver
* *
* Copyright (C) 2003 Oliver Endriss * Copyright (C) 2003 Oliver Endriss
* Copyright (C) 2004 Andrew de Quincey
* *
* based on code originally found in av7110.c: * based on code originally found in av7110.c & dvb_ci.c:
* Copyright (C) 1999-2002 Ralph Metzler * Copyright (C) 1999-2003 Ralph Metzler
* & Marcus Metzler for convergence integrated media GmbH * & Marcus Metzler for convergence integrated media GmbH
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
...@@ -24,6 +25,8 @@ ...@@ -24,6 +25,8 @@
*/ */
#define __KERNEL_SYSCALLS__
#include <linux/errno.h> #include <linux/errno.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/module.h> #include <linux/module.h>
...@@ -33,6 +36,8 @@ ...@@ -33,6 +36,8 @@
#include "dvb_ringbuffer.h" #include "dvb_ringbuffer.h"
#define PKT_READY 0
#define PKT_DISPOSED 1
void dvb_ringbuffer_init(struct dvb_ringbuffer *rbuf, void *data, size_t len) void dvb_ringbuffer_init(struct dvb_ringbuffer *rbuf, void *data, size_t len)
...@@ -158,6 +163,109 @@ ssize_t dvb_ringbuffer_write(struct dvb_ringbuffer *rbuf, const u8 *buf, ...@@ -158,6 +163,109 @@ ssize_t dvb_ringbuffer_write(struct dvb_ringbuffer *rbuf, const u8 *buf,
return len; return len;
} }
ssize_t dvb_ringbuffer_pkt_write(struct dvb_ringbuffer *rbuf, u8* buf, size_t len, int usermem)
{
int status;
ssize_t oldpwrite = rbuf->pwrite;
DVB_RINGBUFFER_WRITE_BYTE(rbuf, len >> 8);
DVB_RINGBUFFER_WRITE_BYTE(rbuf, len & 0xff);
DVB_RINGBUFFER_WRITE_BYTE(rbuf, PKT_READY);
status = dvb_ringbuffer_write(rbuf, buf, len, usermem);
if (status < 0) rbuf->pwrite = oldpwrite;
return status;
}
ssize_t dvb_ringbuffer_pkt_read(struct dvb_ringbuffer *rbuf, size_t idx,
int offset, u8* buf, size_t len, int usermem)
{
size_t todo;
size_t split;
size_t pktlen;
pktlen = rbuf->data[idx] << 8;
pktlen |= rbuf->data[(idx + 1) % rbuf->size];
if (offset > pktlen) return -EINVAL;
if ((offset + len) > pktlen) len = pktlen - offset;
idx = (idx + DVB_RINGBUFFER_PKTHDRSIZE + offset) % rbuf->size;
todo = len;
split = ((idx + len) > rbuf->size) ? rbuf->size - idx : 0;
if (split > 0) {
if (!usermem)
memcpy(buf, rbuf->data+idx, split);
else
if (copy_to_user(buf, rbuf->data+idx, split))
return -EFAULT;
buf += split;
todo -= split;
idx = 0;
}
if (!usermem)
memcpy(buf, rbuf->data+idx, todo);
else
if (copy_to_user(buf, rbuf->data+idx, todo))
return -EFAULT;
return len;
}
void dvb_ringbuffer_pkt_dispose(struct dvb_ringbuffer *rbuf, size_t idx)
{
size_t pktlen;
rbuf->data[(idx + 2) % rbuf->size] = PKT_DISPOSED;
// clean up disposed packets
while(dvb_ringbuffer_avail(rbuf) > DVB_RINGBUFFER_PKTHDRSIZE) {
if (DVB_RINGBUFFER_PEEK(rbuf, 2) == PKT_DISPOSED) {
pktlen = DVB_RINGBUFFER_PEEK(rbuf, 0) << 8;
pktlen |= DVB_RINGBUFFER_PEEK(rbuf, 1);
DVB_RINGBUFFER_SKIP(rbuf, pktlen + DVB_RINGBUFFER_PKTHDRSIZE);
} else {
// first packet is not disposed, so we stop cleaning now
break;
}
}
}
ssize_t dvb_ringbuffer_pkt_next(struct dvb_ringbuffer *rbuf, size_t idx, size_t* pktlen)
{
int consumed;
int curpktlen;
int curpktstatus;
if (idx == -1) {
idx = rbuf->pread;
} else {
curpktlen = rbuf->data[idx] << 8;
curpktlen |= rbuf->data[(idx + 1) % rbuf->size];
idx = (idx + curpktlen + DVB_RINGBUFFER_PKTHDRSIZE) % rbuf->size;
}
consumed = (idx - rbuf->pread) % rbuf->size;
while((dvb_ringbuffer_avail(rbuf) - consumed) > DVB_RINGBUFFER_PKTHDRSIZE) {
curpktlen = rbuf->data[idx] << 8;
curpktlen |= rbuf->data[(idx + 1) % rbuf->size];
curpktstatus = rbuf->data[(idx + 2) % rbuf->size];
if (curpktstatus == PKT_READY) {
*pktlen = curpktlen;
return idx;
}
consumed += curpktlen + DVB_RINGBUFFER_PKTHDRSIZE;
idx = (idx + curpktlen + DVB_RINGBUFFER_PKTHDRSIZE) % rbuf->size;
}
// no packets available
return -1;
}
EXPORT_SYMBOL(dvb_ringbuffer_init); EXPORT_SYMBOL(dvb_ringbuffer_init);
EXPORT_SYMBOL(dvb_ringbuffer_empty); EXPORT_SYMBOL(dvb_ringbuffer_empty);
...@@ -167,3 +275,7 @@ EXPORT_SYMBOL(dvb_ringbuffer_flush); ...@@ -167,3 +275,7 @@ EXPORT_SYMBOL(dvb_ringbuffer_flush);
EXPORT_SYMBOL(dvb_ringbuffer_flush_spinlock_wakeup); EXPORT_SYMBOL(dvb_ringbuffer_flush_spinlock_wakeup);
EXPORT_SYMBOL(dvb_ringbuffer_read); EXPORT_SYMBOL(dvb_ringbuffer_read);
EXPORT_SYMBOL(dvb_ringbuffer_write); EXPORT_SYMBOL(dvb_ringbuffer_write);
EXPORT_SYMBOL(dvb_ringbuffer_pkt_write);
EXPORT_SYMBOL(dvb_ringbuffer_pkt_read);
EXPORT_SYMBOL(dvb_ringbuffer_pkt_dispose);
EXPORT_SYMBOL(dvb_ringbuffer_pkt_next);
...@@ -3,9 +3,10 @@ ...@@ -3,9 +3,10 @@
* dvb_ringbuffer.h: ring buffer implementation for the dvb driver * dvb_ringbuffer.h: ring buffer implementation for the dvb driver
* *
* Copyright (C) 2003 Oliver Endriss * Copyright (C) 2003 Oliver Endriss
* Copyright (C) 2004 Andrew de Quincey
* *
* based on code originally found in av7110.c: * based on code originally found in av7110.c & dvb_ci.c:
* Copyright (C) 1999-2002 Ralph Metzler & Marcus Metzler * Copyright (C) 1999-2003 Ralph Metzler & Marcus Metzler
* for convergence integrated media GmbH * for convergence integrated media GmbH
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
...@@ -39,6 +40,8 @@ struct dvb_ringbuffer { ...@@ -39,6 +40,8 @@ struct dvb_ringbuffer {
spinlock_t lock; spinlock_t lock;
}; };
#define DVB_RINGBUFFER_PKTHDRSIZE 3
/* /*
** Notes: ** Notes:
...@@ -120,4 +123,52 @@ extern ssize_t dvb_ringbuffer_read(struct dvb_ringbuffer *rbuf, u8 *buf, ...@@ -120,4 +123,52 @@ extern ssize_t dvb_ringbuffer_read(struct dvb_ringbuffer *rbuf, u8 *buf,
extern ssize_t dvb_ringbuffer_write(struct dvb_ringbuffer *rbuf, const u8 *buf, extern ssize_t dvb_ringbuffer_write(struct dvb_ringbuffer *rbuf, const u8 *buf,
size_t len, int usermem); size_t len, int usermem);
/**
* Write a packet into the ringbuffer.
*
* <rbuf> Ringbuffer to write to.
* <buf> Buffer to write.
* <len> Length of buffer (currently limited to 65535 bytes max).
* <usermem> Set to 1 if <buf> is in userspace.
* returns Number of bytes written, or -EFAULT, -ENOMEM, -EVINAL.
*/
extern ssize_t dvb_ringbuffer_pkt_write(struct dvb_ringbuffer *rbuf, u8* buf,
size_t len, int usermem);
/**
* Read from a packet in the ringbuffer. Note: unlike dvb_ringbuffer_read(), this
* does NOT update the read pointer in the ringbuffer. You must use
* dvb_ringbuffer_pkt_dispose() to mark a packet as no longer required.
*
* <rbuf> Ringbuffer concerned.
* <idx> Packet index as returned by dvb_ringbuffer_pkt_next().
* <offset> Offset into packet to read from.
* <buf> Destination buffer for data.
* <len> Size of destination buffer.
* <usermem> Set to 1 if <buf> is in userspace.
* returns Number of bytes read, or -EFAULT.
*/
extern ssize_t dvb_ringbuffer_pkt_read(struct dvb_ringbuffer *rbuf, size_t idx,
int offset, u8* buf, size_t len, int usermem);
/**
* Dispose of a packet in the ring buffer.
*
* <rbuf> Ring buffer concerned.
* <idx> Packet index as returned by dvb_ringbuffer_pkt_next().
*/
extern void dvb_ringbuffer_pkt_dispose(struct dvb_ringbuffer *rbuf, size_t idx);
/**
* Get the index of the next packet in a ringbuffer.
*
* <rbuf> Ringbuffer concerned.
* <idx> Previous packet index, or -1 to return the first packet index.
* <pktlen> On success, will be updated to contain the length of the packet in bytes.
* returns Packet index (if >=0), or -1 if no packets available.
*/
extern ssize_t dvb_ringbuffer_pkt_next(struct dvb_ringbuffer *rbuf, size_t idx, size_t* pktlen);
#endif /* _DVB_RINGBUFFER_H_ */ #endif /* _DVB_RINGBUFFER_H_ */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment