summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/media/video/cx18/cx18-driver.c107
-rw-r--r--drivers/media/video/cx18/cx18-driver.h27
-rw-r--r--drivers/media/video/cx18/cx18-fileops.c35
-rw-r--r--drivers/media/video/cx18/cx18-i2c.c2
-rw-r--r--drivers/media/video/cx18/cx18-ioctl.c10
-rw-r--r--drivers/media/video/cx18/cx18-streams.c9
6 files changed, 71 insertions, 119 deletions
diff --git a/drivers/media/video/cx18/cx18-driver.c b/drivers/media/video/cx18/cx18-driver.c
index 2a45bbc757e..f69e688ab6f 100644
--- a/drivers/media/video/cx18/cx18-driver.c
+++ b/drivers/media/video/cx18/cx18-driver.c
@@ -39,10 +39,6 @@
#include <media/tveeprom.h>
-
-/* var to keep track of the number of array elements in use */
-int cx18_cards_active;
-
/* If you have already X v4l cards, then set this to X. This way
the device numbers stay matched. Example: you have a WinTV card
without radio and a Compro H900 with. Normally this would give a
@@ -50,12 +46,6 @@ int cx18_cards_active;
setting this to 1 you ensure that radio0 is now also radio1. */
int cx18_first_minor;
-/* Master variable for all cx18 info */
-struct cx18 *cx18_cards[CX18_MAX_CARDS];
-
-/* Protects cx18_cards_active */
-DEFINE_SPINLOCK(cx18_cards_lock);
-
/* add your revision and whatnot here */
static struct pci_device_id cx18_pci_tbl[] __devinitdata = {
{PCI_VENDOR_ID_CX, PCI_DEVICE_ID_CX23418,
@@ -65,6 +55,8 @@ static struct pci_device_id cx18_pci_tbl[] __devinitdata = {
MODULE_DEVICE_TABLE(pci, cx18_pci_tbl);
+static atomic_t cx18_instance = ATOMIC_INIT(0);
+
/* Parameter declarations */
static int cardtype[CX18_MAX_CARDS];
static int tuner[CX18_MAX_CARDS] = { -1, -1, -1, -1, -1, -1, -1, -1,
@@ -491,9 +483,9 @@ static void cx18_process_options(struct cx18 *cx)
cx->stream_buf_size[i] *= 1024; /* convert from kB to bytes */
}
- cx->options.cardtype = cardtype[cx->num];
- cx->options.tuner = tuner[cx->num];
- cx->options.radio = radio[cx->num];
+ cx->options.cardtype = cardtype[cx->instance];
+ cx->options.tuner = tuner[cx->instance];
+ cx->options.radio = radio[cx->instance];
cx->std = cx18_parse_std(cx);
if (cx->options.cardtype == -1) {
@@ -550,7 +542,7 @@ done:
}
/* Precondition: the cx18 structure has been memset to 0. Only
- the dev and num fields have been filled in.
+ the dev and instance fields have been filled in.
No assumptions on the card type may be made here (see cx18_init_struct2
for that).
*/
@@ -567,7 +559,7 @@ static int __devinit cx18_init_struct1(struct cx18 *cx)
mutex_init(&cx->epu2apu_mb_lock);
mutex_init(&cx->epu2cpu_mb_lock);
- cx->work_queue = create_singlethread_workqueue(cx->name);
+ cx->work_queue = create_singlethread_workqueue(cx->v4l2_dev.name);
if (cx->work_queue == NULL) {
CX18_ERR("Unable to create work hander thread\n");
return -ENOMEM;
@@ -647,15 +639,16 @@ static int cx18_setup_pci(struct cx18 *cx, struct pci_dev *pci_dev,
CX18_DEBUG_INFO("Enabling pci device\n");
if (pci_enable_device(pci_dev)) {
- CX18_ERR("Can't enable device %d!\n", cx->num);
+ CX18_ERR("Can't enable device %d!\n", cx->instance);
return -EIO;
}
if (pci_set_dma_mask(pci_dev, 0xffffffff)) {
- CX18_ERR("No suitable DMA available on card %d.\n", cx->num);
+ CX18_ERR("No suitable DMA available, card %d\n", cx->instance);
return -EIO;
}
if (!request_mem_region(cx->base_addr, CX18_MEM_SIZE, "cx18 encoder")) {
- CX18_ERR("Cannot request encoder memory region on card %d.\n", cx->num);
+ CX18_ERR("Cannot request encoder memory region, card %d\n",
+ cx->instance);
return -EIO;
}
@@ -741,44 +734,42 @@ static int __devinit cx18_probe(struct pci_dev *pci_dev,
u32 devtype;
struct cx18 *cx;
- spin_lock(&cx18_cards_lock);
-
- /* Make sure we've got a place for this card */
- if (cx18_cards_active == CX18_MAX_CARDS) {
- printk(KERN_ERR "cx18: Maximum number of cards detected (%d).\n",
- cx18_cards_active);
- spin_unlock(&cx18_cards_lock);
+ /* FIXME - module parameter arrays constrain max instances */
+ i = atomic_inc_return(&cx18_instance) - 1;
+ if (i >= CX18_MAX_CARDS) {
+ printk(KERN_ERR "cx18: cannot manage card %d, driver has a "
+ "limit of 0 - %d\n", i, CX18_MAX_CARDS - 1);
return -ENOMEM;
}
cx = kzalloc(sizeof(struct cx18), GFP_ATOMIC);
- if (!cx) {
- spin_unlock(&cx18_cards_lock);
+ if (cx == NULL) {
+ printk(KERN_ERR "cx18: cannot manage card %d, out of memory\n",
+ i);
return -ENOMEM;
}
- cx18_cards[cx18_cards_active] = cx;
- cx->num = cx18_cards_active++;
- snprintf(cx->name, sizeof(cx->name), "cx18-%d", cx->num);
- CX18_INFO("Initializing card #%d\n", cx->num);
-
- spin_unlock(&cx18_cards_lock);
-
cx->pci_dev = pci_dev;
+ cx->instance = i;
+
retval = v4l2_device_register(&pci_dev->dev, &cx->v4l2_dev);
if (retval) {
- CX18_ERR("Call to v4l2_device_register() failed\n");
- goto err;
+ printk(KERN_ERR "cx18: v4l2_device_register of card %d failed"
+ "\n", cx->instance);
+ kfree(cx);
+ return retval;
}
- CX18_DEBUG_INFO("registered v4l2_device name: %s\n", cx->v4l2_dev.name);
+ snprintf(cx->v4l2_dev.name, sizeof(cx->v4l2_dev.name), "cx18-%d",
+ cx->instance);
+ CX18_INFO("Initializing card %d\n", cx->instance);
cx18_process_options(cx);
if (cx->options.cardtype == -1) {
retval = -ENODEV;
- goto unregister_v4l2;
+ goto err;
}
if (cx18_init_struct1(cx)) {
retval = -ENOMEM;
- goto unregister_v4l2;
+ goto err;
}
CX18_DEBUG_INFO("base addr: 0x%08x\n", cx->base_addr);
@@ -829,8 +820,6 @@ static int __devinit cx18_probe(struct pci_dev *pci_dev,
goto free_map;
}
- CX18_DEBUG_INFO("Active card count: %d.\n", cx18_cards_active);
-
if (cx->card->hw_all & CX18_HW_TVEEPROM) {
/* Based on the model number the cardtype may be changed.
The PCI IDs are not always reliable. */
@@ -847,7 +836,8 @@ static int __devinit cx18_probe(struct pci_dev *pci_dev,
/* Register IRQ */
retval = request_irq(cx->pci_dev->irq, cx18_irq_handler,
- IRQF_SHARED | IRQF_DISABLED, cx->name, (void *)cx);
+ IRQF_SHARED | IRQF_DISABLED,
+ cx->v4l2_dev.name, (void *)cx);
if (retval) {
CX18_ERR("Failed to register irq %d\n", retval);
goto free_i2c;
@@ -933,8 +923,7 @@ static int __devinit cx18_probe(struct pci_dev *pci_dev,
goto free_streams;
}
- CX18_INFO("Initialized card #%d: %s\n", cx->num, cx->card_name);
-
+ CX18_INFO("Initialized card: %s\n", cx->card_name);
return 0;
free_streams:
@@ -949,18 +938,13 @@ free_mem:
release_mem_region(cx->base_addr, CX18_MEM_SIZE);
free_workqueue:
destroy_workqueue(cx->work_queue);
-unregister_v4l2:
- v4l2_device_unregister(&cx->v4l2_dev);
err:
if (retval == 0)
retval = -ENODEV;
CX18_ERR("Error %d on initialization\n", retval);
- i = cx->num;
- spin_lock(&cx18_cards_lock);
- kfree(cx18_cards[i]);
- cx18_cards[i] = NULL;
- spin_unlock(&cx18_cards_lock);
+ v4l2_device_unregister(&cx->v4l2_dev);
+ kfree(cx);
return retval;
}
@@ -1069,9 +1053,9 @@ static void cx18_cancel_epu_work_orders(struct cx18 *cx)
static void cx18_remove(struct pci_dev *pci_dev)
{
struct v4l2_device *v4l2_dev = pci_get_drvdata(pci_dev);
- struct cx18 *cx = container_of(v4l2_dev, struct cx18, v4l2_dev);
+ struct cx18 *cx = to_cx18(v4l2_dev);
- CX18_DEBUG_INFO("Removing Card #%d\n", cx->num);
+ CX18_DEBUG_INFO("Removing Card\n");
/* Stop all captures */
CX18_DEBUG_INFO("Stopping all streams\n");
@@ -1099,10 +1083,12 @@ static void cx18_remove(struct pci_dev *pci_dev)
release_mem_region(cx->base_addr, CX18_MEM_SIZE);
pci_disable_device(cx->pci_dev);
+ /* FIXME - we leak cx->vbi.sliced_mpeg_data[i] allocations */
- v4l2_device_unregister(v4l2_dev);
+ CX18_INFO("Removed %s\n", cx->card_name);
- CX18_INFO("Removed %s, card #%d\n", cx->card_name, cx->num);
+ v4l2_device_unregister(v4l2_dev);
+ kfree(cx);
}
/* define a pci_driver for card detection */
@@ -1117,8 +1103,6 @@ static int module_start(void)
{
printk(KERN_INFO "cx18: Start initialization, version %s\n", CX18_VERSION);
- memset(cx18_cards, 0, sizeof(cx18_cards));
-
/* Validate parameters */
if (cx18_first_minor < 0 || cx18_first_minor >= CX18_MAX_CARDS) {
printk(KERN_ERR "cx18: Exiting, cx18_first_minor must be between 0 and %d\n",
@@ -1141,16 +1125,7 @@ static int module_start(void)
static void module_cleanup(void)
{
- int i;
-
pci_unregister_driver(&cx18_pci_driver);
-
- for (i = 0; i < cx18_cards_active; i++) {
- if (cx18_cards[i] == NULL)
- continue;
- kfree(cx18_cards[i]);
- }
-
}
module_init(module_start);
diff --git a/drivers/media/video/cx18/cx18-driver.h b/drivers/media/video/cx18/cx18-driver.h
index 7fc914c521f..def82bd1078 100644
--- a/drivers/media/video/cx18/cx18-driver.h
+++ b/drivers/media/video/cx18/cx18-driver.h
@@ -144,12 +144,12 @@
/* Flag to turn on high volume debugging */
#define CX18_DBGFLG_HIGHVOL (1 << 8)
-/* NOTE: extra space before comma in 'cx->num , ## args' is required for
+/* NOTE: extra space before comma in 'fmt , ## args' is required for
gcc-2.95, otherwise it won't compile. */
#define CX18_DEBUG(x, type, fmt, args...) \
do { \
if ((x) & cx18_debug) \
- printk(KERN_INFO "cx18-%d " type ": " fmt, cx->num , ## args); \
+ v4l2_info(&cx->v4l2_dev, " " type ": " fmt , ## args); \
} while (0)
#define CX18_DEBUG_WARN(fmt, args...) CX18_DEBUG(CX18_DBGFLG_WARN, "warning", fmt , ## args)
#define CX18_DEBUG_INFO(fmt, args...) CX18_DEBUG(CX18_DBGFLG_INFO, "info", fmt , ## args)
@@ -163,7 +163,7 @@
#define CX18_DEBUG_HIGH_VOL(x, type, fmt, args...) \
do { \
if (((x) & cx18_debug) && (cx18_debug & CX18_DBGFLG_HIGHVOL)) \
- printk(KERN_INFO "cx18%d " type ": " fmt, cx->num , ## args); \
+ v4l2_info(&cx->v4l2_dev, " " type ": " fmt , ## args); \
} while (0)
#define CX18_DEBUG_HI_WARN(fmt, args...) CX18_DEBUG_HIGH_VOL(CX18_DBGFLG_WARN, "warning", fmt , ## args)
#define CX18_DEBUG_HI_INFO(fmt, args...) CX18_DEBUG_HIGH_VOL(CX18_DBGFLG_INFO, "info", fmt , ## args)
@@ -175,9 +175,9 @@
#define CX18_DEBUG_HI_IRQ(fmt, args...) CX18_DEBUG_HIGH_VOL(CX18_DBGFLG_IRQ, "irq", fmt , ## args)
/* Standard kernel messages */
-#define CX18_ERR(fmt, args...) printk(KERN_ERR "cx18-%d: " fmt, cx->num , ## args)
-#define CX18_WARN(fmt, args...) printk(KERN_WARNING "cx18-%d: " fmt, cx->num , ## args)
-#define CX18_INFO(fmt, args...) printk(KERN_INFO "cx18-%d: " fmt, cx->num , ## args)
+#define CX18_ERR(fmt, args...) v4l2_err(&cx->v4l2_dev, fmt , ## args)
+#define CX18_WARN(fmt, args...) v4l2_warn(&cx->v4l2_dev, fmt , ## args)
+#define CX18_INFO(fmt, args...) v4l2_info(&cx->v4l2_dev, fmt , ## args)
/* Values for CX18_API_DEC_PLAYBACK_SPEED mpeg_frame_type_mask parameter: */
#define MPEG_FRAME_TYPE_IFRAME 1
@@ -445,8 +445,7 @@ struct cx18_i2c_algo_callback_data {
/* Struct to hold info about cx18 cards */
struct cx18 {
- int num; /* board number, -1 during init! */
- char name[8]; /* board name for printk and interrupts (e.g. 'cx180') */
+ int instance;
struct pci_dev *pci_dev;
struct v4l2_device v4l2_dev;
@@ -455,8 +454,8 @@ struct cx18 {
const struct cx18_card_tuner_i2c *card_i2c; /* i2c addresses to probe for tuner */
u8 is_50hz;
u8 is_60hz;
- u8 is_out_50hz;
- u8 is_out_60hz;
+ u8 is_out_50hz; /* FIXME - remove, we don't have an output decoder */
+ u8 is_out_60hz; /* FIXME - remove, we don't have an output decoder */
u8 nof_inputs; /* number of video inputs */
u8 nof_audio_inputs; /* number of audio inputs */
u16 buffer_id; /* buffer ID counter */
@@ -547,11 +546,13 @@ struct cx18 {
v4l2_std_id tuner_std; /* The norm of the tuner (fixed) */
};
+static inline struct cx18 *to_cx18(struct v4l2_device *v4l2_dev)
+{
+ return container_of(v4l2_dev, struct cx18, v4l2_dev);
+}
+
/* Globals */
-extern struct cx18 *cx18_cards[];
-extern int cx18_cards_active;
extern int cx18_first_minor;
-extern spinlock_t cx18_cards_lock;
/*==============Prototypes==================*/
diff --git a/drivers/media/video/cx18/cx18-fileops.c b/drivers/media/video/cx18/cx18-fileops.c
index 68dd50ac4bf..757982ea376 100644
--- a/drivers/media/video/cx18/cx18-fileops.c
+++ b/drivers/media/video/cx18/cx18-fileops.c
@@ -682,38 +682,15 @@ static int cx18_serialized_open(struct cx18_stream *s, struct file *filp)
int cx18_v4l2_open(struct file *filp)
{
- int res, x, y = 0;
- struct cx18 *cx = NULL;
- struct cx18_stream *s = NULL;
- int minor = video_devdata(filp)->minor;
-
- /* Find which card this open was on */
- spin_lock(&cx18_cards_lock);
- for (x = 0; cx == NULL && x < cx18_cards_active; x++) {
- /* find out which stream this open was on */
- for (y = 0; y < CX18_MAX_STREAMS; y++) {
- if (cx18_cards[x] == NULL)
- continue;
- s = &cx18_cards[x]->streams[y];
- if (s->video_dev && s->video_dev->minor == minor) {
- cx = cx18_cards[x];
- break;
- }
- }
- }
- spin_unlock(&cx18_cards_lock);
-
- if (cx == NULL) {
- /* Couldn't find a device registered
- on that minor, shouldn't happen! */
- printk(KERN_WARNING "No cx18 device found on minor %d\n",
- minor);
- return -ENXIO;
- }
+ int res;
+ struct video_device *video_dev = video_devdata(filp);
+ struct cx18_stream *s = video_get_drvdata(video_dev);
+ struct cx18 *cx = s->cx;;
mutex_lock(&cx->serialize_lock);
if (cx18_init_on_first_open(cx)) {
- CX18_ERR("Failed to initialize on minor %d\n", minor);
+ CX18_ERR("Failed to initialize on minor %d\n",
+ video_dev->minor);
mutex_unlock(&cx->serialize_lock);
return -ENXIO;
}
diff --git a/drivers/media/video/cx18/cx18-i2c.c b/drivers/media/video/cx18/cx18-i2c.c
index 200d9257a92..db2c3e6997d 100644
--- a/drivers/media/video/cx18/cx18-i2c.c
+++ b/drivers/media/video/cx18/cx18-i2c.c
@@ -358,7 +358,7 @@ int init_cx18_i2c(struct cx18 *cx)
cx->i2c_adap[i].algo_data = &cx->i2c_algo[i];
sprintf(cx->i2c_adap[i].name + strlen(cx->i2c_adap[i].name),
- " #%d-%d", cx->num, i);
+ " #%d-%d", cx->instance, i);
i2c_set_adapdata(&cx->i2c_adap[i], cx);
memcpy(&cx->i2c_client[i], &cx18_i2c_client_template,
diff --git a/drivers/media/video/cx18/cx18-ioctl.c b/drivers/media/video/cx18/cx18-ioctl.c
index 5c8e9cb244f..3277b3d3cea 100644
--- a/drivers/media/video/cx18/cx18-ioctl.c
+++ b/drivers/media/video/cx18/cx18-ioctl.c
@@ -387,20 +387,17 @@ static int cx18_g_chip_ident(struct file *file, void *fh,
static int cx18_cxc(struct cx18 *cx, unsigned int cmd, void *arg)
{
struct v4l2_dbg_register *regs = arg;
- unsigned long flags;
if (!capable(CAP_SYS_ADMIN))
return -EPERM;
if (regs->reg >= CX18_MEM_OFFSET + CX18_MEM_SIZE)
return -EINVAL;
- spin_lock_irqsave(&cx18_cards_lock, flags);
regs->size = 4;
if (cmd == VIDIOC_DBG_G_REGISTER)
regs->val = cx18_read_enc(cx, regs->reg);
else
cx18_write_enc(cx, regs->val, regs->reg);
- spin_unlock_irqrestore(&cx18_cards_lock, flags);
return 0;
}
@@ -847,7 +844,7 @@ static int cx18_log_status(struct file *file, void *fh)
int i;
CX18_INFO("================= START STATUS CARD #%d "
- "=================\n", cx->num);
+ "=================\n", cx->instance);
CX18_INFO("Version: %s Card: %s\n", CX18_VERSION, cx->card_name);
if (cx->hw_flags & CX18_HW_TVEEPROM) {
struct tveeprom tv;
@@ -865,7 +862,7 @@ static int cx18_log_status(struct file *file, void *fh)
mutex_unlock(&cx->gpio_lock);
CX18_INFO("Tuner: %s\n",
test_bit(CX18_F_I_RADIO_USER, &cx->i_flags) ? "Radio" : "TV");
- cx2341x_log_status(&cx->params, cx->name);
+ cx2341x_log_status(&cx->params, cx->v4l2_dev.name);
CX18_INFO("Status flags: 0x%08lx\n", cx->i_flags);
for (i = 0; i < CX18_MAX_STREAMS; i++) {
struct cx18_stream *s = &cx->streams[i];
@@ -880,7 +877,8 @@ static int cx18_log_status(struct file *file, void *fh)
CX18_INFO("Read MPEG/VBI: %lld/%lld bytes\n",
(long long)cx->mpg_data_received,
(long long)cx->vbi_data_inserted);
- CX18_INFO("================== END STATUS CARD #%d ==================\n", cx->num);
+ CX18_INFO("================== END STATUS CARD #%d "
+ "==================\n", cx->instance);
return 0;
}
diff --git a/drivers/media/video/cx18/cx18-streams.c b/drivers/media/video/cx18/cx18-streams.c
index 778aa0c0f9b..eff4a14d015 100644
--- a/drivers/media/video/cx18/cx18-streams.c
+++ b/drivers/media/video/cx18/cx18-streams.c
@@ -130,7 +130,7 @@ static int cx18_prep_dev(struct cx18 *cx, int type)
struct cx18_stream *s = &cx->streams[type];
u32 cap = cx->v4l2_cap;
int num_offset = cx18_stream_info[type].num_offset;
- int num = cx->num + cx18_first_minor + num_offset;
+ int num = cx->instance + cx18_first_minor + num_offset;
/* These four fields are always initialized. If video_dev == NULL, then
this stream is not in use. In that case no other fields but these
@@ -170,11 +170,11 @@ static int cx18_prep_dev(struct cx18 *cx, int type)
return -ENOMEM;
}
- snprintf(s->video_dev->name, sizeof(s->video_dev->name), "cx18-%d",
- cx->num);
+ snprintf(s->video_dev->name, sizeof(s->video_dev->name), "%s %s",
+ cx->v4l2_dev.name, s->name);
s->video_dev->num = num;
- s->video_dev->parent = &cx->pci_dev->dev;
+ s->video_dev->v4l2_dev = &cx->v4l2_dev;
s->video_dev->fops = &cx18_v4l2_enc_fops;
s->video_dev->release = video_device_release;
s->video_dev->tvnorms = V4L2_STD_ALL;
@@ -239,6 +239,7 @@ static int cx18_reg_dev(struct cx18 *cx, int type)
num = s_mpg->video_dev->num
+ cx18_stream_info[type].num_offset;
}
+ video_set_drvdata(s->video_dev, s);
/* Register device. First try the desired minor, then any free one. */
ret = video_register_device(s->video_dev, vfl_type, num);