Commit d75097d0 authored by Michael Hunold's avatar Michael Hunold Committed by Linus Torvalds

[PATCH] DVB: core update

- [DVB] remove non-linux compatibility stuff from dvb_functions.  rest in
  peace.

- [DVB] remove home-brewn dvb-i2c stuff. rest in peace.

- [DVB] convert MODULE_PARM() to module_param()

- [DVB] convert dvb_delay() to mdelay()

- [DVB] convert C++ comments to C comments

- [DVB] dvb_ca_en50221: fix for matrix CAMs from Sjoerd Simons, use c99
  initializers, Fix for aston CAM read timeout problems, Moved CAM CTRL IF
  reset to a better place, better debugging with multiple cards (Sjoerd
  Simons)

- [DVB] dvb-frontend: patch by Wolfgang Fritz: suppress spurious events
  during tuning, Do not allow write (and related) ioctls when frontend is
  opened RDONLY, Properly lock the frontend module on open/close, patch by
  Christopher Pascoe: remove bogus up(fe->sem) on fe thread exit, patch by
  Christopher Pascoe: remove bogus up(fe->sem) on fe thread exit

- [DVB] dvb-demux: using spin_lock instead of spin_lock_irq caused a race
  condition between irq/tasklet and user space task

- [DVB] dvb-core: add sysfs/udev support using "class_simple", prevent Oops
  when PES filter is set with invalid pes_type, protect feed_list with
  spin_locks
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 67bbef2c
......@@ -3,7 +3,7 @@
#
dvb-core-objs = dvbdev.o dmxdev.o dvb_demux.o dvb_filter.o \
dvb_ca_en50221.o dvb_functions.o dvb_frontend.o \
dvb_i2c.o dvb_net.o dvb_ksyms.o dvb_ringbuffer.o
dvb_ca_en50221.o dvb_frontend.o \
dvb_net.o dvb_ksyms.o dvb_ringbuffer.o
obj-$(CONFIG_DVB_CORE) += dvb-core.o
......@@ -25,6 +25,7 @@
#include <linux/slab.h>
#include <linux/vmalloc.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/sched.h>
#include <linux/poll.h>
#include <linux/ioctl.h>
......@@ -33,10 +34,11 @@
#include <asm/system.h>
#include "dmxdev.h"
#include "dvb_functions.h"
MODULE_PARM(debug,"i");
static int debug = 0;
static int debug;
module_param(debug, int, 0644);
MODULE_PARM_DESC(debug, "Turn on/off debugging (default:off).");
#define dprintk if (debug) printk
......
This diff is collapsed.
......@@ -42,6 +42,9 @@
/* Structure describing a CA interface */
struct dvb_ca_en50221 {
/* NOTE: the read_*, write_* and poll_slot_status functions must use locks as
* they may be called from several threads at once */
/* functions for accessing attribute memory on the CAM */
int (*read_attribute_mem)(struct dvb_ca_en50221* ca, int slot, int address);
int (*write_attribute_mem)(struct dvb_ca_en50221* ca, int slot, int address, u8 value);
......
......@@ -31,7 +31,6 @@
#include <asm/uaccess.h>
#include "dvb_demux.h"
#include "dvb_functions.h"
#define NOBUFS
/*
......@@ -570,24 +569,30 @@ static int dvb_demux_feed_find(struct dvb_demux_feed *feed)
static void dvb_demux_feed_add(struct dvb_demux_feed *feed)
{
spin_lock_irq(&feed->demux->lock);
if (dvb_demux_feed_find(feed)) {
printk(KERN_ERR "%s: feed already in list (type=%x state=%x pid=%x)\n",
__FUNCTION__, feed->type, feed->state, feed->pid);
return;
goto out;
}
list_add(&feed->list_head, &feed->demux->feed_list);
out:
spin_unlock_irq(&feed->demux->lock);
}
static void dvb_demux_feed_del(struct dvb_demux_feed *feed)
{
spin_lock_irq(&feed->demux->lock);
if (!(dvb_demux_feed_find(feed))) {
printk(KERN_ERR "%s: feed not in list (type=%x state=%x pid=%x)\n",
__FUNCTION__, feed->type, feed->state, feed->pid);
return;
goto out;
}
list_del(&feed->list_head);
out:
spin_unlock_irq(&feed->demux->lock);
}
static int dmx_ts_feed_set (struct dmx_ts_feed* ts_feed, u16 pid, int ts_type,
......@@ -789,7 +794,7 @@ static int dvbdmx_release_ts_feed(struct dmx_demux *dmx, struct dmx_ts_feed *ts_
feed->pid = 0xffff;
if (feed->ts_type & TS_DECODER)
if (feed->ts_type & TS_DECODER && feed->pes_type < DMX_TS_PES_OTHER)
demux->pesfilter[feed->pes_type] = NULL;
up(&demux->mutex);
......
This diff is collapsed.
......@@ -31,14 +31,29 @@
#include <linux/i2c.h>
#include <linux/module.h>
#include <linux/errno.h>
#include <linux/delay.h>
#include <linux/dvb/frontend.h>
#include "dvb_i2c.h"
#include "dvbdev.h"
/* FIXME: Move to i2c-id.h */
#define I2C_DRIVERID_DVBFE_ALPS_TDLB7 I2C_DRIVERID_EXP2
#define I2C_DRIVERID_DVBFE_ALPS_TDMB7 I2C_DRIVERID_EXP2
#define I2C_DRIVERID_DVBFE_AT76C651 I2C_DRIVERID_EXP2
#define I2C_DRIVERID_DVBFE_CX24110 I2C_DRIVERID_EXP2
#define I2C_DRIVERID_DVBFE_DST I2C_DRIVERID_EXP2
#define I2C_DRIVERID_DVBFE_DUMMY I2C_DRIVERID_EXP2
#define I2C_DRIVERID_DVBFE_L64781 I2C_DRIVERID_EXP2
#define I2C_DRIVERID_DVBFE_MT312 I2C_DRIVERID_EXP2
#define I2C_DRIVERID_DVBFE_MT352 I2C_DRIVERID_EXP2
#define I2C_DRIVERID_DVBFE_NXT6000 I2C_DRIVERID_EXP2
#define I2C_DRIVERID_DVBFE_SP887X I2C_DRIVERID_EXP2
#define I2C_DRIVERID_DVBFE_STV0299 I2C_DRIVERID_EXP2
#define I2C_DRIVERID_DVBFE_TDA1004X I2C_DRIVERID_EXP2
#define I2C_DRIVERID_DVBFE_TDA8083 I2C_DRIVERID_EXP2
#define I2C_DRIVERID_DVBFE_VES1820 I2C_DRIVERID_EXP2
#define I2C_DRIVERID_DVBFE_VES1X93 I2C_DRIVERID_EXP2
/**
* when before_ioctl is registered and returns value 0, ioctl and after_ioctl
......@@ -50,7 +65,7 @@ struct dvb_frontend {
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_i2c_bus *i2c;
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... */
......@@ -75,19 +90,21 @@ struct dvb_frontend_tune_settings {
#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_i2c_bus *i2c,
struct dvb_adapter *dvb_adapter,
void *data,
struct dvb_frontend_info *info);
struct dvb_frontend_info *info,
struct module *module);
extern int
dvb_unregister_frontend (int (*ioctl) (struct dvb_frontend *frontend,
dvb_unregister_frontend_new (int (*ioctl) (struct dvb_frontend *frontend,
unsigned int cmd, void *arg),
struct dvb_i2c_bus *i2c);
struct dvb_adapter *dvb_adapter);
/**
......
#include <linux/errno.h>
#include <linux/fs.h>
#include <linux/string.h>
#include <linux/module.h>
#include <linux/ioctl.h>
#include <linux/slab.h>
#include <linux/smp_lock.h>
#include <asm/uaccess.h>
void dvb_kernel_thread_setup (const char *thread_name)
{
lock_kernel ();
daemonize (thread_name);
sigfillset (&current->blocked);
unlock_kernel ();
}
/* if the miracle happens and "generic_usercopy()" is included into
the kernel, then this can vanish. please don't make the mistake and
define this as video_usercopy(). this will introduce a dependecy
to the v4l "videodev.o" module, which is unnecessary for some
cards (ie. the budget dvb-cards don't need the v4l module...) */
int dvb_usercopy(struct inode *inode, struct file *file,
unsigned int cmd, unsigned long arg,
int (*func)(struct inode *inode, struct file *file,
unsigned int cmd, void *arg))
{
char sbuf[128];
void *mbuf = NULL;
void *parg = NULL;
int err = -EINVAL;
/* Copy arguments into temp kernel buffer */
switch (_IOC_DIR(cmd)) {
case _IOC_NONE:
/*
* For this command, the pointer is actually an integer
* argument.
*/
parg = (void *) arg;
break;
case _IOC_READ: /* some v4l ioctls are marked wrong ... */
case _IOC_WRITE:
case (_IOC_WRITE | _IOC_READ):
if (_IOC_SIZE(cmd) <= sizeof(sbuf)) {
parg = sbuf;
} else {
/* too big to allocate from stack */
mbuf = kmalloc(_IOC_SIZE(cmd),GFP_KERNEL);
if (NULL == mbuf)
return -ENOMEM;
parg = mbuf;
}
err = -EFAULT;
if (copy_from_user(parg, (void __user *)arg, _IOC_SIZE(cmd)))
goto out;
break;
}
/* call driver */
if ((err = func(inode, file, cmd, parg)) == -ENOIOCTLCMD)
err = -EINVAL;
if (err < 0)
goto out;
/* Copy results into user buffer */
switch (_IOC_DIR(cmd))
{
case _IOC_READ:
case (_IOC_WRITE | _IOC_READ):
if (copy_to_user((void __user *)arg, parg, _IOC_SIZE(cmd)))
err = -EFAULT;
break;
}
out:
if (mbuf)
kfree(mbuf);
return err;
}
EXPORT_SYMBOL(dvb_usercopy);
EXPORT_SYMBOL(dvb_kernel_thread_setup);
/*
* dvb_functions.h: isolate some Linux specific stuff from the dvb-core
* that can't be expressed as a one-liner
* in order to make porting to other environments easier
*
* Copyright (C) 2003 Convergence GmbH
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Lesser Public License
* as published by the Free Software Foundation; either version 2.1
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
*/
#ifndef __DVB_FUNCTIONS_H__
#define __DVB_FUNCTIONS_H__
/**
* a sleeping delay function, waits i ms
*
*/
static inline
void dvb_delay(int i)
{
current->state=TASK_INTERRUPTIBLE;
schedule_timeout((HZ*i)/1000);
}
/* we don't mess with video_usercopy() any more,
we simply define out own dvb_usercopy(), which will hopefull become
generic_usercopy() someday... */
extern int dvb_usercopy(struct inode *inode, struct file *file,
unsigned int cmd, unsigned long arg,
int (*func)(struct inode *inode, struct file *file,
unsigned int cmd, void *arg));
extern void dvb_kernel_thread_setup (const char *thread_name);
#endif
/*
* dvb_i2c.h: simplified i2c interface for DVB adapters to get rid of i2c-core.c
*
* Copyright (C) 2002 Holger Waechtler for convergence integrated media GmbH
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
* Or, point your browser to http://www.gnu.org/copyleft/gpl.html
*/
#include <linux/errno.h>
#include <linux/slab.h>
#include <linux/list.h>
#include <linux/module.h>
#include <asm/semaphore.h>
#include "dvb_i2c.h"
#include "dvb_functions.h"
struct dvb_i2c_device {
struct list_head list_head;
struct module *owner;
int (*attach) (struct dvb_i2c_bus *i2c, void **data);
void (*detach) (struct dvb_i2c_bus *i2c, void *data);
void *data;
};
LIST_HEAD(dvb_i2c_buslist);
LIST_HEAD(dvb_i2c_devicelist);
DECLARE_MUTEX(dvb_i2c_mutex);
static int register_i2c_client (struct dvb_i2c_bus *i2c, struct dvb_i2c_device *dev)
{
struct dvb_i2c_device *client;
if (!(client = kmalloc (sizeof (struct dvb_i2c_device), GFP_KERNEL)))
return -ENOMEM;
client->detach = dev->detach;
client->owner = dev->owner;
client->data = dev->data;
INIT_LIST_HEAD(&client->list_head);
list_add_tail (&client->list_head, &i2c->client_list);
return 0;
}
static void try_attach_device (struct dvb_i2c_bus *i2c, struct dvb_i2c_device *dev)
{
if (dev->owner) {
if (!try_module_get(dev->owner))
return;
}
if (dev->attach (i2c, &dev->data) == 0) {
register_i2c_client (i2c, dev);
} else {
if (dev->owner)
module_put (dev->owner);
}
}
static void detach_device (struct dvb_i2c_bus *i2c, struct dvb_i2c_device *dev)
{
dev->detach (i2c, dev->data);
if (dev->owner)
module_put (dev->owner);
}
static void unregister_i2c_client_from_bus (struct dvb_i2c_device *dev,
struct dvb_i2c_bus *i2c)
{
struct list_head *entry, *n;
list_for_each_safe (entry, n, &i2c->client_list) {
struct dvb_i2c_device *client;
client = list_entry (entry, struct dvb_i2c_device, list_head);
if (client->detach == dev->detach) {
list_del (entry);
detach_device (i2c, dev);
}
}
}
static void unregister_i2c_client_from_all_busses (struct dvb_i2c_device *dev)
{
struct list_head *entry, *n;
list_for_each_safe (entry, n, &dvb_i2c_buslist) {
struct dvb_i2c_bus *i2c;
i2c = list_entry (entry, struct dvb_i2c_bus, list_head);
unregister_i2c_client_from_bus (dev, i2c);
}
}
static void unregister_all_clients_from_bus (struct dvb_i2c_bus *i2c)
{
struct list_head *entry, *n;
list_for_each_safe (entry, n, &(i2c->client_list)) {
struct dvb_i2c_device *dev;
dev = list_entry (entry, struct dvb_i2c_device, list_head);
unregister_i2c_client_from_bus (dev, i2c);
}
}
static void probe_device_on_all_busses (struct dvb_i2c_device *dev)
{
struct list_head *entry;
list_for_each (entry, &dvb_i2c_buslist) {
struct dvb_i2c_bus *i2c;
i2c = list_entry (entry, struct dvb_i2c_bus, list_head);
try_attach_device (i2c, dev);
}
}
static void probe_devices_on_bus (struct dvb_i2c_bus *i2c)
{
struct list_head *entry;
list_for_each (entry, &dvb_i2c_devicelist) {
struct dvb_i2c_device *dev;
dev = list_entry (entry, struct dvb_i2c_device, list_head);
try_attach_device (i2c, dev);
}
}
static struct dvb_i2c_bus* dvb_find_i2c_bus (int (*xfer) (struct dvb_i2c_bus *i2c,
const struct i2c_msg msgs[],
int num),
struct dvb_adapter *adapter,
int id)
{
struct list_head *entry;
list_for_each (entry, &dvb_i2c_buslist) {
struct dvb_i2c_bus *i2c;
i2c = list_entry (entry, struct dvb_i2c_bus, list_head);
if (i2c->xfer == xfer && i2c->adapter == adapter && i2c->id == id)
return i2c;
}
return NULL;
}
struct dvb_i2c_bus*
dvb_register_i2c_bus (int (*xfer) (struct dvb_i2c_bus *i2c,
const struct i2c_msg *msgs, int num),
void *data, struct dvb_adapter *adapter, int id)
{
struct dvb_i2c_bus *i2c;
if (down_interruptible (&dvb_i2c_mutex))
return NULL;
if (!(i2c = kmalloc (sizeof (struct dvb_i2c_bus), GFP_KERNEL))) {
up (&dvb_i2c_mutex);
return NULL;
}
INIT_LIST_HEAD(&i2c->list_head);
INIT_LIST_HEAD(&i2c->client_list);
i2c->xfer = xfer;
i2c->data = data;
i2c->adapter = adapter;
i2c->id = id;
probe_devices_on_bus (i2c);
list_add_tail (&i2c->list_head, &dvb_i2c_buslist);
up (&dvb_i2c_mutex);
return i2c;
}
void dvb_unregister_i2c_bus (int (*xfer) (struct dvb_i2c_bus *i2c,
const struct i2c_msg msgs[], int num),
struct dvb_adapter *adapter, int id)
{
struct dvb_i2c_bus *i2c;
down (&dvb_i2c_mutex);
if ((i2c = dvb_find_i2c_bus (xfer, adapter, id))) {
unregister_all_clients_from_bus (i2c);
list_del (&i2c->list_head);
kfree (i2c);
}
up (&dvb_i2c_mutex);
}
int dvb_register_i2c_device (struct module *owner,
int (*attach) (struct dvb_i2c_bus *i2c, void **data),
void (*detach) (struct dvb_i2c_bus *i2c, void *data))
{
struct dvb_i2c_device *entry;
if (down_interruptible (&dvb_i2c_mutex))
return -ERESTARTSYS;
if (!(entry = kmalloc (sizeof (struct dvb_i2c_device), GFP_KERNEL))) {
up(&dvb_i2c_mutex);
return -ENOMEM;
}
entry->owner = owner;
entry->attach = attach;
entry->detach = detach;
INIT_LIST_HEAD(&entry->list_head);
probe_device_on_all_busses (entry);
list_add_tail (&entry->list_head, &dvb_i2c_devicelist);
up (&dvb_i2c_mutex);
return 0;
}
int dvb_unregister_i2c_device (int (*attach) (struct dvb_i2c_bus *i2c, void **data))
{
struct list_head *entry, *n;
down (&dvb_i2c_mutex);
list_for_each_safe (entry, n, &dvb_i2c_devicelist) {
struct dvb_i2c_device *dev;
dev = list_entry (entry, struct dvb_i2c_device, list_head);
if (dev->attach == attach) {
list_del (entry);
unregister_i2c_client_from_all_busses (dev);
kfree (entry);
up (&dvb_i2c_mutex);
return 0;
}
}
up (&dvb_i2c_mutex);
return -EINVAL;
}
/*
* dvb_i2c.h: i2c interface to get rid of i2c-core.c
*
* Copyright (C) 2002 Holger Waechtler for convergence integrated media GmbH
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2.1
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#ifndef _DVB_I2C_H_
#define _DVB_I2C_H_
#include <linux/list.h>
#include <linux/i2c.h>
#include "dvbdev.h"
struct dvb_i2c_bus {
struct list_head list_head;
int (*xfer) (struct dvb_i2c_bus *i2c,
const struct i2c_msg msgs[],
int num);
void *data;
struct dvb_adapter *adapter;
int id;
struct list_head client_list;
};
extern struct dvb_i2c_bus*
dvb_register_i2c_bus (int (*xfer) (struct dvb_i2c_bus *i2c,
const struct i2c_msg *msgs, int num),
void *data,
struct dvb_adapter *adapter,
int id);
extern
void dvb_unregister_i2c_bus (int (*xfer) (struct dvb_i2c_bus *i2c,
const struct i2c_msg msgs[], int num),
struct dvb_adapter *adapter,
int id);
extern int dvb_register_i2c_device (struct module *owner,
int (*attach) (struct dvb_i2c_bus *i2c, void **data),
void (*detach) (struct dvb_i2c_bus *i2c, void *data));
extern int dvb_unregister_i2c_device (int (*attach) (struct dvb_i2c_bus *i2c, void **data));
#endif
......@@ -24,17 +24,12 @@ EXPORT_SYMBOL(dvbdmx_connect_frontend);
EXPORT_SYMBOL(dvbdmx_disconnect_frontend);
EXPORT_SYMBOL(dvb_register_frontend);
EXPORT_SYMBOL(dvb_unregister_frontend);
EXPORT_SYMBOL(dvb_unregister_frontend_new);
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_register_i2c_bus);
EXPORT_SYMBOL(dvb_unregister_i2c_bus);
EXPORT_SYMBOL(dvb_register_i2c_device);
EXPORT_SYMBOL(dvb_unregister_i2c_device);
EXPORT_SYMBOL(dvb_net_init);
EXPORT_SYMBOL(dvb_net_release);
......
......@@ -40,8 +40,6 @@
#include "dvb_demux.h"
#include "dvb_net.h"
#include "dvb_functions.h"
static inline __u32 iov_crc32( __u32 c, struct kvec *iov, unsigned int cnt )
{
......
......@@ -25,22 +25,26 @@
#include <linux/errno.h>
#include <linux/string.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/device.h>
#include "dvbdev.h"
#include "dvb_functions.h"
static int dvbdev_debug = 0;
static int dvbdev_debug;
module_param(dvbdev_debug, int, 0644);
MODULE_PARM_DESC(dvbdev_debug, "Turn on/off device debugging (default:off).");
#define dprintk if (dvbdev_debug) printk
static LIST_HEAD(dvb_adapter_list);
static DECLARE_MUTEX(dvbdev_register_lock);
static char *dnames[] = {
static const char * const dnames[] = {
"video", "audio", "sec", "frontend", "demux", "dvr", "ca",
"net", "osd"
};
......@@ -49,6 +53,9 @@ static char *dnames[] = {
#define DVB_MAX_IDS 4
#define nums2minor(num,type,id) ((num << 6) | (id << 4) | type)
struct class_simple *dvb_class;
EXPORT_SYMBOL(dvb_class);
static struct dvb_device* dvbdev_find_device (int minor)
{
struct list_head *entry;
......@@ -219,6 +226,9 @@ int dvb_register_device(struct dvb_adapter *adap, struct dvb_device **pdvbdev,
S_IFCHR | S_IRUSR | S_IWUSR,
"dvb/adapter%d/%s%d", adap->num, dnames[type], id);
class_simple_device_add(dvb_class, MKDEV(DVB_MAJOR, nums2minor(adap->num, type, id)),
NULL, "dvb%d.%s%d", adap->num, dnames[type], id);
dprintk("DVB: register adapter%d/%s%d @ minor: %i (0x%02x)\n",
adap->num, dnames[type], id, nums2minor(adap->num, type, id),
nums2minor(adap->num, type, id));
......@@ -235,6 +245,9 @@ void dvb_unregister_device(struct dvb_device *dvbdev)
devfs_remove("dvb/adapter%d/%s%d", dvbdev->adapter->num,
dnames[dvbdev->type], dvbdev->id);
class_simple_device_remove(MKDEV(DVB_MAJOR, nums2minor(dvbdev->adapter->num,
dvbdev->type, dvbdev->id)));
list_del(&dvbdev->list_head);
kfree(dvbdev);
}
......@@ -300,24 +313,95 @@ int dvb_register_adapter(struct dvb_adapter **padap, const char *name, struct mo
int dvb_unregister_adapter(struct dvb_adapter *adap)
{
devfs_remove("dvb/adapter%d", adap->num);
if (down_interruptible (&dvbdev_register_lock))
return -ERESTARTSYS;
devfs_remove("dvb/adapter%d", adap->num);
list_del (&adap->list_head);
up (&dvbdev_register_lock);
kfree (adap);
return 0;
}
/* if the miracle happens and "generic_usercopy()" is included into
the kernel, then this can vanish. please don't make the mistake and
define this as video_usercopy(). this will introduce a dependecy
to the v4l "videodev.o" module, which is unnecessary for some
cards (ie. the budget dvb-cards don't need the v4l module...) */
int dvb_usercopy(struct inode *inode, struct file *file,
unsigned int cmd, unsigned long arg,
int (*func)(struct inode *inode, struct file *file,
unsigned int cmd, void *arg))
{
char sbuf[128];
void *mbuf = NULL;
void *parg = NULL;
int err = -EINVAL;
/* Copy arguments into temp kernel buffer */
switch (_IOC_DIR(cmd)) {
case _IOC_NONE:
/*
* For this command, the pointer is actually an integer
* argument.
*/
parg = (void *) arg;
break;
case _IOC_READ: /* some v4l ioctls are marked wrong ... */
case _IOC_WRITE:
case (_IOC_WRITE | _IOC_READ):
if (_IOC_SIZE(cmd) <= sizeof(sbuf)) {
parg = sbuf;
} else {
/* too big to allocate from stack */
mbuf = kmalloc(_IOC_SIZE(cmd),GFP_KERNEL);
if (NULL == mbuf)
return -ENOMEM;
parg = mbuf;
}
err = -EFAULT;
if (copy_from_user(parg, (void __user *)arg, _IOC_SIZE(cmd)))
goto out;
break;
}
/* call driver */
if ((err = func(inode, file, cmd, parg)) == -ENOIOCTLCMD)
err = -EINVAL;
if (err < 0)
goto out;
/* Copy results into user buffer */
switch (_IOC_DIR(cmd))
{
case _IOC_READ:
case (_IOC_WRITE | _IOC_READ):
if (copy_to_user((void __user *)arg, parg, _IOC_SIZE(cmd)))
err = -EFAULT;
break;
}
out:
if (mbuf)
kfree(mbuf);
return err;
}
static int __init init_dvbdev(void)
{
int retval;
if ((retval = register_chrdev(DVB_MAJOR,"DVB", &dvb_device_fops)))
printk("dvb-core: unable to get major %d\n", DVB_MAJOR);
devfs_mk_dir("dvb");
retval = register_chrdev(DVB_MAJOR,"DVB", &dvb_device_fops);
if (retval)
printk("video_dev: unable to get major %d\n", DVB_MAJOR);
dvb_class = class_simple_create(THIS_MODULE, "dvb");
if (IS_ERR(dvb_class))
return PTR_ERR(dvb_class);
return retval;
}
......@@ -327,6 +411,7 @@ static void __exit exit_dvbdev(void)
{
unregister_chrdev(DVB_MAJOR, "DVB");
devfs_remove("dvb");
class_simple_destroy(dvb_class);
}
module_init(init_dvbdev);
......@@ -336,6 +421,3 @@ MODULE_DESCRIPTION("DVB Core Driver");
MODULE_AUTHOR("Marcus Metzler, Ralph Metzler, Holger Waechtler");
MODULE_LICENSE("GPL");
MODULE_PARM(dvbdev_debug,"i");
MODULE_PARM_DESC(dvbdev_debug, "enable verbose debug messages");
......@@ -28,6 +28,7 @@
#include <linux/fs.h>
#include <linux/list.h>
#include <linux/devfs_fs_kernel.h>
#include <linux/smp_lock.h>
#define DVB_MAJOR 212
......@@ -92,5 +93,15 @@ extern int dvb_generic_open (struct inode *inode, struct file *file);
extern int dvb_generic_release (struct inode *inode, struct file *file);
extern int dvb_generic_ioctl (struct inode *inode, struct file *file,
unsigned int cmd, unsigned long arg);
/* we don't mess with video_usercopy() any more,
we simply define out own dvb_usercopy(), which will hopefully become
generic_usercopy() someday... */
extern int dvb_usercopy(struct inode *inode, struct file *file,
unsigned int cmd, unsigned long arg,
int (*func)(struct inode *inode, struct file *file,
unsigned int cmd, void *arg));
#endif /* #ifndef _DVBDEV_H_ */
......@@ -32,7 +32,8 @@
typedef enum fe_type {
FE_QPSK,
FE_QAM,
FE_OFDM
FE_OFDM,
FE_ATSC
} fe_type_t;
......@@ -59,6 +60,8 @@ typedef enum fe_caps {
FE_CAN_BANDWIDTH_AUTO = 0x40000,
FE_CAN_GUARD_INTERVAL_AUTO = 0x80000,
FE_CAN_HIERARCHY_AUTO = 0x100000,
FE_CAN_8VSB = 0x200000,
FE_CAN_16VSB = 0x400000,
FE_NEEDS_BENDING = 0x20000000, // frontend requires frequency bending
FE_CAN_RECOVER = 0x40000000, // frontend can recover from a cable unplug automatically
FE_CAN_MUTE_TS = 0x80000000 // frontend can stop spurious TS data output
......
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