Commit aa337ef1 authored by Scott Smedley's avatar Scott Smedley Committed by Greg Kroah-Hartman

Staging: add dt3155 driver

This is a driver for the DT3155 Digitizer
Signed-off-by: default avatarScott Smedley <ss@aao.gov.au>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@suse.de>
parent da94a755
ifeq ($(shell [[ `uname -r | cut -f 1,2 -d\.` < 2.6 ]] && echo pre2.6),pre2.6)
# system with a pre 2.6 kernel _don't_ use kbuild.
all:
$(MAKE) -f Makefile.pre-2.6
clean:
rm -f *.o
else
# systems with a 2.6 or later kernel use kbuild.
ifneq ($(KERNELRELEASE),)
obj-m := dt3155.o
dt3155-objs := dt3155_drv.o dt3155_isr.o dt3155_io.o allocator.o
else
KDIR := /lib/modules/$(shell uname -r)/build
PWD := $(shell pwd)
all:
$(MAKE) -C $(KDIR) M=$(PWD) modules
clean:
rm -rf *.o *.mod *.mod.c *.ko .dt3155* .allocator.o.cmd .tmp_versions
endif
endif
The allocator shown here exploits high memory. This document explains
how a user can deal with drivers uses this allocator and how a
programmer can link in the module.
The module is being used by my pxc and pxdrv device drivers (as well as
other ones), available from ftp.systemy.it/pub/develop and
ftp.linux.it/pub/People/Rubini
User's manual
=============
One of the most compelling problems with any DMA-capable device is the
allocation of a suitable memory buffer. The "allocator" module tries
to deal with the problem in a clean way. The module is able to use
high memory (above the one used in normal operation) for DMA
allocation.
To prevent the kernel for using high memory, so that it remains
available for DMA, you should pass a command line argument to the
kernel. Command line arguments can be passed to Lilo, to Loadlin or
to whichever loader you are using (unless it's very poor in design).
For Lilo, either use "append=" in /etc/lilo.conf or add commandline
arguments to the interactive prompt. For example, I have a 32MB box
and reserve two megs for DMA:
In lilo.conf:
image = /zImage
label = linux
append = "mem=30M"
Or, interactively:
LILO: linux mem=30M
Once the kernel is booted with the right command-line argument, any
driver linked with the allocator module will be able to get
DMA-capable memory without much trouble (unless the various drivers
need more memory than available).
The module implements an alloc/free mechanism, so that it can serve
multiple drivers at the same time. Note however that the allocator
uses all of high memory and assumes to be the only piece of software
using such memory.
Programmer's manual
===================
The allocator, as released, is designed to be linked to a device
driver. In this case, the driver must call allocator_init() before
using the allocator and must call allocator_cleanup() before
unloading. This is usually done from within init_module() and
cleanup_module(). If the allocator is linked to a driver, it won't be
possible for several drivers to allocate high DMA memory, as explained
above.
It is possible, on the other hand, to compile the module as a standalone
module, so that several modules can rely on the allocator for they DMA
buffers. To compile the allocator as a standalone module, do the
following in this directory (or provide a suitable Makefile, or edit
the source code):
make allocator.o CC="gcc -Dallocator_init=init_module -Dallocator_cleanup=cleanup_module -include /usr/include/linux/module.h"
The previous commandline tells to include <linux/module.h> in the
first place, and to rename the init and cleanup function to the ones
needed for module loading and unloading. Drivers using a standalone
allocator won't need to call allocator_init() nor allocator_cleanup().
The allocator exports the following functions (declared in allocator.h):
unsigned long allocator_allocate_dma (unsigned long kilobytes,
int priority);
This function returns a physical address, over high_memory,
which corresponds to an area of at least "kilobytes" kilobytes.
The area will be owned by the module calling the function.
The returned address can be passed to device boards, to instruct
their DMA controllers, via phys_to_bus(). The address can be used
by C code after vremap()/ioremap(). The "priority" argument should
be GFP_KERNEL or GFP_ATOMIC, according to the context of the
caller; it is used to call kmalloc(), as the allocator must keep
track of any region it gives away. In case of error the function
returns 0, and the caller is expected to issue a -ENOMEM error.
void allocator_free_dma (unsigned long address);
This function is the reverse of the previous one. If a driver
doesn't free the DMA memory it allocated, the allocator will
consider such memory as busy. Note, however, that
allocator_cleanup() calls kfree() on every region it reclaimed,
so that a driver with the allocator linked in can avoid calling
allocator_free_dma() at unload time.
/*
* allocator.c -- allocate after high_memory, if available
*
* NOTE: this is different from my previous allocator, the one that
* assembles pages, which revealed itself both slow and unreliable.
*
* Copyright (C) 1998 rubini@linux.it (Alessandro Rubini)
*
* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
*
-- Changes --
Date Programmer Description of changes made
-------------------------------------------------------------------
02-Aug-2002 NJC allocator now steps in 1MB increments, rather
than doubling its size each time.
Also, allocator_init(u_int *) now returns
(in the first arg) the size of the free
space. This is no longer consistent with
using the allocator as a module, and some changes
may be necessary for that purpose. This was
designed to work with the DT3155 driver, in
stand alone mode only!!!
26-Oct-2009 SS Port to 2.6.30 kernel.
*/
#ifndef __KERNEL__
# define __KERNEL__
#endif
#ifndef MODULE
# define MODULE
#endif
#include <linux/version.h>
#include <linux/sched.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/proc_fs.h>
#include <linux/errno.h>
#include <linux/types.h>
#include <linux/mm.h> /* PAGE_ALIGN() */
#include <asm/page.h>
#include "sysdep.h"
/*#define ALL_DEBUG*/
#define ALL_MSG "allocator: "
#undef PDEBUG /* undef it, just in case */
#ifdef ALL_DEBUG
# define __static
# define DUMP_LIST() dump_list()
# ifdef __KERNEL__
/* This one if debugging is on, and kernel space */
# define PDEBUG(fmt, args...) printk( KERN_DEBUG ALL_MSG fmt, ## args)
# else
/* This one for user space */
# define PDEBUG(fmt, args...) fprintf(stderr, fmt, ## args)
# endif
#else
# define PDEBUG(fmt, args...) /* not debugging: nothing */
# define DUMP_LIST()
# define __static static
#endif
#undef PDEBUGG
#define PDEBUGG(fmt, args...)
/*#define PDEBUGG(fmt, args...) printk( KERN_DEBUG ALL_MSG fmt, ## args)*/
int allocator_himem = 1; /* 0 = probe, pos. = megs, neg. = disable */
int allocator_step = 1; /* This is the step size in MB */
int allocator_probe = 1; /* This is a flag -- 1=probe, 0=don't probe */
static unsigned long allocator_buffer = 0; /* physical address */
static unsigned long allocator_buffer_size = 0; /* kilobytes */
/*
* The allocator keeps a list of DMA areas, so multiple devices
* can coexist. The list is kept sorted by address
*/
struct allocator_struct {
unsigned long address;
unsigned long size;
struct allocator_struct *next;
};
struct allocator_struct *allocator_list = NULL;
#ifdef ALL_DEBUG
static int dump_list(void)
{
struct allocator_struct *ptr;
PDEBUG("Current list:\n");
for (ptr = allocator_list; ptr; ptr = ptr->next) {
PDEBUG("0x%08lx (size %likB)\n",ptr->address,ptr->size>>10);
}
return 0;
}
#endif
/* ========================================================================
* This function is the actual allocator.
*
* If space is available in high memory (as detected at load time), that
* one is returned. The return value is a physical address (i.e., it can
* be used straight ahead for DMA, but needs remapping for program use).
*/
unsigned long allocator_allocate_dma (unsigned long kilobytes, int prio)
{
struct allocator_struct *ptr = allocator_list, *newptr;
unsigned long bytes = kilobytes << 10;
/* check if high memory is available */
if (!allocator_buffer)
return 0;
/* Round it to a multiple of the pagesize */
bytes = PAGE_ALIGN(bytes);
PDEBUG("request for %li bytes\n", bytes);
while (ptr && ptr->next) {
if (ptr->next->address - (ptr->address + ptr->size) >= bytes)
break; /* enough space */
ptr = ptr->next;
}
if (!ptr->next) {
DUMP_LIST();
PDEBUG("alloc failed\n");
return 0; /* end of list */
}
newptr = kmalloc(sizeof(struct allocator_struct),prio);
if (!newptr)
return 0;
/* ok, now stick it after ptr */
newptr->address = ptr->address + ptr->size;
newptr->size = bytes;
newptr->next = ptr->next;
ptr->next = newptr;
DUMP_LIST();
PDEBUG("returning 0x%08lx\n",newptr->address);
return newptr->address;
}
int allocator_free_dma (unsigned long address)
{
struct allocator_struct *ptr = allocator_list, *prev;
while (ptr && ptr->next) {
if (ptr->next->address == address)
break;
ptr = ptr->next;
}
/* the one being freed is ptr->next */
prev = ptr; ptr = ptr->next;
if (!ptr) {
printk(KERN_ERR ALL_MSG "free_dma(0x%08lx) but add. not allocated\n",
ptr->address);
return -EINVAL;
}
PDEBUGG("freeing: %08lx (%li) next %08lx\n",ptr->address,ptr->size,
ptr->next->address);
prev->next = ptr->next;
kfree(ptr);
/* dump_list(); */
return 0;
}
/* ========================================================================
* Init and cleanup
*
* On cleanup everything is released. If the list is not empty, that a
* problem of our clients
*/
int allocator_init(u_long *allocator_max)
{
/* check how much free memory is there */
volatile void *remapped;
unsigned long max;
unsigned long trial_size = allocator_himem<<20;
unsigned long last_trial = 0;
unsigned long step = allocator_step<<20;
unsigned long i=0;
struct allocator_struct *head, *tail;
char test_string[]="0123456789abcde"; /* 16 bytes */
PDEBUGG("himem = %i\n",allocator_himem);
if (allocator_himem < 0) /* don't even try */
return -EINVAL;
if (!trial_size) trial_size = 1<<20; /* not specified: try one meg */
while (1) {
remapped = ioremap(__pa(high_memory), trial_size);
if (!remapped)
{
PDEBUGG("%li megs failed!\n",trial_size>>20);
break;
}
PDEBUGG("Trying %li megs (at %p, %p)\n",trial_size>>20,
(void *)__pa(high_memory), remapped);
for (i=last_trial; i<trial_size; i+=16) {
strcpy((char *)(remapped)+i, test_string);
if (strcmp((char *)(remapped)+i, test_string))
break;
}
iounmap((void *)remapped);
schedule();
last_trial = trial_size;
if (i==trial_size)
trial_size += step; /* increment, if all went well */
else
{
PDEBUGG("%li megs copy test failed!\n",trial_size>>20);
break;
}
if (!allocator_probe) break;
}
PDEBUG("%li megs (%li k, %li b)\n",i>>20,i>>10,i);
allocator_buffer_size = i>>10; /* kilobytes */
allocator_buffer = __pa(high_memory);
if (!allocator_buffer_size) {
printk(KERN_WARNING ALL_MSG "no free high memory to use\n");
return -ENOMEM;
}
/*
* to simplify things, always have two cells in the list:
* the first and the last. This avoids some conditionals and
* extra code when allocating and deallocating: we only play
* in the middle of the list
*/
head = kmalloc(sizeof(struct allocator_struct),GFP_KERNEL);
if (!head)
return -ENOMEM;
tail = kmalloc(sizeof(struct allocator_struct),GFP_KERNEL);
if (!tail) {
kfree(head);
return -ENOMEM;
}
max = allocator_buffer_size<<10;
head->size = tail->size = 0;
head->address = allocator_buffer;
tail->address = allocator_buffer + max;
head->next = tail;
tail->next = NULL;
allocator_list = head;
*allocator_max = allocator_buffer_size; /* Back to the user code, in KB */
return 0; /* ok, ready */
}
void allocator_cleanup(void)
{
struct allocator_struct *ptr, *next;
for (ptr = allocator_list; ptr; ptr = next) {
next = ptr->next;
PDEBUG("freeing list: 0x%08lx\n",ptr->address);
kfree(ptr);
}
allocator_buffer = 0;
allocator_buffer_size = 0;
allocator_list = NULL;
}
/*
* allocator.h -- prototypes for allocating high memory
*
* NOTE: this is different from my previous allocator, the one that
* assembles pages, which revealed itself both slow and unreliable.
*
* Copyright (C) 1998 rubini@linux.it (Alessandro Rubini)
*
* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
*
*/
void allocator_free_dma(unsigned long address);
unsigned long allocator_allocate_dma (unsigned long kilobytes, int priority);
int allocator_init(u_long *);
void allocator_cleanup(void);
/*
Copyright 1996,2002,2005 Gregory D. Hager, Alfred A. Rizzi, Noah J. Cowan,
Jason Lapenta, Scott Smedley
This file is part of the DT3155 Device Driver.
The DT3155 Device Driver 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.
The DT3155 Device Driver 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 the DT3155 Device Driver; if not, write to the Free
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
MA 02111-1307 USA
$Id: dt3155.h,v 1.11 2005/08/09 06:08:51 ssmedley Exp $
-- Changes --
Date Programmer Description of changes made
-------------------------------------------------------------------
03-Jul-2000 JML n/a
10-Oct-2001 SS port to 2.4 kernel.
24-Jul-2002 SS remove unused code & added GPL licence.
05-Aug-2005 SS port to 2.6 kernel; make CCIR mode default.
*/
#ifndef _DT3155_INC
#define _DT3155_INC
#ifdef __KERNEL__
#include <linux/types.h> /* u_int etc. */
#include <linux/time.h> /* struct timeval */
#else
#include <sys/ioctl.h>
#include <sys/param.h>
#include <sys/time.h>
#include <unistd.h>
#endif
#define TRUE 1
#define FALSE 0
/* Uncomment this for 50Hz CCIR */
#define CCIR 1
/* Can be 1 or 2 */
#define MAXBOARDS 1
#define BOARD_MAX_BUFFS 3
#define MAXBUFFERS BOARD_MAX_BUFFS*MAXBOARDS
#define PCI_PAGE_SIZE (1 << 12)
#ifdef CCIR
#define DT3155_MAX_ROWS 576
#define DT3155_MAX_COLS 768
#define FORMAT50HZ TRUE
#else
#define DT3155_MAX_ROWS 480
#define DT3155_MAX_COLS 640
#define FORMAT50HZ FALSE
#endif
/* Configuration structure */
struct dt3155_config_s {
u_int acq_mode;
u_int cols, rows;
u_int continuous;
};
/* hold data for each frame */
typedef struct
{
u_long addr; /* address of the buffer with the frame */
u_long tag; /* unique number for the frame */
struct timeval time; /* time that capture took place */
} frame_info_t;
/* Structure for interrupt and buffer handling. */
/* This is the setup for 1 card */
struct dt3155_fbuffer_s {
int nbuffers;
frame_info_t frame_info[ BOARD_MAX_BUFFS ];
int empty_buffers[ BOARD_MAX_BUFFS ]; /* indexes empty frames */
int empty_len; /* Number of empty buffers */
/* Zero means empty */
int active_buf; /* Where data is currently dma'ing */
int locked_buf; /* Buffers used by user */
int ready_que[ BOARD_MAX_BUFFS ];
u_long ready_head; /* The most recent buffer located here */
u_long ready_len; /* The number of ready buffers */
int even_happened;
int even_stopped;
int stop_acquire; /* Flag to stop interrupts */
u_long frame_count; /* Counter for frames acquired by this card */
};
#define DT3155_MODE_FRAME 1
#define DT3155_MODE_FIELD 2
#define DT3155_SNAP 1
#define DT3155_ACQ 2
/* There is one status structure for each card. */
typedef struct dt3155_status_s
{
int fixed_mode; /* if 1, we are in fixed frame mode */
u_long reg_addr; /* Register address for a single card */
u_long mem_addr; /* Buffer start addr for this card */
u_long mem_size; /* This is the amount of mem available */
u_int irq; /* this card's irq */
struct dt3155_config_s config; /* configuration struct */
struct dt3155_fbuffer_s fbuffer;/* frame buffer state struct */
u_long state; /* this card's state */
u_int device_installed; /* Flag if installed. 1=installed */
} dt3155_status_t;
/* Reference to global status structure */
extern struct dt3155_status_s dt3155_status[MAXBOARDS];
#define DT3155_STATE_IDLE 0x00
#define DT3155_STATE_FRAME 0x01
#define DT3155_STATE_FLD 0x02
#define DT3155_STATE_STOP 0x100
#define DT3155_STATE_ERROR 0x200
#define DT3155_STATE_MODE 0x0ff
#define DT3155_IOC_MAGIC '!'
#define DT3155_SET_CONFIG _IOW( DT3155_IOC_MAGIC, 1, struct dt3155_config_s )
#define DT3155_GET_CONFIG _IOR( DT3155_IOC_MAGIC, 2, struct dt3155_status_s )
#define DT3155_STOP _IO( DT3155_IOC_MAGIC, 3 )
#define DT3155_START _IO( DT3155_IOC_MAGIC, 4 )
#define DT3155_FLUSH _IO( DT3155_IOC_MAGIC, 5 )
#define DT3155_IOC_MAXNR 5
/* Error codes */
#define DT_ERR_NO_BUFFERS 0x10000 /* not used but it might be one day - SS */
#define DT_ERR_CORRUPT 0x20000
#define DT_ERR_OVERRUN 0x30000
#define DT_ERR_I2C_TIMEOUT 0x40000
#define DT_ERR_MASK 0xff0000/* not used but it might be one day - SS */
/* User code will probably want to declare one of these for each card */
typedef struct dt3155_read_s
{
u_long offset;
u_long frame_seq;
u_long state;
frame_info_t frame_info;
} dt3155_read_t;
#endif /* _DT3155_inc */
#! /bin/sh
#
# Module load/unload script for use with SysV-style /etc/init.d/ systems.
# On a Debian system, copy this to /etc/init.d/dt3155 and then run
# /usr/sbin/update-rc.d dt3155 defaults 55
# to create the appropriate /etc/rc?.d/[SK]55dt3155 start/stop links.
# (The "55" is arbitrary but is what I use to load this rather late.)
#
# Andy Dougherty Feb 22 2000 doughera@lafayette.edu
# Dept. of Physics
# Lafayette College, Easton PA 18042
#
PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
# Edit to point to your local copy.
FILE=/usr/local/lib/modules/dt3155/dt3155.o
NAME="dt3155"
DESC="dt3155 Frame Grabber module"
DEV="dt3155"
if test ! -f $FILE; then
echo "Unable to locate $FILE"
exit 0
fi
set -e
case "$1" in
start)
echo -n "Loading $DESC "
if /sbin/insmod -v -f $FILE; then
major=`grep $DEV /proc/devices | awk "{print \\$1}"`
rm -f /dev/dt3155?
mknod /dev/dt3155a c $major 0
mknod /dev/dt3155b c $major 1
chmod go+rw /dev/dt3155?
echo
else
echo "$FILE not loaded."
fi
;;
stop)
echo -n "Unloading $DESC: "
if /sbin/rmmod $NAME ; then
echo
else
echo "$DEV not removed"
exit 0
fi
rm -f /dev/dt3155?
;;
*)
echo "Usage: /etc/init.d/$NAME {start|stop}"
exit 1
;;
esac
exit 0
This diff is collapsed.
/*
Copyright 1996,2002 Gregory D. Hager, Alfred A. Rizzi, Noah J. Cowan,
Scott Smedley
This file is part of the DT3155 Device Driver.
The DT3155 Device Driver 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.
The DT3155 Device Driver 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 the DT3155 Device Driver; if not, write to the Free
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
MA 02111-1307 USA
*/
#ifndef DT3155_DRV_INC
#define DT3155_DRV_INC
/* kernel logical address of the frame grabbers */
extern u_char *dt3155_lbase[ MAXBOARDS ];
/* kernel logical address of ram buffer */
extern u_char *dt3155_bbase;
#ifdef __KERNEL__
#include <linux/wait.h>
#include <linux/version.h> /* need access to LINUX_VERSION_CODE */
/* wait queue for reads */
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,1)
extern wait_queue_head_t dt3155_read_wait_queue[MAXBOARDS];
#else
extern struct wait_queue *dt3155_read_wait_queue[MAXBOARDS];
#endif
#endif
/* number of devices */
extern u_int ndevices;
extern int dt3155_errno;
#endif
/*
Copyright 1996,2002,2005 Gregory D. Hager, Alfred A. Rizzi, Noah J. Cowan,
Jason Lapenta, Scott Smedley
This file is part of the DT3155 Device Driver.
The DT3155 Device Driver 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.
The DT3155 Device Driver 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 the DT3155 Device Driver; if not, write to the Free
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
MA 02111-1307 USA
-- Changes --
Date Programmer Description of changes made
-------------------------------------------------------------------
10-Oct-2001 SS port to 2.4 kernel.
24-Jul-2002 SS GPL licence.
26-Jul-2002 SS Bug fix: timing logic was wrong.
08-Aug-2005 SS port to 2.6 kernel.
*/
/* This file provides some basic register io routines. It is modified
from demo code provided by Data Translations. */
#ifdef __KERNEL__
#include <asm/delay.h>
#endif
#if 0
#include <sys/param.h>
#include <sys/time.h>
#include <unistd.h>
#endif
#include "dt3155.h"
#include "dt3155_io.h"
#include "dt3155_drv.h"
#ifndef __KERNEL__
#include <stdio.h>
#endif
/****** local copies of board's 32 bit registers ******/
u_long even_dma_start_r; /* bit 0 should always be 0 */
u_long odd_dma_start_r; /* .. */
u_long even_dma_stride_r; /* bits 0&1 should always be 0 */
u_long odd_dma_stride_r; /* .. */
u_long even_pixel_fmt_r;
u_long odd_pixel_fmt_r;
FIFO_TRIGGER_R fifo_trigger_r;
XFER_MODE_R xfer_mode_r;
CSR1_R csr1_r;
RETRY_WAIT_CNT_R retry_wait_cnt_r;
INT_CSR_R int_csr_r;
u_long even_fld_mask_r;
u_long odd_fld_mask_r;
MASK_LENGTH_R mask_length_r;
FIFO_FLAG_CNT_R fifo_flag_cnt_r;
IIC_CLK_DUR_R iic_clk_dur_r;
IIC_CSR1_R iic_csr1_r;
IIC_CSR2_R iic_csr2_r;
DMA_UPPER_LMT_R even_dma_upper_lmt_r;
DMA_UPPER_LMT_R odd_dma_upper_lmt_r;
/******** local copies of board's 8 bit I2C registers ******/
I2C_CSR2 i2c_csr2;
I2C_EVEN_CSR i2c_even_csr;
I2C_ODD_CSR i2c_odd_csr;
I2C_CONFIG i2c_config;
u_char i2c_dt_id;
u_char i2c_x_clip_start;
u_char i2c_y_clip_start;
u_char i2c_x_clip_end;
u_char i2c_y_clip_end;
u_char i2c_ad_addr;
u_char i2c_ad_lut;
I2C_AD_CMD i2c_ad_cmd;
u_char i2c_dig_out;
u_char i2c_pm_lut_addr;
u_char i2c_pm_lut_data;
// return the time difference (in microseconds) b/w <a> & <b>.
long elapsed2 (const struct timeval *pStart, const struct timeval *pEnd)
{
long i = (pEnd->tv_sec - pStart->tv_sec) * 1000000;
i += pEnd->tv_usec - pStart->tv_usec;
return i;
}
/***********************************************************************
wait_ibsyclr()
This function handles read/write timing and r/w timeout error
Returns TRUE if NEW_CYCLE clears
Returns FALSE if NEW_CYCLE doesn't clear in roughly 3 msecs,
otherwise returns 0
***********************************************************************/
int wait_ibsyclr(u_char * lpReg)
{
/* wait 100 microseconds */
#ifdef __KERNEL__
udelay(100L);
/* __delay(loops_per_sec/10000); */
if (iic_csr2_r.fld.NEW_CYCLE )
{ /* if NEW_CYCLE didn't clear */
/* TIMEOUT ERROR */
dt3155_errno = DT_ERR_I2C_TIMEOUT;
return FALSE;
}
else
return TRUE; /* no error */
#else
struct timeval StartTime;
struct timeval EndTime;
const int to_3ms = 3000; /* time out of 3ms = 3000us */
gettimeofday( &StartTime, NULL );
do {
/* get new iic_csr2 value: */
ReadMReg((lpReg + IIC_CSR2), iic_csr2_r.reg);
gettimeofday( &EndTime, NULL );
}
while ((elapsed2(&StartTime, &EndTime) < to_3ms) && iic_csr2_r.fld.NEW_CYCLE);
if (iic_csr2_r.fld.NEW_CYCLE )
{ /* if NEW_CYCLE didn't clear */
printf("Timed out waiting for NEW_CYCLE to clear!");
return FALSE;
}
else
return TRUE; /* no error */
#endif
}
/***********************************************************************
WriteI2C()
This function handles writing to 8-bit DT3155 registers
1st parameter is pointer to 32-bit register base address
2nd parameter is reg. index;
3rd is value to be written
Returns TRUE - Successful completion
FALSE - Timeout error - cycle did not complete!
***********************************************************************/
int WriteI2C (u_char * lpReg, u_short wIregIndex, u_char byVal)
{
int writestat; /* status for return */
/* read 32 bit IIC_CSR2 register data into union */
ReadMReg((lpReg + IIC_CSR2), iic_csr2_r.reg);
iic_csr2_r.fld.DIR_RD = 0; /* for write operation */
iic_csr2_r.fld.DIR_ADDR = wIregIndex; /* I2C address of I2C register: */
iic_csr2_r.fld.DIR_WR_DATA = byVal; /* 8 bit data to be written to I2C reg */
iic_csr2_r.fld.NEW_CYCLE = 1; /* will start a direct I2C cycle: */
/* xfer union data into 32 bit IIC_CSR2 register */
WriteMReg((lpReg + IIC_CSR2), iic_csr2_r.reg);
/* wait for IIC cycle to finish */
writestat = wait_ibsyclr( lpReg );
return writestat; /* return with status */
}
/***********************************************************************
ReadI2C()
This function handles reading from 8-bit DT3155 registers
1st parameter is pointer to 32-bit register base address
2nd parameter is reg. index;
3rd is adrs of value to be read
Returns TRUE - Successful completion
FALSE - Timeout error - cycle did not complete!
***********************************************************************/
int ReadI2C (u_char * lpReg, u_short wIregIndex, u_char * byVal)
{
int writestat; /* status for return */
/* read 32 bit IIC_CSR2 register data into union */
ReadMReg((lpReg + IIC_CSR2), iic_csr2_r.reg);
/* for read operation */
iic_csr2_r.fld.DIR_RD = 1;
/* I2C address of I2C register: */
iic_csr2_r.fld.DIR_ADDR = wIregIndex;
/* will start a direct I2C cycle: */
iic_csr2_r.fld.NEW_CYCLE = 1;
/* xfer union's data into 32 bit IIC_CSR2 register */
WriteMReg((lpReg + IIC_CSR2), iic_csr2_r.reg);
/* wait for IIC cycle to finish */
writestat = wait_ibsyclr(lpReg);
/* Next 2 commands read 32 bit IIC_CSR1 register's data into union */
/* first read data is in IIC_CSR1 */
ReadMReg((lpReg + IIC_CSR1), iic_csr1_r.reg);
/* now get data u_char out of register */
*byVal = (u_char) iic_csr1_r.fld.RD_DATA;
return writestat; /* return with status */
}
This diff is collapsed.
This diff is collapsed.
/*
Copyright 1996,2002 Gregory D. Hager, Alfred A. Rizzi, Noah J. Cowan,
Jason Lapenta, Scott Smedley
This file is part of the DT3155 Device Driver.
The DT3155 Device Driver 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.
The DT3155 Device Driver 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 the DT3155 Device Driver; if not, write to the Free
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
MA 02111-1307 USA
-- Changes --
Date Programmer Description of changes made
-------------------------------------------------------------------
03-Jul-2000 JML n/a
24-Jul-2002 SS GPL licence.
26-Oct-2009 SS Porting to 2.6.30 kernel.
-- notes --
*/
#ifndef DT3155_ISR_H
#define DT3155_ISR_H
extern struct dt3155_fbuffer_s *dt3155_fbuffer[MAXBOARDS];
/* User functions for buffering */
/* Initialize the buffering system. This should */
/* be called prior to enabling interrupts */
u_long dt3155_setup_buffers(u_long *allocatorAddr);
/* Get the next frame of data if it is ready. Returns */
/* zero if no data is ready. If there is data but */
/* the user has a locked buffer, it will unlock that */
/* buffer and return it to the free list. */
int dt3155_get_ready_buffer(int minor);
/* Return a locked buffer to the free list */
void dt3155_release_locked_buffer(int minor);
/* Flush the buffer system */
int dt3155_flush(int minor);
/**********************************
* Simple array based que struct
**********************************/
bool are_empty_buffers( int minor );
void push_empty( int index, int minor );
int pop_empty( int minor );
bool is_ready_buf_empty( int minor );
bool is_ready_buf_full( int minor );
void push_ready( int minor, int index );
int pop_ready( int minor );
#endif
/* This header only makes send when included in a 2.0 compile */
#ifndef _PCI_COMPAT_H_
#define _PCI_COMPAT_H_
#ifdef __KERNEL__
#include <linux/bios32.h> /* pcibios_* */
#include <linux/pci.h> /* pcibios_* */
#include <linux/malloc.h> /* kmalloc */
/* fake the new pci interface based on the old one: encapsulate bus/devfn */
struct pci_fake_dev {
u8 bus;
u8 devfn;
int index;
};
#define pci_dev pci_fake_dev /* the other pci_dev is unused by 2.0 drivers */
extern inline struct pci_dev *pci_find_device(unsigned int vendorid,
unsigned int devid,
struct pci_dev *from)
{
struct pci_dev *pptr = kmalloc(sizeof(*pptr), GFP_KERNEL);
int index = 0;
int ret;
if (!pptr) return NULL;
if (from) index = pptr->index + 1;
ret = pcibios_find_device(vendorid, devid, index,
&pptr->bus, &pptr->devfn);
if (ret) { kfree(pptr); return NULL; }
return pptr;
}
extern inline struct pci_dev *pci_find_class(unsigned int class,
struct pci_dev *from)
{
return NULL; /* FIXME */
}
extern inline void pci_release_device(struct pci_dev *dev)
{
kfree(dev);
}
/* struct pci_dev *pci_find_slot (unsigned int bus, unsigned int devfn); */
#define pci_present pcibios_present
extern inline int
pci_read_config_byte(struct pci_dev *dev, u8 where, u8 *val)
{
return pcibios_read_config_byte(dev->bus, dev->devfn, where, val);
}
extern inline int
pci_read_config_word(struct pci_dev *dev, u8 where, u16 *val)
{
return pcibios_read_config_word(dev->bus, dev->devfn, where, val);
}
extern inline int
pci_read_config_dword(struct pci_dev *dev, u8 where, u32 *val)
{
return pcibios_read_config_dword(dev->bus, dev->devfn, where, val);
}
extern inline int
pci_write_config_byte(struct pci_dev *dev, u8 where, u8 val)
{
return pcibios_write_config_byte(dev->bus, dev->devfn, where, val);
}
extern inline int
pci_write_config_word(struct pci_dev *dev, u8 where, u16 val)
{
return pcibios_write_config_word(dev->bus, dev->devfn, where, val);
}
extern inline int
pci_write_config_dword(struct pci_dev *dev, u8 where, u32 val)
{
return pcibios_write_config_dword(dev->bus, dev->devfn, where, val);
}
extern inline void pci_set_master(struct pci_dev *dev)
{
u16 cmd;
pcibios_read_config_word(dev->bus, dev->devfn, PCI_COMMAND, &cmd);
cmd |= PCI_COMMAND_MASTER;
pcibios_write_config_word(dev->bus, dev->devfn, PCI_COMMAND, cmd);
}
#endif /* __KERNEL__ */
#endif /* _PCI_COMPAT_H_ */
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment