Commit 9d49da8a authored by Michael Hunold's avatar Michael Hunold Committed by Linus Torvalds

[PATCH] dvb: core changes

- [DVB] dvb-core: follow Linux coding style, kill dvb_ksyms.c and move the
  EXPORT_SYMBOLs to the files where the functions are, thanks to Adrian Bunk
  <bunk@stusta.de>

- [DVB] dvb-core: #if 0'ing unused code, make needlessly global code static,
  whitespace and newline cleanups, thanks to Adrian Bunk <bunk@stusta.de>

- [DVB] dvb_ca_en50221.c: support for KNC1/Cinergy CI modules, fix
  segfaults, enhanced poll_slot_status to support non-IRQ interfaces, Fix
  module usage count problem

- [DVB] dvb-frontend.c: core changes to support the refactorized frontend
  drivers
Signed-off-by: default avatarMichael Hunold <hunold@linuxtv.org>
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent b0da8f73
...@@ -42,18 +42,12 @@ MODULE_PARM_DESC(debug, "Turn on/off debugging (default:off)."); ...@@ -42,18 +42,12 @@ MODULE_PARM_DESC(debug, "Turn on/off debugging (default:off).");
#define dprintk if (debug) printk #define dprintk if (debug) printk
inline struct dmxdev_filter * static inline struct dmxdev_filter *
dvb_dmxdev_file_to_filter(struct file *file) dvb_dmxdev_file_to_filter(struct file *file)
{ {
return (struct dmxdev_filter *) file->private_data; return (struct dmxdev_filter *) file->private_data;
} }
inline struct dmxdev_dvr *
dvb_dmxdev_file_to_dvr(struct dmxdev *dmxdev, struct file *file)
{
return (struct dmxdev_dvr *) file->private_data;
}
static inline void dvb_dmxdev_buffer_init(struct dmxdev_buffer *buffer) static inline void dvb_dmxdev_buffer_init(struct dmxdev_buffer *buffer)
{ {
buffer->data=NULL; buffer->data=NULL;
...@@ -846,7 +840,7 @@ static ssize_t dvb_dmxdev_read_sec(struct dmxdev_filter *dfil, ...@@ -846,7 +840,7 @@ static ssize_t dvb_dmxdev_read_sec(struct dmxdev_filter *dfil,
} }
ssize_t static ssize_t
dvb_demux_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) dvb_demux_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)
{ {
struct dmxdev_filter *dmxdevfilter=dvb_dmxdev_file_to_filter(file); struct dmxdev_filter *dmxdevfilter=dvb_dmxdev_file_to_filter(file);
...@@ -1122,6 +1116,7 @@ dvb_dmxdev_init(struct dmxdev *dmxdev, struct dvb_adapter *dvb_adapter) ...@@ -1122,6 +1116,7 @@ dvb_dmxdev_init(struct dmxdev *dmxdev, struct dvb_adapter *dvb_adapter)
return 0; return 0;
} }
EXPORT_SYMBOL(dvb_dmxdev_init);
void void
dvb_dmxdev_release(struct dmxdev *dmxdev) dvb_dmxdev_release(struct dmxdev *dmxdev)
...@@ -1138,5 +1133,5 @@ dvb_dmxdev_release(struct dmxdev *dmxdev) ...@@ -1138,5 +1133,5 @@ dvb_dmxdev_release(struct dmxdev *dmxdev)
} }
dmxdev->demux->close(dmxdev->demux); dmxdev->demux->close(dmxdev->demux);
} }
EXPORT_SYMBOL(dvb_dmxdev_release);
...@@ -181,10 +181,12 @@ static u8* findstr(u8* haystack, int hlen, u8* needle, int nlen) ...@@ -181,10 +181,12 @@ static u8* findstr(u8* haystack, int hlen, u8* needle, int nlen)
{ {
int i; int i;
if (hlen < nlen) return NULL; if (hlen < nlen)
return NULL;
for(i=0; i<= hlen - nlen; i++) { for(i=0; i<= hlen - nlen; i++) {
if (!strncmp(haystack+i, needle, nlen)) return haystack+i; if (!strncmp(haystack + i, needle, nlen))
return haystack + i;
} }
return NULL; return NULL;
...@@ -211,7 +213,7 @@ static int dvb_ca_en50221_check_camstatus(struct dvb_ca_private* ca, int slot) ...@@ -211,7 +213,7 @@ static int dvb_ca_en50221_check_camstatus(struct dvb_ca_private* ca, int slot)
} }
/* poll mode */ /* poll mode */
slot_status = ca->pub->poll_slot_status(ca->pub, slot); slot_status = ca->pub->poll_slot_status(ca->pub, slot, ca->open);
cam_present_now = (slot_status & DVB_CA_EN50221_POLL_CAM_PRESENT) ? 1: 0; cam_present_now = (slot_status & DVB_CA_EN50221_POLL_CAM_PRESENT) ? 1: 0;
cam_changed = (slot_status & DVB_CA_EN50221_POLL_CAM_CHANGED) ? 1: 0; cam_changed = (slot_status & DVB_CA_EN50221_POLL_CAM_CHANGED) ? 1: 0;
...@@ -250,7 +252,8 @@ static int dvb_ca_en50221_check_camstatus(struct dvb_ca_private* ca, int slot) ...@@ -250,7 +252,8 @@ static int dvb_ca_en50221_check_camstatus(struct dvb_ca_private* ca, int slot)
* *
* @return 0 on success, nonzero on error. * @return 0 on success, nonzero on error.
*/ */
static int dvb_ca_en50221_wait_if_status(struct dvb_ca_private* ca, int slot, u8 waitfor, int timeout_hz) static int dvb_ca_en50221_wait_if_status(struct dvb_ca_private *ca, int slot,
u8 waitfor, int timeout_hz)
{ {
unsigned long timeout; unsigned long timeout;
unsigned long start; unsigned long start;
...@@ -263,7 +266,8 @@ static int dvb_ca_en50221_wait_if_status(struct dvb_ca_private* ca, int slot, u8 ...@@ -263,7 +266,8 @@ static int dvb_ca_en50221_wait_if_status(struct dvb_ca_private* ca, int slot, u8
while(1) { while(1) {
/* read the status and check for error */ /* read the status and check for error */
int res = ca->pub->read_cam_control(ca->pub, slot, CTRLIF_STATUS); int res = ca->pub->read_cam_control(ca->pub, slot, CTRLIF_STATUS);
if (res < 0) return -EIO; if (res < 0)
return -EIO;
/* if we got the flags, it was successful! */ /* if we got the flags, it was successful! */
if (res & waitfor) { if (res & waitfor) {
...@@ -311,24 +315,33 @@ static int dvb_ca_en50221_link_init(struct dvb_ca_private* ca, int slot) ...@@ -311,24 +315,33 @@ static int dvb_ca_en50221_link_init(struct dvb_ca_private* ca, int slot)
ca->slot_info[slot].link_buf_size = 2; ca->slot_info[slot].link_buf_size = 2;
/* read the buffer size from the CAM */ /* read the buffer size from the CAM */
if ((ret = ca->pub->write_cam_control(ca->pub, slot, CTRLIF_COMMAND, IRQEN | CMDREG_SR)) != 0) return ret; if ((ret = ca->pub->write_cam_control(ca->pub, slot, CTRLIF_COMMAND, IRQEN | CMDREG_SR)) != 0)
if ((ret = dvb_ca_en50221_wait_if_status(ca, slot, STATUSREG_DA, HZ/10)) != 0) return ret; return ret;
if ((ret = dvb_ca_en50221_read_data(ca, slot, buf, 2)) != 2) return -EIO; if ((ret = dvb_ca_en50221_wait_if_status(ca, slot, STATUSREG_DA, HZ / 10)) != 0)
if ((ret = ca->pub->write_cam_control(ca->pub, slot, CTRLIF_COMMAND, IRQEN)) != 0) return ret; return ret;
if ((ret = dvb_ca_en50221_read_data(ca, slot, buf, 2)) != 2)
return -EIO;
if ((ret = ca->pub->write_cam_control(ca->pub, slot, CTRLIF_COMMAND, IRQEN)) != 0)
return ret;
/* store it, and choose the minimum of our buffer and the CAM's buffer size */ /* store it, and choose the minimum of our buffer and the CAM's buffer size */
buf_size = (buf[0] << 8) | buf[1]; buf_size = (buf[0] << 8) | buf[1];
if (buf_size > HOST_LINK_BUF_SIZE) buf_size = HOST_LINK_BUF_SIZE; if (buf_size > HOST_LINK_BUF_SIZE)
buf_size = HOST_LINK_BUF_SIZE;
ca->slot_info[slot].link_buf_size = buf_size; ca->slot_info[slot].link_buf_size = buf_size;
buf[0] = buf_size >> 8; buf[0] = buf_size >> 8;
buf[1] = buf_size & 0xff; buf[1] = buf_size & 0xff;
dprintk("Chosen link buffer size of %i\n", buf_size); dprintk("Chosen link buffer size of %i\n", buf_size);
/* write the buffer size to the CAM */ /* write the buffer size to the CAM */
if ((ret = ca->pub->write_cam_control(ca->pub, slot, CTRLIF_COMMAND, IRQEN | CMDREG_SW)) != 0) return ret; if ((ret = ca->pub->write_cam_control(ca->pub, slot, CTRLIF_COMMAND, IRQEN | CMDREG_SW)) != 0)
if ((ret = dvb_ca_en50221_wait_if_status(ca, slot, STATUSREG_FR, HZ/10)) != 0) return ret; return ret;
if ((ret = dvb_ca_en50221_write_data(ca, slot, buf, 2)) != 2) return -EIO; if ((ret = dvb_ca_en50221_wait_if_status(ca, slot, STATUSREG_FR, HZ / 10)) != 0)
if ((ret = ca->pub->write_cam_control(ca->pub, slot, CTRLIF_COMMAND, IRQEN)) != 0) return ret; return ret;
if ((ret = dvb_ca_en50221_write_data(ca, slot, buf, 2)) != 2)
return -EIO;
if ((ret = ca->pub->write_cam_control(ca->pub, slot, CTRLIF_COMMAND, IRQEN)) != 0)
return ret;
/* success */ /* success */
return 0; return 0;
...@@ -355,7 +368,8 @@ static int dvb_ca_en50221_read_tuple(struct dvb_ca_private* ca, int slot, ...@@ -355,7 +368,8 @@ static int dvb_ca_en50221_read_tuple(struct dvb_ca_private* ca, int slot,
int _address = *address; int _address = *address;
/* grab the next tuple length and type */ /* grab the next tuple length and type */
if ((_tupleType = ca->pub->read_attribute_mem(ca->pub, slot, _address)) < 0) return _tupleType; if ((_tupleType = ca->pub->read_attribute_mem(ca->pub, slot, _address)) < 0)
return _tupleType;
if (_tupleType == 0xff) { if (_tupleType == 0xff) {
dprintk("END OF CHAIN TUPLE type:0x%x\n", _tupleType); dprintk("END OF CHAIN TUPLE type:0x%x\n", _tupleType);
*address += 2; *address += 2;
...@@ -363,7 +377,8 @@ static int dvb_ca_en50221_read_tuple(struct dvb_ca_private* ca, int slot, ...@@ -363,7 +377,8 @@ static int dvb_ca_en50221_read_tuple(struct dvb_ca_private* ca, int slot,
*tupleLength = 0; *tupleLength = 0;
return 0; return 0;
} }
if ((_tupleLength = ca->pub->read_attribute_mem(ca->pub, slot, _address+2)) < 0) return _tupleLength; if ((_tupleLength = ca->pub->read_attribute_mem(ca->pub, slot, _address + 2)) < 0)
return _tupleLength;
_address += 4; _address += 4;
dprintk("TUPLE type:0x%x length:%i\n", _tupleType, _tupleLength); dprintk("TUPLE type:0x%x length:%i\n", _tupleType, _tupleLength);
...@@ -371,7 +386,9 @@ static int dvb_ca_en50221_read_tuple(struct dvb_ca_private* ca, int slot, ...@@ -371,7 +386,9 @@ static int dvb_ca_en50221_read_tuple(struct dvb_ca_private* ca, int slot,
/* read in the whole tuple */ /* read in the whole tuple */
for(i=0; i< _tupleLength; i++) { for(i=0; i< _tupleLength; i++) {
tuple[i] = ca->pub->read_attribute_mem(ca->pub, slot, _address + (i*2)); tuple[i] = ca->pub->read_attribute_mem(ca->pub, slot, _address + (i*2));
dprintk(" 0x%02x: 0x%02x %c\n", i, tuple[i] & 0xff, ((tuple[i] > 31) && (tuple[i] < 127)) ? tuple[i] : '.'); dprintk(" 0x%02x: 0x%02x %c\n",
i, tuple[i] & 0xff,
((tuple[i] > 31) && (tuple[i] < 127)) ? tuple[i] : '.');
} }
_address += (_tupleLength*2); _address += (_tupleLength*2);
...@@ -409,40 +426,58 @@ static int dvb_ca_en50221_parse_attributes(struct dvb_ca_private* ca, int slot) ...@@ -409,40 +426,58 @@ static int dvb_ca_en50221_parse_attributes(struct dvb_ca_private* ca, int slot)
// CISTPL_DEVICE_0A // CISTPL_DEVICE_0A
if ((status = dvb_ca_en50221_read_tuple(ca, slot, &address, &tupleType, &tupleLength, tuple)) < 0) return status; if ((status =
if (tupleType != 0x1D) return -EINVAL; dvb_ca_en50221_read_tuple(ca, slot, &address, &tupleType, &tupleLength, tuple)) < 0)
return status;
if (tupleType != 0x1D)
return -EINVAL;
// CISTPL_DEVICE_0C // CISTPL_DEVICE_0C
if ((status = dvb_ca_en50221_read_tuple(ca, slot, &address, &tupleType, &tupleLength, tuple)) < 0) return status; if ((status =
if (tupleType != 0x1C) return -EINVAL; dvb_ca_en50221_read_tuple(ca, slot, &address, &tupleType, &tupleLength, tuple)) < 0)
return status;
if (tupleType != 0x1C)
return -EINVAL;
// CISTPL_VERS_1 // CISTPL_VERS_1
if ((status = dvb_ca_en50221_read_tuple(ca, slot, &address, &tupleType, &tupleLength, tuple)) < 0) return status; if ((status =
if (tupleType != 0x15) return -EINVAL; dvb_ca_en50221_read_tuple(ca, slot, &address, &tupleType, &tupleLength, tuple)) < 0)
return status;
if (tupleType != 0x15)
return -EINVAL;
// CISTPL_MANFID // CISTPL_MANFID
if ((status = dvb_ca_en50221_read_tuple(ca, slot, &address, &tupleType, &tupleLength, tuple)) < 0) return status; if ((status = dvb_ca_en50221_read_tuple(ca, slot, &address, &tupleType,
if (tupleType != 0x20) return -EINVAL; &tupleLength, tuple)) < 0)
if (tupleLength != 4) return -EINVAL; return status;
if (tupleType != 0x20)
return -EINVAL;
if (tupleLength != 4)
return -EINVAL;
manfid = (tuple[1] << 8) | tuple[0]; manfid = (tuple[1] << 8) | tuple[0];
devid = (tuple[3] << 8) | tuple[2]; devid = (tuple[3] << 8) | tuple[2];
// CISTPL_CONFIG // CISTPL_CONFIG
if ((status = dvb_ca_en50221_read_tuple(ca, slot, &address, &tupleType, &tupleLength, tuple)) < 0) return status; if ((status = dvb_ca_en50221_read_tuple(ca, slot, &address, &tupleType,
if (tupleType != 0x1A) return -EINVAL; &tupleLength, tuple)) < 0)
if (tupleLength < 3) return -EINVAL; return status;
if (tupleType != 0x1A)
return -EINVAL;
if (tupleLength < 3)
return -EINVAL;
/* extract the configbase */ /* extract the configbase */
rasz = tuple[0] & 3; rasz = tuple[0] & 3;
if (tupleLength < (3 + rasz + 14)) return -EINVAL; if (tupleLength < (3 + rasz + 14))
return -EINVAL;
ca->slot_info[slot].config_base = 0; ca->slot_info[slot].config_base = 0;
for(i=0; i< rasz+1; i++) { for(i=0; i< rasz+1; i++) {
ca->slot_info[slot].config_base |= (tuple[2+i] << (8*i)); ca->slot_info[slot].config_base |= (tuple[2+i] << (8*i));
...@@ -450,8 +485,10 @@ static int dvb_ca_en50221_parse_attributes(struct dvb_ca_private* ca, int slot) ...@@ -450,8 +485,10 @@ static int dvb_ca_en50221_parse_attributes(struct dvb_ca_private* ca, int slot)
/* check it contains the correct DVB string */ /* check it contains the correct DVB string */
dvb_str = findstr(tuple, tupleLength, "DVB_CI_V", 8); dvb_str = findstr(tuple, tupleLength, "DVB_CI_V", 8);
if (dvb_str == NULL) return -EINVAL; if (dvb_str == NULL)
if (tupleLength < ((dvb_str - (char*) tuple) + 12)) return -EINVAL; return -EINVAL;
if (tupleLength < ((dvb_str - (char *) tuple) + 12))
return -EINVAL;
/* is it a version we support? */ /* is it a version we support? */
if (strncmp(dvb_str + 8, "1.00", 4)) { if (strncmp(dvb_str + 8, "1.00", 4)) {
...@@ -462,20 +499,25 @@ static int dvb_ca_en50221_parse_attributes(struct dvb_ca_private* ca, int slot) ...@@ -462,20 +499,25 @@ static int dvb_ca_en50221_parse_attributes(struct dvb_ca_private* ca, int slot)
/* process the CFTABLE_ENTRY tuples, and any after those */ /* process the CFTABLE_ENTRY tuples, and any after those */
while((!end_chain) && (address < 0x1000)) { while((!end_chain) && (address < 0x1000)) {
if ((status = dvb_ca_en50221_read_tuple(ca, slot, &address, &tupleType, &tupleLength, tuple)) < 0) return status; if ((status = dvb_ca_en50221_read_tuple(ca, slot, &address, &tupleType,
&tupleLength, tuple)) < 0)
return status;
switch(tupleType) { switch(tupleType) {
case 0x1B: // CISTPL_CFTABLE_ENTRY case 0x1B: // CISTPL_CFTABLE_ENTRY
if (tupleLength < (2+11+17)) break; if (tupleLength < (2 + 11 + 17))
break;
/* if we've already parsed one, just use it */ /* if we've already parsed one, just use it */
if (got_cftableentry) break; if (got_cftableentry)
break;
/* get the config option */ /* get the config option */
ca->slot_info[slot].config_option = tuple[0] & 0x3f; ca->slot_info[slot].config_option = tuple[0] & 0x3f;
/* OK, check it contains the correct strings */ /* OK, check it contains the correct strings */
if ((findstr(tuple, tupleLength, "DVB_HOST", 8) == NULL) || if ((findstr(tuple, tupleLength, "DVB_HOST", 8) == NULL) ||
(findstr(tuple, tupleLength, "DVB_CI_MODULE", 13) == NULL)) break; (findstr(tuple, tupleLength, "DVB_CI_MODULE", 13) == NULL))
break;
got_cftableentry = 1; got_cftableentry = 1;
break; break;
...@@ -488,17 +530,17 @@ static int dvb_ca_en50221_parse_attributes(struct dvb_ca_private* ca, int slot) ...@@ -488,17 +530,17 @@ static int dvb_ca_en50221_parse_attributes(struct dvb_ca_private* ca, int slot)
break; break;
default: /* Unknown tuple type - just skip this tuple and move to the next one */ default: /* Unknown tuple type - just skip this tuple and move to the next one */
dprintk("dvb_ca: Skipping unknown tuple type:0x%x length:0x%x\n", tupleType, tupleLength); dprintk("dvb_ca: Skipping unknown tuple type:0x%x length:0x%x\n", tupleType,
tupleLength);
break; break;
} }
} }
if ((address > 0x1000) || (!got_cftableentry)) return -EINVAL; if ((address > 0x1000) || (!got_cftableentry))
return -EINVAL;
dprintk("Valid DVB CAM detected MANID:%x DEVID:%x CONFIGBASE:0x%x CONFIGOPTION:0x%x\n", dprintk("Valid DVB CAM detected MANID:%x DEVID:%x CONFIGBASE:0x%x CONFIGOPTION:0x%x\n",
manfid, devid, manfid, devid, ca->slot_info[slot].config_base, ca->slot_info[slot].config_option);
ca->slot_info[slot].config_base,
ca->slot_info[slot].config_option);
// success! // success!
return 0; return 0;
...@@ -518,7 +560,9 @@ static int dvb_ca_en50221_set_configoption(struct dvb_ca_private* ca, int slot) ...@@ -518,7 +560,9 @@ static int dvb_ca_en50221_set_configoption(struct dvb_ca_private* ca, int slot)
dprintk ("%s\n", __FUNCTION__); dprintk ("%s\n", __FUNCTION__);
/* set the config option */ /* set the config option */
ca->pub->write_attribute_mem(ca->pub, slot, ca->slot_info[slot].config_base, ca->slot_info[slot].config_option); ca->pub->write_attribute_mem(ca->pub, slot,
ca->slot_info[slot].config_base,
ca->slot_info[slot].config_option);
/* check it */ /* check it */
configoption = ca->pub->read_attribute_mem(ca->pub, slot, ca->slot_info[slot].config_base); configoption = ca->pub->read_attribute_mem(ca->pub, slot, ca->slot_info[slot].config_base);
...@@ -558,6 +602,11 @@ static int dvb_ca_en50221_read_data(struct dvb_ca_private* ca, int slot, u8* ebu ...@@ -558,6 +602,11 @@ static int dvb_ca_en50221_read_data(struct dvb_ca_private* ca, int slot, u8* ebu
int buf_free; int buf_free;
down_read(&ca->slot_info[slot].sem); down_read(&ca->slot_info[slot].sem);
if (ca->slot_info[slot].rx_buffer.data == NULL) {
up_read(&ca->slot_info[slot].sem);
status = -EIO;
goto exit;
}
buf_free = dvb_ringbuffer_free(&ca->slot_info[slot].rx_buffer); buf_free = dvb_ringbuffer_free(&ca->slot_info[slot].rx_buffer);
up_read(&ca->slot_info[slot].sem); up_read(&ca->slot_info[slot].sem);
...@@ -568,7 +617,8 @@ static int dvb_ca_en50221_read_data(struct dvb_ca_private* ca, int slot, u8* ebu ...@@ -568,7 +617,8 @@ static int dvb_ca_en50221_read_data(struct dvb_ca_private* ca, int slot, u8* ebu
} }
/* check if there is data available */ /* check if there is data available */
if ((status = ca->pub->read_cam_control(ca->pub, slot, CTRLIF_STATUS)) < 0) goto exit; if ((status = ca->pub->read_cam_control(ca->pub, slot, CTRLIF_STATUS)) < 0)
goto exit;
if (!(status & STATUSREG_DA)) { if (!(status & STATUSREG_DA)) {
/* no data */ /* no data */
status = 0; status = 0;
...@@ -576,28 +626,33 @@ static int dvb_ca_en50221_read_data(struct dvb_ca_private* ca, int slot, u8* ebu ...@@ -576,28 +626,33 @@ static int dvb_ca_en50221_read_data(struct dvb_ca_private* ca, int slot, u8* ebu
} }
/* read the amount of data */ /* read the amount of data */
if ((status = ca->pub->read_cam_control(ca->pub, slot, CTRLIF_SIZE_HIGH)) < 0) goto exit; if ((status = ca->pub->read_cam_control(ca->pub, slot, CTRLIF_SIZE_HIGH)) < 0)
goto exit;
bytes_read = status << 8; bytes_read = status << 8;
if ((status = ca->pub->read_cam_control(ca->pub, slot, CTRLIF_SIZE_LOW)) < 0) goto exit; if ((status = ca->pub->read_cam_control(ca->pub, slot, CTRLIF_SIZE_LOW)) < 0)
goto exit;
bytes_read |= status; bytes_read |= status;
/* check it will fit */ /* check it will fit */
if (ebuf == NULL) { if (ebuf == NULL) {
if (bytes_read > ca->slot_info[slot].link_buf_size) { if (bytes_read > ca->slot_info[slot].link_buf_size) {
printk("dvb_ca adapter %d: CAM tried to send a buffer larger than the link buffer size!\n", ca->dvbdev->adapter->num); printk("dvb_ca adapter %d: CAM tried to send a buffer larger than the link buffer size (%i > %i)!\n",
ca->dvbdev->adapter->num, bytes_read, ca->slot_info[slot].link_buf_size);
ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_LINKINIT; ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_LINKINIT;
status = -EIO; status = -EIO;
goto exit; goto exit;
} }
if (bytes_read < 2) { if (bytes_read < 2) {
printk("dvb_ca adapter %d: CAM sent a buffer that was less than 2 bytes!\n", ca->dvbdev->adapter->num); printk("dvb_ca adapter %d: CAM sent a buffer that was less than 2 bytes!\n",
ca->dvbdev->adapter->num);
ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_LINKINIT; ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_LINKINIT;
status = -EIO; status = -EIO;
goto exit; goto exit;
} }
} else { } else {
if (bytes_read > ecount) { if (bytes_read > ecount) {
printk("dvb_ca adapter %d: CAM tried to send a buffer larger than the ecount size!\n", ca->dvbdev->adapter->num); printk("dvb_ca adapter %d: CAM tried to send a buffer larger than the ecount size!\n",
ca->dvbdev->adapter->num);
status = -EIO; status = -EIO;
goto exit; goto exit;
} }
...@@ -606,14 +661,16 @@ static int dvb_ca_en50221_read_data(struct dvb_ca_private* ca, int slot, u8* ebu ...@@ -606,14 +661,16 @@ static int dvb_ca_en50221_read_data(struct dvb_ca_private* ca, int slot, u8* ebu
/* fill the buffer */ /* fill the buffer */
for(i=0; i < bytes_read; i++) { for(i=0; i < bytes_read; i++) {
/* read byte and check */ /* read byte and check */
if ((status = ca->pub->read_cam_control(ca->pub, slot, CTRLIF_DATA)) < 0) goto exit; if ((status = ca->pub->read_cam_control(ca->pub, slot, CTRLIF_DATA)) < 0)
goto exit;
/* OK, store it in the buffer */ /* OK, store it in the buffer */
buf[i] = status; buf[i] = status;
} }
/* check for read error (RE should now be 0) */ /* check for read error (RE should now be 0) */
if ((status = ca->pub->read_cam_control(ca->pub, slot, CTRLIF_STATUS)) < 0) goto exit; if ((status = ca->pub->read_cam_control(ca->pub, slot, CTRLIF_STATUS)) < 0)
goto exit;
if (status & STATUSREG_RE) { if (status & STATUSREG_RE) {
ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_LINKINIT; ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_LINKINIT;
status = -EIO; status = -EIO;
...@@ -623,13 +680,19 @@ static int dvb_ca_en50221_read_data(struct dvb_ca_private* ca, int slot, u8* ebu ...@@ -623,13 +680,19 @@ static int dvb_ca_en50221_read_data(struct dvb_ca_private* ca, int slot, u8* ebu
/* OK, add it to the receive buffer, or copy into external buffer if supplied */ /* OK, add it to the receive buffer, or copy into external buffer if supplied */
if (ebuf == NULL) { if (ebuf == NULL) {
down_read(&ca->slot_info[slot].sem); down_read(&ca->slot_info[slot].sem);
if (ca->slot_info[slot].rx_buffer.data == NULL) {
up_read(&ca->slot_info[slot].sem);
status = -EIO;
goto exit;
}
dvb_ringbuffer_pkt_write(&ca->slot_info[slot].rx_buffer, buf, bytes_read); dvb_ringbuffer_pkt_write(&ca->slot_info[slot].rx_buffer, buf, bytes_read);
up_read(&ca->slot_info[slot].sem); up_read(&ca->slot_info[slot].sem);
} else { } else {
memcpy(ebuf, buf, bytes_read); memcpy(ebuf, buf, bytes_read);
} }
dprintk("Received CA packet for slot %i connection id 0x%x last_frag:%i size:0x%x\n", slot, buf[0], (buf[1] & 0x80) == 0, bytes_read); dprintk("Received CA packet for slot %i connection id 0x%x last_frag:%i size:0x%x\n", slot,
buf[0], (buf[1] & 0x80) == 0, bytes_read);
/* wake up readers when a last_fragment is received */ /* wake up readers when a last_fragment is received */
if ((buf[1] & 0x80) == 0x00) { if ((buf[1] & 0x80) == 0x00) {
...@@ -664,20 +727,25 @@ static int dvb_ca_en50221_write_data(struct dvb_ca_private* ca, int slot, u8* bu ...@@ -664,20 +727,25 @@ static int dvb_ca_en50221_write_data(struct dvb_ca_private* ca, int slot, u8* bu
// sanity check // sanity check
if (bytes_write > ca->slot_info[slot].link_buf_size) return -EINVAL; if (bytes_write > ca->slot_info[slot].link_buf_size)
return -EINVAL;
/* check if interface is actually waiting for us to read from it, or if a read is in progress */ /* check if interface is actually waiting for us to read from it, or if a read is in progress */
if ((status = ca->pub->read_cam_control(ca->pub, slot, CTRLIF_STATUS)) < 0) goto exitnowrite; if ((status = ca->pub->read_cam_control(ca->pub, slot, CTRLIF_STATUS)) < 0)
goto exitnowrite;
if (status & (STATUSREG_DA|STATUSREG_RE)) { if (status & (STATUSREG_DA|STATUSREG_RE)) {
status = -EAGAIN; status = -EAGAIN;
goto exitnowrite; goto exitnowrite;
} }
/* OK, set HC bit */ /* OK, set HC bit */
if ((status = ca->pub->write_cam_control(ca->pub, slot, CTRLIF_COMMAND, IRQEN | CMDREG_HC)) != 0) goto exit; if ((status = ca->pub->write_cam_control(ca->pub, slot, CTRLIF_COMMAND,
IRQEN | CMDREG_HC)) != 0)
goto exit;
/* check if interface is still free */ /* check if interface is still free */
if ((status = ca->pub->read_cam_control(ca->pub, slot, CTRLIF_STATUS)) < 0) goto exit; if ((status = ca->pub->read_cam_control(ca->pub, slot, CTRLIF_STATUS)) < 0)
goto exit;
if (!(status & STATUSREG_FR)) { if (!(status & STATUSREG_FR)) {
/* it wasn't free => try again later */ /* it wasn't free => try again later */
status = -EAGAIN; status = -EAGAIN;
...@@ -685,16 +753,21 @@ static int dvb_ca_en50221_write_data(struct dvb_ca_private* ca, int slot, u8* bu ...@@ -685,16 +753,21 @@ static int dvb_ca_en50221_write_data(struct dvb_ca_private* ca, int slot, u8* bu
} }
/* send the amount of data */ /* send the amount of data */
if ((status = ca->pub->write_cam_control(ca->pub, slot, CTRLIF_SIZE_HIGH, bytes_write >> 8)) != 0) goto exit; if ((status = ca->pub->write_cam_control(ca->pub, slot, CTRLIF_SIZE_HIGH, bytes_write >> 8)) != 0)
if ((status = ca->pub->write_cam_control(ca->pub, slot, CTRLIF_SIZE_LOW, bytes_write & 0xff)) != 0) goto exit; goto exit;
if ((status = ca->pub->write_cam_control(ca->pub, slot, CTRLIF_SIZE_LOW,
bytes_write & 0xff)) != 0)
goto exit;
/* send the buffer */ /* send the buffer */
for(i=0; i < bytes_write; i++) { for(i=0; i < bytes_write; i++) {
if ((status = ca->pub->write_cam_control(ca->pub, slot, CTRLIF_DATA, buf[i])) != 0) goto exit; if ((status = ca->pub->write_cam_control(ca->pub, slot, CTRLIF_DATA, buf[i])) != 0)
goto exit;
} }
/* check for write error (WE should now be 0) */ /* check for write error (WE should now be 0) */
if ((status = ca->pub->read_cam_control(ca->pub, slot, CTRLIF_STATUS)) < 0) goto exit; if ((status = ca->pub->read_cam_control(ca->pub, slot, CTRLIF_STATUS)) < 0)
goto exit;
if (status & STATUSREG_WE) { if (status & STATUSREG_WE) {
ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_LINKINIT; ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_LINKINIT;
status = -EIO; status = -EIO;
...@@ -702,7 +775,8 @@ static int dvb_ca_en50221_write_data(struct dvb_ca_private* ca, int slot, u8* bu ...@@ -702,7 +775,8 @@ static int dvb_ca_en50221_write_data(struct dvb_ca_private* ca, int slot, u8* bu
} }
status = bytes_write; status = bytes_write;
dprintk("Wrote CA packet for slot %i, connection id 0x%x last_frag:%i size:0x%x\n", slot, buf[0], (buf[1] & 0x80) == 0, bytes_write); dprintk("Wrote CA packet for slot %i, connection id 0x%x last_frag:%i size:0x%x\n", slot,
buf[0], (buf[1] & 0x80) == 0, bytes_write);
exit: exit:
ca->pub->write_cam_control(ca->pub, slot, CTRLIF_COMMAND, IRQEN); ca->pub->write_cam_control(ca->pub, slot, CTRLIF_COMMAND, IRQEN);
...@@ -710,6 +784,7 @@ static int dvb_ca_en50221_write_data(struct dvb_ca_private* ca, int slot, u8* bu ...@@ -710,6 +784,7 @@ static int dvb_ca_en50221_write_data(struct dvb_ca_private* ca, int slot, u8* bu
exitnowrite: exitnowrite:
return status; return status;
} }
EXPORT_SYMBOL(dvb_ca_en50221_camchange_irq);
...@@ -730,7 +805,8 @@ static int dvb_ca_en50221_slot_shutdown(struct dvb_ca_private* ca, int slot) ...@@ -730,7 +805,8 @@ static int dvb_ca_en50221_slot_shutdown(struct dvb_ca_private* ca, int slot)
down_write(&ca->slot_info[slot].sem); down_write(&ca->slot_info[slot].sem);
ca->pub->slot_shutdown(ca->pub, slot); ca->pub->slot_shutdown(ca->pub, slot);
ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_NONE; ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_NONE;
if (ca->slot_info[slot].rx_buffer.data) vfree(ca->slot_info[slot].rx_buffer.data); if (ca->slot_info[slot].rx_buffer.data)
vfree(ca->slot_info[slot].rx_buffer.data);
ca->slot_info[slot].rx_buffer.data = NULL; ca->slot_info[slot].rx_buffer.data = NULL;
up_write(&ca->slot_info[slot].sem); up_write(&ca->slot_info[slot].sem);
...@@ -743,6 +819,7 @@ static int dvb_ca_en50221_slot_shutdown(struct dvb_ca_private* ca, int slot) ...@@ -743,6 +819,7 @@ static int dvb_ca_en50221_slot_shutdown(struct dvb_ca_private* ca, int slot)
/* success */ /* success */
return 0; return 0;
} }
EXPORT_SYMBOL(dvb_ca_en50221_camready_irq);
/** /**
...@@ -771,6 +848,7 @@ void dvb_ca_en50221_camchange_irq(struct dvb_ca_en50221* pubca, int slot, int ch ...@@ -771,6 +848,7 @@ void dvb_ca_en50221_camchange_irq(struct dvb_ca_en50221* pubca, int slot, int ch
atomic_inc(&ca->slot_info[slot].camchange_count); atomic_inc(&ca->slot_info[slot].camchange_count);
dvb_ca_en50221_thread_wakeup(ca); dvb_ca_en50221_thread_wakeup(ca);
} }
EXPORT_SYMBOL(dvb_ca_en50221_frda_irq);
/** /**
...@@ -815,7 +893,8 @@ void dvb_ca_en50221_frda_irq(struct dvb_ca_en50221* pubca, int slot) ...@@ -815,7 +893,8 @@ void dvb_ca_en50221_frda_irq(struct dvb_ca_en50221* pubca, int slot)
break; break;
case DVB_CA_SLOTSTATE_RUNNING: case DVB_CA_SLOTSTATE_RUNNING:
if (ca->open) dvb_ca_en50221_read_data(ca, slot, NULL, 0); if (ca->open)
dvb_ca_en50221_read_data(ca, slot, NULL, 0);
break; break;
} }
} }
...@@ -851,7 +930,8 @@ static int dvb_ca_en50221_thread_should_wakeup(struct dvb_ca_private* ca) ...@@ -851,7 +930,8 @@ static int dvb_ca_en50221_thread_should_wakeup(struct dvb_ca_private* ca)
ca->wakeup = 0; ca->wakeup = 0;
return 1; return 1;
} }
if (ca->exit) return 1; if (ca->exit)
return 1;
return 0; return 0;
} }
...@@ -901,7 +981,8 @@ static void dvb_ca_en50221_thread_update_delay(struct dvb_ca_private* ca) ...@@ -901,7 +981,8 @@ static void dvb_ca_en50221_thread_update_delay(struct dvb_ca_private* ca)
break; break;
} }
if (delay < curdelay) curdelay = delay; if (delay < curdelay)
curdelay = delay;
} }
ca->delay = curdelay; ca->delay = curdelay;
...@@ -918,6 +999,7 @@ static int dvb_ca_en50221_thread(void* data) ...@@ -918,6 +999,7 @@ static int dvb_ca_en50221_thread(void* data)
char name[15]; char name[15];
int slot; int slot;
int flags; int flags;
int status;
int pktcount; int pktcount;
void* rxbuf; void* rxbuf;
...@@ -938,7 +1020,9 @@ static int dvb_ca_en50221_thread(void* data) ...@@ -938,7 +1020,9 @@ static int dvb_ca_en50221_thread(void* data)
while(!ca->exit) { while(!ca->exit) {
/* sleep for a bit */ /* sleep for a bit */
if (!ca->wakeup) { if (!ca->wakeup) {
flags = wait_event_interruptible_timeout(ca->thread_queue, dvb_ca_en50221_thread_should_wakeup(ca), ca->delay); flags = wait_event_interruptible_timeout(ca->thread_queue,
dvb_ca_en50221_thread_should_wakeup(ca),
ca->delay);
if ((flags == -ERESTARTSYS) || ca->exit) { if ((flags == -ERESTARTSYS) || ca->exit) {
/* got signal or quitting */ /* got signal or quitting */
break; break;
...@@ -952,7 +1036,8 @@ static int dvb_ca_en50221_thread(void* data) ...@@ -952,7 +1036,8 @@ static int dvb_ca_en50221_thread(void* data)
// check the cam status + deal with CAMCHANGEs // check the cam status + deal with CAMCHANGEs
while(dvb_ca_en50221_check_camstatus(ca, slot)) { while(dvb_ca_en50221_check_camstatus(ca, slot)) {
/* clear down an old CI slot if necessary */ /* clear down an old CI slot if necessary */
if (ca->slot_info[slot].slot_state != DVB_CA_SLOTSTATE_NONE) dvb_ca_en50221_slot_shutdown(ca, slot); if (ca->slot_info[slot].slot_state != DVB_CA_SLOTSTATE_NONE)
dvb_ca_en50221_slot_shutdown(ca, slot);
/* if a CAM is NOW present, initialise it */ /* if a CAM is NOW present, initialise it */
if (ca->slot_info[slot].camchange_type == DVB_CA_EN50221_CAMCHANGE_INSERTED) { if (ca->slot_info[slot].camchange_type == DVB_CA_EN50221_CAMCHANGE_INSERTED) {
...@@ -979,7 +1064,8 @@ static int dvb_ca_en50221_thread(void* data) ...@@ -979,7 +1064,8 @@ static int dvb_ca_en50221_thread(void* data)
case DVB_CA_SLOTSTATE_WAITREADY: case DVB_CA_SLOTSTATE_WAITREADY:
if (time_after(jiffies, ca->slot_info[slot].timeout)) { if (time_after(jiffies, ca->slot_info[slot].timeout)) {
printk("dvb_ca adaptor %d: PC card did not respond :(\n", ca->dvbdev->adapter->num); printk("dvb_ca adaptor %d: PC card did not respond :(\n",
ca->dvbdev->adapter->num);
ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_INVALID; ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_INVALID;
dvb_ca_en50221_thread_update_delay(ca); dvb_ca_en50221_thread_update_delay(ca);
break; break;
...@@ -988,20 +1074,25 @@ static int dvb_ca_en50221_thread(void* data) ...@@ -988,20 +1074,25 @@ static int dvb_ca_en50221_thread(void* data)
break; break;
case DVB_CA_SLOTSTATE_VALIDATE: case DVB_CA_SLOTSTATE_VALIDATE:
if (dvb_ca_en50221_parse_attributes(ca, slot) != 0) { if (dvb_ca_en50221_parse_attributes(ca, slot)
printk("dvb_ca adapter %d: Invalid PC card inserted :(\n", ca->dvbdev->adapter->num); != 0) {
printk("dvb_ca adapter %d: Invalid PC card inserted :(\n",
ca->dvbdev->adapter->num);
ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_INVALID; ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_INVALID;
dvb_ca_en50221_thread_update_delay(ca); dvb_ca_en50221_thread_update_delay(ca);
break; break;
} }
if (dvb_ca_en50221_set_configoption(ca, slot) != 0) { if (dvb_ca_en50221_set_configoption(ca, slot) != 0) {
printk("dvb_ca adapter %d: Unable to initialise CAM :(\n", ca->dvbdev->adapter->num); printk("dvb_ca adapter %d: Unable to initialise CAM :(\n",
ca->dvbdev->adapter->num);
ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_INVALID; ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_INVALID;
dvb_ca_en50221_thread_update_delay(ca); dvb_ca_en50221_thread_update_delay(ca);
break; break;
} }
if (ca->pub->write_cam_control(ca->pub, slot, CTRLIF_COMMAND, CMDREG_RS) != 0) { if (ca->pub->write_cam_control(ca->pub, slot,
printk("dvb_ca adapter %d: Unable to reset CAM IF\n", ca->dvbdev->adapter->num); CTRLIF_COMMAND, CMDREG_RS) != 0) {
printk("dvb_ca adapter %d: Unable to reset CAM IF\n",
ca->dvbdev->adapter->num);
ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_INVALID; ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_INVALID;
dvb_ca_en50221_thread_update_delay(ca); dvb_ca_en50221_thread_update_delay(ca);
break; break;
...@@ -1016,7 +1107,8 @@ static int dvb_ca_en50221_thread(void* data) ...@@ -1016,7 +1107,8 @@ static int dvb_ca_en50221_thread(void* data)
case DVB_CA_SLOTSTATE_WAITFR: case DVB_CA_SLOTSTATE_WAITFR:
if (time_after(jiffies, ca->slot_info[slot].timeout)) { if (time_after(jiffies, ca->slot_info[slot].timeout)) {
printk("dvb_ca adapter %d: DVB CAM did not respond :(\n", ca->dvbdev->adapter->num); printk("dvb_ca adapter %d: DVB CAM did not respond :(\n",
ca->dvbdev->adapter->num);
ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_INVALID; ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_INVALID;
dvb_ca_en50221_thread_update_delay(ca); dvb_ca_en50221_thread_update_delay(ca);
break; break;
...@@ -1044,7 +1136,9 @@ static int dvb_ca_en50221_thread(void* data) ...@@ -1044,7 +1136,9 @@ static int dvb_ca_en50221_thread(void* data)
dvb_ca_en50221_thread_update_delay(ca); dvb_ca_en50221_thread_update_delay(ca);
break; break;
} }
down_write(&ca->slot_info[slot].sem);
dvb_ringbuffer_init(&ca->slot_info[slot].rx_buffer, rxbuf, RX_BUFFER_SIZE); dvb_ringbuffer_init(&ca->slot_info[slot].rx_buffer, rxbuf, RX_BUFFER_SIZE);
up_write(&ca->slot_info[slot].sem);
ca->pub->slot_ts_enable(ca->pub, slot); ca->pub->slot_ts_enable(ca->pub, slot);
ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_RUNNING; ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_RUNNING;
...@@ -1053,15 +1147,18 @@ static int dvb_ca_en50221_thread(void* data) ...@@ -1053,15 +1147,18 @@ static int dvb_ca_en50221_thread(void* data)
break; break;
case DVB_CA_SLOTSTATE_RUNNING: case DVB_CA_SLOTSTATE_RUNNING:
if (!ca->open) break; if (!ca->open)
continue;
// no need to poll if the CAM supports IRQs // no need to poll if the CAM supports IRQs
if (ca->slot_info[slot].da_irq_supported) break; if (ca->slot_info[slot].da_irq_supported)
break;
// poll mode // poll mode
pktcount = 0; pktcount = 0;
while(dvb_ca_en50221_read_data(ca, slot, NULL, 0) > 0) { while ((status = dvb_ca_en50221_read_data(ca, slot, NULL, 0)) > 0) {
if (!ca->open) break; if (!ca->open)
break;
/* if a CAMCHANGE occurred at some point, do not do any more processing of this slot */ /* if a CAMCHANGE occurred at some point, do not do any more processing of this slot */
if (dvb_ca_en50221_check_camstatus(ca, slot)) { if (dvb_ca_en50221_check_camstatus(ca, slot)) {
...@@ -1105,7 +1202,8 @@ static int dvb_ca_en50221_thread(void* data) ...@@ -1105,7 +1202,8 @@ static int dvb_ca_en50221_thread(void* data)
* *
* @return 0 on success, <0 on error. * @return 0 on success, <0 on error.
*/ */
static int dvb_ca_en50221_io_do_ioctl(struct inode *inode, struct file *file, unsigned int cmd, void *parg) static int dvb_ca_en50221_io_do_ioctl(struct inode *inode, struct file *file,
unsigned int cmd, void *parg)
{ {
struct dvb_device* dvbdev=(struct dvb_device*) file->private_data; struct dvb_device* dvbdev=(struct dvb_device*) file->private_data;
struct dvb_ca_private* ca = (struct dvb_ca_private*) dvbdev->priv; struct dvb_ca_private* ca = (struct dvb_ca_private*) dvbdev->priv;
...@@ -1120,15 +1218,16 @@ static int dvb_ca_en50221_io_do_ioctl(struct inode *inode, struct file *file, un ...@@ -1120,15 +1218,16 @@ static int dvb_ca_en50221_io_do_ioctl(struct inode *inode, struct file *file, un
if (ca->slot_info[slot].slot_state != DVB_CA_SLOTSTATE_NONE) { if (ca->slot_info[slot].slot_state != DVB_CA_SLOTSTATE_NONE) {
dvb_ca_en50221_slot_shutdown(ca, slot); dvb_ca_en50221_slot_shutdown(ca, slot);
if (ca->flags & DVB_CA_EN50221_FLAG_IRQ_CAMCHANGE) if (ca->flags & DVB_CA_EN50221_FLAG_IRQ_CAMCHANGE)
dvb_ca_en50221_camchange_irq(ca->pub, slot, DVB_CA_EN50221_CAMCHANGE_INSERTED); dvb_ca_en50221_camchange_irq(ca->pub,
slot,
DVB_CA_EN50221_CAMCHANGE_INSERTED);
} }
} }
ca->next_read_slot = 0; ca->next_read_slot = 0;
dvb_ca_en50221_thread_wakeup(ca); dvb_ca_en50221_thread_wakeup(ca);
break; break;
case CA_GET_CAP: case CA_GET_CAP: {
{
struct ca_caps *caps = (struct ca_caps*) parg; struct ca_caps *caps = (struct ca_caps*) parg;
caps->slot_num=ca->slot_count; caps->slot_num=ca->slot_count;
...@@ -1138,9 +1237,7 @@ static int dvb_ca_en50221_io_do_ioctl(struct inode *inode, struct file *file, un ...@@ -1138,9 +1237,7 @@ static int dvb_ca_en50221_io_do_ioctl(struct inode *inode, struct file *file, un
break; break;
} }
case CA_GET_SLOT_INFO: {
case CA_GET_SLOT_INFO:
{
struct ca_slot_info *info=(struct ca_slot_info *)parg; struct ca_slot_info *info=(struct ca_slot_info *)parg;
if ((info->num > ca->slot_count) || (info->num < 0)) if ((info->num > ca->slot_count) || (info->num < 0))
...@@ -1148,8 +1245,8 @@ static int dvb_ca_en50221_io_do_ioctl(struct inode *inode, struct file *file, un ...@@ -1148,8 +1245,8 @@ static int dvb_ca_en50221_io_do_ioctl(struct inode *inode, struct file *file, un
info->type = CA_CI_LINK; info->type = CA_CI_LINK;
info->flags = 0; info->flags = 0;
if ((ca->slot_info[info->num].slot_state != DVB_CA_SLOTSTATE_NONE) && if ((ca->slot_info[info->num].slot_state != DVB_CA_SLOTSTATE_NONE)
(ca->slot_info[info->num].slot_state != DVB_CA_SLOTSTATE_INVALID)) { && (ca->slot_info[info->num].slot_state != DVB_CA_SLOTSTATE_INVALID)) {
info->flags = CA_CI_MODULE_PRESENT; info->flags = CA_CI_MODULE_PRESENT;
} }
if (ca->slot_info[info->num].slot_state == DVB_CA_SLOTSTATE_RUNNING) { if (ca->slot_info[info->num].slot_state == DVB_CA_SLOTSTATE_RUNNING) {
...@@ -1177,7 +1274,8 @@ static int dvb_ca_en50221_io_do_ioctl(struct inode *inode, struct file *file, un ...@@ -1177,7 +1274,8 @@ static int dvb_ca_en50221_io_do_ioctl(struct inode *inode, struct file *file, un
* *
* @return 0 on success, <0 on error. * @return 0 on success, <0 on error.
*/ */
static int dvb_ca_en50221_io_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) static int dvb_ca_en50221_io_ioctl(struct inode *inode, struct file *file,
unsigned int cmd, unsigned long arg)
{ {
return dvb_usercopy(inode, file, cmd, arg, dvb_ca_en50221_io_do_ioctl); return dvb_usercopy(inode, file, cmd, arg, dvb_ca_en50221_io_do_ioctl);
} }
...@@ -1193,7 +1291,8 @@ static int dvb_ca_en50221_io_ioctl(struct inode *inode, struct file *file, unsig ...@@ -1193,7 +1291,8 @@ static int dvb_ca_en50221_io_ioctl(struct inode *inode, struct file *file, unsig
* *
* @return Number of bytes read, or <0 on error. * @return Number of bytes read, or <0 on error.
*/ */
static ssize_t dvb_ca_en50221_io_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) static ssize_t dvb_ca_en50221_io_write(struct file *file,
const char __user * buf, size_t count, loff_t * ppos)
{ {
struct dvb_device *dvbdev=(struct dvb_device *) file->private_data; struct dvb_device *dvbdev=(struct dvb_device *) file->private_data;
struct dvb_ca_private *ca=(struct dvb_ca_private*) dvbdev->priv; struct dvb_ca_private *ca=(struct dvb_ca_private*) dvbdev->priv;
...@@ -1208,35 +1307,48 @@ static ssize_t dvb_ca_en50221_io_write(struct file *file, const char __user *buf ...@@ -1208,35 +1307,48 @@ static ssize_t dvb_ca_en50221_io_write(struct file *file, const char __user *buf
dprintk ("%s\n", __FUNCTION__); dprintk ("%s\n", __FUNCTION__);
/* Incoming packet has a 2 byte header. hdr[0] = slot_id, hdr[1] = connection_id */ /* Incoming packet has a 2 byte header. hdr[0] = slot_id, hdr[1] = connection_id */
if (count < 2) return -EINVAL; if (count < 2)
return -EINVAL;
/* extract slot & connection id */ /* extract slot & connection id */
if (copy_from_user(&slot, buf, 1)) return -EFAULT; if (copy_from_user(&slot, buf, 1))
if (copy_from_user(&connection_id, buf+1, 1)) return -EFAULT; return -EFAULT;
if (copy_from_user(&connection_id, buf + 1, 1))
return -EFAULT;
buf+=2; buf+=2;
count-=2; count-=2;
/* check if the slot is actually running */ /* check if the slot is actually running */
if (ca->slot_info[slot].slot_state != DVB_CA_SLOTSTATE_RUNNING) return -EINVAL; if (ca->slot_info[slot].slot_state != DVB_CA_SLOTSTATE_RUNNING)
return -EINVAL;
/* fragment the packets & store in the buffer */ /* fragment the packets & store in the buffer */
while(fragpos < count) { while(fragpos < count) {
fraglen = ca->slot_info[slot].link_buf_size - 2; fraglen = ca->slot_info[slot].link_buf_size - 2;
if ((count - fragpos) < fraglen) fraglen = count - fragpos; if ((count - fragpos) < fraglen)
fraglen = count - fragpos;
fragbuf[0] = connection_id; fragbuf[0] = connection_id;
fragbuf[1] = ((fragpos + fraglen) < count) ? 0x80 : 0x00; fragbuf[1] = ((fragpos + fraglen) < count) ? 0x80 : 0x00;
if ((status = copy_from_user(fragbuf+2, buf+fragpos, fraglen)) != 0) goto exit; if ((status = copy_from_user(fragbuf + 2, buf + fragpos, fraglen)) != 0)
goto exit;
timeout = jiffies + HZ/2; timeout = jiffies + HZ/2;
written = 0; written = 0;
while(!time_after(jiffies, timeout)) { while(!time_after(jiffies, timeout)) {
/* check the CAM hasn't been removed/reset in the meantime */
if (ca->slot_info[slot].slot_state != DVB_CA_SLOTSTATE_RUNNING) {
status = -EIO;
goto exit;
}
status = dvb_ca_en50221_write_data(ca, slot, fragbuf, fraglen+2); status = dvb_ca_en50221_write_data(ca, slot, fragbuf, fraglen+2);
if (status == (fraglen+2)) { if (status == (fraglen+2)) {
written = 1; written = 1;
break; break;
} }
if (status != -EAGAIN) goto exit; if (status != -EAGAIN)
goto exit;
msleep(1); msleep(1);
} }
...@@ -1269,14 +1381,21 @@ static int dvb_ca_en50221_io_read_condition(struct dvb_ca_private* ca, int* resu ...@@ -1269,14 +1381,21 @@ static int dvb_ca_en50221_io_read_condition(struct dvb_ca_private* ca, int* resu
slot = ca->next_read_slot; slot = ca->next_read_slot;
while((slot_count < ca->slot_count) && (!found)) { while((slot_count < ca->slot_count) && (!found)) {
if (ca->slot_info[slot].slot_state != DVB_CA_SLOTSTATE_RUNNING) goto nextslot; if (ca->slot_info[slot].slot_state != DVB_CA_SLOTSTATE_RUNNING)
goto nextslot;
down_read(&ca->slot_info[slot].sem); down_read(&ca->slot_info[slot].sem);
if (ca->slot_info[slot].rx_buffer.data == NULL) {
up_read(&ca->slot_info[slot].sem);
return 0;
}
idx = dvb_ringbuffer_pkt_next(&ca->slot_info[slot].rx_buffer, -1, &fraglen); idx = dvb_ringbuffer_pkt_next(&ca->slot_info[slot].rx_buffer, -1, &fraglen);
while(idx != -1) { while(idx != -1) {
dvb_ringbuffer_pkt_read(&ca->slot_info[slot].rx_buffer, idx, 0, hdr, 2, 0); dvb_ringbuffer_pkt_read(&ca->slot_info[slot].rx_buffer, idx, 0, hdr, 2, 0);
if (connection_id == -1) connection_id = hdr[0]; if (connection_id == -1)
connection_id = hdr[0];
if ((hdr[0] == connection_id) && ((hdr[1] & 0x80) == 0)) { if ((hdr[0] == connection_id) && ((hdr[1] & 0x80) == 0)) {
*_slot = slot; *_slot = slot;
found = 1; found = 1;
...@@ -1286,7 +1405,8 @@ static int dvb_ca_en50221_io_read_condition(struct dvb_ca_private* ca, int* resu ...@@ -1286,7 +1405,8 @@ static int dvb_ca_en50221_io_read_condition(struct dvb_ca_private* ca, int* resu
idx = dvb_ringbuffer_pkt_next(&ca->slot_info[slot].rx_buffer, idx, &fraglen); idx = dvb_ringbuffer_pkt_next(&ca->slot_info[slot].rx_buffer, idx, &fraglen);
} }
if (!found) up_read(&ca->slot_info[slot].sem); if (!found)
up_read(&ca->slot_info[slot].sem);
nextslot: nextslot:
slot = (slot + 1) % ca->slot_count; slot = (slot + 1) % ca->slot_count;
...@@ -1308,7 +1428,8 @@ static int dvb_ca_en50221_io_read_condition(struct dvb_ca_private* ca, int* resu ...@@ -1308,7 +1428,8 @@ static int dvb_ca_en50221_io_read_condition(struct dvb_ca_private* ca, int* resu
* *
* @return Number of bytes read, or <0 on error. * @return Number of bytes read, or <0 on error.
*/ */
static ssize_t dvb_ca_en50221_io_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) static ssize_t dvb_ca_en50221_io_read(struct file *file, char __user * buf,
size_t count, loff_t * ppos)
{ {
struct dvb_device *dvbdev=(struct dvb_device *) file->private_data; struct dvb_device *dvbdev=(struct dvb_device *) file->private_data;
struct dvb_ca_private *ca=(struct dvb_ca_private*) dvbdev->priv; struct dvb_ca_private *ca=(struct dvb_ca_private*) dvbdev->priv;
...@@ -1326,19 +1447,24 @@ static ssize_t dvb_ca_en50221_io_read(struct file *file, char __user *buf, size_ ...@@ -1326,19 +1447,24 @@ static ssize_t dvb_ca_en50221_io_read(struct file *file, char __user *buf, size_
dprintk ("%s\n", __FUNCTION__); dprintk ("%s\n", __FUNCTION__);
/* Outgoing packet has a 2 byte header. hdr[0] = slot_id, hdr[1] = connection_id */ /* Outgoing packet has a 2 byte header. hdr[0] = slot_id, hdr[1] = connection_id */
if (count < 2) return -EINVAL; if (count < 2)
return -EINVAL;
/* wait for some data */ /* wait for some data */
if ((status = dvb_ca_en50221_io_read_condition(ca, &result, &slot)) == 0) { if ((status = dvb_ca_en50221_io_read_condition(ca, &result, &slot)) == 0) {
/* if we're in nonblocking mode, exit immediately */ /* if we're in nonblocking mode, exit immediately */
if (file->f_flags & O_NONBLOCK) return -EWOULDBLOCK; if (file->f_flags & O_NONBLOCK)
return -EWOULDBLOCK;
/* wait for some data */ /* wait for some data */
status = wait_event_interruptible(ca->wait_queue, dvb_ca_en50221_io_read_condition(ca, &result, &slot)); status = wait_event_interruptible(ca->wait_queue,
dvb_ca_en50221_io_read_condition
(ca, &result, &slot));
} }
if ((status < 0) || (result < 0)) { if ((status < 0) || (result < 0)) {
if (result) return result; if (result)
return result;
return status; return status;
} }
...@@ -1352,7 +1478,8 @@ static ssize_t dvb_ca_en50221_io_read(struct file *file, char __user *buf, size_ ...@@ -1352,7 +1478,8 @@ static ssize_t dvb_ca_en50221_io_read(struct file *file, char __user *buf, size_
} }
dvb_ringbuffer_pkt_read(&ca->slot_info[slot].rx_buffer, idx, 0, hdr, 2, 0); dvb_ringbuffer_pkt_read(&ca->slot_info[slot].rx_buffer, idx, 0, hdr, 2, 0);
if (connection_id == -1) connection_id = hdr[0]; if (connection_id == -1)
connection_id = hdr[0];
if (hdr[0] == connection_id) { if (hdr[0] == connection_id) {
if (pktlen < count) { if (pktlen < count) {
if ((pktlen + fraglen - 2) > count) { if ((pktlen + fraglen - 2) > count) {
...@@ -1361,25 +1488,29 @@ static ssize_t dvb_ca_en50221_io_read(struct file *file, char __user *buf, size_ ...@@ -1361,25 +1488,29 @@ static ssize_t dvb_ca_en50221_io_read(struct file *file, char __user *buf, size_
fraglen -= 2; fraglen -= 2;
} }
if ((status = dvb_ringbuffer_pkt_read(&ca->slot_info[slot].rx_buffer, idx, 2, buf + pktlen, fraglen, 1)) < 0) { if ((status = dvb_ringbuffer_pkt_read(&ca->slot_info[slot].rx_buffer, idx, 2,
buf + pktlen, fraglen, 1)) < 0) {
goto exit; goto exit;
} }
pktlen += fraglen; pktlen += fraglen;
} }
if ((hdr[1] & 0x80) == 0) last_fragment = 1; if ((hdr[1] & 0x80) == 0)
last_fragment = 1;
dispose = 1; dispose = 1;
} }
idx2 = dvb_ringbuffer_pkt_next(&ca->slot_info[slot].rx_buffer, idx, &fraglen); idx2 = dvb_ringbuffer_pkt_next(&ca->slot_info[slot].rx_buffer, idx, &fraglen);
if (dispose) dvb_ringbuffer_pkt_dispose(&ca->slot_info[slot].rx_buffer, idx); if (dispose)
dvb_ringbuffer_pkt_dispose(&ca->slot_info[slot].rx_buffer, idx);
idx = idx2; idx = idx2;
dispose = 0; dispose = 0;
} while (!last_fragment); } while (!last_fragment);
hdr[0] = slot; hdr[0] = slot;
hdr[1] = connection_id; hdr[1] = connection_id;
if ((status = copy_to_user(buf, hdr, 2)) != 0) goto exit; if ((status = copy_to_user(buf, hdr, 2)) != 0)
goto exit;
status = pktlen; status = pktlen;
exit: exit:
...@@ -1405,14 +1536,20 @@ static int dvb_ca_en50221_io_open(struct inode *inode, struct file *file) ...@@ -1405,14 +1536,20 @@ static int dvb_ca_en50221_io_open(struct inode *inode, struct file *file)
dprintk ("%s\n", __FUNCTION__); dprintk ("%s\n", __FUNCTION__);
if (!try_module_get(ca->pub->owner))
return -EIO;
err=dvb_generic_open(inode, file); err=dvb_generic_open(inode, file);
if (err<0) if (err<0)
return err; return err;
for(i=0; i< ca->slot_count; i++) { for(i=0; i< ca->slot_count; i++) {
if (ca->slot_info[i].slot_state == DVB_CA_SLOTSTATE_RUNNING) { if (ca->slot_info[i].slot_state == DVB_CA_SLOTSTATE_RUNNING) {
down_write(&ca->slot_info[i].sem); down_write(&ca->slot_info[i].sem);
if (ca->slot_info[i].rx_buffer.data != NULL) {
dvb_ringbuffer_flush(&ca->slot_info[i].rx_buffer); dvb_ringbuffer_flush(&ca->slot_info[i].rx_buffer);
}
up_write(&ca->slot_info[i].sem); up_write(&ca->slot_info[i].sem);
} }
} }
...@@ -1437,7 +1574,7 @@ static int dvb_ca_en50221_io_release(struct inode *inode, struct file *file) ...@@ -1437,7 +1574,7 @@ static int dvb_ca_en50221_io_release(struct inode *inode, struct file *file)
{ {
struct dvb_device *dvbdev=(struct dvb_device *) file->private_data; struct dvb_device *dvbdev=(struct dvb_device *) file->private_data;
struct dvb_ca_private *ca=(struct dvb_ca_private*) dvbdev->priv; struct dvb_ca_private *ca=(struct dvb_ca_private*) dvbdev->priv;
int err; int err = 0;
dprintk ("%s\n", __FUNCTION__); dprintk ("%s\n", __FUNCTION__);
...@@ -1446,8 +1583,9 @@ static int dvb_ca_en50221_io_release(struct inode *inode, struct file *file) ...@@ -1446,8 +1583,9 @@ static int dvb_ca_en50221_io_release(struct inode *inode, struct file *file)
dvb_ca_en50221_thread_update_delay(ca); dvb_ca_en50221_thread_update_delay(ca);
err=dvb_generic_release(inode, file); err=dvb_generic_release(inode, file);
if (err<0)
return err; module_put(ca->pub->owner);
return 0; return 0;
} }
...@@ -1476,7 +1614,8 @@ static unsigned int dvb_ca_en50221_io_poll(struct file *file, poll_table *wait) ...@@ -1476,7 +1614,8 @@ static unsigned int dvb_ca_en50221_io_poll(struct file *file, poll_table *wait)
} }
/* if there is something, return now */ /* if there is something, return now */
if (mask) return mask; if (mask)
return mask;
/* wait for something to happen */ /* wait for something to happen */
poll_wait(file, &ca->wait_queue, wait); poll_wait(file, &ca->wait_queue, wait);
...@@ -1488,6 +1627,8 @@ static unsigned int dvb_ca_en50221_io_poll(struct file *file, poll_table *wait) ...@@ -1488,6 +1627,8 @@ static unsigned int dvb_ca_en50221_io_poll(struct file *file, poll_table *wait)
return mask; return mask;
} }
EXPORT_SYMBOL(dvb_ca_en50221_init);
static struct file_operations dvb_ca_fops = { static struct file_operations dvb_ca_fops = {
.owner = THIS_MODULE, .owner = THIS_MODULE,
...@@ -1521,7 +1662,8 @@ static struct dvb_device dvbdev_ca = { ...@@ -1521,7 +1662,8 @@ static struct dvb_device dvbdev_ca = {
* *
* @return 0 on success, nonzero on failure * @return 0 on success, nonzero on failure
*/ */
int dvb_ca_en50221_init(struct dvb_adapter *dvb_adapter, struct dvb_ca_en50221* pubca, int flags, int slot_count) int dvb_ca_en50221_init(struct dvb_adapter *dvb_adapter,
struct dvb_ca_en50221 *pubca, int flags, int slot_count)
{ {
int ret; int ret;
struct dvb_ca_private* ca = NULL; struct dvb_ca_private* ca = NULL;
...@@ -1529,10 +1671,13 @@ int dvb_ca_en50221_init(struct dvb_adapter *dvb_adapter, struct dvb_ca_en50221* ...@@ -1529,10 +1671,13 @@ int dvb_ca_en50221_init(struct dvb_adapter *dvb_adapter, struct dvb_ca_en50221*
dprintk ("%s\n", __FUNCTION__); dprintk ("%s\n", __FUNCTION__);
if (slot_count < 1) return -EINVAL; if (slot_count < 1)
return -EINVAL;
/* initialise the system data */ /* initialise the system data */
if ((ca = (struct dvb_ca_private*) kmalloc(sizeof(struct dvb_ca_private), GFP_KERNEL)) == NULL) { if ((ca =
(struct dvb_ca_private *) kmalloc(sizeof(struct dvb_ca_private),
GFP_KERNEL)) == NULL) {
ret = -ENOMEM; ret = -ENOMEM;
goto error; goto error;
} }
...@@ -1556,7 +1701,8 @@ int dvb_ca_en50221_init(struct dvb_adapter *dvb_adapter, struct dvb_ca_en50221* ...@@ -1556,7 +1701,8 @@ int dvb_ca_en50221_init(struct dvb_adapter *dvb_adapter, struct dvb_ca_en50221*
/* register the DVB device */ /* register the DVB device */
ret = dvb_register_device(dvb_adapter, &ca->dvbdev, &dvbdev_ca, ca, DVB_DEVICE_CA); ret = dvb_register_device(dvb_adapter, &ca->dvbdev, &dvbdev_ca, ca, DVB_DEVICE_CA);
if (ret) goto error; if (ret)
goto error;
/* now initialise each slot */ /* now initialise each slot */
for(i=0; i< slot_count; i++) { for(i=0; i< slot_count; i++) {
...@@ -1584,13 +1730,16 @@ int dvb_ca_en50221_init(struct dvb_adapter *dvb_adapter, struct dvb_ca_en50221* ...@@ -1584,13 +1730,16 @@ int dvb_ca_en50221_init(struct dvb_adapter *dvb_adapter, struct dvb_ca_en50221*
error: error:
if (ca != NULL) { if (ca != NULL) {
if (ca->dvbdev != NULL) dvb_unregister_device(ca->dvbdev); if (ca->dvbdev != NULL)
if (ca->slot_info != NULL) kfree(ca->slot_info); dvb_unregister_device(ca->dvbdev);
if (ca->slot_info != NULL)
kfree(ca->slot_info);
kfree(ca); kfree(ca);
} }
pubca->private = NULL; pubca->private = NULL;
return ret; return ret;
} }
EXPORT_SYMBOL(dvb_ca_en50221_release);
...@@ -1610,7 +1759,8 @@ void dvb_ca_en50221_release(struct dvb_ca_en50221* pubca) ...@@ -1610,7 +1759,8 @@ void dvb_ca_en50221_release(struct dvb_ca_en50221* pubca)
/* shutdown the thread if there was one */ /* shutdown the thread if there was one */
if (ca->thread_pid) { if (ca->thread_pid) {
if (kill_proc(ca->thread_pid, 0, 1) == -ESRCH) { if (kill_proc(ca->thread_pid, 0, 1) == -ESRCH) {
printk("dvb_ca_release adapter %d: thread PID %d already died\n", ca->dvbdev->adapter->num, ca->thread_pid); printk("dvb_ca_release adapter %d: thread PID %d already died\n",
ca->dvbdev->adapter->num, ca->thread_pid);
} else { } else {
ca->exit = 1; ca->exit = 1;
mb(); mb();
......
...@@ -42,6 +42,9 @@ ...@@ -42,6 +42,9 @@
/* Structure describing a CA interface */ /* Structure describing a CA interface */
struct dvb_ca_en50221 { struct dvb_ca_en50221 {
/* the module owning this structure */
struct module* owner;
/* NOTE: the read_*, write_* and poll_slot_status functions must use locks as /* NOTE: the read_*, write_* and poll_slot_status functions must use locks as
* they may be called from several threads at once */ * they may be called from several threads at once */
...@@ -62,7 +65,7 @@ struct dvb_ca_en50221 { ...@@ -62,7 +65,7 @@ struct dvb_ca_en50221 {
* Poll slot status. * Poll slot status.
* Only necessary if DVB_CA_FLAG_EN50221_IRQ_CAMCHANGE is not set * Only necessary if DVB_CA_FLAG_EN50221_IRQ_CAMCHANGE is not set
*/ */
int (*poll_slot_status)(struct dvb_ca_en50221* ca, int slot); int (*poll_slot_status)(struct dvb_ca_en50221* ca, int slot, int open);
/* private data, used by caller */ /* private data, used by caller */
void* data; void* data;
......
...@@ -424,7 +424,7 @@ void dvb_dmx_swfilter_packet(struct dvb_demux *demux, const u8 *buf) ...@@ -424,7 +424,7 @@ void dvb_dmx_swfilter_packet(struct dvb_demux *demux, const u8 *buf)
feed->cb.ts(buf, 188, NULL, 0, &feed->feed.ts, DMX_OK); feed->cb.ts(buf, 188, NULL, 0, &feed->feed.ts, DMX_OK);
} }
} }
EXPORT_SYMBOL(dvb_dmx_swfilter_packet);
void dvb_dmx_swfilter_packets(struct dvb_demux *demux, const u8 *buf, size_t count) void dvb_dmx_swfilter_packets(struct dvb_demux *demux, const u8 *buf, size_t count)
{ {
...@@ -439,6 +439,7 @@ void dvb_dmx_swfilter_packets(struct dvb_demux *demux, const u8 *buf, size_t cou ...@@ -439,6 +439,7 @@ void dvb_dmx_swfilter_packets(struct dvb_demux *demux, const u8 *buf, size_t cou
spin_unlock(&demux->lock); spin_unlock(&demux->lock);
} }
EXPORT_SYMBOL(dvb_dmx_swfilter_packets);
void dvb_dmx_swfilter(struct dvb_demux *demux, const u8 *buf, size_t count) void dvb_dmx_swfilter(struct dvb_demux *demux, const u8 *buf, size_t count)
...@@ -478,6 +479,7 @@ void dvb_dmx_swfilter(struct dvb_demux *demux, const u8 *buf, size_t count) ...@@ -478,6 +479,7 @@ void dvb_dmx_swfilter(struct dvb_demux *demux, const u8 *buf, size_t count)
bailout: bailout:
spin_unlock(&demux->lock); spin_unlock(&demux->lock);
} }
EXPORT_SYMBOL(dvb_dmx_swfilter);
void dvb_dmx_swfilter_204(struct dvb_demux *demux, const u8 *buf, size_t count) void dvb_dmx_swfilter_204(struct dvb_demux *demux, const u8 *buf, size_t count)
{ {
...@@ -522,6 +524,7 @@ void dvb_dmx_swfilter_204(struct dvb_demux *demux, const u8 *buf, size_t count) ...@@ -522,6 +524,7 @@ void dvb_dmx_swfilter_204(struct dvb_demux *demux, const u8 *buf, size_t count)
bailout: bailout:
spin_unlock(&demux->lock); spin_unlock(&demux->lock);
} }
EXPORT_SYMBOL(dvb_dmx_swfilter_204);
static struct dvb_demux_filter * dvb_dmx_filter_alloc(struct dvb_demux *demux) static struct dvb_demux_filter * dvb_dmx_filter_alloc(struct dvb_demux *demux)
...@@ -1163,6 +1166,7 @@ int dvbdmx_connect_frontend(struct dmx_demux *demux, struct dmx_frontend *fronte ...@@ -1163,6 +1166,7 @@ int dvbdmx_connect_frontend(struct dmx_demux *demux, struct dmx_frontend *fronte
up(&dvbdemux->mutex); up(&dvbdemux->mutex);
return 0; return 0;
} }
EXPORT_SYMBOL(dvbdmx_connect_frontend);
int dvbdmx_disconnect_frontend(struct dmx_demux *demux) int dvbdmx_disconnect_frontend(struct dmx_demux *demux)
...@@ -1176,6 +1180,7 @@ int dvbdmx_disconnect_frontend(struct dmx_demux *demux) ...@@ -1176,6 +1180,7 @@ int dvbdmx_disconnect_frontend(struct dmx_demux *demux)
up(&dvbdemux->mutex); up(&dvbdemux->mutex);
return 0; return 0;
} }
EXPORT_SYMBOL(dvbdmx_disconnect_frontend);
static int dvbdmx_get_pes_pids(struct dmx_demux *demux, u16 *pids) static int dvbdmx_get_pes_pids(struct dmx_demux *demux, u16 *pids)
...@@ -1256,6 +1261,7 @@ int dvb_dmx_init(struct dvb_demux *dvbdemux) ...@@ -1256,6 +1261,7 @@ int dvb_dmx_init(struct dvb_demux *dvbdemux)
return 0; return 0;
} }
EXPORT_SYMBOL(dvb_dmx_init);
int dvb_dmx_release(struct dvb_demux *dvbdemux) int dvb_dmx_release(struct dvb_demux *dvbdemux)
...@@ -1269,3 +1275,5 @@ int dvb_dmx_release(struct dvb_demux *dvbdemux) ...@@ -1269,3 +1275,5 @@ int dvb_dmx_release(struct dvb_demux *dvbdemux)
vfree(dvbdemux->feed); vfree(dvbdemux->feed);
return 0; return 0;
} }
EXPORT_SYMBOL(dvb_dmx_release);
...@@ -3,19 +3,20 @@ ...@@ -3,19 +3,20 @@
#include <linux/string.h> #include <linux/string.h>
#include "dvb_filter.h" #include "dvb_filter.h"
unsigned int bitrates[3][16] = #if 0
static unsigned int bitrates[3][16] =
{{0,32,64,96,128,160,192,224,256,288,320,352,384,416,448,0}, {{0,32,64,96,128,160,192,224,256,288,320,352,384,416,448,0},
{0,32,48,56,64,80,96,112,128,160,192,224,256,320,384,0}, {0,32,48,56,64,80,96,112,128,160,192,224,256,320,384,0},
{0,32,40,48,56,64,80,96,112,128,160,192,224,256,320,0}}; {0,32,40,48,56,64,80,96,112,128,160,192,224,256,320,0}};
#endif
u32 freq[4] = {441, 480, 320, 0}; static u32 freq[4] = {480, 441, 320, 0};
unsigned int ac3_bitrates[32] = static unsigned int ac3_bitrates[32] =
{32,40,48,56,64,80,96,112,128,160,192,224,256,320,384,448,512,576,640, {32,40,48,56,64,80,96,112,128,160,192,224,256,320,384,448,512,576,640,
0,0,0,0,0,0,0,0,0,0,0,0,0}; 0,0,0,0,0,0,0,0,0,0,0,0,0};
u32 ac3_freq[4] = {480, 441, 320, 0}; static u32 ac3_frames[3][32] =
u32 ac3_frames[3][32] =
{{64,80,96,112,128,160,192,224,256,320,384,448,512,640,768,896,1024, {{64,80,96,112,128,160,192,224,256,320,384,448,512,640,768,896,1024,
1152,1280,0,0,0,0,0,0,0,0,0,0,0,0,0}, 1152,1280,0,0,0,0,0,0,0,0,0,0,0,0,0},
{69,87,104,121,139,174,208,243,278,348,417,487,557,696,835,975,1114, {69,87,104,121,139,174,208,243,278,348,417,487,557,696,835,975,1114,
...@@ -389,6 +390,7 @@ int dvb_filter_get_ac3info(u8 *mbuf, int count, struct dvb_audio_info *ai, int p ...@@ -389,6 +390,7 @@ int dvb_filter_get_ac3info(u8 *mbuf, int count, struct dvb_audio_info *ai, int p
return 0; return 0;
} }
EXPORT_SYMBOL(dvb_filter_get_ac3info);
#if 0 #if 0
...@@ -563,6 +565,7 @@ void dvb_filter_pes2ts_init(struct dvb_filter_pes2ts *p2ts, unsigned short pid, ...@@ -563,6 +565,7 @@ void dvb_filter_pes2ts_init(struct dvb_filter_pes2ts *p2ts, unsigned short pid,
p2ts->cb=cb; p2ts->cb=cb;
p2ts->priv=priv; p2ts->priv=priv;
} }
EXPORT_SYMBOL(dvb_filter_pes2ts_init);
int dvb_filter_pes2ts(struct dvb_filter_pes2ts *p2ts, unsigned char *pes, int dvb_filter_pes2ts(struct dvb_filter_pes2ts *p2ts, unsigned char *pes,
int len, int payload_start) int len, int payload_start)
...@@ -597,4 +600,5 @@ int dvb_filter_pes2ts(struct dvb_filter_pes2ts *p2ts, unsigned char *pes, ...@@ -597,4 +600,5 @@ int dvb_filter_pes2ts(struct dvb_filter_pes2ts *p2ts, unsigned char *pes,
memcpy(buf+5+rest, pes, len); memcpy(buf+5+rest, pes, len);
return p2ts->cb(p2ts->priv, buf); return p2ts->cb(p2ts->priv, buf);
} }
EXPORT_SYMBOL(dvb_filter_pes2ts);
...@@ -34,6 +34,7 @@ ...@@ -34,6 +34,7 @@
#include <linux/module.h> #include <linux/module.h>
#include <linux/moduleparam.h> #include <linux/moduleparam.h>
#include <linux/list.h> #include <linux/list.h>
#include <linux/suspend.h>
#include <asm/processor.h> #include <asm/processor.h>
#include <asm/semaphore.h> #include <asm/semaphore.h>
...@@ -45,6 +46,7 @@ static int dvb_shutdown_timeout = 5; ...@@ -45,6 +46,7 @@ static int dvb_shutdown_timeout = 5;
static int dvb_override_frequency_bending; static int dvb_override_frequency_bending;
static int dvb_force_auto_inversion; static int dvb_force_auto_inversion;
static int dvb_override_tune_delay; static int dvb_override_tune_delay;
static int dvb_powerdown_on_sleep = 1;
static int do_frequency_bending; static int do_frequency_bending;
module_param_named(frontend_debug, dvb_frontend_debug, int, 0644); module_param_named(frontend_debug, dvb_frontend_debug, int, 0644);
...@@ -57,6 +59,8 @@ module_param(dvb_force_auto_inversion, int, 0444); ...@@ -57,6 +59,8 @@ module_param(dvb_force_auto_inversion, int, 0444);
MODULE_PARM_DESC(dvb_force_auto_inversion, "0: normal (default), 1: INVERSION_AUTO forced always"); MODULE_PARM_DESC(dvb_force_auto_inversion, "0: normal (default), 1: INVERSION_AUTO forced always");
module_param(dvb_override_tune_delay, int, 0444); module_param(dvb_override_tune_delay, int, 0444);
MODULE_PARM_DESC(dvb_override_tune_delay, "0: normal (default), >0 => delay in milliseconds to wait for lock after a tune attempt"); MODULE_PARM_DESC(dvb_override_tune_delay, "0: normal (default), >0 => delay in milliseconds to wait for lock after a tune attempt");
module_param(dvb_powerdown_on_sleep, int, 0444);
MODULE_PARM_DESC(dvb_powerdown_on_sleep, "0: do not power down, 1: turn LNB volatage off on sleep (default)");
#define dprintk if (dvb_frontend_debug) printk #define dprintk if (dvb_frontend_debug) printk
...@@ -100,12 +104,10 @@ struct dvb_fe_events { ...@@ -100,12 +104,10 @@ struct dvb_fe_events {
struct dvb_frontend_data { struct dvb_frontend_data {
struct dvb_frontend_info *info; struct dvb_frontend *frontend;
struct dvb_frontend frontend;
struct dvb_device *dvbdev; struct dvb_device *dvbdev;
struct dvb_frontend_parameters parameters; struct dvb_frontend_parameters parameters;
struct dvb_fe_events events; struct dvb_fe_events events;
struct module *module;
struct semaphore sem; struct semaphore sem;
struct list_head list_head; struct list_head list_head;
wait_queue_head_t wait_queue; wait_queue_head_t wait_queue;
...@@ -126,53 +128,11 @@ struct dvb_frontend_data { ...@@ -126,53 +128,11 @@ struct dvb_frontend_data {
fe_status_t status; fe_status_t status;
}; };
struct dvb_frontend_ioctl_data {
struct list_head list_head;
struct dvb_adapter *adapter;
int (*before_ioctl) (struct dvb_frontend *frontend,
unsigned int cmd, void *arg);
int (*after_ioctl) (struct dvb_frontend *frontend,
unsigned int cmd, void *arg);
void *before_after_data;
};
struct dvb_frontend_notifier_data {
struct list_head list_head;
struct dvb_adapter *adapter;
void (*callback) (fe_status_t s, void *data);
void *data;
};
static LIST_HEAD(frontend_list); static LIST_HEAD(frontend_list);
static LIST_HEAD(frontend_ioctl_list);
static LIST_HEAD(frontend_notifier_list);
static DECLARE_MUTEX(frontend_mutex); static DECLARE_MUTEX(frontend_mutex);
static int dvb_frontend_internal_ioctl (struct dvb_frontend *frontend,
unsigned int cmd, void *arg)
{
int err = -EOPNOTSUPP;
dprintk ("%s\n", __FUNCTION__);
if (frontend->before_ioctl)
err = frontend->before_ioctl (frontend, cmd, arg);
if (err == -EOPNOTSUPP) {
err = frontend->ioctl (frontend, cmd, arg);
if ((err == -EOPNOTSUPP) && frontend->after_ioctl)
err = frontend->after_ioctl (frontend, cmd, arg);
}
return err;
}
/** /**
* if 2 tuners are located side by side you can get interferences when * if 2 tuners are located side by side you can get interferences when
...@@ -184,8 +144,8 @@ static int dvb_frontend_internal_ioctl (struct dvb_frontend *frontend, ...@@ -184,8 +144,8 @@ static int dvb_frontend_internal_ioctl (struct dvb_frontend *frontend,
static void dvb_bend_frequency (struct dvb_frontend_data *this_fe, int recursive) static void dvb_bend_frequency (struct dvb_frontend_data *this_fe, int recursive)
{ {
struct list_head *entry; struct list_head *entry;
int stepsize = this_fe->info->frequency_stepsize; int stepsize = this_fe->frontend->ops->info.frequency_stepsize;
int this_fe_adap_num = this_fe->frontend.dvb_adapter->num; int this_fe_adap_num = this_fe->frontend->dvb->num;
int frequency; int frequency;
if (!stepsize || recursive > 10) { if (!stepsize || recursive > 10) {
...@@ -209,7 +169,7 @@ static void dvb_bend_frequency (struct dvb_frontend_data *this_fe, int recursive ...@@ -209,7 +169,7 @@ static void dvb_bend_frequency (struct dvb_frontend_data *this_fe, int recursive
fe = list_entry (entry, struct dvb_frontend_data, list_head); fe = list_entry (entry, struct dvb_frontend_data, list_head);
if (fe->frontend.dvb_adapter->num != this_fe_adap_num) if (fe->frontend->dvb->num != this_fe_adap_num)
continue; continue;
f = fe->parameters.frequency; f = fe->parameters.frequency;
...@@ -237,25 +197,6 @@ static void dvb_bend_frequency (struct dvb_frontend_data *this_fe, int recursive ...@@ -237,25 +197,6 @@ static void dvb_bend_frequency (struct dvb_frontend_data *this_fe, int recursive
up (&frontend_mutex); up (&frontend_mutex);
} }
static void dvb_call_frontend_notifiers (struct dvb_frontend_data *fe,
fe_status_t s)
{
dprintk ("%s\n", __FUNCTION__);
if (((s ^ fe->status) & FE_HAS_LOCK) && (s & FE_HAS_LOCK))
msleep (fe->info->notifier_delay);
fe->status = s;
/**
* now tell the Demux about the TS status changes...
*/
if (fe->frontend.notifier_callback)
fe->frontend.notifier_callback(fe->status, fe->frontend.notifier_data);
}
static void dvb_frontend_add_event (struct dvb_frontend_data *fe, fe_status_t status) static void dvb_frontend_add_event (struct dvb_frontend_data *fe, fe_status_t status)
{ {
struct dvb_fe_events *events = &fe->events; struct dvb_fe_events *events = &fe->events;
...@@ -280,15 +221,13 @@ static void dvb_frontend_add_event (struct dvb_frontend_data *fe, fe_status_t st ...@@ -280,15 +221,13 @@ static void dvb_frontend_add_event (struct dvb_frontend_data *fe, fe_status_t st
sizeof (struct dvb_frontend_parameters)); sizeof (struct dvb_frontend_parameters));
if (status & FE_HAS_LOCK) if (status & FE_HAS_LOCK)
dvb_frontend_internal_ioctl (&fe->frontend, if (fe->frontend->ops->get_frontend) fe->frontend->ops->get_frontend(fe->frontend, &e->parameters);
FE_GET_FRONTEND,
&e->parameters);
events->eventw = wp; events->eventw = wp;
up (&events->sem); up (&events->sem);
e->status = status; e->status = status;
dvb_call_frontend_notifiers (fe, status);
wake_up_interruptible (&events->wait_queue); wake_up_interruptible (&events->wait_queue);
} }
...@@ -339,13 +278,11 @@ static int dvb_frontend_get_event (struct dvb_frontend_data *fe, ...@@ -339,13 +278,11 @@ static int dvb_frontend_get_event (struct dvb_frontend_data *fe,
static void dvb_frontend_init (struct dvb_frontend_data *fe) static void dvb_frontend_init (struct dvb_frontend_data *fe)
{ {
struct dvb_frontend *frontend = &fe->frontend;
dprintk ("DVB: initialising frontend %i (%s)...\n", dprintk ("DVB: initialising frontend %i (%s)...\n",
frontend->dvb_adapter->num, fe->frontend->dvb->num,
fe->info->name); fe->frontend->ops->info.name);
dvb_frontend_internal_ioctl (frontend, FE_INIT, NULL); if (fe->frontend->ops->init) fe->frontend->ops->init(fe->frontend);
} }
static void update_delay (int *quality, int *delay, int min_delay, int locked) static void update_delay (int *quality, int *delay, int min_delay, int locked)
...@@ -380,7 +317,7 @@ static int dvb_frontend_autotune(struct dvb_frontend_data *fe, int check_wrapped ...@@ -380,7 +317,7 @@ static int dvb_frontend_autotune(struct dvb_frontend_data *fe, int check_wrapped
u32 original_frequency = fe->parameters.frequency; u32 original_frequency = fe->parameters.frequency;
/* are we using autoinversion? */ /* are we using autoinversion? */
autoinversion = ((!(fe->info->caps & FE_CAN_INVERSION_AUTO)) && autoinversion = ((!(fe->frontend->ops->info.caps & FE_CAN_INVERSION_AUTO)) &&
(fe->parameters.inversion == INVERSION_AUTO)); (fe->parameters.inversion == INVERSION_AUTO));
/* setup parameters correctly */ /* setup parameters correctly */
...@@ -453,7 +390,7 @@ static int dvb_frontend_autotune(struct dvb_frontend_data *fe, int check_wrapped ...@@ -453,7 +390,7 @@ static int dvb_frontend_autotune(struct dvb_frontend_data *fe, int check_wrapped
/* set the frontend itself */ /* set the frontend itself */
fe->parameters.frequency += fe->lnb_drift + fe->bending; fe->parameters.frequency += fe->lnb_drift + fe->bending;
if (autoinversion) fe->parameters.inversion = fe->inversion; if (autoinversion) fe->parameters.inversion = fe->inversion;
dvb_frontend_internal_ioctl (&fe->frontend, FE_SET_FRONTEND, &fe->parameters); if (fe->frontend->ops->set_frontend) fe->frontend->ops->set_frontend(fe->frontend, &fe->parameters);
fe->parameters.frequency = original_frequency; fe->parameters.frequency = original_frequency;
fe->parameters.inversion = original_inversion; fe->parameters.inversion = original_inversion;
...@@ -489,6 +426,9 @@ static void dvb_frontend_wakeup (struct dvb_frontend_data *fe) { ...@@ -489,6 +426,9 @@ static void dvb_frontend_wakeup (struct dvb_frontend_data *fe) {
wake_up_interruptible(&fe->wait_queue); wake_up_interruptible(&fe->wait_queue);
} }
/*
* FIXME: use linux/kthread.h
*/
static int dvb_frontend_thread (void *data) static int dvb_frontend_thread (void *data)
{ {
struct dvb_frontend_data *fe = (struct dvb_frontend_data *) data; struct dvb_frontend_data *fe = (struct dvb_frontend_data *) data;
...@@ -501,14 +441,14 @@ static int dvb_frontend_thread (void *data) ...@@ -501,14 +441,14 @@ static int dvb_frontend_thread (void *data)
dprintk ("%s\n", __FUNCTION__); dprintk ("%s\n", __FUNCTION__);
snprintf (name, sizeof(name), "kdvb-fe-%i", snprintf (name, sizeof(name), "kdvb-fe-%i",
fe->frontend.dvb_adapter->num); fe->frontend->dvb->num);
lock_kernel (); lock_kernel ();
daemonize (name); daemonize (name);
sigfillset (&current->blocked); sigfillset (&current->blocked);
unlock_kernel (); unlock_kernel ();
dvb_call_frontend_notifiers (fe, 0); fe->status = 0;
dvb_frontend_init (fe); dvb_frontend_init (fe);
fe->wakeup = 0; fe->wakeup = 0;
...@@ -516,11 +456,14 @@ static int dvb_frontend_thread (void *data) ...@@ -516,11 +456,14 @@ static int dvb_frontend_thread (void *data)
up (&fe->sem); /* is locked when we enter the thread... */ up (&fe->sem); /* is locked when we enter the thread... */
timeout = wait_event_interruptible_timeout(fe->wait_queue,0 != dvb_frontend_should_wakeup (fe), delay); timeout = wait_event_interruptible_timeout(fe->wait_queue,0 != dvb_frontend_should_wakeup (fe), delay);
if (-ERESTARTSYS == timeout || 0 != dvb_frontend_is_exiting (fe)) { if (0 != dvb_frontend_is_exiting (fe)) {
/* got signal or quitting */ /* got signal or quitting */
break; break;
} }
if (current->flags & PF_FREEZE)
refrigerator(PF_FREEZE);
if (down_interruptible (&fe->sem)) if (down_interruptible (&fe->sem))
break; break;
...@@ -535,9 +478,10 @@ static int dvb_frontend_thread (void *data) ...@@ -535,9 +478,10 @@ static int dvb_frontend_thread (void *data)
if (fe->state & FESTATE_RETUNE) { if (fe->state & FESTATE_RETUNE) {
s = 0; s = 0;
} else { } else {
dvb_frontend_internal_ioctl (&fe->frontend, FE_READ_STATUS, &s); if (fe->frontend->ops->read_status) fe->frontend->ops->read_status(fe->frontend, &s);
if (s != fe->status) { if (s != fe->status) {
dvb_frontend_add_event (fe, s); dvb_frontend_add_event (fe, s);
fe->status = s;
} }
} }
/* if we're not tuned, and we have a lock, move to the TUNED state */ /* if we're not tuned, and we have a lock, move to the TUNED state */
...@@ -546,7 +490,7 @@ static int dvb_frontend_thread (void *data) ...@@ -546,7 +490,7 @@ static int dvb_frontend_thread (void *data)
fe->state = FESTATE_TUNED; fe->state = FESTATE_TUNED;
/* if we're tuned, then we have determined the correct inversion */ /* if we're tuned, then we have determined the correct inversion */
if ((!(fe->info->caps & FE_CAN_INVERSION_AUTO)) && if ((!(fe->frontend->ops->info.caps & FE_CAN_INVERSION_AUTO)) &&
(fe->parameters.inversion == INVERSION_AUTO)) { (fe->parameters.inversion == INVERSION_AUTO)) {
fe->parameters.inversion = fe->inversion; fe->parameters.inversion = fe->inversion;
} }
...@@ -572,7 +516,7 @@ static int dvb_frontend_thread (void *data) ...@@ -572,7 +516,7 @@ static int dvb_frontend_thread (void *data)
/* don't actually do anything if we're in the LOSTLOCK state, /* don't actually do anything if we're in the LOSTLOCK state,
* the frontend is set to FE_CAN_RECOVER, and the max_drift is 0 */ * the frontend is set to FE_CAN_RECOVER, and the max_drift is 0 */
if ((fe->state & FESTATE_LOSTLOCK) && if ((fe->state & FESTATE_LOSTLOCK) &&
(fe->info->caps & FE_CAN_RECOVER) && (fe->max_drift == 0)) { (fe->frontend->ops->info.caps & FE_CAN_RECOVER) && (fe->max_drift == 0)) {
update_delay(&quality, &delay, fe->min_delay, s & FE_HAS_LOCK); update_delay(&quality, &delay, fe->min_delay, s & FE_HAS_LOCK);
continue; continue;
} }
...@@ -630,8 +574,11 @@ static int dvb_frontend_thread (void *data) ...@@ -630,8 +574,11 @@ static int dvb_frontend_thread (void *data)
} }
}; };
if (dvb_shutdown_timeout) if (dvb_shutdown_timeout) {
dvb_frontend_internal_ioctl (&fe->frontend, FE_SLEEP, NULL); if (dvb_powerdown_on_sleep)
if (fe->frontend->ops->set_voltage) fe->frontend->ops->set_voltage(fe->frontend, SEC_VOLTAGE_OFF);
if (fe->frontend->ops->sleep) fe->frontend->ops->sleep(fe->frontend);
}
fe->thread_pid = 0; fe->thread_pid = 0;
mb(); mb();
...@@ -720,12 +667,11 @@ static int dvb_frontend_ioctl (struct inode *inode, struct file *file, ...@@ -720,12 +667,11 @@ static int dvb_frontend_ioctl (struct inode *inode, struct file *file,
{ {
struct dvb_device *dvbdev = file->private_data; struct dvb_device *dvbdev = file->private_data;
struct dvb_frontend_data *fe = dvbdev->priv; struct dvb_frontend_data *fe = dvbdev->priv;
struct dvb_frontend_tune_settings fetunesettings; int err = -EOPNOTSUPP;
int err = 0;
dprintk ("%s\n", __FUNCTION__); dprintk ("%s\n", __FUNCTION__);
if (!fe || !fe->frontend.ioctl || fe->exit) if (!fe || fe->exit)
return -ENODEV; return -ENODEV;
if ((file->f_flags & O_ACCMODE) == O_RDONLY && if ((file->f_flags & O_ACCMODE) == O_RDONLY &&
...@@ -737,18 +683,103 @@ static int dvb_frontend_ioctl (struct inode *inode, struct file *file, ...@@ -737,18 +683,103 @@ static int dvb_frontend_ioctl (struct inode *inode, struct file *file,
return -ERESTARTSYS; return -ERESTARTSYS;
switch (cmd) { switch (cmd) {
case FE_GET_INFO: {
struct dvb_frontend_info* info = (struct dvb_frontend_info*) parg;
memcpy(info, &fe->frontend->ops->info, sizeof(struct dvb_frontend_info));
/* Force the CAN_INVERSION_AUTO bit on. If the frontend doesn't
* do it, it is done for it. */
info->caps |= FE_CAN_INVERSION_AUTO;
err = 0;
break;
}
case FE_READ_STATUS:
if (fe->frontend->ops->read_status)
err = fe->frontend->ops->read_status(fe->frontend, (fe_status_t*) parg);
break;
case FE_READ_BER:
if (fe->frontend->ops->read_ber)
err = fe->frontend->ops->read_ber(fe->frontend, (__u32*) parg);
break;
case FE_READ_SIGNAL_STRENGTH:
if (fe->frontend->ops->read_signal_strength)
err = fe->frontend->ops->read_signal_strength(fe->frontend, (__u16*) parg);
break;
case FE_READ_SNR:
if (fe->frontend->ops->read_snr)
err = fe->frontend->ops->read_snr(fe->frontend, (__u16*) parg);
break;
case FE_READ_UNCORRECTED_BLOCKS:
if (fe->frontend->ops->read_ucblocks)
err = fe->frontend->ops->read_ucblocks(fe->frontend, (__u32*) parg);
break;
case FE_DISEQC_RESET_OVERLOAD:
if (fe->frontend->ops->diseqc_reset_overload) {
err = fe->frontend->ops->diseqc_reset_overload(fe->frontend);
fe->state = FESTATE_DISEQC;
fe->status = 0;
}
break;
case FE_DISEQC_SEND_MASTER_CMD: case FE_DISEQC_SEND_MASTER_CMD:
if (fe->frontend->ops->diseqc_send_master_cmd) {
err = fe->frontend->ops->diseqc_send_master_cmd(fe->frontend, (struct dvb_diseqc_master_cmd*) parg);
fe->state = FESTATE_DISEQC;
fe->status = 0;
}
break;
case FE_DISEQC_SEND_BURST: case FE_DISEQC_SEND_BURST:
if (fe->frontend->ops->diseqc_send_burst) {
err = fe->frontend->ops->diseqc_send_burst(fe->frontend, (fe_sec_mini_cmd_t) parg);
fe->state = FESTATE_DISEQC;
fe->status = 0;
}
break;
case FE_SET_TONE: case FE_SET_TONE:
if (fe->frontend->ops->set_tone) {
err = fe->frontend->ops->set_tone(fe->frontend, (fe_sec_tone_mode_t) parg);
fe->state = FESTATE_DISEQC;
fe->status = 0;
}
break;
case FE_SET_VOLTAGE: case FE_SET_VOLTAGE:
if (fe->status) if (fe->frontend->ops->set_voltage) {
dvb_call_frontend_notifiers (fe, 0); err = fe->frontend->ops->set_voltage(fe->frontend, (fe_sec_voltage_t) parg);
dvb_frontend_internal_ioctl (&fe->frontend, cmd, parg);
fe->state = FESTATE_DISEQC; fe->state = FESTATE_DISEQC;
fe->status = 0;
}
break; break;
case FE_SET_FRONTEND: case FE_DISHNETWORK_SEND_LEGACY_CMD:
fe->state = FESTATE_RETUNE; if (fe->frontend->ops->dishnetwork_send_legacy_command) {
err = fe->frontend->ops->dishnetwork_send_legacy_command(fe->frontend, (unsigned int) parg);
fe->state = FESTATE_DISEQC;
fe->status = 0;
}
break;
case FE_DISEQC_RECV_SLAVE_REPLY:
if (fe->frontend->ops->diseqc_recv_slave_reply)
err = fe->frontend->ops->diseqc_recv_slave_reply(fe->frontend, (struct dvb_diseqc_slave_reply*) parg);
break;
case FE_ENABLE_HIGH_LNB_VOLTAGE:
if (fe->frontend->ops->enable_high_lnb_voltage);
err = fe->frontend->ops->enable_high_lnb_voltage(fe->frontend, (int) parg);
break;
case FE_SET_FRONTEND: {
struct dvb_frontend_tune_settings fetunesettings;
memcpy (&fe->parameters, parg, memcpy (&fe->parameters, parg,
sizeof (struct dvb_frontend_parameters)); sizeof (struct dvb_frontend_parameters));
...@@ -762,7 +793,7 @@ static int dvb_frontend_ioctl (struct inode *inode, struct file *file, ...@@ -762,7 +793,7 @@ static int dvb_frontend_ioctl (struct inode *inode, struct file *file,
fe->parameters.inversion = INVERSION_AUTO; fe->parameters.inversion = INVERSION_AUTO;
fetunesettings.parameters.inversion = INVERSION_AUTO; fetunesettings.parameters.inversion = INVERSION_AUTO;
} }
if (fe->info->type == FE_OFDM) { if (fe->frontend->ops->info.type == FE_OFDM) {
/* without hierachical coding code_rate_LP is irrelevant, /* without hierachical coding code_rate_LP is irrelevant,
* so we tolerate the otherwise invalid FEC_NONE setting */ * so we tolerate the otherwise invalid FEC_NONE setting */
if (fe->parameters.u.ofdm.hierarchy_information == HIERARCHY_NONE && if (fe->parameters.u.ofdm.hierarchy_information == HIERARCHY_NONE &&
...@@ -771,14 +802,13 @@ static int dvb_frontend_ioctl (struct inode *inode, struct file *file, ...@@ -771,14 +802,13 @@ static int dvb_frontend_ioctl (struct inode *inode, struct file *file,
} }
/* get frontend-specific tuning settings */ /* get frontend-specific tuning settings */
if (dvb_frontend_internal_ioctl(&fe->frontend, FE_GET_TUNE_SETTINGS, if (fe->frontend->ops->get_tune_settings && (fe->frontend->ops->get_tune_settings(fe->frontend, &fetunesettings) == 0)) {
&fetunesettings) == 0) {
fe->min_delay = (fetunesettings.min_delay_ms * HZ) / 1000; fe->min_delay = (fetunesettings.min_delay_ms * HZ) / 1000;
fe->max_drift = fetunesettings.max_drift; fe->max_drift = fetunesettings.max_drift;
fe->step_size = fetunesettings.step_size; fe->step_size = fetunesettings.step_size;
} else { } else {
/* default values */ /* default values */
switch(fe->info->type) { switch(fe->frontend->ops->info.type) {
case FE_QPSK: case FE_QPSK:
fe->min_delay = HZ/20; fe->min_delay = HZ/20;
fe->step_size = fe->parameters.u.qpsk.symbol_rate / 16000; fe->step_size = fe->parameters.u.qpsk.symbol_rate / 16000;
...@@ -793,8 +823,8 @@ static int dvb_frontend_ioctl (struct inode *inode, struct file *file, ...@@ -793,8 +823,8 @@ static int dvb_frontend_ioctl (struct inode *inode, struct file *file,
case FE_OFDM: case FE_OFDM:
fe->min_delay = HZ/20; fe->min_delay = HZ/20;
fe->step_size = fe->info->frequency_stepsize * 2; fe->step_size = fe->frontend->ops->info.frequency_stepsize * 2;
fe->max_drift = (fe->info->frequency_stepsize * 2) + 1; fe->max_drift = (fe->frontend->ops->info.frequency_stepsize * 2) + 1;
break; break;
case FE_ATSC: case FE_ATSC:
printk("dvb-core: FE_ATSC not handled yet.\n"); printk("dvb-core: FE_ATSC not handled yet.\n");
...@@ -805,32 +835,27 @@ static int dvb_frontend_ioctl (struct inode *inode, struct file *file, ...@@ -805,32 +835,27 @@ static int dvb_frontend_ioctl (struct inode *inode, struct file *file,
fe->min_delay = (dvb_override_tune_delay * HZ) / 1000; fe->min_delay = (dvb_override_tune_delay * HZ) / 1000;
} }
fe->state = FESTATE_RETUNE;
dvb_frontend_wakeup(fe); dvb_frontend_wakeup(fe);
dvb_frontend_add_event (fe, 0); dvb_frontend_add_event (fe, 0);
fe->status = 0;
err = 0;
break; break;
}
case FE_GET_EVENT: case FE_GET_EVENT:
err = dvb_frontend_get_event (fe, parg, file->f_flags); err = dvb_frontend_get_event (fe, parg, file->f_flags);
break; break;
case FE_GET_FRONTEND: case FE_GET_FRONTEND:
memcpy (parg, &fe->parameters, if (fe->frontend->ops->get_frontend) {
sizeof (struct dvb_frontend_parameters)); memcpy (parg, &fe->parameters, sizeof (struct dvb_frontend_parameters));
/* fall-through... */ err = fe->frontend->ops->get_frontend(fe->frontend, (struct dvb_frontend_parameters*) parg);
default: }
err = dvb_frontend_internal_ioctl (&fe->frontend, cmd, parg); break;
}; };
up (&fe->sem); up (&fe->sem);
if (err < 0)
return err;
/* Force the CAN_INVERSION_AUTO bit on. If the frontend doesn't
* do it, it is done for it. */
if ((cmd == FE_GET_INFO) && (err == 0)) {
struct dvb_frontend_info* tmp = (struct dvb_frontend_info*) parg;
tmp->caps |= FE_CAN_INVERSION_AUTO;
}
return err; return err;
} }
...@@ -871,11 +896,6 @@ static int dvb_frontend_open (struct inode *inode, struct file *file) ...@@ -871,11 +896,6 @@ static int dvb_frontend_open (struct inode *inode, struct file *file)
fe->events.eventr = fe->events.eventw = 0; fe->events.eventr = fe->events.eventw = 0;
} }
if (!ret && fe->module) {
if (!try_module_get(fe->module))
return -EINVAL;
}
return ret; return ret;
} }
...@@ -884,206 +904,13 @@ static int dvb_frontend_release (struct inode *inode, struct file *file) ...@@ -884,206 +904,13 @@ static int dvb_frontend_release (struct inode *inode, struct file *file)
{ {
struct dvb_device *dvbdev = file->private_data; struct dvb_device *dvbdev = file->private_data;
struct dvb_frontend_data *fe = dvbdev->priv; struct dvb_frontend_data *fe = dvbdev->priv;
int ret = 0;
dprintk ("%s\n", __FUNCTION__); dprintk ("%s\n", __FUNCTION__);
if ((file->f_flags & O_ACCMODE) != O_RDONLY) if ((file->f_flags & O_ACCMODE) != O_RDONLY)
fe->release_jiffies = jiffies; fe->release_jiffies = jiffies;
ret = dvb_generic_release (inode, file); return dvb_generic_release (inode, file);
if (!ret && fe->module)
module_put(fe->module);
return ret;
}
int
dvb_add_frontend_ioctls (struct dvb_adapter *adapter,
int (*before_ioctl) (struct dvb_frontend *frontend,
unsigned int cmd, void *arg),
int (*after_ioctl) (struct dvb_frontend *frontend,
unsigned int cmd, void *arg),
void *before_after_data)
{
struct dvb_frontend_ioctl_data *ioctl;
struct list_head *entry;
dprintk ("%s\n", __FUNCTION__);
if (down_interruptible (&frontend_mutex))
return -ERESTARTSYS;
ioctl = kmalloc (sizeof(struct dvb_frontend_ioctl_data), GFP_KERNEL);
if (!ioctl) {
up (&frontend_mutex);
return -ENOMEM;
}
ioctl->adapter = adapter;
ioctl->before_ioctl = before_ioctl;
ioctl->after_ioctl = after_ioctl;
ioctl->before_after_data = before_after_data;
list_add_tail (&ioctl->list_head, &frontend_ioctl_list);
list_for_each (entry, &frontend_list) {
struct dvb_frontend_data *fe;
fe = list_entry (entry, struct dvb_frontend_data, list_head);
if (fe->frontend.dvb_adapter == adapter &&
fe->frontend.before_ioctl == NULL &&
fe->frontend.after_ioctl == NULL)
{
fe->frontend.before_ioctl = before_ioctl;
fe->frontend.after_ioctl = after_ioctl;
fe->frontend.before_after_data = before_after_data;
}
}
up (&frontend_mutex);
return 0;
}
void
dvb_remove_frontend_ioctls (struct dvb_adapter *adapter,
int (*before_ioctl) (struct dvb_frontend *frontend,
unsigned int cmd, void *arg),
int (*after_ioctl) (struct dvb_frontend *frontend,
unsigned int cmd, void *arg))
{
struct list_head *entry, *n;
dprintk ("%s\n", __FUNCTION__);
down (&frontend_mutex);
list_for_each (entry, &frontend_list) {
struct dvb_frontend_data *fe;
fe = list_entry (entry, struct dvb_frontend_data, list_head);
if (fe->frontend.dvb_adapter == adapter &&
fe->frontend.before_ioctl == before_ioctl &&
fe->frontend.after_ioctl == after_ioctl)
{
fe->frontend.before_ioctl = NULL;
fe->frontend.after_ioctl = NULL;
}
}
list_for_each_safe (entry, n, &frontend_ioctl_list) {
struct dvb_frontend_ioctl_data *ioctl;
ioctl = list_entry (entry, struct dvb_frontend_ioctl_data, list_head);
if (ioctl->adapter == adapter &&
ioctl->before_ioctl == before_ioctl &&
ioctl->after_ioctl == after_ioctl)
{
list_del (&ioctl->list_head);
kfree (ioctl);
break;
}
}
up (&frontend_mutex);
}
int
dvb_add_frontend_notifier (struct dvb_adapter *adapter,
void (*callback) (fe_status_t s, void *data),
void *data)
{
struct dvb_frontend_notifier_data *notifier;
struct list_head *entry;
dprintk ("%s\n", __FUNCTION__);
if (down_interruptible (&frontend_mutex))
return -ERESTARTSYS;
notifier = kmalloc (sizeof(struct dvb_frontend_notifier_data), GFP_KERNEL);
if (!notifier) {
up (&frontend_mutex);
return -ENOMEM;
}
notifier->adapter = adapter;
notifier->callback = callback;
notifier->data = data;
list_add_tail (&notifier->list_head, &frontend_notifier_list);
list_for_each (entry, &frontend_list) {
struct dvb_frontend_data *fe;
fe = list_entry (entry, struct dvb_frontend_data, list_head);
if (fe->frontend.dvb_adapter == adapter &&
fe->frontend.notifier_callback == NULL)
{
fe->frontend.notifier_callback = callback;
fe->frontend.notifier_data = data;
}
}
up (&frontend_mutex);
return 0;
}
void
dvb_remove_frontend_notifier (struct dvb_adapter *adapter,
void (*callback) (fe_status_t s, void *data))
{
struct list_head *entry, *n;
dprintk ("%s\n", __FUNCTION__);
down (&frontend_mutex);
list_for_each (entry, &frontend_list) {
struct dvb_frontend_data *fe;
fe = list_entry (entry, struct dvb_frontend_data, list_head);
if (fe->frontend.dvb_adapter == adapter &&
fe->frontend.notifier_callback == callback)
{
fe->frontend.notifier_callback = NULL;
}
}
list_for_each_safe (entry, n, &frontend_notifier_list) {
struct dvb_frontend_notifier_data *notifier;
notifier = list_entry (entry, struct dvb_frontend_notifier_data, list_head);
if (notifier->adapter == adapter &&
notifier->callback == callback)
{
list_del (&notifier->list_head);
kfree (notifier);
break;
}
}
up (&frontend_mutex);
} }
...@@ -1096,16 +923,9 @@ static struct file_operations dvb_frontend_fops = { ...@@ -1096,16 +923,9 @@ static struct file_operations dvb_frontend_fops = {
}; };
int dvb_register_frontend(struct dvb_adapter* dvb,
int struct dvb_frontend* frontend)
dvb_register_frontend (int (*ioctl) (struct dvb_frontend *frontend,
unsigned int cmd, void *arg),
struct dvb_adapter *dvb_adapter,
void *data,
struct dvb_frontend_info *info,
struct module *module)
{ {
struct list_head *entry;
struct dvb_frontend_data *fe; struct dvb_frontend_data *fe;
static const struct dvb_device dvbdev_template = { static const struct dvb_device dvbdev_template = {
.users = ~0, .users = ~0,
...@@ -1133,63 +953,30 @@ dvb_register_frontend (int (*ioctl) (struct dvb_frontend *frontend, ...@@ -1133,63 +953,30 @@ dvb_register_frontend (int (*ioctl) (struct dvb_frontend *frontend,
init_MUTEX (&fe->events.sem); init_MUTEX (&fe->events.sem);
fe->events.eventw = fe->events.eventr = 0; fe->events.eventw = fe->events.eventr = 0;
fe->events.overflow = 0; fe->events.overflow = 0;
fe->module = module;
fe->frontend.ioctl = ioctl;
fe->frontend.dvb_adapter = dvb_adapter;
fe->frontend.data = data;
fe->info = info;
fe->inversion = INVERSION_OFF;
list_for_each (entry, &frontend_ioctl_list) {
struct dvb_frontend_ioctl_data *ioctl;
ioctl = list_entry (entry, fe->frontend = frontend;
struct dvb_frontend_ioctl_data, fe->frontend->dvb = dvb;
list_head);
if (ioctl->adapter == dvb_adapter) { fe->inversion = INVERSION_OFF;
fe->frontend.before_ioctl = ioctl->before_ioctl;
fe->frontend.after_ioctl = ioctl->after_ioctl;
fe->frontend.before_after_data = ioctl->before_after_data;
break;
}
}
list_for_each (entry, &frontend_notifier_list) {
struct dvb_frontend_notifier_data *notifier;
notifier = list_entry (entry,
struct dvb_frontend_notifier_data,
list_head);
if (notifier->adapter == dvb_adapter) {
fe->frontend.notifier_callback = notifier->callback;
fe->frontend.notifier_data = notifier->data;
break;
}
}
list_add_tail (&fe->list_head, &frontend_list); list_add_tail (&fe->list_head, &frontend_list);
printk ("DVB: registering frontend %i (%s)...\n", printk ("DVB: registering frontend %i (%s)...\n",
fe->frontend.dvb_adapter->num, fe->frontend->dvb->num,
fe->info->name); fe->frontend->ops->info.name);
dvb_register_device (dvb_adapter, &fe->dvbdev, &dvbdev_template, dvb_register_device (fe->frontend->dvb, &fe->dvbdev, &dvbdev_template,
fe, DVB_DEVICE_FRONTEND); fe, DVB_DEVICE_FRONTEND);
if ((info->caps & FE_NEEDS_BENDING) || (dvb_override_frequency_bending == 2)) if ((fe->frontend->ops->info.caps & FE_NEEDS_BENDING) || (dvb_override_frequency_bending == 2))
do_frequency_bending = 1; do_frequency_bending = 1;
up (&frontend_mutex); up (&frontend_mutex);
return 0; return 0;
} }
EXPORT_SYMBOL(dvb_register_frontend);
int dvb_unregister_frontend (int (*ioctl) (struct dvb_frontend *frontend, int dvb_unregister_frontend (struct dvb_frontend* frontend)
unsigned int cmd, void *arg),
struct dvb_adapter *dvb_adapter)
{ {
struct list_head *entry, *n; struct list_head *entry, *n;
...@@ -1202,11 +989,16 @@ int dvb_unregister_frontend (int (*ioctl) (struct dvb_frontend *frontend, ...@@ -1202,11 +989,16 @@ int dvb_unregister_frontend (int (*ioctl) (struct dvb_frontend *frontend,
fe = list_entry (entry, struct dvb_frontend_data, list_head); fe = list_entry (entry, struct dvb_frontend_data, list_head);
if (fe->frontend.ioctl == ioctl && fe->frontend.dvb_adapter == dvb_adapter) { if (fe->frontend == frontend) {
dvb_unregister_device (fe->dvbdev); dvb_unregister_device (fe->dvbdev);
list_del (entry); list_del (entry);
up (&frontend_mutex); up (&frontend_mutex);
dvb_frontend_stop (fe); dvb_frontend_stop (fe);
if (fe->frontend->ops->release) {
fe->frontend->ops->release(fe->frontend);
} else {
printk("dvb_frontend: Demodulator (%s) does not have a release callback!\n", fe->frontend->ops->info.name);
}
kfree (fe); kfree (fe);
return 0; return 0;
} }
...@@ -1215,4 +1007,4 @@ int dvb_unregister_frontend (int (*ioctl) (struct dvb_frontend *frontend, ...@@ -1215,4 +1007,4 @@ int dvb_unregister_frontend (int (*ioctl) (struct dvb_frontend *frontend,
up (&frontend_mutex); up (&frontend_mutex);
return -EINVAL; return -EINVAL;
} }
EXPORT_SYMBOL(dvb_unregister_frontend);
/* /*
* dvb_frontend.h * dvb_frontend.h
* *
* Copyright (C) 2001 Ralph Metzler for convergence integrated media GmbH * Copyright (C) 2001 convergence integrated media GmbH
* overhauled by Holger Waechtler for Convergence GmbH * Copyright (C) 2004 convergence GmbH
* *
* Written by Ralph Metzler
* Overhauled by Holger Waechtler
* Kernel I2C stuff by Michael Hunold <hunold@convergence.de>
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License * modify it under the terms of the GNU Lesser General Public License
...@@ -38,8 +41,8 @@ ...@@ -38,8 +41,8 @@
#include "dvbdev.h" #include "dvbdev.h"
/* FIXME: Move to i2c-id.h */ /* FIXME: Move to i2c-id.h */
#define I2C_DRIVERID_DVBFE_ALPS_TDLB7 I2C_DRIVERID_EXP2 #define I2C_DRIVERID_DVBFE_SP8870 I2C_DRIVERID_EXP2
#define I2C_DRIVERID_DVBFE_ALPS_TDMB7 I2C_DRIVERID_EXP2 #define I2C_DRIVERID_DVBFE_CX22700 I2C_DRIVERID_EXP2
#define I2C_DRIVERID_DVBFE_AT76C651 I2C_DRIVERID_EXP2 #define I2C_DRIVERID_DVBFE_AT76C651 I2C_DRIVERID_EXP2
#define I2C_DRIVERID_DVBFE_CX24110 I2C_DRIVERID_EXP2 #define I2C_DRIVERID_DVBFE_CX24110 I2C_DRIVERID_EXP2
#define I2C_DRIVERID_DVBFE_CX22702 I2C_DRIVERID_EXP2 #define I2C_DRIVERID_DVBFE_CX22702 I2C_DRIVERID_EXP2
...@@ -56,22 +59,8 @@ ...@@ -56,22 +59,8 @@
#define I2C_DRIVERID_DVBFE_TDA8083 I2C_DRIVERID_EXP2 #define I2C_DRIVERID_DVBFE_TDA8083 I2C_DRIVERID_EXP2
#define I2C_DRIVERID_DVBFE_VES1820 I2C_DRIVERID_EXP2 #define I2C_DRIVERID_DVBFE_VES1820 I2C_DRIVERID_EXP2
#define I2C_DRIVERID_DVBFE_VES1X93 I2C_DRIVERID_EXP2 #define I2C_DRIVERID_DVBFE_VES1X93 I2C_DRIVERID_EXP2
#define I2C_DRIVERID_DVBFE_TDA80XX I2C_DRIVERID_EXP2
/**
* when before_ioctl is registered and returns value 0, ioctl and after_ioctl
* are not executed.
*/
struct dvb_frontend {
int (*before_ioctl) (struct dvb_frontend *frontend, unsigned int cmd, void *arg);
int (*ioctl) (struct dvb_frontend *frontend, unsigned int cmd, void *arg);
int (*after_ioctl) (struct dvb_frontend *frontend, unsigned int cmd, void *arg);
void (*notifier_callback) (fe_status_t s, void *data);
struct dvb_adapter *dvb_adapter;
void *before_after_data; /* can be used by hardware module... */
void *notifier_data; /* can be used by hardware module... */
void *data; /* can be used by hardware module... */
};
struct dvb_frontend_tune_settings { struct dvb_frontend_tune_settings {
int min_delay_ms; int min_delay_ms;
...@@ -80,67 +69,47 @@ struct dvb_frontend_tune_settings { ...@@ -80,67 +69,47 @@ struct dvb_frontend_tune_settings {
struct dvb_frontend_parameters parameters; struct dvb_frontend_parameters parameters;
}; };
struct dvb_frontend;
/** struct dvb_frontend_ops {
* private frontend command ioctl's.
* keep them in sync with the public ones defined in linux/dvb/frontend.h
*
* FE_SLEEP. Ioctl used to put frontend into a low power mode.
* FE_INIT. Ioctl used to initialise the frontend.
* FE_GET_TUNE_SETTINGS. Get the frontend-specific tuning loop settings for the supplied set of parameters.
*/
#define FE_SLEEP _IO('v', 80)
#define FE_INIT _IO('v', 81)
#define FE_GET_TUNE_SETTINGS _IOWR('v', 83, struct dvb_frontend_tune_settings)
#define FE_REGISTER _IO ('v', 84)
#define FE_UNREGISTER _IO ('v', 85)
extern int
dvb_register_frontend (int (*ioctl) (struct dvb_frontend *frontend,
unsigned int cmd, void *arg),
struct dvb_adapter *dvb_adapter,
void *data,
struct dvb_frontend_info *info,
struct module *module);
extern int
dvb_unregister_frontend (int (*ioctl) (struct dvb_frontend *frontend,
unsigned int cmd, void *arg),
struct dvb_adapter *dvb_adapter);
/**
* Add special ioctl code performed before and after the main ioctl
* to all frontend devices on the specified DVB adapter.
* This is necessairy because the 22kHz/13V-18V/DiSEqC stuff depends
* heavily on the hardware around the frontend, the same tuner can create
* these signals on about a million different ways...
*
* Return value: number of frontends where the ioctl's were applied.
*/
extern int
dvb_add_frontend_ioctls (struct dvb_adapter *adapter,
int (*before_ioctl) (struct dvb_frontend *frontend,
unsigned int cmd, void *arg),
int (*after_ioctl) (struct dvb_frontend *frontend,
unsigned int cmd, void *arg),
void *before_after_data);
extern void
dvb_remove_frontend_ioctls (struct dvb_adapter *adapter,
int (*before_ioctl) (struct dvb_frontend *frontend,
unsigned int cmd, void *arg),
int (*after_ioctl) (struct dvb_frontend *frontend,
unsigned int cmd, void *arg));
extern int
dvb_add_frontend_notifier (struct dvb_adapter *adapter,
void (*callback) (fe_status_t s, void *data),
void *data);
extern void
dvb_remove_frontend_notifier (struct dvb_adapter *adapter,
void (*callback) (fe_status_t s, void *data));
#endif struct dvb_frontend_info info;
void (*release)(struct dvb_frontend* fe);
int (*init)(struct dvb_frontend* fe);
int (*sleep)(struct dvb_frontend* fe);
int (*set_frontend)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params);
int (*get_frontend)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params);
int (*get_tune_settings)(struct dvb_frontend* fe, struct dvb_frontend_tune_settings* settings);
int (*read_status)(struct dvb_frontend* fe, fe_status_t* status);
int (*read_ber)(struct dvb_frontend* fe, u32* ber);
int (*read_signal_strength)(struct dvb_frontend* fe, u16* strength);
int (*read_snr)(struct dvb_frontend* fe, u16* snr);
int (*read_ucblocks)(struct dvb_frontend* fe, u32* ucblocks);
int (*diseqc_reset_overload)(struct dvb_frontend* fe);
int (*diseqc_send_master_cmd)(struct dvb_frontend* fe, struct dvb_diseqc_master_cmd* cmd);
int (*diseqc_recv_slave_reply)(struct dvb_frontend* fe, struct dvb_diseqc_slave_reply* reply);
int (*diseqc_send_burst)(struct dvb_frontend* fe, fe_sec_mini_cmd_t minicmd);
int (*set_tone)(struct dvb_frontend* fe, fe_sec_tone_mode_t tone);
int (*set_voltage)(struct dvb_frontend* fe, fe_sec_voltage_t voltage);
int (*enable_high_lnb_voltage)(struct dvb_frontend* fe, int arg);
int (*dishnetwork_send_legacy_command)(struct dvb_frontend* fe, unsigned int cmd);
};
struct dvb_frontend {
struct dvb_frontend_ops* ops;
struct dvb_adapter *dvb;
void* demodulator_priv;
};
extern int dvb_register_frontend(struct dvb_adapter* dvb,
struct dvb_frontend* fe);
extern int dvb_unregister_frontend(struct dvb_frontend* fe);
#endif
#include <linux/errno.h>
#include <linux/module.h>
#include <linux/ioctl.h>
#include <linux/slab.h>
#include <linux/fs.h>
#include <asm/uaccess.h>
#include "dmxdev.h"
#include "dvb_demux.h"
#include "dvb_frontend.h"
#include "dvb_net.h"
#include "dvb_filter.h"
#include "dvb_ca_en50221.h"
EXPORT_SYMBOL(dvb_dmxdev_init);
EXPORT_SYMBOL(dvb_dmxdev_release);
EXPORT_SYMBOL(dvb_dmx_init);
EXPORT_SYMBOL(dvb_dmx_release);
EXPORT_SYMBOL(dvb_dmx_swfilter_packet);
EXPORT_SYMBOL(dvb_dmx_swfilter_packets);
EXPORT_SYMBOL(dvb_dmx_swfilter);
EXPORT_SYMBOL(dvb_dmx_swfilter_204);
EXPORT_SYMBOL(dvbdmx_connect_frontend);
EXPORT_SYMBOL(dvbdmx_disconnect_frontend);
EXPORT_SYMBOL(dvb_register_frontend);
EXPORT_SYMBOL(dvb_unregister_frontend);
EXPORT_SYMBOL(dvb_add_frontend_ioctls);
EXPORT_SYMBOL(dvb_remove_frontend_ioctls);
EXPORT_SYMBOL(dvb_add_frontend_notifier);
EXPORT_SYMBOL(dvb_remove_frontend_notifier);
EXPORT_SYMBOL(dvb_net_init);
EXPORT_SYMBOL(dvb_net_release);
EXPORT_SYMBOL(dvb_register_adapter);
EXPORT_SYMBOL(dvb_unregister_adapter);
EXPORT_SYMBOL(dvb_register_device);
EXPORT_SYMBOL(dvb_unregister_device);
EXPORT_SYMBOL(dvb_generic_ioctl);
EXPORT_SYMBOL(dvb_generic_open);
EXPORT_SYMBOL(dvb_generic_release);
EXPORT_SYMBOL(dvb_filter_pes2ts_init);
EXPORT_SYMBOL(dvb_filter_pes2ts);
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);
...@@ -30,6 +30,7 @@ ...@@ -30,6 +30,7 @@
* Or, point your browser to http://www.gnu.org/copyleft/gpl.html * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
*/ */
#include <linux/module.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/netdevice.h> #include <linux/netdevice.h>
#include <linux/etherdevice.h> #include <linux/etherdevice.h>
...@@ -141,7 +142,11 @@ static unsigned short dvb_net_eth_type_trans(struct sk_buff *skb, ...@@ -141,7 +142,11 @@ static unsigned short dvb_net_eth_type_trans(struct sk_buff *skb,
skb->mac.raw=skb->data; skb->mac.raw=skb->data;
skb_pull(skb,dev->hard_header_len); skb_pull(skb,dev->hard_header_len);
#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,8)
eth = skb->mac.ethernet;
#else
eth = eth_hdr(skb); eth = eth_hdr(skb);
#endif
if (*eth->h_dest & 1) { if (*eth->h_dest & 1) {
if(memcmp(eth->h_dest,dev->broadcast, ETH_ALEN)==0) if(memcmp(eth->h_dest,dev->broadcast, ETH_ALEN)==0)
...@@ -1193,6 +1198,7 @@ void dvb_net_release (struct dvb_net *dvbnet) ...@@ -1193,6 +1198,7 @@ void dvb_net_release (struct dvb_net *dvbnet)
dvb_net_remove_if(dvbnet, i); dvb_net_remove_if(dvbnet, i);
} }
} }
EXPORT_SYMBOL(dvb_net_release);
int dvb_net_init (struct dvb_adapter *adap, struct dvb_net *dvbnet, int dvb_net_init (struct dvb_adapter *adap, struct dvb_net *dvbnet,
...@@ -1210,4 +1216,4 @@ int dvb_net_init (struct dvb_adapter *adap, struct dvb_net *dvbnet, ...@@ -1210,4 +1216,4 @@ int dvb_net_init (struct dvb_adapter *adap, struct dvb_net *dvbnet,
return 0; return 0;
} }
EXPORT_SYMBOL(dvb_net_init);
...@@ -132,6 +132,7 @@ int dvb_generic_open(struct inode *inode, struct file *file) ...@@ -132,6 +132,7 @@ int dvb_generic_open(struct inode *inode, struct file *file)
dvbdev->users--; dvbdev->users--;
return 0; return 0;
} }
EXPORT_SYMBOL(dvb_generic_open);
int dvb_generic_release(struct inode *inode, struct file *file) int dvb_generic_release(struct inode *inode, struct file *file)
...@@ -150,6 +151,7 @@ int dvb_generic_release(struct inode *inode, struct file *file) ...@@ -150,6 +151,7 @@ int dvb_generic_release(struct inode *inode, struct file *file)
dvbdev->users++; dvbdev->users++;
return 0; return 0;
} }
EXPORT_SYMBOL(dvb_generic_release);
int dvb_generic_ioctl(struct inode *inode, struct file *file, int dvb_generic_ioctl(struct inode *inode, struct file *file,
...@@ -165,6 +167,7 @@ int dvb_generic_ioctl(struct inode *inode, struct file *file, ...@@ -165,6 +167,7 @@ int dvb_generic_ioctl(struct inode *inode, struct file *file,
return dvb_usercopy (inode, file, cmd, arg, dvbdev->kernel_ioctl); return dvb_usercopy (inode, file, cmd, arg, dvbdev->kernel_ioctl);
} }
EXPORT_SYMBOL(dvb_generic_ioctl);
static int dvbdev_get_free_id (struct dvb_adapter *adap, int type) static int dvbdev_get_free_id (struct dvb_adapter *adap, int type)
...@@ -235,6 +238,7 @@ int dvb_register_device(struct dvb_adapter *adap, struct dvb_device **pdvbdev, ...@@ -235,6 +238,7 @@ int dvb_register_device(struct dvb_adapter *adap, struct dvb_device **pdvbdev,
return 0; return 0;
} }
EXPORT_SYMBOL(dvb_register_device);
void dvb_unregister_device(struct dvb_device *dvbdev) void dvb_unregister_device(struct dvb_device *dvbdev)
...@@ -251,6 +255,7 @@ void dvb_unregister_device(struct dvb_device *dvbdev) ...@@ -251,6 +255,7 @@ void dvb_unregister_device(struct dvb_device *dvbdev)
list_del(&dvbdev->list_head); list_del(&dvbdev->list_head);
kfree(dvbdev); kfree(dvbdev);
} }
EXPORT_SYMBOL(dvb_unregister_device);
static int dvbdev_get_free_adapter_num (void) static int dvbdev_get_free_adapter_num (void)
...@@ -309,6 +314,7 @@ int dvb_register_adapter(struct dvb_adapter **padap, const char *name, struct mo ...@@ -309,6 +314,7 @@ int dvb_register_adapter(struct dvb_adapter **padap, const char *name, struct mo
return num; return num;
} }
EXPORT_SYMBOL(dvb_register_adapter);
int dvb_unregister_adapter(struct dvb_adapter *adap) int dvb_unregister_adapter(struct dvb_adapter *adap)
...@@ -322,6 +328,7 @@ int dvb_unregister_adapter(struct dvb_adapter *adap) ...@@ -322,6 +328,7 @@ int dvb_unregister_adapter(struct dvb_adapter *adap)
kfree (adap); kfree (adap);
return 0; return 0;
} }
EXPORT_SYMBOL(dvb_unregister_adapter);
/* if the miracle happens and "generic_usercopy()" is included into /* if the miracle happens and "generic_usercopy()" is included into
the kernel, then this can vanish. please don't make the mistake and the kernel, then this can vanish. please don't make the mistake and
......
...@@ -49,6 +49,7 @@ struct dvb_adapter { ...@@ -49,6 +49,7 @@ struct dvb_adapter {
struct list_head device_list; struct list_head device_list;
const char *name; const char *name;
u8 proposed_mac [6]; u8 proposed_mac [6];
void* priv;
struct module *module; struct module *module;
}; };
......
...@@ -78,7 +78,7 @@ struct dvb_frontend_info { ...@@ -78,7 +78,7 @@ struct dvb_frontend_info {
__u32 symbol_rate_min; __u32 symbol_rate_min;
__u32 symbol_rate_max; __u32 symbol_rate_max;
__u32 symbol_rate_tolerance; /* ppm */ __u32 symbol_rate_tolerance; /* ppm */
__u32 notifier_delay; /* ms */ __u32 notifier_delay; /* DEPRECATED */
fe_caps_t caps; fe_caps_t caps;
}; };
......
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