diff options
-rw-r--r-- | drivers/media/video/cx18/cx18-driver.c | 107 | ||||
-rw-r--r-- | drivers/media/video/cx18/cx18-driver.h | 27 | ||||
-rw-r--r-- | drivers/media/video/cx18/cx18-fileops.c | 35 | ||||
-rw-r--r-- | drivers/media/video/cx18/cx18-i2c.c | 2 | ||||
-rw-r--r-- | drivers/media/video/cx18/cx18-ioctl.c | 10 | ||||
-rw-r--r-- | drivers/media/video/cx18/cx18-streams.c | 9 |
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 2a45bbc..f69e688 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 7fc914c..def82bd 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 68dd50a..757982e 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 200d925..db2c3e6 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 5c8e9cb..3277b3d 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 778aa0c..eff4a14 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); |