summaryrefslogtreecommitdiff
path: root/linux/drivers/media/video/hdpvr/hdpvr-video.c
diff options
context:
space:
mode:
Diffstat (limited to 'linux/drivers/media/video/hdpvr/hdpvr-video.c')
-rw-r--r--linux/drivers/media/video/hdpvr/hdpvr-video.c133
1 files changed, 78 insertions, 55 deletions
diff --git a/linux/drivers/media/video/hdpvr/hdpvr-video.c b/linux/drivers/media/video/hdpvr/hdpvr-video.c
index 235978003..3e6ffee8d 100644
--- a/linux/drivers/media/video/hdpvr/hdpvr-video.c
+++ b/linux/drivers/media/video/hdpvr/hdpvr-video.c
@@ -28,6 +28,13 @@
#define BULK_URB_TIMEOUT 1250 /* 1.25 seconds */
+#define print_buffer_status() { \
+ v4l2_dbg(MSG_BUFFER, hdpvr_debug, &dev->v4l2_dev, \
+ "%s:%d buffer stat: %d free, %d proc\n", \
+ __func__, __LINE__, \
+ list_size(&dev->free_buff_list), \
+ list_size(&dev->rec_buff_list)); }
+
struct hdpvr_fh {
struct hdpvr_device *dev;
};
@@ -117,21 +124,21 @@ int hdpvr_alloc_buffers(struct hdpvr_device *dev, uint count)
struct hdpvr_buffer *buf;
struct urb *urb;
- v4l2_dbg(MSG_INFO, hdpvr_debug, dev->video_dev,
+ v4l2_dbg(MSG_INFO, hdpvr_debug, &dev->v4l2_dev,
"allocating %u buffers\n", count);
for (i = 0; i < count; i++) {
buf = kzalloc(sizeof(struct hdpvr_buffer), GFP_KERNEL);
if (!buf) {
- err("cannot allocate buffer");
+ v4l2_err(&dev->v4l2_dev, "cannot allocate buffer\n");
goto exit;
}
buf->dev = dev;
urb = usb_alloc_urb(0, GFP_KERNEL);
if (!urb) {
- err("cannot allocate urb");
+ v4l2_err(&dev->v4l2_dev, "cannot allocate urb\n");
goto exit;
}
buf->urb = urb;
@@ -139,7 +146,8 @@ int hdpvr_alloc_buffers(struct hdpvr_device *dev, uint count)
mem = usb_buffer_alloc(dev->udev, dev->bulk_in_size, GFP_KERNEL,
&urb->transfer_dma);
if (!mem) {
- err("cannot allocate usb transfer buffer");
+ v4l2_err(&dev->v4l2_dev,
+ "cannot allocate usb transfer buffer\n");
goto exit;
}
@@ -172,7 +180,8 @@ static int hdpvr_submit_buffers(struct hdpvr_device *dev)
buf = list_entry(dev->free_buff_list.next, struct hdpvr_buffer,
buff_list);
if (buf->status != BUFSTAT_AVAILABLE) {
- err("buffer not marked as availbale");
+ v4l2_err(&dev->v4l2_dev,
+ "buffer not marked as availbale\n");
ret = -EFAULT;
goto err;
}
@@ -182,7 +191,9 @@ static int hdpvr_submit_buffers(struct hdpvr_device *dev)
urb->actual_length = 0;
ret = usb_submit_urb(urb, GFP_KERNEL);
if (ret) {
- err("usb_submit_urb in %s returned %d", __func__, ret);
+ v4l2_err(&dev->v4l2_dev,
+ "usb_submit_urb in %s returned %d\n",
+ __func__, ret);
if (++err_count > 2)
break;
continue;
@@ -191,10 +202,7 @@ static int hdpvr_submit_buffers(struct hdpvr_device *dev)
list_move_tail(&buf->buff_list, &dev->rec_buff_list);
}
err:
- v4l2_dbg(MSG_BUFFER, hdpvr_debug, dev->video_dev,
- "buffer queue stat: %d free, %d proc\n",
- list_size(&dev->free_buff_list),
- list_size(&dev->rec_buff_list));
+ print_buffer_status();
mutex_unlock(&dev->io_mutex);
return ret;
}
@@ -225,7 +233,7 @@ static void hdpvr_transmit_buffers(struct work_struct *work)
while (dev->status == STATUS_STREAMING) {
if (hdpvr_submit_buffers(dev)) {
- v4l2_err(dev->video_dev, "couldn't submit buffers\n");
+ v4l2_err(&dev->v4l2_dev, "couldn't submit buffers\n");
goto error;
}
if (wait_event_interruptible(dev->wait_buffer,
@@ -234,11 +242,11 @@ static void hdpvr_transmit_buffers(struct work_struct *work)
goto error;
}
- v4l2_dbg(MSG_INFO, hdpvr_debug, dev->video_dev,
+ v4l2_dbg(MSG_INFO, hdpvr_debug, &dev->v4l2_dev,
"transmit worker exited\n");
return;
error:
- v4l2_dbg(MSG_INFO, hdpvr_debug, dev->video_dev,
+ v4l2_dbg(MSG_INFO, hdpvr_debug, &dev->v4l2_dev,
"transmit buffers errored\n");
dev->status = STATUS_ERROR;
}
@@ -257,7 +265,7 @@ static int hdpvr_start_streaming(struct hdpvr_device *dev)
vidinf = get_video_info(dev);
if (vidinf) {
- v4l2_dbg(MSG_BUFFER, hdpvr_debug, dev->video_dev,
+ v4l2_dbg(MSG_BUFFER, hdpvr_debug, &dev->v4l2_dev,
"video signal: %dx%d@%dhz\n", vidinf->width,
vidinf->height, vidinf->fps);
kfree(vidinf);
@@ -266,7 +274,7 @@ static int hdpvr_start_streaming(struct hdpvr_device *dev)
ret = usb_control_msg(dev->udev,
usb_sndctrlpipe(dev->udev, 0),
0xb8, 0x38, 0x1, 0, NULL, 0, 8000);
- v4l2_dbg(MSG_BUFFER, hdpvr_debug, dev->video_dev,
+ v4l2_dbg(MSG_BUFFER, hdpvr_debug, &dev->v4l2_dev,
"encoder start control request returned %d\n", ret);
hdpvr_config_call(dev, CTRL_START_STREAMING_VALUE, 0x00);
@@ -274,14 +282,14 @@ static int hdpvr_start_streaming(struct hdpvr_device *dev)
INIT_WORK(&dev->worker, hdpvr_transmit_buffers);
queue_work(dev->workqueue, &dev->worker);
- v4l2_dbg(MSG_BUFFER, hdpvr_debug, dev->video_dev,
+ v4l2_dbg(MSG_BUFFER, hdpvr_debug, &dev->v4l2_dev,
"streaming started\n");
dev->status = STATUS_STREAMING;
return 0;
}
msleep(250);
- v4l2_dbg(MSG_INFO, hdpvr_debug, dev->video_dev,
+ v4l2_dbg(MSG_INFO, hdpvr_debug, &dev->v4l2_dev,
"no video signal at input %d\n", dev->options.video_input);
return -EAGAIN;
}
@@ -290,22 +298,50 @@ static int hdpvr_start_streaming(struct hdpvr_device *dev)
/* function expects dev->io_mutex to be hold by caller */
static int hdpvr_stop_streaming(struct hdpvr_device *dev)
{
+ uint actual_length, c = 0;
+ u8 *buf;
+
if (dev->status == STATUS_IDLE)
return 0;
else if (dev->status != STATUS_STREAMING)
return -EAGAIN;
+ buf = kmalloc(dev->bulk_in_size, GFP_KERNEL);
+ if (!buf)
+ v4l2_err(&dev->v4l2_dev, "failed to allocate temporary buffer "
+ "for emptying the internal device buffer. "
+ "Next capture start will be slow\n");
+
dev->status = STATUS_SHUTTING_DOWN;
hdpvr_config_call(dev, CTRL_STOP_STREAMING_VALUE, 0x00);
+ mutex_unlock(&dev->io_mutex);
wake_up_interruptible(&dev->wait_buffer);
msleep(50);
flush_workqueue(dev->workqueue);
+ mutex_lock(&dev->io_mutex);
/* kill the still outstanding urbs */
hdpvr_cancel_queue(dev);
+ /* emptying the device buffer beforeshutting it down */
+ while (buf && ++c < 500 &&
+ !usb_bulk_msg(dev->udev,
+ usb_rcvbulkpipe(dev->udev,
+ dev->bulk_in_endpointAddr),
+ buf, dev->bulk_in_size, &actual_length,
+ BULK_URB_TIMEOUT)) {
+ /* wait */
+ msleep(5);
+ v4l2_dbg(MSG_BUFFER, hdpvr_debug, &dev->v4l2_dev,
+ "%2d: got %d bytes\n", c, actual_length);
+ }
+ kfree(buf);
+ v4l2_dbg(MSG_BUFFER, hdpvr_debug, &dev->v4l2_dev,
+ "used %d urbs to empty device buffers\n", c-1);
+ msleep(10);
+
dev->status = STATUS_IDLE;
return 0;
@@ -325,14 +361,14 @@ static int hdpvr_open(struct file *file)
dev = (struct hdpvr_device *)video_get_drvdata(video_devdata(file));
if (!dev) {
- err("open failing with with ENODEV");
+ v4l2_err(&dev->v4l2_dev, "open failing with with ENODEV\n");
retval = -ENODEV;
goto err;
}
fh = kzalloc(sizeof(struct hdpvr_fh), GFP_KERNEL);
if (!fh) {
- err("Out of memory?");
+ v4l2_err(&dev->v4l2_dev, "Out of memory\n");
goto err;
}
/* lock the device to allow correctly handling errors
@@ -391,19 +427,15 @@ static ssize_t hdpvr_read(struct file *file, char __user *buffer, size_t count,
mutex_lock(&dev->io_mutex);
if (dev->status == STATUS_IDLE) {
if (hdpvr_start_streaming(dev)) {
- v4l2_dbg(MSG_INFO, hdpvr_debug, dev->video_dev,
- "start_streaming failed");
+ v4l2_dbg(MSG_INFO, hdpvr_debug, &dev->v4l2_dev,
+ "start_streaming failed\n");
ret = -EIO;
msleep(200);
dev->status = STATUS_IDLE;
mutex_unlock(&dev->io_mutex);
goto err;
}
-
- v4l2_dbg(MSG_BUFFER, hdpvr_debug, dev->video_dev,
- "buffer queue stat: %d free, %d proc\n",
- list_size(&dev->free_buff_list),
- list_size(&dev->rec_buff_list));
+ print_buffer_status();
}
mutex_unlock(&dev->io_mutex);
@@ -444,7 +476,7 @@ static ssize_t hdpvr_read(struct file *file, char __user *buffer, size_t count,
if (copy_to_user(buffer, urb->transfer_buffer + buf->pos,
cnt)) {
- err("read: copy_to_user failed");
+ v4l2_err(&dev->v4l2_dev, "read: copy_to_user failed\n");
if (!ret)
ret = -EFAULT;
goto err;
@@ -463,10 +495,7 @@ static ssize_t hdpvr_read(struct file *file, char __user *buffer, size_t count,
list_move_tail(&buf->buff_list, &dev->free_buff_list);
- v4l2_dbg(MSG_BUFFER, hdpvr_debug, dev->video_dev,
- "buffer queue stat: %d free, %d proc\n",
- list_size(&dev->free_buff_list),
- list_size(&dev->rec_buff_list));
+ print_buffer_status();
mutex_unlock(&dev->io_mutex);
@@ -483,6 +512,7 @@ err:
static unsigned int hdpvr_poll(struct file *filp, poll_table *wait)
{
+ struct hdpvr_buffer *buf = NULL;
struct hdpvr_fh *fh = (struct hdpvr_fh *)filp->private_data;
struct hdpvr_device *dev = fh->dev;
unsigned int mask = 0;
@@ -494,31 +524,23 @@ static unsigned int hdpvr_poll(struct file *filp, poll_table *wait)
if (dev->status == STATUS_IDLE) {
if (hdpvr_start_streaming(dev)) {
- v4l2_dbg(MSG_BUFFER, hdpvr_debug, dev->video_dev,
- "start_streaming failed");
+ v4l2_dbg(MSG_BUFFER, hdpvr_debug, &dev->v4l2_dev,
+ "start_streaming failed\n");
dev->status = STATUS_IDLE;
}
- v4l2_dbg(MSG_BUFFER, hdpvr_debug, dev->video_dev,
- "buffer queue stat: %d free, %d proc\n",
- list_size(&dev->free_buff_list),
- list_size(&dev->rec_buff_list));
+ print_buffer_status();
}
mutex_unlock(&dev->io_mutex);
- poll_wait(filp, &dev->wait_data, wait);
-
- mutex_lock(&dev->io_mutex);
- if (!list_empty(&dev->rec_buff_list)) {
-
- struct hdpvr_buffer *buf = list_entry(dev->rec_buff_list.next,
- struct hdpvr_buffer,
- buff_list);
-
- if (buf->status == BUFSTAT_READY)
- mask |= POLLIN | POLLRDNORM;
+ buf = hdpvr_get_next_buffer(dev);
+ /* only wait if no data is available */
+ if (!buf || buf->status != BUFSTAT_READY) {
+ poll_wait(filp, &dev->wait_data, wait);
+ buf = hdpvr_get_next_buffer(dev);
}
- mutex_unlock(&dev->io_mutex);
+ if (buf && buf->status == BUFSTAT_READY)
+ mask |= POLLIN | POLLRDNORM;
return mask;
}
@@ -1139,9 +1161,9 @@ static int vidioc_encoder_cmd(struct file *filp, void *priv,
res = hdpvr_stop_streaming(dev);
break;
default:
- v4l2_dbg(MSG_INFO, hdpvr_debug, dev->video_dev,
+ v4l2_dbg(MSG_INFO, hdpvr_debug, &dev->v4l2_dev,
"Unsupported encoder cmd %d\n", a->cmd);
- return -EINVAL;
+ res = -EINVAL;
}
mutex_unlock(&dev->io_mutex);
return res;
@@ -1200,22 +1222,23 @@ static const struct video_device hdpvr_video_template = {
V4L2_STD_PAL_60,
};
-int hdpvr_register_videodev(struct hdpvr_device *dev, int devnum)
+int hdpvr_register_videodev(struct hdpvr_device *dev, struct device *parent,
+ int devnum)
{
/* setup and register video device */
dev->video_dev = video_device_alloc();
if (!dev->video_dev) {
- err("video_device_alloc() failed");
+ v4l2_err(&dev->v4l2_dev, "video_device_alloc() failed\n");
goto error;
}
*(dev->video_dev) = hdpvr_video_template;
strcpy(dev->video_dev->name, "Hauppauge HD PVR");
- dev->video_dev->parent = &dev->udev->dev;
+ dev->video_dev->parent = parent;
video_set_drvdata(dev->video_dev, dev);
if (video_register_device(dev->video_dev, VFL_TYPE_GRABBER, devnum)) {
- err("V4L2 device registration failed");
+ v4l2_err(&dev->v4l2_dev, "video_device registration failed\n");
goto error;
}