diff options
Diffstat (limited to 'drivers/media/platform/vino.c')
-rw-r--r-- | drivers/media/platform/vino.c | 4345 |
1 files changed, 0 insertions, 4345 deletions
diff --git a/drivers/media/platform/vino.c b/drivers/media/platform/vino.c deleted file mode 100644 index 2c85357f774d..000000000000 --- a/drivers/media/platform/vino.c +++ /dev/null @@ -1,4345 +0,0 @@ -/* - * Driver for the VINO (Video In No Out) system found in SGI Indys. - * - * This file is subject to the terms and conditions of the GNU General Public - * License version 2 as published by the Free Software Foundation. - * - * Copyright (C) 2004,2005 Mikael Nousiainen <tmnousia@cc.hut.fi> - * - * Based on the previous version of the driver for 2.4 kernels by: - * Copyright (C) 2003 Ladislav Michl <ladis@linux-mips.org> - * - * v4l2_device/v4l2_subdev conversion by: - * Copyright (C) 2009 Hans Verkuil <hverkuil@xs4all.nl> - * - * Note: this conversion is untested! Please contact the linux-media - * mailinglist if you can test this, together with the test results. - */ - -/* - * TODO: - * - remove "mark pages reserved-hacks" from memory allocation code - * and implement fault() - * - check decimation, calculating and reporting image size when - * using decimation - * - implement read(), user mode buffers and overlay (?) - */ - -#include <linux/init.h> -#include <linux/module.h> -#include <linux/delay.h> -#include <linux/dma-mapping.h> -#include <linux/errno.h> -#include <linux/fs.h> -#include <linux/interrupt.h> -#include <linux/kernel.h> -#include <linux/slab.h> -#include <linux/mm.h> -#include <linux/time.h> -#include <linux/kmod.h> - -#include <linux/i2c.h> - -#include <linux/videodev2.h> -#include <media/v4l2-device.h> -#include <media/v4l2-ioctl.h> -#include <linux/mutex.h> - -#include <asm/paccess.h> -#include <asm/io.h> -#include <asm/sgi/ip22.h> -#include <asm/sgi/mc.h> - -#include "vino.h" -#include "saa7191.h" -#include "indycam.h" - -/* Uncomment the following line to get lots and lots of (mostly useless) - * debug info. - * Note that the debug output also slows down the driver significantly */ -// #define VINO_DEBUG -// #define VINO_DEBUG_INT - -#define VINO_MODULE_VERSION "0.0.7" - -MODULE_DESCRIPTION("SGI VINO Video4Linux2 driver"); -MODULE_VERSION(VINO_MODULE_VERSION); -MODULE_AUTHOR("Mikael Nousiainen <tmnousia@cc.hut.fi>"); -MODULE_LICENSE("GPL"); - -#ifdef VINO_DEBUG -#define dprintk(x...) printk("VINO: " x); -#else -#define dprintk(x...) -#endif - -#define VINO_NO_CHANNEL 0 -#define VINO_CHANNEL_A 1 -#define VINO_CHANNEL_B 2 - -#define VINO_PAL_WIDTH 768 -#define VINO_PAL_HEIGHT 576 -#define VINO_NTSC_WIDTH 640 -#define VINO_NTSC_HEIGHT 480 - -#define VINO_MIN_WIDTH 32 -#define VINO_MIN_HEIGHT 32 - -#define VINO_CLIPPING_START_ODD_D1 1 -#define VINO_CLIPPING_START_ODD_PAL 15 -#define VINO_CLIPPING_START_ODD_NTSC 12 - -#define VINO_CLIPPING_START_EVEN_D1 2 -#define VINO_CLIPPING_START_EVEN_PAL 15 -#define VINO_CLIPPING_START_EVEN_NTSC 12 - -#define VINO_INPUT_CHANNEL_COUNT 3 - -/* the number is the index for vino_inputs */ -#define VINO_INPUT_NONE -1 -#define VINO_INPUT_COMPOSITE 0 -#define VINO_INPUT_SVIDEO 1 -#define VINO_INPUT_D1 2 - -#define VINO_PAGE_RATIO (PAGE_SIZE / VINO_PAGE_SIZE) - -#define VINO_FIFO_THRESHOLD_DEFAULT 16 - -#define VINO_FRAMEBUFFER_SIZE ((VINO_PAL_WIDTH \ - * VINO_PAL_HEIGHT * 4 \ - + 3 * PAGE_SIZE) & ~(PAGE_SIZE - 1)) - -#define VINO_FRAMEBUFFER_COUNT_MAX 8 - -#define VINO_FRAMEBUFFER_UNUSED 0 -#define VINO_FRAMEBUFFER_IN_USE 1 -#define VINO_FRAMEBUFFER_READY 2 - -#define VINO_QUEUE_ERROR -1 -#define VINO_QUEUE_MAGIC 0x20050125 - -#define VINO_MEMORY_NONE 0 -#define VINO_MEMORY_MMAP 1 -#define VINO_MEMORY_USERPTR 2 - -#define VINO_DUMMY_DESC_COUNT 4 -#define VINO_DESC_FETCH_DELAY 5 /* microseconds */ - -#define VINO_MAX_FRAME_SKIP_COUNT 128 - -/* the number is the index for vino_data_formats */ -#define VINO_DATA_FMT_NONE -1 -#define VINO_DATA_FMT_GREY 0 -#define VINO_DATA_FMT_RGB332 1 -#define VINO_DATA_FMT_RGB32 2 -#define VINO_DATA_FMT_YUV 3 - -#define VINO_DATA_FMT_COUNT 4 - -/* the number is the index for vino_data_norms */ -#define VINO_DATA_NORM_NONE -1 -#define VINO_DATA_NORM_NTSC 0 -#define VINO_DATA_NORM_PAL 1 -#define VINO_DATA_NORM_SECAM 2 -#define VINO_DATA_NORM_D1 3 - -#define VINO_DATA_NORM_COUNT 4 - -/* I2C controller flags */ -#define SGI_I2C_FORCE_IDLE (0 << 0) -#define SGI_I2C_NOT_IDLE (1 << 0) -#define SGI_I2C_WRITE (0 << 1) -#define SGI_I2C_READ (1 << 1) -#define SGI_I2C_RELEASE_BUS (0 << 2) -#define SGI_I2C_HOLD_BUS (1 << 2) -#define SGI_I2C_XFER_DONE (0 << 4) -#define SGI_I2C_XFER_BUSY (1 << 4) -#define SGI_I2C_ACK (0 << 5) -#define SGI_I2C_NACK (1 << 5) -#define SGI_I2C_BUS_OK (0 << 7) -#define SGI_I2C_BUS_ERR (1 << 7) - -/* Internal data structure definitions */ - -struct vino_input { - char *name; - v4l2_std_id std; -}; - -struct vino_clipping { - unsigned int left, right, top, bottom; -}; - -struct vino_data_format { - /* the description */ - char *description; - /* bytes per pixel */ - unsigned int bpp; - /* V4L2 fourcc code */ - __u32 pixelformat; - /* V4L2 colorspace (duh!) */ - enum v4l2_colorspace colorspace; -}; - -struct vino_data_norm { - char *description; - unsigned int width, height; - struct vino_clipping odd; - struct vino_clipping even; - - v4l2_std_id std; - unsigned int fps_min, fps_max; - __u32 framelines; -}; - -struct vino_descriptor_table { - /* the number of PAGE_SIZE sized pages in the buffer */ - unsigned int page_count; - /* virtual (kmalloc'd) pointers to the actual data - * (in PAGE_SIZE chunks, used with mmap streaming) */ - unsigned long *virtual; - - /* cpu address for the VINO descriptor table - * (contains DMA addresses, VINO_PAGE_SIZE chunks) */ - unsigned long *dma_cpu; - /* dma address for the VINO descriptor table - * (contains DMA addresses, VINO_PAGE_SIZE chunks) */ - dma_addr_t dma; -}; - -struct vino_framebuffer { - /* identifier nubmer */ - unsigned int id; - /* the length of the whole buffer */ - unsigned int size; - /* the length of actual data in buffer */ - unsigned int data_size; - /* the data format */ - unsigned int data_format; - /* the state of buffer data */ - unsigned int state; - /* is the buffer mapped in user space? */ - unsigned int map_count; - /* memory offset for mmap() */ - unsigned int offset; - /* frame counter */ - unsigned int frame_counter; - /* timestamp (written when image capture finishes) */ - struct timeval timestamp; - - struct vino_descriptor_table desc_table; - - spinlock_t state_lock; -}; - -struct vino_framebuffer_fifo { - unsigned int length; - - unsigned int used; - unsigned int head; - unsigned int tail; - - unsigned int data[VINO_FRAMEBUFFER_COUNT_MAX]; -}; - -struct vino_framebuffer_queue { - unsigned int magic; - - /* VINO_MEMORY_NONE, VINO_MEMORY_MMAP or VINO_MEMORY_USERPTR */ - unsigned int type; - unsigned int length; - - /* data field of in and out contain index numbers for buffer */ - struct vino_framebuffer_fifo in; - struct vino_framebuffer_fifo out; - - struct vino_framebuffer *buffer[VINO_FRAMEBUFFER_COUNT_MAX]; - - spinlock_t queue_lock; - struct mutex queue_mutex; - wait_queue_head_t frame_wait_queue; -}; - -struct vino_interrupt_data { - struct timeval timestamp; - unsigned int frame_counter; - unsigned int skip_count; - unsigned int skip; -}; - -struct vino_channel_settings { - unsigned int channel; - - int input; - unsigned int data_format; - unsigned int data_norm; - struct vino_clipping clipping; - unsigned int decimation; - unsigned int line_size; - unsigned int alpha; - unsigned int fps; - unsigned int framert_reg; - - unsigned int fifo_threshold; - - struct vino_framebuffer_queue fb_queue; - - /* number of the current field */ - unsigned int field; - - /* read in progress */ - int reading; - /* streaming is active */ - int streaming; - /* the driver is currently processing the queue */ - int capturing; - - struct mutex mutex; - spinlock_t capture_lock; - - unsigned int users; - - struct vino_interrupt_data int_data; - - /* V4L support */ - struct video_device *vdev; -}; - -struct vino_settings { - struct v4l2_device v4l2_dev; - struct vino_channel_settings a; - struct vino_channel_settings b; - - /* the channel which owns this client: - * VINO_NO_CHANNEL, VINO_CHANNEL_A or VINO_CHANNEL_B */ - unsigned int decoder_owner; - struct v4l2_subdev *decoder; - unsigned int camera_owner; - struct v4l2_subdev *camera; - - /* a lock for vino register access */ - spinlock_t vino_lock; - /* a lock for channel input changes */ - spinlock_t input_lock; - - unsigned long dummy_page; - struct vino_descriptor_table dummy_desc_table; -}; - -/* Module parameters */ - -/* - * Using vino_pixel_conversion the ABGR32-format pixels supplied - * by the VINO chip can be converted to more common formats - * like RGBA32 (or probably RGB24 in the future). This way we - * can give out data that can be specified correctly with - * the V4L2-definitions. - * - * The pixel format is specified as RGBA32 when no conversion - * is used. - * - * Note that this only affects the 32-bit bit depth. - * - * Use non-zero value to enable conversion. - */ -static int vino_pixel_conversion; - -module_param_named(pixelconv, vino_pixel_conversion, int, 0); - -MODULE_PARM_DESC(pixelconv, - "enable pixel conversion (non-zero value enables)"); - -/* Internal data structures */ - -static struct sgi_vino *vino; - -static struct vino_settings *vino_drvdata; - -#define camera_call(o, f, args...) \ - v4l2_subdev_call(vino_drvdata->camera, o, f, ##args) -#define decoder_call(o, f, args...) \ - v4l2_subdev_call(vino_drvdata->decoder, o, f, ##args) - -static const char *vino_driver_name = "vino"; -static const char *vino_driver_description = "SGI VINO"; -static const char *vino_bus_name = "GIO64 bus"; -static const char *vino_vdev_name_a = "SGI VINO Channel A"; -static const char *vino_vdev_name_b = "SGI VINO Channel B"; - -static void vino_capture_tasklet(unsigned long channel); - -DECLARE_TASKLET(vino_tasklet_a, vino_capture_tasklet, VINO_CHANNEL_A); -DECLARE_TASKLET(vino_tasklet_b, vino_capture_tasklet, VINO_CHANNEL_B); - -static const struct vino_input vino_inputs[] = { - { - .name = "Composite", - .std = V4L2_STD_NTSC | V4L2_STD_PAL - | V4L2_STD_SECAM, - }, { - .name = "S-Video", - .std = V4L2_STD_NTSC | V4L2_STD_PAL - | V4L2_STD_SECAM, - }, { - .name = "D1/IndyCam", - .std = V4L2_STD_NTSC, - } -}; - -static const struct vino_data_format vino_data_formats[] = { - { - .description = "8-bit greyscale", - .bpp = 1, - .pixelformat = V4L2_PIX_FMT_GREY, - .colorspace = V4L2_COLORSPACE_SMPTE170M, - }, { - .description = "8-bit dithered RGB 3-3-2", - .bpp = 1, - .pixelformat = V4L2_PIX_FMT_RGB332, - .colorspace = V4L2_COLORSPACE_SRGB, - }, { - .description = "32-bit RGB", - .bpp = 4, - .pixelformat = V4L2_PIX_FMT_RGB32, - .colorspace = V4L2_COLORSPACE_SRGB, - }, { - .description = "YUV 4:2:2", - .bpp = 2, - .pixelformat = V4L2_PIX_FMT_YUYV, // XXX: swapped? - .colorspace = V4L2_COLORSPACE_SMPTE170M, - } -}; - -static const struct vino_data_norm vino_data_norms[] = { - { - .description = "NTSC", - .std = V4L2_STD_NTSC, - .fps_min = 6, - .fps_max = 30, - .framelines = 525, - .width = VINO_NTSC_WIDTH, - .height = VINO_NTSC_HEIGHT, - .odd = { - .top = VINO_CLIPPING_START_ODD_NTSC, - .left = 0, - .bottom = VINO_CLIPPING_START_ODD_NTSC - + VINO_NTSC_HEIGHT / 2 - 1, - .right = VINO_NTSC_WIDTH, - }, - .even = { - .top = VINO_CLIPPING_START_EVEN_NTSC, - .left = 0, - .bottom = VINO_CLIPPING_START_EVEN_NTSC - + VINO_NTSC_HEIGHT / 2 - 1, - .right = VINO_NTSC_WIDTH, - }, - }, { - .description = "PAL", - .std = V4L2_STD_PAL, - .fps_min = 5, - .fps_max = 25, - .framelines = 625, - .width = VINO_PAL_WIDTH, - .height = VINO_PAL_HEIGHT, - .odd = { - .top = VINO_CLIPPING_START_ODD_PAL, - .left = 0, - .bottom = VINO_CLIPPING_START_ODD_PAL - + VINO_PAL_HEIGHT / 2 - 1, - .right = VINO_PAL_WIDTH, - }, - .even = { - .top = VINO_CLIPPING_START_EVEN_PAL, - .left = 0, - .bottom = VINO_CLIPPING_START_EVEN_PAL - + VINO_PAL_HEIGHT / 2 - 1, - .right = VINO_PAL_WIDTH, - }, - }, { - .description = "SECAM", - .std = V4L2_STD_SECAM, - .fps_min = 5, - .fps_max = 25, - .framelines = 625, - .width = VINO_PAL_WIDTH, - .height = VINO_PAL_HEIGHT, - .odd = { - .top = VINO_CLIPPING_START_ODD_PAL, - .left = 0, - .bottom = VINO_CLIPPING_START_ODD_PAL - + VINO_PAL_HEIGHT / 2 - 1, - .right = VINO_PAL_WIDTH, - }, - .even = { - .top = VINO_CLIPPING_START_EVEN_PAL, - .left = 0, - .bottom = VINO_CLIPPING_START_EVEN_PAL - + VINO_PAL_HEIGHT / 2 - 1, - .right = VINO_PAL_WIDTH, - }, - }, { - .description = "NTSC/D1", - .std = V4L2_STD_NTSC, - .fps_min = 6, - .fps_max = 30, - .framelines = 525, - .width = VINO_NTSC_WIDTH, - .height = VINO_NTSC_HEIGHT, - .odd = { - .top = VINO_CLIPPING_START_ODD_D1, - .left = 0, - .bottom = VINO_CLIPPING_START_ODD_D1 - + VINO_NTSC_HEIGHT / 2 - 1, - .right = VINO_NTSC_WIDTH, - }, - .even = { - .top = VINO_CLIPPING_START_EVEN_D1, - .left = 0, - .bottom = VINO_CLIPPING_START_EVEN_D1 - + VINO_NTSC_HEIGHT / 2 - 1, - .right = VINO_NTSC_WIDTH, - }, - } -}; - -#define VINO_INDYCAM_V4L2_CONTROL_COUNT 9 - -struct v4l2_queryctrl vino_indycam_v4l2_controls[] = { - { - .id = V4L2_CID_AUTOGAIN, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "Automatic Gain Control", - .minimum = 0, - .maximum = 1, - .step = 1, - .default_value = INDYCAM_AGC_DEFAULT, - }, { - .id = V4L2_CID_AUTO_WHITE_BALANCE, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "Automatic White Balance", - .minimum = 0, - .maximum = 1, - .step = 1, - .default_value = INDYCAM_AWB_DEFAULT, - }, { - .id = V4L2_CID_GAIN, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Gain", - .minimum = INDYCAM_GAIN_MIN, - .maximum = INDYCAM_GAIN_MAX, - .step = 1, - .default_value = INDYCAM_GAIN_DEFAULT, - }, { - .id = INDYCAM_CONTROL_RED_SATURATION, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Red Saturation", - .minimum = INDYCAM_RED_SATURATION_MIN, - .maximum = INDYCAM_RED_SATURATION_MAX, - .step = 1, - .default_value = INDYCAM_RED_SATURATION_DEFAULT, - }, { - .id = INDYCAM_CONTROL_BLUE_SATURATION, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Blue Saturation", - .minimum = INDYCAM_BLUE_SATURATION_MIN, - .maximum = INDYCAM_BLUE_SATURATION_MAX, - .step = 1, - .default_value = INDYCAM_BLUE_SATURATION_DEFAULT, - }, { - .id = V4L2_CID_RED_BALANCE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Red Balance", - .minimum = INDYCAM_RED_BALANCE_MIN, - .maximum = INDYCAM_RED_BALANCE_MAX, - .step = 1, - .default_value = INDYCAM_RED_BALANCE_DEFAULT, - }, { - .id = V4L2_CID_BLUE_BALANCE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Blue Balance", - .minimum = INDYCAM_BLUE_BALANCE_MIN, - .maximum = INDYCAM_BLUE_BALANCE_MAX, - .step = 1, - .default_value = INDYCAM_BLUE_BALANCE_DEFAULT, - }, { - .id = V4L2_CID_EXPOSURE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Shutter Control", - .minimum = INDYCAM_SHUTTER_MIN, - .maximum = INDYCAM_SHUTTER_MAX, - .step = 1, - .default_value = INDYCAM_SHUTTER_DEFAULT, - }, { - .id = V4L2_CID_GAMMA, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Gamma", - .minimum = INDYCAM_GAMMA_MIN, - .maximum = INDYCAM_GAMMA_MAX, - .step = 1, - .default_value = INDYCAM_GAMMA_DEFAULT, - } -}; - -#define VINO_SAA7191_V4L2_CONTROL_COUNT 9 - -struct v4l2_queryctrl vino_saa7191_v4l2_controls[] = { - { - .id = V4L2_CID_HUE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Hue", - .minimum = SAA7191_HUE_MIN, - .maximum = SAA7191_HUE_MAX, - .step = 1, - .default_value = SAA7191_HUE_DEFAULT, - }, { - .id = SAA7191_CONTROL_BANDPASS, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Luminance Bandpass", - .minimum = SAA7191_BANDPASS_MIN, - .maximum = SAA7191_BANDPASS_MAX, - .step = 1, - .default_value = SAA7191_BANDPASS_DEFAULT, - }, { - .id = SAA7191_CONTROL_BANDPASS_WEIGHT, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Luminance Bandpass Weight", - .minimum = SAA7191_BANDPASS_WEIGHT_MIN, - .maximum = SAA7191_BANDPASS_WEIGHT_MAX, - .step = 1, - .default_value = SAA7191_BANDPASS_WEIGHT_DEFAULT, - }, { - .id = SAA7191_CONTROL_CORING, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "HF Luminance Coring", - .minimum = SAA7191_CORING_MIN, - .maximum = SAA7191_CORING_MAX, - .step = 1, - .default_value = SAA7191_CORING_DEFAULT, - }, { - .id = SAA7191_CONTROL_FORCE_COLOUR, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "Force Colour", - .minimum = SAA7191_FORCE_COLOUR_MIN, - .maximum = SAA7191_FORCE_COLOUR_MAX, - .step = 1, - .default_value = SAA7191_FORCE_COLOUR_DEFAULT, - }, { - .id = SAA7191_CONTROL_CHROMA_GAIN, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Chrominance Gain Control", - .minimum = SAA7191_CHROMA_GAIN_MIN, - .maximum = SAA7191_CHROMA_GAIN_MAX, - .step = 1, - .default_value = SAA7191_CHROMA_GAIN_DEFAULT, - }, { - .id = SAA7191_CONTROL_VTRC, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "VTR Time Constant", - .minimum = SAA7191_VTRC_MIN, - .maximum = SAA7191_VTRC_MAX, - .step = 1, - .default_value = SAA7191_VTRC_DEFAULT, - }, { - .id = SAA7191_CONTROL_LUMA_DELAY, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Luminance Delay Compensation", - .minimum = SAA7191_LUMA_DELAY_MIN, - .maximum = SAA7191_LUMA_DELAY_MAX, - .step = 1, - .default_value = SAA7191_LUMA_DELAY_DEFAULT, - }, { - .id = SAA7191_CONTROL_VNR, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Vertical Noise Reduction", - .minimum = SAA7191_VNR_MIN, - .maximum = SAA7191_VNR_MAX, - .step = 1, - .default_value = SAA7191_VNR_DEFAULT, - } -}; - -/* VINO framebuffer/DMA descriptor management */ - -static void vino_free_buffer_with_count(struct vino_framebuffer *fb, - unsigned int count) -{ - unsigned int i; - - dprintk("vino_free_buffer_with_count(): count = %d\n", count); - - for (i = 0; i < count; i++) { - ClearPageReserved(virt_to_page((void *)fb->desc_table.virtual[i])); - dma_unmap_single(NULL, - fb->desc_table.dma_cpu[VINO_PAGE_RATIO * i], - PAGE_SIZE, DMA_FROM_DEVICE); - free_page(fb->desc_table.virtual[i]); - } - - dma_free_coherent(NULL, - VINO_PAGE_RATIO * (fb->desc_table.page_count + 4) * - sizeof(dma_addr_t), (void *)fb->desc_table.dma_cpu, - fb->desc_table.dma); - kfree(fb->desc_table.virtual); - - memset(fb, 0, sizeof(struct vino_framebuffer)); -} - -static void vino_free_buffer(struct vino_framebuffer *fb) -{ - vino_free_buffer_with_count(fb, fb->desc_table.page_count); -} - -static int vino_allocate_buffer(struct vino_framebuffer *fb, - unsigned int size) -{ - unsigned int count, i, j; - int ret = 0; - - dprintk("vino_allocate_buffer():\n"); - - if (size < 1) - return -EINVAL; - - memset(fb, 0, sizeof(struct vino_framebuffer)); - - count = ((size / PAGE_SIZE) + 4) & ~3; - - dprintk("vino_allocate_buffer(): size = %d, count = %d\n", - size, count); - - /* allocate memory for table with virtual (page) addresses */ - fb->desc_table.virtual = - kmalloc(count * sizeof(unsigned long), GFP_KERNEL); - if (!fb->desc_table.virtual) - return -ENOMEM; - - /* allocate memory for table with dma addresses - * (has space for four extra descriptors) */ - fb->desc_table.dma_cpu = - dma_alloc_coherent(NULL, VINO_PAGE_RATIO * (count + 4) * - sizeof(dma_addr_t), &fb->desc_table.dma, - GFP_KERNEL | GFP_DMA); - if (!fb->desc_table.dma_cpu) { - ret = -ENOMEM; - goto out_free_virtual; - } - - /* allocate pages for the buffer and acquire the according - * dma addresses */ - for (i = 0; i < count; i++) { - dma_addr_t dma_data_addr; - - fb->desc_table.virtual[i] = - get_zeroed_page(GFP_KERNEL | GFP_DMA); - if (!fb->desc_table.virtual[i]) { - ret = -ENOBUFS; - break; - } - - dma_data_addr = - dma_map_single(NULL, - (void *)fb->desc_table.virtual[i], - PAGE_SIZE, DMA_FROM_DEVICE); - - for (j = 0; j < VINO_PAGE_RATIO; j++) { - fb->desc_table.dma_cpu[VINO_PAGE_RATIO * i + j] = - dma_data_addr + VINO_PAGE_SIZE * j; - } - - SetPageReserved(virt_to_page((void *)fb->desc_table.virtual[i])); - } - - /* page_count needs to be set anyway, because the descriptor table has - * been allocated according to this number */ - fb->desc_table.page_count = count; - - if (ret) { - /* the descriptor with index i doesn't contain - * a valid address yet */ - vino_free_buffer_with_count(fb, i); - return ret; - } - - //fb->size = size; - fb->size = count * PAGE_SIZE; - fb->data_format = VINO_DATA_FMT_NONE; - - /* set the dma stop-bit for the last (count+1)th descriptor */ - fb->desc_table.dma_cpu[VINO_PAGE_RATIO * count] = VINO_DESC_STOP; - return 0; - - out_free_virtual: - kfree(fb->desc_table.virtual); - return ret; -} - -#if 0 -/* user buffers not fully implemented yet */ -static int vino_prepare_user_buffer(struct vino_framebuffer *fb, - void *user, - unsigned int size) -{ - unsigned int count, i, j; - int ret = 0; - - dprintk("vino_prepare_user_buffer():\n"); - - if (size < 1) - return -EINVAL; - - memset(fb, 0, sizeof(struct vino_framebuffer)); - - count = ((size / PAGE_SIZE)) & ~3; - - dprintk("vino_prepare_user_buffer(): size = %d, count = %d\n", - size, count); - - /* allocate memory for table with virtual (page) addresses */ - fb->desc_table.virtual = (unsigned long *) - kmalloc(count * sizeof(unsigned long), GFP_KERNEL); - if (!fb->desc_table.virtual) - return -ENOMEM; - - /* allocate memory for table with dma addresses - * (has space for four extra descriptors) */ - fb->desc_table.dma_cpu = - dma_alloc_coherent(NULL, VINO_PAGE_RATIO * (count + 4) * - sizeof(dma_addr_t), &fb->desc_table.dma, - GFP_KERNEL | GFP_DMA); - if (!fb->desc_table.dma_cpu) { - ret = -ENOMEM; - goto out_free_virtual; - } - - /* allocate pages for the buffer and acquire the according - * dma addresses */ - for (i = 0; i < count; i++) { - dma_addr_t dma_data_addr; - - fb->desc_table.virtual[i] = - get_zeroed_page(GFP_KERNEL | GFP_DMA); - if (!fb->desc_table.virtual[i]) { - ret = -ENOBUFS; - break; - } - - dma_data_addr = - dma_map_single(NULL, - (void *)fb->desc_table.virtual[i], - PAGE_SIZE, DMA_FROM_DEVICE); - - for (j = 0; j < VINO_PAGE_RATIO; j++) { - fb->desc_table.dma_cpu[VINO_PAGE_RATIO * i + j] = - dma_data_addr + VINO_PAGE_SIZE * j; - } - - SetPageReserved(virt_to_page((void *)fb->desc_table.virtual[i])); - } - - /* page_count needs to be set anyway, because the descriptor table has - * been allocated according to this number */ - fb->desc_table.page_count = count; - - if (ret) { - /* the descriptor with index i doesn't contain - * a valid address yet */ - vino_free_buffer_with_count(fb, i); - return ret; - } - - //fb->size = size; - fb->size = count * PAGE_SIZE; - - /* set the dma stop-bit for the last (count+1)th descriptor */ - fb->desc_table.dma_cpu[VINO_PAGE_RATIO * count] = VINO_DESC_STOP; - return 0; - - out_free_virtual: - kfree(fb->desc_table.virtual); - return ret; -} -#endif - -static void vino_sync_buffer(struct vino_framebuffer *fb) -{ - int i; - - dprintk("vino_sync_buffer():\n"); - - for (i = 0; i < fb->desc_table.page_count; i++) - dma_sync_single_for_cpu(NULL, - fb->desc_table.dma_cpu[VINO_PAGE_RATIO * i], - PAGE_SIZE, DMA_FROM_DEVICE); -} - -/* Framebuffer fifo functions (need to be locked externally) */ - -static inline void vino_fifo_init(struct vino_framebuffer_fifo *f, - unsigned int length) -{ - f->length = 0; - f->used = 0; - f->head = 0; - f->tail = 0; - - if (length > VINO_FRAMEBUFFER_COUNT_MAX) - length = VINO_FRAMEBUFFER_COUNT_MAX; - - f->length = length; -} - -/* returns true/false */ -static inline int vino_fifo_has_id(struct vino_framebuffer_fifo *f, - unsigned int id) -{ - unsigned int i; - - for (i = f->head; i == (f->tail - 1); i = (i + 1) % f->length) { - if (f->data[i] == id) - return 1; - } - - return 0; -} - -#if 0 -/* returns true/false */ -static inline int vino_fifo_full(struct vino_framebuffer_fifo *f) -{ - return (f->used == f->length); -} -#endif - -static inline unsigned int vino_fifo_get_used(struct vino_framebuffer_fifo *f) -{ - return f->used; -} - -static int vino_fifo_enqueue(struct vino_framebuffer_fifo *f, unsigned int id) -{ - if (id >= f->length) { - return VINO_QUEUE_ERROR; - } - - if (vino_fifo_has_id(f, id)) { - return VINO_QUEUE_ERROR; - } - - if (f->used < f->length) { - f->data[f->tail] = id; - f->tail = (f->tail + 1) % f->length; - f->used++; - } else { - return VINO_QUEUE_ERROR; - } - - return 0; -} - -static int vino_fifo_peek(struct vino_framebuffer_fifo *f, unsigned int *id) -{ - if (f->used > 0) { - *id = f->data[f->head]; - } else { - return VINO_QUEUE_ERROR; - } - - return 0; -} - -static int vino_fifo_dequeue(struct vino_framebuffer_fifo *f, unsigned int *id) -{ - if (f->used > 0) { - *id = f->data[f->head]; - f->head = (f->head + 1) % f->length; - f->used--; - } else { - return VINO_QUEUE_ERROR; - } - - return 0; -} - -/* Framebuffer queue functions */ - -/* execute with queue_lock locked */ -static void vino_queue_free_with_count(struct vino_framebuffer_queue *q, - unsigned int length) -{ - unsigned int i; - - q->length = 0; - memset(&q->in, 0, sizeof(struct vino_framebuffer_fifo)); - memset(&q->out, 0, sizeof(struct vino_framebuffer_fifo)); - for (i = 0; i < length; i++) { - dprintk("vino_queue_free_with_count(): freeing buffer %d\n", - i); - vino_free_buffer(q->buffer[i]); - kfree(q->buffer[i]); - } - - q->type = VINO_MEMORY_NONE; - q->magic = 0; -} - -static void vino_queue_free(struct vino_framebuffer_queue *q) -{ - dprintk("vino_queue_free():\n"); - - if (q->magic != VINO_QUEUE_MAGIC) - return; - if (q->type != VINO_MEMORY_MMAP) - return; - - mutex_lock(&q->queue_mutex); - - vino_queue_free_with_count(q, q->length); - - mutex_unlock(&q->queue_mutex); -} - -static int vino_queue_init(struct vino_framebuffer_queue *q, - unsigned int *length) -{ - unsigned int i; - int ret = 0; - - dprintk("vino_queue_init(): length = %d\n", *length); - - if (q->magic == VINO_QUEUE_MAGIC) { - dprintk("vino_queue_init(): queue already initialized!\n"); - return -EINVAL; - } - - if (q->type != VINO_MEMORY_NONE) { - dprintk("vino_queue_init(): queue already initialized!\n"); - return -EINVAL; - } - - if (*length < 1) - return -EINVAL; - - mutex_lock(&q->queue_mutex); - - if (*length > VINO_FRAMEBUFFER_COUNT_MAX) - *length = VINO_FRAMEBUFFER_COUNT_MAX; - - q->length = 0; - - for (i = 0; i < *length; i++) { - dprintk("vino_queue_init(): allocating buffer %d\n", i); - q->buffer[i] = kmalloc(sizeof(struct vino_framebuffer), - GFP_KERNEL); - if (!q->buffer[i]) { - dprintk("vino_queue_init(): kmalloc() failed\n"); - ret = -ENOMEM; - break; - } - - ret = vino_allocate_buffer(q->buffer[i], - VINO_FRAMEBUFFER_SIZE); - if (ret) { - kfree(q->buffer[i]); - dprintk("vino_queue_init(): " - "vino_allocate_buffer() failed\n"); - break; - } - - q->buffer[i]->id = i; - if (i > 0) { - q->buffer[i]->offset = q->buffer[i - 1]->offset + - q->buffer[i - 1]->size; - } else { - q->buffer[i]->offset = 0; - } - - spin_lock_init(&q->buffer[i]->state_lock); - - dprintk("vino_queue_init(): buffer = %d, offset = %d, " - "size = %d\n", i, q->buffer[i]->offset, - q->buffer[i]->size); - } - - if (ret) { - vino_queue_free_with_count(q, i); - *length = 0; - } else { - q->length = *length; - vino_fifo_init(&q->in, q->length); - vino_fifo_init(&q->out, q->length); - q->type = VINO_MEMORY_MMAP; - q->magic = VINO_QUEUE_MAGIC; - } - - mutex_unlock(&q->queue_mutex); - - return ret; -} - -static struct vino_framebuffer *vino_queue_add(struct - vino_framebuffer_queue *q, - unsigned int id) -{ - struct vino_framebuffer *ret = NULL; - unsigned int total; - unsigned long flags; - - dprintk("vino_queue_add(): id = %d\n", id); - - if (q->magic != VINO_QUEUE_MAGIC) { - return ret; - } - - spin_lock_irqsave(&q->queue_lock, flags); - - if (q->length == 0) - goto out; - - if (id >= q->length) - goto out; - - /* not needed?: if (vino_fifo_full(&q->out)) { - goto out; - }*/ - /* check that outgoing queue isn't already full - * (or that it won't become full) */ - total = vino_fifo_get_used(&q->in) + - vino_fifo_get_used(&q->out); - if (total >= q->length) - goto out; - - if (vino_fifo_enqueue(&q->in, id)) - goto out; - - ret = q->buffer[id]; - -out: - spin_unlock_irqrestore(&q->queue_lock, flags); - - return ret; -} - -static struct vino_framebuffer *vino_queue_transfer(struct - vino_framebuffer_queue *q) -{ - struct vino_framebuffer *ret = NULL; - struct vino_framebuffer *fb; - int id; - unsigned long flags; - - dprintk("vino_queue_transfer():\n"); - - if (q->magic != VINO_QUEUE_MAGIC) { - return ret; - } - - spin_lock_irqsave(&q->queue_lock, flags); - - if (q->length == 0) - goto out; - - // now this actually removes an entry from the incoming queue - if (vino_fifo_dequeue(&q->in, &id)) { - goto out; - } - - dprintk("vino_queue_transfer(): id = %d\n", id); - fb = q->buffer[id]; - - // we have already checked that the outgoing queue is not full, but... - if (vino_fifo_enqueue(&q->out, id)) { - printk(KERN_ERR "vino_queue_transfer(): " - "outgoing queue is full, this shouldn't happen!\n"); - goto out; - } - - ret = fb; -out: - spin_unlock_irqrestore(&q->queue_lock, flags); - - return ret; -} - -/* returns true/false */ -static int vino_queue_incoming_contains(struct vino_framebuffer_queue *q, - unsigned int id) -{ - int ret = 0; - unsigned long flags; - - if (q->magic != VINO_QUEUE_MAGIC) { - return ret; - } - - spin_lock_irqsave(&q->queue_lock, flags); - - if (q->length == 0) - goto out; - - ret = vino_fifo_has_id(&q->in, id); - -out: - spin_unlock_irqrestore(&q->queue_lock, flags); - - return ret; -} - -/* returns true/false */ -static int vino_queue_outgoing_contains(struct vino_framebuffer_queue *q, - unsigned int id) -{ - int ret = 0; - unsigned long flags; - - if (q->magic != VINO_QUEUE_MAGIC) { - return ret; - } - - spin_lock_irqsave(&q->queue_lock, flags); - - if (q->length == 0) - goto out; - - ret = vino_fifo_has_id(&q->out, id); - -out: - spin_unlock_irqrestore(&q->queue_lock, flags); - - return ret; -} - -static int vino_queue_get_incoming(struct vino_framebuffer_queue *q, - unsigned int *used) -{ - int ret = 0; - unsigned long flags; - - if (q->magic != VINO_QUEUE_MAGIC) { - return VINO_QUEUE_ERROR; - } - - spin_lock_irqsave(&q->queue_lock, flags); - - if (q->length == 0) { - ret = VINO_QUEUE_ERROR; - goto out; - } - - *used = vino_fifo_get_used(&q->in); - -out: - spin_unlock_irqrestore(&q->queue_lock, flags); - - return ret; -} - -static int vino_queue_get_outgoing(struct vino_framebuffer_queue *q, - unsigned int *used) -{ - int ret = 0; - unsigned long flags; - - if (q->magic != VINO_QUEUE_MAGIC) { - return VINO_QUEUE_ERROR; - } - - spin_lock_irqsave(&q->queue_lock, flags); - - if (q->length == 0) { - ret = VINO_QUEUE_ERROR; - goto out; - } - - *used = vino_fifo_get_used(&q->out); - -out: - spin_unlock_irqrestore(&q->queue_lock, flags); - - return ret; -} - -#if 0 -static int vino_queue_get_total(struct vino_framebuffer_queue *q, - unsigned int *total) -{ - int ret = 0; |