V4L/DVB (10756): cx18: Slim down instance handling, build names from v4l2_device.name

Convert card instance handling to a lighter weight mechanism like ivtv.
Also convert name strings and debug messages to use v4l2_device.name.

Signed-off-by: Andy Walls <awalls@radix.net>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
This commit is contained in:
Andy Walls 2009-02-14 17:08:37 -03:00 committed by Mauro Carvalho Chehab
parent 1a2670465e
commit 5811cf99df
6 changed files with 71 additions and 119 deletions

View File

@ -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 */
CX18_INFO("Removed %s\n", cx->card_name);
v4l2_device_unregister(v4l2_dev);
CX18_INFO("Removed %s, card #%d\n", cx->card_name, cx->num);
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);

View File

@ -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==================*/

View File

@ -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;
}

View File

@ -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,

View File

@ -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;
}

View File

@ -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);