/*
* Hauppauge HD PVR USB driver - video 4 linux 2 interface
*
* Copyright (C) 2008 Janne Grunau (j@jannau.net)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation, version 2.
*
*/
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/module.h>
#include <linux/uaccess.h>
#include <linux/usb.h>
#include <linux/mutex.h>
#include <linux/version.h>
#include <linux/workqueue.h>
#include <linux/videodev2.h>
#include <media/v4l2-dev.h>
#include <media/v4l2-common.h>
#include <media/v4l2-ioctl.h>
#include "hdpvr.h"
#define BULK_URB_TIMEOUT 1250 /* 1.25 seconds */
struct hdpvr_fh {
struct hdpvr_device *dev;
};
static uint list_size(struct list_head *list)
{
struct list_head *tmp;
uint count = 0;
list_for_each(tmp, list) {
count++;
}
return count;
}
/*=========================================================================*/
/* urb callback */
static void hdpvr_read_bulk_callback(struct urb *urb)
{
struct hdpvr_buffer *buf = (struct hdpvr_buffer *)urb->context;
struct hdpvr_device *dev = buf->dev;
/* marking buffer as received and wake waiting */
buf->status = BUFSTAT_READY;
wake_up_interruptible(&dev->wait_data);
}
/*=========================================================================*/
/* bufffer bits */
/* function expects dev->io_mutex to be hold by caller */
int hdpvr_cancel_queue(struct hdpvr_device *dev)
{
struct hdpvr_buffer *buf;
list_for_each_entry(buf, &dev->rec_buff_list, buff_list) {
usb_kill_urb(buf->urb);
buf->status = BUFSTAT_AVAILABLE;
}
list_splice_init(&dev->rec_buff_list, dev->free_buff_list.prev);
return 0;
}
static int hdpvr_free_queue(struct list_head *q)
{
struct list_head *tmp;
struct list_head *p;
struct hdpvr_buffer *buf;
struct urb *urb;
for (p = q->next; p != q;) {
buf = list_entry(p, struct hdpvr_buffer, buff_list);
urb = buf->urb;
usb_buffer_free(urb->dev, urb->transfer_buffer_length,
urb->transfer_buffer, urb->transfer_dma);
usb_free_urb(urb);
tmp = p->next;
list_del(p);
kfree(buf);
p = tmp;
}
return 0;
}
/* function expects dev->io_mutex to be hold by caller */
int hdpvr_free_buffers(struct hdpvr_device *dev)
{
hdpvr_cancel_queue(dev);
hdpvr_free_queue(&dev->free_buff_list);
hdpvr_free_queue(&dev->rec_buff_list);
return 0;
}
/* function expects dev->io_mutex to be hold by caller */
int hdpvr_alloc_buffers(struct hdpvr_device *dev, uint count)
{
uint i;
int retval = -ENOMEM;
u8 *mem