-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Staging: Yet another (third) dt3155 driver PCI/video4linux compliant
Kernel module (device driver) for dt3155 frame grabber video4linux2 compliant (finally). Works with "xawtv -f". ====================================================== This driver is written (almost) from scratch, using the allocator developed for dt3155pci see bellow). The driver uses videobuf-dma-contig interface modified to use the above mentioned allocator instead of dma_alloc_coheren(). The first thing to do was to design a new allocator based on allocating a configurable number of 4MB chunks of memory, that latter are broken into frame buffers of 768x576 bytes kept in different FIFOs (queues). As far as the driver autoloads as a kernel module during kernel boot, the allocation of 4MB chunks succeeds. The driver keeps three FIFOs: one for 4MB chunks, one for free buffers (available for allocations) and one for buffers already allocated. Allocation/deallocation is done automatically though the video4linux videobuf subsystem (some pointers to functions are replaced by driver supplied functions). Sure, there are problems: 1. The device tested to work with "xawtv -f" either via read() method (DT3155_STREAMING not selected), or via mmap() method (DT3155_STREAMING is selected) only. This coresponds to either cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE; or cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING; but not when cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING | V4L2_CAP_READWRITE; This is because xawtv calls poll() before starting streaming, but videobuf_poll_stream() automatically starts reading if streaming is not started. This selection is made during kernel configuration (for now). 2. Works for CCIR, but should work for RS-170 (not tested) This is made also during kernel configuration. 3. Could work for multiple dt3155 frame grabbers in a PC, (private data is allocated during PCI probe() method), but is not tested due to lack of a second board. 4. Not tested on a BIG ENDIAN architecture. 5. Many others you could find .... :-) All critics, comments, suggestions are wellcome. Signed-off-by: Marin Mitov <mitov@issp.bas.bg> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
- Loading branch information
Marin Mitov
authored and
Greg Kroah-Hartman
committed
May 11, 2010
1 parent
6608224
commit d42bffb
Showing
7 changed files
with
2,135 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
config VIDEO_DT3155 | ||
tristate "DT3155 frame grabber, Video4Linux interface" | ||
depends on PCI && VIDEO_DEV && VIDEO_V4L2 | ||
select VIDEOBUF_DMA_CONTIG | ||
default n | ||
---help--- | ||
Enables dt3155 device driver for the DataTranslation DT3155 frame grabber. | ||
Say Y here if you have this hardware. | ||
In doubt, say N. | ||
|
||
To compile this driver as a module, choose M here: the | ||
module will be called dt3155_v4l. | ||
|
||
config DT3155_CCIR | ||
bool "Selects CCIR/50Hz vertical refresh" | ||
depends on VIDEO_DT3155 | ||
default y | ||
---help--- | ||
Select it for CCIR/50Hz (European region), | ||
or leave it unselected for RS-170/60Hz (North America). | ||
|
||
config DT3155_STREAMING | ||
bool "Selects mmap streaming instead of read method" | ||
depends on VIDEO_DT3155 | ||
default y | ||
---help--- | ||
Select it if you wish to try mmap streaming, or | ||
or leave it unselected for using read method. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
obj-$(CONFIG_VIDEO_DT3155) += dt3155_v4l.o | ||
dt3155_v4l-objs := \ | ||
dt3155-bufs.o \ | ||
dt3155v4l.o |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,256 @@ | ||
/*************************************************************************** | ||
* Copyright (C) 2006-2010 by Marin Mitov * | ||
* mitov@issp.bas.bg * | ||
* * | ||
* 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; either version 2 of the License, or * | ||
* (at your option) any later version. * | ||
* * | ||
* This program is distributed in the hope that it will be useful, * | ||
* but WITHOUT ANY WARRANTY; without even the implied warranty of * | ||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * | ||
* GNU General Public License for more details. * | ||
* * | ||
* You should have received a copy of the GNU General Public License * | ||
* along with this program; if not, write to the * | ||
* Free Software Foundation, Inc., * | ||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * | ||
***************************************************************************/ | ||
|
||
#include "dt3155-bufs.h" | ||
|
||
/** | ||
* dt3155_init_chunks_buf - creates a chunk buffer and allocates memory for it | ||
* | ||
* returns: a pointer to the struct dt3155_buf or NULL if failed | ||
* | ||
* Creates a struct dt3155_buf, then allocates a chunk of memory of | ||
* size DT3155_CHUNK_SIZE and sets all the pages in it as Reserved. | ||
* This is done to be able to use remap_pfn_range() on these buffers | ||
* (which do not work on normal memory if Reserved bit is not set) | ||
*/ | ||
struct dt3155_buf * | ||
dt3155_init_chunks_buf(void) | ||
{ /* could sleep */ | ||
struct dt3155_buf *buf; | ||
int i; | ||
|
||
buf = kzalloc(sizeof(*buf), GFP_KERNEL); | ||
if (!buf) | ||
return NULL; | ||
buf->cpu = (void *)__get_free_pages(DT3155_CHUNK_FLAGS, | ||
get_order(DT3155_CHUNK_SIZE)); | ||
if (!buf->cpu) { | ||
kfree(buf); | ||
return NULL; | ||
} | ||
for (i = 0; i < DT3155_CHUNK_SIZE; i += PAGE_SIZE) | ||
SetPageReserved(virt_to_page(buf->cpu + i)); | ||
return buf; /* success */ | ||
} | ||
|
||
/** | ||
* dt3155_free_chunks_buf - destroys the specified buffer | ||
* | ||
* @buf: the buffer to be freed | ||
* | ||
* Clears Reserved bit of all pages in the chunk, frees the chunk memory | ||
* and destroys struct dt3155_buf. | ||
*/ | ||
void | ||
dt3155_free_chunks_buf(struct dt3155_buf *buf) | ||
{ | ||
int i; | ||
|
||
for (i = 0; i < DT3155_CHUNK_SIZE; i += PAGE_SIZE) | ||
ClearPageReserved(virt_to_page(buf->cpu + i)); | ||
free_pages((unsigned long)buf->cpu, get_order(DT3155_CHUNK_SIZE)); | ||
kfree(buf); | ||
} | ||
|
||
/** | ||
* dt3155_init_fifo - creates and initializes a fifo | ||
* | ||
* returns: a pointer to the crated and initialized struct dt3155_fifo | ||
* or NULL if failed | ||
*/ | ||
struct dt3155_fifo * | ||
dt3155_init_fifo(void) | ||
{ /* could sleep */ | ||
struct dt3155_fifo *fifo = kzalloc(sizeof(*fifo), GFP_KERNEL); | ||
if (fifo) | ||
spin_lock_init(&fifo->lock); | ||
return fifo; | ||
} | ||
|
||
/* dt3155_free_fifo(x) defined as macro in dt3155.h */ | ||
|
||
/** | ||
* dt3155_get_buf - gets a buffer from the fifo | ||
* | ||
* @fifo: the fifo to get a buffer from | ||
* | ||
* returns: a pointer to the buffer or NULL if failed | ||
* | ||
* dt3155_get_buf gets the fifo's spin_lock and returns the | ||
* buffer pointed by the head. Could be used in any context. | ||
*/ | ||
struct dt3155_buf * | ||
dt3155_get_buf(struct dt3155_fifo *fifo) | ||
{ | ||
unsigned long flags; | ||
struct dt3155_buf *tmp_buf; | ||
|
||
spin_lock_irqsave(&fifo->lock, flags); | ||
tmp_buf = fifo->head; | ||
if (fifo->head) | ||
fifo->head = fifo->head->next; | ||
if (!fifo->head) | ||
fifo->tail = NULL; | ||
spin_unlock_irqrestore(&fifo->lock, flags); | ||
return tmp_buf; | ||
} | ||
|
||
/** | ||
* dt3155_put_buf - puts a buffer into a fifo | ||
* | ||
* @buf: the buffer to put | ||
* @fifo: the fifo to put the buffer in | ||
* | ||
* dt3155_put_buf gets the fifo's spin_lock and puts the buf | ||
* at the tail of the fifo. Could be used in any context. | ||
*/ | ||
void | ||
dt3155_put_buf(struct dt3155_buf *buf, struct dt3155_fifo *fifo) | ||
{ | ||
unsigned long flags; | ||
|
||
spin_lock_irqsave(&fifo->lock, flags); | ||
buf->next = NULL; | ||
if (fifo->tail) | ||
fifo->tail->next = buf; | ||
fifo->tail = buf; | ||
if (!fifo->head) | ||
fifo->head = buf; | ||
spin_unlock_irqrestore(&fifo->lock, flags); | ||
} | ||
|
||
/** | ||
* dt3155_init_chunks_fifo - creates and fills a chunks_fifo | ||
* | ||
* returns: a pointer to the fifo or NULL if failed | ||
* | ||
* dt3155_init_chunks_fifo creates and fills the fifo with | ||
* a number of chunks <= DT3155_CHUNK_NUM. The returned fifo | ||
* contains at least one chunk. | ||
*/ | ||
struct dt3155_fifo * | ||
dt3155_init_chunks_fifo(void) | ||
{ /* could sleep */ | ||
int i; | ||
|
||
struct dt3155_fifo *chunks; | ||
struct dt3155_buf *tmp_buf; | ||
|
||
chunks = dt3155_init_fifo(); | ||
if (!chunks) | ||
return NULL; | ||
tmp_buf = dt3155_init_chunks_buf(); | ||
if (!tmp_buf) { | ||
dt3155_free_fifo(chunks); | ||
return NULL; | ||
} | ||
dt3155_put_buf(tmp_buf, chunks); | ||
for (i = 1; i < DT3155_CHUNK_NUM; i++) { | ||
tmp_buf = dt3155_init_chunks_buf(); | ||
if (!tmp_buf) | ||
break; | ||
dt3155_put_buf(tmp_buf, chunks); | ||
} | ||
return chunks; | ||
} | ||
|
||
/** | ||
* dt3155_free_chunks_fifo - empties and destroys the chunks_fifo | ||
* | ||
* @chunks: the chunks_fifo to be freed | ||
* | ||
* dt3155_free_chunks_fifo deallocates all chunks in the fifo and | ||
* destroys it. | ||
*/ | ||
void | ||
dt3155_free_chunks_fifo(struct dt3155_fifo *chunks) | ||
{ | ||
int buf_count = 0; | ||
struct dt3155_buf *buf; | ||
|
||
while ((buf = dt3155_get_buf(chunks))) { | ||
dt3155_free_chunks_buf(buf); | ||
buf_count++; | ||
} | ||
dt3155_free_fifo(chunks); | ||
printk(KERN_INFO "dt3155: %i chunks freed\n", buf_count); | ||
} | ||
|
||
/** | ||
* dt3155_init_ibufs_fifo - creates and fills an image buffer fifo | ||
* | ||
* @chunks: chunks_fifo to take memory from | ||
* @buf_size: the size of image buffers | ||
* | ||
* returns: a pointer to the fifo filled with image buffers | ||
* | ||
* dt3155_init_ibufs_fifo takes chunks from chunks_fifo, chops them | ||
* into pieces of size buf_size and fills image fifo with them. | ||
*/ | ||
struct dt3155_fifo * | ||
dt3155_init_ibufs_fifo(struct dt3155_fifo *chunks, int buf_size) | ||
{ /* could sleep */ | ||
int i, buf_count = 0; | ||
struct dt3155_buf *tmp_ibuf, *chunks_buf, *last_chunk; | ||
struct dt3155_fifo *tmp_fifo; | ||
|
||
tmp_fifo = dt3155_init_fifo(); | ||
if (!tmp_fifo) | ||
return NULL; | ||
last_chunk = chunks->tail; | ||
do { | ||
chunks_buf = dt3155_get_buf(chunks); | ||
dt3155_put_buf(chunks_buf, chunks); | ||
for (i = 0; i < DT3155_CHUNK_SIZE / buf_size; i++) { | ||
tmp_ibuf = kzalloc(sizeof(*tmp_ibuf), GFP_KERNEL); | ||
if (tmp_ibuf) { | ||
tmp_ibuf->cpu = | ||
chunks_buf->cpu + DT3155_BUF_SIZE * i; | ||
dt3155_put_buf(tmp_ibuf, tmp_fifo); | ||
buf_count++; | ||
} else { | ||
if (buf_count) { | ||
goto print_num_bufs; | ||
} else { | ||
dt3155_free_fifo(tmp_fifo); | ||
return NULL; | ||
} | ||
} | ||
} | ||
} while (chunks_buf != last_chunk); | ||
print_num_bufs: | ||
printk(KERN_INFO "dt3155: %i image buffers available\n", buf_count); | ||
return tmp_fifo; | ||
} | ||
|
||
/** | ||
* dt3155_free_ibufs_fifo - empties and destroys an image fifo | ||
* | ||
* @fifo: the fifo to free | ||
*/ | ||
void | ||
dt3155_free_ibufs_fifo(struct dt3155_fifo *fifo) | ||
{ | ||
struct dt3155_buf *tmp_ibuf; | ||
|
||
while ((tmp_ibuf = dt3155_get_buf(fifo))) | ||
kfree(tmp_ibuf); | ||
kfree(fifo); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,88 @@ | ||
/*************************************************************************** | ||
* Copyright (C) 2006-2010 by Marin Mitov * | ||
* mitov@issp.bas.bg * | ||
* * | ||
* 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; either version 2 of the License, or * | ||
* (at your option) any later version. * | ||
* * | ||
* This program is distributed in the hope that it will be useful, * | ||
* but WITHOUT ANY WARRANTY; without even the implied warranty of * | ||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * | ||
* GNU General Public License for more details. * | ||
* * | ||
* You should have received a copy of the GNU General Public License * | ||
* along with this program; if not, write to the * | ||
* Free Software Foundation, Inc., * | ||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * | ||
***************************************************************************/ | ||
|
||
#ifndef _DT3155_BUFS_H_ | ||
#define _DT3155_BUFS_H_ | ||
|
||
#include <linux/pci.h> | ||
|
||
/* 4 chunks of 4MB, 9 buffers each = 36 buffers (> VIDEO_MAX_FRAME) */ | ||
#define DT3155_CHUNK_NUM 4 | ||
|
||
/* DT3155_CHUNK_SIZE should be 4M (2^22) or less, but more than image size */ | ||
#define DT3155_CHUNK_SIZE (1U << 22) | ||
#define DT3155_CHUNK_FLAGS (GFP_KERNEL | GFP_DMA32 | __GFP_COLD | __GFP_NOWARN) | ||
|
||
/* DT3155_BUF_SIZE = 108 * PAGE_SIZE, so each buf is PAGE_SIZE alligned */ | ||
#define DT3155_BUF_SIZE (768 * 576) | ||
|
||
/** | ||
* struct dt3155_buf - image buffer structure | ||
* | ||
* @cpu: virtual kernel address of the buffer | ||
* @dma: dma (bus) address of the buffer | ||
* @next: pointer to the next buffer in the fifo | ||
* @tv: time value when the image has been acquired | ||
*/ | ||
struct dt3155_buf { | ||
void *cpu; | ||
dma_addr_t dma; | ||
struct dt3155_buf *next; | ||
struct timeval tv; | ||
}; | ||
|
||
/** | ||
* struct dt3155_fifo - fifo structure | ||
* | ||
* @head: pointer to the head of the fifo | ||
* @tail: pionter to the tail of the fifo | ||
* @lock: spin_lock to protect the fifo | ||
*/ | ||
struct dt3155_fifo { | ||
struct dt3155_buf *head; | ||
struct dt3155_buf *tail; | ||
spinlock_t lock; | ||
}; | ||
|
||
struct dt3155_buf * __must_check | ||
dt3155_init_chunks_buf(void); | ||
void | ||
dt3155_free_chunks_buf(struct dt3155_buf *buf); | ||
|
||
struct dt3155_fifo * __must_check | ||
dt3155_init_fifo(void); | ||
#define dt3155_free_fifo(x) kfree(x) | ||
|
||
struct dt3155_buf * __must_check | ||
dt3155_get_buf(struct dt3155_fifo *fifo); | ||
void | ||
dt3155_put_buf(struct dt3155_buf *buf, struct dt3155_fifo *fifo); | ||
|
||
struct dt3155_fifo * __must_check | ||
dt3155_init_chunks_fifo(void); | ||
void | ||
dt3155_free_chunks_fifo(struct dt3155_fifo *chunks); | ||
|
||
struct dt3155_fifo * __must_check | ||
dt3155_init_ibufs_fifo(struct dt3155_fifo *chunks, int buf_size); | ||
void | ||
dt3155_free_ibufs_fifo(struct dt3155_fifo *fifo); | ||
|
||
#endif /* _DT3155_BUFS_H_ */ |
Oops, something went wrong.