diff options
author | Hans Verkuil <hverkuil@xs4all.nl> | 2009-02-14 15:54:23 +0100 |
---|---|---|
committer | Hans Verkuil <hverkuil@xs4all.nl> | 2009-02-14 15:54:23 +0100 |
commit | 9511f472cfb47c53ad0f210dd137dedfb753cea7 (patch) | |
tree | 0cf9536219edd3bfe9266f264a3ae5395e3a785c /linux | |
parent | 398608cab6406080ef01e4cbfbd88a4c401f4fc0 (diff) | |
download | mediapointer-dvb-s2-9511f472cfb47c53ad0f210dd137dedfb753cea7.tar.gz mediapointer-dvb-s2-9511f472cfb47c53ad0f210dd137dedfb753cea7.tar.bz2 |
v4l2-device: allow a NULL parent device when registering.
From: Hans Verkuil <hverkuil@xs4all.nl>
Some drivers (e.g. for ISA devices) have no parent device because there
is no associated bus driver. Allow the parent device to be NULL in
those cases when registering v4l2_device.
Priority: normal
Signed-off-by: Hans Verkuil <hverkuil@xs4all.nl>
Diffstat (limited to 'linux')
-rw-r--r-- | linux/Documentation/video4linux/v4l2-framework.txt | 58 | ||||
-rw-r--r-- | linux/drivers/media/video/v4l2-device.c | 37 | ||||
-rw-r--r-- | linux/include/media/v4l2-device.h | 31 |
3 files changed, 72 insertions, 54 deletions
diff --git a/linux/Documentation/video4linux/v4l2-framework.txt b/linux/Documentation/video4linux/v4l2-framework.txt index a6005257a..e1620e2a3 100644 --- a/linux/Documentation/video4linux/v4l2-framework.txt +++ b/linux/Documentation/video4linux/v4l2-framework.txt @@ -84,12 +84,14 @@ You must register the device instance: v4l2_device_register(struct device *dev, struct v4l2_device *v4l2_dev); Registration will initialize the v4l2_device struct and link dev->driver_data -to v4l2_dev. Registration will also set v4l2_dev->name to a value derived from -dev (driver name followed by the bus_id, to be precise). You may change the -name after registration if you want. +to v4l2_dev. If v4l2_dev->name is empty then it will be set to a value derived +from dev (driver name followed by the bus_id, to be precise). If you set it +up before calling v4l2_device_register then it will be untouched. If dev is +NULL, then you *must* setup v4l2_dev->name before calling v4l2_device_register. The first 'dev' argument is normally the struct device pointer of a pci_dev, -usb_device or platform_device. +usb_device or platform_device. It is rare for dev to be NULL, but it happens +with ISA devices, for example. You unregister with: @@ -531,11 +533,11 @@ struct v4l2_device *v4l2_dev = vdev->v4l2_dev; video buffer helper functions ----------------------------- -The v4l2 core API provides a standard method for dealing with video -buffers. Those methods allow a driver to implement read(), mmap() and +The v4l2 core API provides a standard method for dealing with video +buffers. Those methods allow a driver to implement read(), mmap() and overlay() on a consistent way. -There are currently methods for using video buffers on devices that +There are currently methods for using video buffers on devices that supports DMA with scatter/gather method (videobuf-dma-sg), DMA with linear access (videobuf-dma-contig), and vmalloced buffers, mostly used on USB drivers (videobuf-vmalloc). @@ -544,50 +546,50 @@ Any driver using videobuf should provide operations (callbacks) for four handlers: ops->buf_setup - calculates the size of the video buffers and avoid they - to waste more than some maximum limit of RAM; + to waste more than some maximum limit of RAM; ops->buf_prepare - fills the video buffer structs and calls videobuf_iolock() to alloc and prepare mmaped memory; ops->buf_queue - advices the driver that another buffer were - requested (by read() or by QBUF); + requested (by read() or by QBUF); ops->buf_release - frees any buffer that were allocated. In order to use it, the driver need to have a code (generally called at interrupt context) that will properly handle the buffer request lists, announcing that a new buffer were filled. -The irq handling code should handle the videobuf task lists, in order -to advice videobuf that a new frame were filled, in order to honor to a +The irq handling code should handle the videobuf task lists, in order +to advice videobuf that a new frame were filled, in order to honor to a request. The code is generally like this one: - if (list_empty(&dma_q->active)) + if (list_empty(&dma_q->active)) return; - buf = list_entry(dma_q->active.next, struct vbuffer, vb.queue); + buf = list_entry(dma_q->active.next, struct vbuffer, vb.queue); - if (!waitqueue_active(&buf->vb.done)) + if (!waitqueue_active(&buf->vb.done)) return; /* Some logic to handle the buf may be needed here */ - list_del(&buf->vb.queue); - do_gettimeofday(&buf->vb.ts); - wake_up(&buf->vb.done); + list_del(&buf->vb.queue); + do_gettimeofday(&buf->vb.ts); + wake_up(&buf->vb.done); -Those are the videobuffer functions used on drivers, implemented on +Those are the videobuffer functions used on drivers, implemented on videobuf-core: - Videobuf init functions videobuf_queue_sg_init() - Initializes the videobuf infrastructure. This function should be - called before any other videobuf function on drivers that uses DMA + Initializes the videobuf infrastructure. This function should be + called before any other videobuf function on drivers that uses DMA Scatter/Gather buffers. videobuf_queue_dma_contig_init - Initializes the videobuf infrastructure. This function should be - called before any other videobuf function on drivers that need DMA + Initializes the videobuf infrastructure. This function should be + called before any other videobuf function on drivers that need DMA contiguous buffers. videobuf_queue_vmalloc_init() - Initializes the videobuf infrastructure. This function should be + Initializes the videobuf infrastructure. This function should be called before any other videobuf function on USB (and other drivers) that need a vmalloced type of videobuf. @@ -607,12 +609,12 @@ videobuf-core: Stops video handling, ends mmap and frees mmap and other buffers. - V4L2 api functions. Those functions correspond to VIDIOC_foo ioctls: - videobuf_reqbufs(), videobuf_querybuf(), videobuf_qbuf(), + videobuf_reqbufs(), videobuf_querybuf(), videobuf_qbuf(), videobuf_dqbuf(), videobuf_streamon(), videobuf_streamoff(). - V4L1 api function (corresponds to VIDIOCMBUF ioctl): videobuf_cgmbuf() - This function is used to provide backward compatibility with V4L1 + This function is used to provide backward compatibility with V4L1 API. - Some help functions for read()/poll() operations: @@ -623,7 +625,7 @@ videobuf-core: videobuf_poll_stream() polling help function -The better way to understand it is to take a look at vivi driver. One -of the main reasons for vivi is to be a videobuf usage example. the -vivi_thread_tick() does the task that the IRQ callback would do on PCI +The better way to understand it is to take a look at vivi driver. One +of the main reasons for vivi is to be a videobuf usage example. the +vivi_thread_tick() does the task that the IRQ callback would do on PCI drivers (or the irq callback on USB). diff --git a/linux/drivers/media/video/v4l2-device.c b/linux/drivers/media/video/v4l2-device.c index e84925976..cb8234437 100644 --- a/linux/drivers/media/video/v4l2-device.c +++ b/linux/drivers/media/video/v4l2-device.c @@ -27,15 +27,24 @@ int v4l2_device_register(struct device *dev, struct v4l2_device *v4l2_dev) { - if (dev == NULL || v4l2_dev == NULL) + if (v4l2_dev == NULL) return -EINVAL; - /* Warn if we apparently re-register a device */ - WARN_ON(dev_get_drvdata(dev) != NULL); + INIT_LIST_HEAD(&v4l2_dev->subdevs); spin_lock_init(&v4l2_dev->lock); v4l2_dev->dev = dev; - snprintf(v4l2_dev->name, sizeof(v4l2_dev->name), "%s %s", + if (dev == NULL) { + /* If dev == NULL, then name must be filled in by the caller */ + WARN_ON(!v4l2_dev->name[0]); + return 0; + } + + /* Set name to driver name + device name if it is empty. */ + if (!v4l2_dev->name[0]) + snprintf(v4l2_dev->name, sizeof(v4l2_dev->name), "%s %s", dev->driver->name, dev_name(dev)); + if (dev_get_drvdata(dev)) + v4l2_warn(v4l2_dev, "Non-NULL drvdata on register\n"); dev_set_drvdata(dev, v4l2_dev); return 0; } @@ -45,10 +54,11 @@ void v4l2_device_unregister(struct v4l2_device *v4l2_dev) { struct v4l2_subdev *sd, *next; - if (v4l2_dev == NULL || v4l2_dev->dev == NULL) + if (v4l2_dev == NULL) return; - dev_set_drvdata(v4l2_dev->dev, NULL); - /* unregister subdevs */ + if (v4l2_dev->dev) + dev_set_drvdata(v4l2_dev->dev, NULL); + /* Unregister subdevs */ list_for_each_entry_safe(sd, next, &v4l2_dev->subdevs, list) v4l2_device_unregister_subdev(sd); @@ -56,19 +66,20 @@ void v4l2_device_unregister(struct v4l2_device *v4l2_dev) } EXPORT_SYMBOL_GPL(v4l2_device_unregister); -int v4l2_device_register_subdev(struct v4l2_device *dev, struct v4l2_subdev *sd) +int v4l2_device_register_subdev(struct v4l2_device *v4l2_dev, + struct v4l2_subdev *sd) { /* Check for valid input */ - if (dev == NULL || sd == NULL || !sd->name[0]) + if (v4l2_dev == NULL || sd == NULL || !sd->name[0]) return -EINVAL; /* Warn if we apparently re-register a subdev */ WARN_ON(sd->dev != NULL); if (!try_module_get(sd->owner)) return -ENODEV; - sd->dev = dev; - spin_lock(&dev->lock); - list_add_tail(&sd->list, &dev->subdevs); - spin_unlock(&dev->lock); + sd->dev = v4l2_dev; + spin_lock(&v4l2_dev->lock); + list_add_tail(&sd->list, &v4l2_dev->subdevs); + spin_unlock(&v4l2_dev->lock); return 0; } EXPORT_SYMBOL_GPL(v4l2_device_register_subdev); diff --git a/linux/include/media/v4l2-device.h b/linux/include/media/v4l2-device.h index 55e41afd9..5d7146dc2 100644 --- a/linux/include/media/v4l2-device.h +++ b/linux/include/media/v4l2-device.h @@ -33,7 +33,9 @@ #define V4L2_DEVICE_NAME_SIZE (BUS_ID_SIZE + 16) struct v4l2_device { - /* dev->driver_data points to this struct */ + /* dev->driver_data points to this struct. + Note: dev might be NULL if there is no parent device + as is the case with e.g. ISA devices. */ struct device *dev; /* used to keep track of the registered subdevs */ struct list_head subdevs; @@ -44,7 +46,9 @@ struct v4l2_device { char name[V4L2_DEVICE_NAME_SIZE]; }; -/* Initialize v4l2_dev and make dev->driver_data point to v4l2_dev */ +/* Initialize v4l2_dev and make dev->driver_data point to v4l2_dev. + dev may be NULL in rare cases (ISA devices). In that case you + must fill in the v4l2_dev->name field before calling this function. */ int __must_check v4l2_device_register(struct device *dev, struct v4l2_device *v4l2_dev); /* Set v4l2_dev->dev->driver_data to NULL and unregister all sub-devices */ void v4l2_device_unregister(struct v4l2_device *v4l2_dev); @@ -52,23 +56,24 @@ void v4l2_device_unregister(struct v4l2_device *v4l2_dev); /* Register a subdev with a v4l2 device. While registered the subdev module is marked as in-use. An error is returned if the module is no longer loaded when you attempt to register it. */ -int __must_check v4l2_device_register_subdev(struct v4l2_device *dev, struct v4l2_subdev *sd); +int __must_check v4l2_device_register_subdev(struct v4l2_device *v4l2_dev, + struct v4l2_subdev *sd); /* Unregister a subdev with a v4l2 device. Can also be called if the subdev wasn't registered. In that case it will do nothing. */ void v4l2_device_unregister_subdev(struct v4l2_subdev *sd); /* Iterate over all subdevs. */ -#define v4l2_device_for_each_subdev(sd, dev) \ - list_for_each_entry(sd, &(dev)->subdevs, list) +#define v4l2_device_for_each_subdev(sd, v4l2_dev) \ + list_for_each_entry(sd, &(v4l2_dev)->subdevs, list) /* Call the specified callback for all subdevs matching the condition. Ignore any errors. Note that you cannot add or delete a subdev while walking the subdevs list. */ -#define __v4l2_device_call_subdevs(dev, cond, o, f, args...) \ +#define __v4l2_device_call_subdevs(v4l2_dev, cond, o, f, args...) \ do { \ struct v4l2_subdev *sd; \ \ - list_for_each_entry(sd, &(dev)->subdevs, list) \ + list_for_each_entry(sd, &(v4l2_dev)->subdevs, list) \ if ((cond) && sd->ops->o && sd->ops->o->f) \ sd->ops->o->f(sd , ##args); \ } while (0) @@ -77,12 +82,12 @@ void v4l2_device_unregister_subdev(struct v4l2_subdev *sd); If the callback returns an error other than 0 or -ENOIOCTLCMD, then return with that error code. Note that you cannot add or delete a subdev while walking the subdevs list. */ -#define __v4l2_device_call_subdevs_until_err(dev, cond, o, f, args...) \ +#define __v4l2_device_call_subdevs_until_err(v4l2_dev, cond, o, f, args...) \ ({ \ struct v4l2_subdev *sd; \ long err = 0; \ \ - list_for_each_entry(sd, &(dev)->subdevs, list) { \ + list_for_each_entry(sd, &(v4l2_dev)->subdevs, list) { \ if ((cond) && sd->ops->o && sd->ops->o->f) \ err = sd->ops->o->f(sd , ##args); \ if (err && err != -ENOIOCTLCMD) \ @@ -94,16 +99,16 @@ void v4l2_device_unregister_subdev(struct v4l2_subdev *sd); /* Call the specified callback for all subdevs matching grp_id (if 0, then match them all). Ignore any errors. Note that you cannot add or delete a subdev while walking the subdevs list. */ -#define v4l2_device_call_all(dev, grpid, o, f, args...) \ - __v4l2_device_call_subdevs(dev, \ +#define v4l2_device_call_all(v4l2_dev, grpid, o, f, args...) \ + __v4l2_device_call_subdevs(v4l2_dev, \ !(grpid) || sd->grp_id == (grpid), o, f , ##args) /* Call the specified callback for all subdevs matching grp_id (if 0, then match them all). If the callback returns an error other than 0 or -ENOIOCTLCMD, then return with that error code. Note that you cannot add or delete a subdev while walking the subdevs list. */ -#define v4l2_device_call_until_err(dev, grpid, o, f, args...) \ - __v4l2_device_call_subdevs_until_err(dev, \ +#define v4l2_device_call_until_err(v4l2_dev, grpid, o, f, args...) \ + __v4l2_device_call_subdevs_until_err(v4l2_dev, \ !(grpid) || sd->grp_id == (grpid), o, f , ##args) #endif |