Staging: add dt3155 driver
This is a driver for the DT3155 Digitizer Signed-off-by: Scott Smedley <ss@aao.gov.au> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
This commit is contained in:
parent
da94a755ca
commit
aa337ef1fb
|
@ -0,0 +1,27 @@
|
|||
|
||||
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
|
|
@ -0,0 +1,98 @@
|
|||
|
||||
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.
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,296 @@
|
|||
/*
|
||||
* 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;
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
/*
|
||||
* 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);
|
|
@ -0,0 +1,175 @@
|
|||
/*
|
||||
|
||||
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 */
|
|
@ -0,0 +1,60 @@
|
|||
#! /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
|
||||
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,50 @@
|
|||
/*
|
||||
|
||||
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
|
|
@ -0,0 +1,236 @@
|
|||
/*
|
||||
|
||||
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 */
|
||||
}
|
|
@ -0,0 +1,400 @@
|
|||
/*
|
||||
|
||||
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
|
||||
-------------------------------------------------------------------
|
||||
24-Jul-2002 SS GPL licence.
|
||||
|
||||
*/
|
||||
|
||||
/* This code is a modified version of examples provided by Data Translations.*/
|
||||
|
||||
#ifndef DT3155_IO_INC
|
||||
#define DT3155_IO_INC
|
||||
|
||||
/* macros to access registers */
|
||||
|
||||
#define WriteMReg(Address, Data) * ((u_long *) (Address)) = Data
|
||||
#define ReadMReg(Address, Data) Data = * ((u_long *) (Address))
|
||||
|
||||
/***************** 32 bit register globals **************/
|
||||
|
||||
/* offsets for 32-bit memory mapped registers */
|
||||
|
||||
#define EVEN_DMA_START 0x000
|
||||
#define ODD_DMA_START 0x00C
|
||||
#define EVEN_DMA_STRIDE 0x018
|
||||
#define ODD_DMA_STRIDE 0x024
|
||||
#define EVEN_PIXEL_FMT 0x030
|
||||
#define ODD_PIXEL_FMT 0x034
|
||||
#define FIFO_TRIGGER 0x038
|
||||
#define XFER_MODE 0x03C
|
||||
#define CSR1 0x040
|
||||
#define RETRY_WAIT_CNT 0x044
|
||||
#define INT_CSR 0x048
|
||||
#define EVEN_FLD_MASK 0x04C
|
||||
#define ODD_FLD_MASK 0x050
|
||||
#define MASK_LENGTH 0x054
|
||||
#define FIFO_FLAG_CNT 0x058
|
||||
#define IIC_CLK_DUR 0x05C
|
||||
#define IIC_CSR1 0x060
|
||||
#define IIC_CSR2 0x064
|
||||
#define EVEN_DMA_UPPR_LMT 0x08C
|
||||
#define ODD_DMA_UPPR_LMT 0x090
|
||||
|
||||
#define CLK_DUR_VAL 0x01010101
|
||||
|
||||
|
||||
|
||||
/******** Assignments and Typedefs for 32 bit Memory Mapped Registers ********/
|
||||
|
||||
/**********************************
|
||||
* fifo_trigger_tag
|
||||
*/
|
||||
typedef union fifo_trigger_tag {
|
||||
u_long reg;
|
||||
struct
|
||||
{
|
||||
u_long PACKED : 6;
|
||||
u_long : 9;
|
||||
u_long PLANER : 7;
|
||||
u_long : 9;
|
||||
} fld;
|
||||
} FIFO_TRIGGER_R;
|
||||
|
||||
/**********************************
|
||||
* xfer_mode_tag
|
||||
*/
|
||||
typedef union xfer_mode_tag {
|
||||
u_long reg;
|
||||
struct
|
||||
{
|
||||
u_long : 2;
|
||||
u_long FIELD_TOGGLE : 1;
|
||||
u_long : 5;
|
||||
u_long : 2;
|
||||
u_long : 22;
|
||||
} fld;
|
||||
} XFER_MODE_R;
|
||||
|
||||
/**********************************
|
||||
* csr1_tag
|
||||
*/
|
||||
typedef union csr1_tag {
|
||||
u_long reg;
|
||||
struct
|
||||
{
|
||||
u_long CAP_CONT_EVE : 1;
|
||||
u_long CAP_CONT_ODD : 1;
|
||||
u_long CAP_SNGL_EVE : 1;
|
||||
u_long CAP_SNGL_ODD : 1;
|
||||
u_long FLD_DN_EVE : 1;
|
||||
u_long FLD_DN_ODD : 1;
|
||||
u_long SRST : 1;
|
||||
u_long FIFO_EN : 1;
|
||||
u_long FLD_CRPT_EVE : 1;
|
||||
u_long FLD_CRPT_ODD : 1;
|
||||
u_long ADDR_ERR_EVE : 1;
|
||||
u_long ADDR_ERR_ODD : 1;
|
||||
u_long CRPT_DIS : 1;
|
||||
u_long RANGE_EN : 1;
|
||||
u_long : 16;
|
||||
} fld;
|
||||
} CSR1_R;
|
||||
|
||||
/**********************************
|
||||
* retry_wait_cnt_tag
|
||||
*/
|
||||
typedef union retry_wait_cnt_tag {
|
||||
u_long reg;
|
||||
struct
|
||||
{
|
||||
u_long RTRY_WAIT_CNT : 8;
|
||||
u_long : 24;
|
||||
} fld;
|
||||
} RETRY_WAIT_CNT_R;
|
||||
|
||||
/**********************************
|
||||
* int_csr_tag
|
||||
*/
|
||||
typedef union int_csr_tag {
|
||||
u_long reg;
|
||||
struct
|
||||
{
|
||||
u_long FLD_END_EVE : 1;
|
||||
u_long FLD_END_ODD : 1;
|
||||
u_long FLD_START : 1;
|
||||
u_long : 5;
|
||||
u_long FLD_END_EVE_EN : 1;
|
||||
u_long FLD_END_ODD_EN : 1;
|
||||
u_long FLD_START_EN : 1;
|
||||
u_long : 21;
|
||||
} fld;
|
||||
} INT_CSR_R;
|
||||
|
||||
/**********************************
|
||||
* mask_length_tag
|
||||
*/
|
||||
typedef union mask_length_tag {
|
||||
u_long reg;
|
||||
struct
|
||||
{
|
||||
u_long MASK_LEN_EVE : 5;
|
||||
u_long : 11;
|
||||
u_long MASK_LEN_ODD : 5;
|
||||
u_long : 11;
|
||||
} fld;
|
||||
} MASK_LENGTH_R;
|
||||
|
||||
/**********************************
|
||||
* fifo_flag_cnt_tag
|
||||
*/
|
||||
typedef union fifo_flag_cnt_tag {
|
||||
u_long reg;
|
||||
struct
|
||||
{
|
||||
u_long AF_COUNT : 7;
|
||||
u_long : 9;
|
||||
u_long AE_COUNT : 7;
|
||||
u_long : 9;
|
||||
} fld;
|
||||
} FIFO_FLAG_CNT_R;
|
||||
|
||||
/**********************************
|
||||
* iic_clk_dur
|
||||
*/
|
||||
typedef union iic_clk_dur {
|
||||
u_long reg;
|
||||
struct
|
||||
{
|
||||
u_long PHASE_1 : 8;
|
||||
u_long PHASE_2 : 8;
|
||||
u_long PHASE_3 : 8;
|
||||
u_long PHASE_4 : 8;
|
||||
} fld;
|
||||
} IIC_CLK_DUR_R;
|
||||
|
||||
/**********************************
|
||||
* iic_csr1_tag
|
||||
*/
|
||||
typedef union iic_csr1_tag {
|
||||
u_long reg;
|
||||
struct
|
||||
{
|
||||
u_long AUTO_EN : 1;
|
||||
u_long BYPASS : 1;
|
||||
u_long SDA_OUT : 1;
|
||||
u_long SCL_OUT : 1;
|
||||
u_long : 4;
|
||||
u_long AUTO_ABORT : 1;
|
||||
u_long DIRECT_ABORT : 1;
|
||||
u_long SDA_IN : 1;
|
||||
u_long SCL_IN : 1;
|
||||
u_long : 4;
|
||||
u_long AUTO_ADDR : 8;
|
||||
u_long RD_DATA : 8;
|
||||
} fld;
|
||||
} IIC_CSR1_R;
|
||||
|
||||
/**********************************
|
||||
* iic_csr2_tag
|
||||
*/
|
||||
typedef union iic_csr2_tag {
|
||||
u_long reg;
|
||||
struct
|
||||
{
|
||||
u_long DIR_WR_DATA : 8;
|
||||
u_long DIR_SUB_ADDR : 8;
|
||||
u_long DIR_RD : 1;
|
||||
u_long DIR_ADDR : 7;
|
||||
u_long NEW_CYCLE : 1;
|
||||
u_long : 7;
|
||||
} fld;
|
||||
} IIC_CSR2_R;
|
||||
|
||||
/* use for both EVEN and ODD DMA UPPER LIMITS */
|
||||
|
||||
/**********************************
|
||||
* dma_upper_lmt_tag
|
||||
*/
|
||||
typedef union dma_upper_lmt_tag {
|
||||
u_long reg;
|
||||
struct
|
||||
{
|
||||
u_long DMA_UPPER_LMT_VAL : 24;
|
||||
u_long : 8;
|
||||
} fld;
|
||||
} DMA_UPPER_LMT_R;
|
||||
|
||||
|
||||
/***************************************
|
||||
* Global declarations of local copies
|
||||
* of boards' 32 bit registers
|
||||
***************************************/
|
||||
extern u_long even_dma_start_r; /* bit 0 should always be 0 */
|
||||
extern u_long odd_dma_start_r; /* .. */
|
||||
extern u_long even_dma_stride_r; /* bits 0&1 should always be 0 */
|
||||
extern u_long odd_dma_stride_r; /* .. */
|
||||
extern u_long even_pixel_fmt_r;
|
||||
extern u_long odd_pixel_fmt_r;
|
||||
|
||||
extern FIFO_TRIGGER_R fifo_trigger_r;
|
||||
extern XFER_MODE_R xfer_mode_r;
|
||||
extern CSR1_R csr1_r;
|
||||
extern RETRY_WAIT_CNT_R retry_wait_cnt_r;
|
||||
extern INT_CSR_R int_csr_r;
|
||||
|
||||
extern u_long even_fld_mask_r;
|
||||
extern u_long odd_fld_mask_r;
|
||||
|
||||
extern MASK_LENGTH_R mask_length_r;
|
||||
extern FIFO_FLAG_CNT_R fifo_flag_cnt_r;
|
||||
extern IIC_CLK_DUR_R iic_clk_dur_r;
|
||||
extern IIC_CSR1_R iic_csr1_r;
|
||||
extern IIC_CSR2_R iic_csr2_r;
|
||||
extern DMA_UPPER_LMT_R even_dma_upper_lmt_r;
|
||||
extern DMA_UPPER_LMT_R odd_dma_upper_lmt_r;
|
||||
|
||||
|
||||
|
||||
/***************** 8 bit I2C register globals ***********/
|
||||
|
||||
#define CSR2 0x010 /* indices of 8-bit I2C mapped reg's*/
|
||||
#define EVEN_CSR 0x011
|
||||
#define ODD_CSR 0x012
|
||||
#define CONFIG 0x013
|
||||
#define DT_ID 0x01F
|
||||
#define X_CLIP_START 0x020
|
||||
#define Y_CLIP_START 0x022
|
||||
#define X_CLIP_END 0x024
|
||||
#define Y_CLIP_END 0x026
|
||||
#define AD_ADDR 0x030
|
||||
#define AD_LUT 0x031
|
||||
#define AD_CMD 0x032
|
||||
#define DIG_OUT 0x040
|
||||
#define PM_LUT_ADDR 0x050
|
||||
#define PM_LUT_DATA 0x051
|
||||
|
||||
|
||||
/******** Assignments and Typedefs for 8 bit I2C Registers********************/
|
||||
|
||||
typedef union i2c_csr2_tag {
|
||||
u_char reg;
|
||||
struct
|
||||
{
|
||||
u_char CHROM_FIL : 1;
|
||||
u_char SYNC_SNTL : 1;
|
||||
u_char HZ50 : 1;
|
||||
u_char SYNC_PRESENT : 1;
|
||||
u_char BUSY_EVE : 1;
|
||||
u_char BUSY_ODD : 1;
|
||||
u_char DISP_PASS : 1;
|
||||
} fld;
|
||||
} I2C_CSR2;
|
||||
|
||||
typedef union i2c_even_csr_tag {
|
||||
u_char reg;
|
||||
struct
|
||||
{
|
||||
u_char DONE_EVE : 1;
|
||||
u_char SNGL_EVE : 1;
|
||||
u_char ERROR_EVE : 1;
|
||||
u_char : 5;
|
||||
} fld;
|
||||
} I2C_EVEN_CSR;
|
||||
|
||||
typedef union i2c_odd_csr_tag {
|
||||
u_char reg;
|
||||
struct
|
||||
{
|
||||
u_char DONE_ODD : 1;
|
||||
u_char SNGL_ODD : 1;
|
||||
u_char ERROR_ODD : 1;
|
||||
u_char : 5;
|
||||
} fld;
|
||||
} I2C_ODD_CSR;
|
||||
|
||||
typedef union i2c_config_tag {
|
||||
u_char reg;
|
||||
struct
|
||||
{
|
||||
u_char ACQ_MODE : 2;
|
||||
u_char EXT_TRIG_EN : 1;
|
||||
u_char EXT_TRIG_POL : 1;
|
||||
u_char H_SCALE : 1;
|
||||
u_char CLIP : 1;
|
||||
u_char PM_LUT_SEL : 1;
|
||||
u_char PM_LUT_PGM : 1;
|
||||
} fld;
|
||||
} I2C_CONFIG;
|
||||
|
||||
|
||||
typedef union i2c_ad_cmd_tag { /* bits can have 3 different meanings
|
||||
depending on value of AD_ADDR */
|
||||
u_char reg;
|
||||
struct
|
||||
{
|
||||
u_char : 2;
|
||||
u_char SYNC_LVL_SEL : 2;
|
||||
u_char SYNC_CNL_SEL : 2;
|
||||
u_char DIGITIZE_CNL_SEL1 : 2;
|
||||
} bt252_command; /* Bt252 Command Register */
|
||||
struct /* if AD_ADDR = 00h */
|
||||
{
|
||||
u_char IOUT_DATA : 8;
|
||||
} bt252_iout0; /* Bt252 IOUT0 register */
|
||||
struct /* if AD_ADDR = 01h */
|
||||
{
|
||||
u_char IOUT_DATA : 8;
|
||||
} bt252_iout1; /* BT252 IOUT1 register */
|
||||
} I2C_AD_CMD; /* if AD_ADDR = 02h */
|
||||
|
||||
|
||||
/***** Global declarations of local copies of boards' 8 bit I2C registers ***/
|
||||
|
||||
extern I2C_CSR2 i2c_csr2;
|
||||
extern I2C_EVEN_CSR i2c_even_csr;
|
||||
extern I2C_ODD_CSR i2c_odd_csr;
|
||||
extern I2C_CONFIG i2c_config;
|
||||
extern u_char i2c_dt_id;
|
||||
extern u_char i2c_x_clip_start;
|
||||
extern u_char i2c_y_clip_start;
|
||||
extern u_char i2c_x_clip_end;
|
||||
extern u_char i2c_y_clip_end;
|
||||
extern u_char i2c_ad_addr;
|
||||
extern u_char i2c_ad_lut;
|
||||
extern I2C_AD_CMD i2c_ad_cmd;
|
||||
extern u_char i2c_dig_out;
|
||||
extern u_char i2c_pm_lut_addr;
|
||||
extern u_char i2c_pm_lut_data;
|
||||
|
||||
/* Functions for Global use */
|
||||
|
||||
/* access 8-bit IIC registers */
|
||||
|
||||
extern int ReadI2C (u_char * lpReg, u_short wIregIndex, u_char * byVal);
|
||||
extern int WriteI2C (u_char * lpReg, u_short wIregIndex, u_char byVal);
|
||||
|
||||
#endif
|
|
@ -0,0 +1,545 @@
|
|||
/*
|
||||
|
||||
Copyright 1996,2002,2005 Gregory D. Hager, Alfred A. Rizzi, Noah J. Cowan,
|
||||
Jason Lapenta, Scott Smedley, Greg Sharp
|
||||
|
||||
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
|
||||
|
||||
File: dt3155_isr.c
|
||||
Purpose: Buffer management routines, and other routines for the ISR
|
||||
(the actual isr is in dt3155_drv.c)
|
||||
|
||||
-- Changes --
|
||||
|
||||
Date Programmer Description of changes made
|
||||
-------------------------------------------------------------------
|
||||
03-Jul-2000 JML n/a
|
||||
02-Apr-2002 SS Mods to make work with separate allocator
|
||||
module; Merged John Roll's mods to make work with
|
||||
multiple boards.
|
||||
10-Jul-2002 GCS Complete rewrite of setup_buffers to disallow
|
||||
buffers which span a 4MB boundary.
|
||||
24-Jul-2002 SS GPL licence.
|
||||
30-Jul-2002 NJC Added support for buffer loop.
|
||||
31-Jul-2002 NJC Complete rewrite of buffer management
|
||||
02-Aug-2002 NJC Including slab.h instead of malloc.h (no warning).
|
||||
Also, allocator_init() now returns allocator_max
|
||||
so cleaned up allocate_buffers() accordingly.
|
||||
08-Aug-2005 SS port to 2.6 kernel.
|
||||
|
||||
*/
|
||||
|
||||
#include <asm/system.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
#include "dt3155.h"
|
||||
#include "dt3155_drv.h"
|
||||
#include "dt3155_io.h"
|
||||
#include "dt3155_isr.h"
|
||||
#include "allocator.h"
|
||||
|
||||
#define FOUR_MB (0x0400000) /* Can't DMA accross a 4MB boundary!*/
|
||||
#define UPPER_10_BITS (0x3FF<<22) /* Can't DMA accross a 4MB boundary!*/
|
||||
|
||||
|
||||
/* Pointer into global structure for handling buffers */
|
||||
struct dt3155_fbuffer_s *dt3155_fbuffer[MAXBOARDS] = {NULL
|
||||
#if MAXBOARDS == 2
|
||||
, NULL
|
||||
#endif
|
||||
};
|
||||
|
||||
/******************************************************************************
|
||||
* Simple array based que struct
|
||||
*
|
||||
* Some handy functions using the buffering structure.
|
||||
*****************************************************************************/
|
||||
|
||||
|
||||
/***************************
|
||||
* are_empty_buffers
|
||||
* m is minor # of device
|
||||
***************************/
|
||||
inline bool are_empty_buffers( int m )
|
||||
{
|
||||
return ( dt3155_fbuffer[ m ]->empty_len );
|
||||
}
|
||||
|
||||
/**************************
|
||||
* push_empty
|
||||
* m is minor # of device
|
||||
*
|
||||
* This is slightly confusing. The number empty_len is the literal #
|
||||
* of empty buffers. After calling, empty_len-1 is the index into the
|
||||
* empty buffer stack. So, if empty_len == 1, there is one empty buffer,
|
||||
* given by dt3155_fbuffer[m]->empty_buffers[0].
|
||||
* empty_buffers should never fill up, though this is not checked.
|
||||
**************************/
|
||||
inline void push_empty( int index, int m )
|
||||
{
|
||||
dt3155_fbuffer[m]->empty_buffers[ dt3155_fbuffer[m]->empty_len ] = index;
|
||||
dt3155_fbuffer[m]->empty_len++;
|
||||
}
|
||||
|
||||
/**************************
|
||||
* pop_empty( m )
|
||||
* m is minor # of device
|
||||
**************************/
|
||||
inline int pop_empty( int m )
|
||||
{
|
||||
dt3155_fbuffer[m]->empty_len--;
|
||||
return dt3155_fbuffer[m]->empty_buffers[ dt3155_fbuffer[m]->empty_len ];
|
||||
}
|
||||
|
||||
/*************************
|
||||
* is_ready_buf_empty( m )
|
||||
* m is minor # of device
|
||||
*************************/
|
||||
inline bool is_ready_buf_empty( int m )
|
||||
{
|
||||
return ((dt3155_fbuffer[ m ]->ready_len) == 0);
|
||||
}
|
||||
|
||||
/*************************
|
||||
* is_ready_buf_full( m )
|
||||
* m is minor # of device
|
||||
* this should *never* be true if there are any active, locked or empty
|
||||
* buffers, since it corresponds to nbuffers ready buffers!!
|
||||
* 7/31/02: total rewrite. --NJC
|
||||
*************************/
|
||||
inline bool is_ready_buf_full( int m )
|
||||
{
|
||||
return ( dt3155_fbuffer[ m ]->ready_len == dt3155_fbuffer[ m ]->nbuffers );
|
||||
}
|
||||
|
||||
/*****************************************************
|
||||
* push_ready( m, buffer )
|
||||
* m is minor # of device
|
||||
*
|
||||
*****************************************************/
|
||||
inline void push_ready( int m, int index )
|
||||
{
|
||||
int head = dt3155_fbuffer[m]->ready_head;
|
||||
|
||||
dt3155_fbuffer[ m ]->ready_que[ head ] = index;
|
||||
dt3155_fbuffer[ m ]->ready_head = ( (head + 1) %
|
||||
(dt3155_fbuffer[ m ]->nbuffers) );
|
||||
dt3155_fbuffer[ m ]->ready_len++;
|
||||
|
||||
}
|
||||
|
||||
/*****************************************************
|
||||
* get_tail()
|
||||
* m is minor # of device
|
||||
*
|
||||
* Simply comptutes the tail given the head and the length.
|
||||
*****************************************************/
|
||||
static inline int get_tail( int m )
|
||||
{
|
||||
return ((dt3155_fbuffer[ m ]->ready_head -
|
||||
dt3155_fbuffer[ m ]->ready_len +
|
||||
dt3155_fbuffer[ m ]->nbuffers)%
|
||||
(dt3155_fbuffer[ m ]->nbuffers));
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*****************************************************
|
||||
* pop_ready()
|
||||
* m is minor # of device
|
||||
*
|
||||
* This assumes that there is a ready buffer ready... should
|
||||
* be checked (e.g. with is_ready_buf_empty() prior to call.
|
||||
*****************************************************/
|
||||
inline int pop_ready( int m )
|
||||
{
|
||||
int tail;
|
||||
tail = get_tail(m);
|
||||
dt3155_fbuffer[ m ]->ready_len--;
|
||||
return dt3155_fbuffer[ m ]->ready_que[ tail ];
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************
|
||||
* printques
|
||||
* m is minor # of device
|
||||
*****************************************************/
|
||||
inline void printques( int m )
|
||||
{
|
||||
int head = dt3155_fbuffer[ m ]->ready_head;
|
||||
int tail;
|
||||
int num = dt3155_fbuffer[ m ]->nbuffers;
|
||||
int frame_index;
|
||||
int index;
|
||||
|
||||
tail = get_tail(m);
|
||||
|
||||
printk("\n R:");
|
||||
for ( index = tail; index != head; index++, index = index % (num) )
|
||||
{
|
||||
frame_index = dt3155_fbuffer[ m ]->ready_que[ index ];
|
||||
printk(" %d ", frame_index );
|
||||
}
|
||||
|
||||
printk("\n E:");
|
||||
for ( index = 0; index < dt3155_fbuffer[ m ]->empty_len; index++ )
|
||||
{
|
||||
frame_index = dt3155_fbuffer[ m ]->empty_buffers[ index ];
|
||||
printk(" %d ", frame_index );
|
||||
}
|
||||
|
||||
frame_index = dt3155_fbuffer[ m ]->active_buf;
|
||||
printk("\n A: %d", frame_index);
|
||||
|
||||
frame_index = dt3155_fbuffer[ m ]->locked_buf;
|
||||
printk("\n L: %d \n", frame_index );
|
||||
|
||||
}
|
||||
|
||||
/*****************************************************
|
||||
* adjust_4MB
|
||||
*
|
||||
* If a buffer intersects the 4MB boundary, push
|
||||
* the start address up to the beginning of the
|
||||
* next 4MB chunk (assuming bufsize < 4MB).
|
||||
*****************************************************/
|
||||
u_long adjust_4MB (u_long buf_addr, u_long bufsize) {
|
||||
if (((buf_addr+bufsize) & UPPER_10_BITS) != (buf_addr & UPPER_10_BITS))
|
||||
return (buf_addr+bufsize) & UPPER_10_BITS;
|
||||
else
|
||||
return buf_addr;
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************
|
||||
* allocate_buffers
|
||||
*
|
||||
* Try to allocate enough memory for all requested
|
||||
* buffers. If there is not enough free space
|
||||
* try for less memory.
|
||||
*****************************************************/
|
||||
void allocate_buffers (u_long *buf_addr, u_long* total_size_kbs,
|
||||
u_long bufsize)
|
||||
{
|
||||
/* Compute the minimum amount of memory guaranteed to hold all
|
||||
MAXBUFFERS such that no buffer crosses the 4MB boundary.
|
||||
Store this value in the variable "full_size" */
|
||||
|
||||
u_long allocator_max;
|
||||
u_long bufs_per_chunk = (FOUR_MB / bufsize);
|
||||
u_long filled_chunks = (MAXBUFFERS-1) / bufs_per_chunk;
|
||||
u_long leftover_bufs = MAXBUFFERS - filled_chunks * bufs_per_chunk;
|
||||
|
||||
u_long full_size = bufsize /* possibly unusable part of 1st chunk */
|
||||
+ filled_chunks * FOUR_MB /* max # of completely filled 4mb chunks */
|
||||
+ leftover_bufs * bufsize; /* these buffs will be in a partly filled
|
||||
chunk at beginning or end */
|
||||
|
||||
u_long full_size_kbs = 1 + (full_size-1) / 1024;
|
||||
u_long min_size_kbs = 2*ndevices*bufsize / 1024;
|
||||
u_long size_kbs;
|
||||
|
||||
/* Now, try to allocate full_size. If this fails, keep trying for
|
||||
less & less memory until it succeeds. */
|
||||
#ifndef STANDALONE_ALLOCATOR
|
||||
/* initialize the allocator */
|
||||
allocator_init(&allocator_max);
|
||||
#endif
|
||||
size_kbs = full_size_kbs;
|
||||
*buf_addr = 0;
|
||||
printk ("DT3155: We would like to get: %d KB\n", (u_int)(full_size_kbs));
|
||||
printk ("DT3155: ...but need at least: %d KB\n", (u_int)(min_size_kbs));
|
||||
printk ("DT3155: ...the allocator has: %d KB\n", (u_int)(allocator_max));
|
||||
size_kbs = (full_size_kbs <= allocator_max ? full_size_kbs : allocator_max);
|
||||
if (size_kbs > min_size_kbs) {
|
||||
if ((*buf_addr = allocator_allocate_dma (size_kbs, GFP_KERNEL)) != 0) {
|
||||
printk ("DT3155: Managed to allocate: %d KB\n", (u_int)size_kbs);
|
||||
*total_size_kbs = size_kbs;
|
||||
return;
|
||||
}
|
||||
}
|
||||
/* If we got here, the allocation failed */
|
||||
printk ("DT3155: Allocator failed!\n");
|
||||
*buf_addr = 0;
|
||||
*total_size_kbs = 0;
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************
|
||||
* dt3155_setup_buffers
|
||||
*
|
||||
* setup_buffers just puts the buffering system into
|
||||
* a consistent state before the start of interrupts
|
||||
*
|
||||
* JML : it looks like all the buffers need to be
|
||||
* continuous. So I'm going to try and allocate one
|
||||
* continuous buffer.
|
||||
*
|
||||
* GCS : Fix DMA problems when buffer spans
|
||||
* 4MB boundary. Also, add error checking. This
|
||||
* function will return -ENOMEM when not enough memory.
|
||||
*****************************************************/
|
||||
u_long dt3155_setup_buffers(u_long *allocatorAddr)
|
||||
|
||||
{
|
||||
u_long index;
|
||||
u_long rambuff_addr; /* start of allocation */
|
||||
u_long rambuff_size; /* total size allocated to driver */
|
||||
u_long rambuff_acm; /* accumlator, keep track of how much
|
||||
is left after being split up*/
|
||||
u_long rambuff_end; /* end of rambuff */
|
||||
u_long numbufs; /* number of useful buffers allocated (per device) */
|
||||
u_long bufsize = DT3155_MAX_ROWS * DT3155_MAX_COLS;
|
||||
int m; /* minor # of device, looped for all devs */
|
||||
|
||||
/* zero the fbuffer status and address structure */
|
||||
for ( m = 0; m < ndevices; m++)
|
||||
{
|
||||
dt3155_fbuffer[ m ] = &(dt3155_status[ m ].fbuffer);
|
||||
|
||||
/* Make sure the buffering variables are consistent */
|
||||
{
|
||||
u_char *ptr = (u_char *) dt3155_fbuffer[ m ];
|
||||
for( index = 0; index < sizeof(struct dt3155_fbuffer_s); index++)
|
||||
*(ptr++)=0;
|
||||
}
|
||||
}
|
||||
|
||||
/* allocate a large contiguous chunk of RAM */
|
||||
allocate_buffers (&rambuff_addr, &rambuff_size, bufsize);
|
||||
printk( "DT3155: mem info\n" );
|
||||
printk( " - rambuf_addr = 0x%x \n", (u_int)rambuff_addr );
|
||||
printk( " - length (kb) = %u \n", (u_int)rambuff_size );
|
||||
if( rambuff_addr == 0 )
|
||||
{
|
||||
printk( KERN_INFO
|
||||
"DT3155: Error setup_buffers() allocator dma failed \n" );
|
||||
return -ENOMEM;
|
||||
}
|
||||
*allocatorAddr = rambuff_addr;
|
||||
rambuff_end = rambuff_addr + 1024 * rambuff_size;
|
||||
|
||||
/* after allocation, we need to count how many useful buffers there
|
||||
are so we can give an equal number to each device */
|
||||
rambuff_acm = rambuff_addr;
|
||||
for ( index = 0; index < MAXBUFFERS; index++) {
|
||||
rambuff_acm = adjust_4MB (rambuff_acm, bufsize);/*avoid spanning 4MB bdry*/
|
||||
if (rambuff_acm + bufsize > rambuff_end)
|
||||
break;
|
||||
rambuff_acm += bufsize;
|
||||
}
|
||||
/* Following line is OK, will waste buffers if index
|
||||
* not evenly divisible by ndevices -NJC*/
|
||||
numbufs = index / ndevices;
|
||||
printk (" - numbufs = %u\n", (u_int) numbufs);
|
||||
if (numbufs < 2) {
|
||||
printk( KERN_INFO
|
||||
"DT3155: Error setup_buffers() couldn't allocate 2 bufs/board\n" );
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
/* now that we have board memory we spit it up */
|
||||
/* between the boards and the buffers */
|
||||
rambuff_acm = rambuff_addr;
|
||||
for ( m = 0; m < ndevices; m ++)
|
||||
{
|
||||
rambuff_acm = adjust_4MB (rambuff_acm, bufsize);
|
||||
|
||||
/* Save the start of this boards buffer space (for mmap). */
|
||||
dt3155_status[ m ].mem_addr = rambuff_acm;
|
||||
|
||||
for (index = 0; index < numbufs; index++)
|
||||
{
|
||||
rambuff_acm = adjust_4MB (rambuff_acm, bufsize);
|
||||
if (rambuff_acm + bufsize > rambuff_end) {
|
||||
/* Should never happen */
|
||||
printk ("DT3155 PROGRAM ERROR (GCS)\n"
|
||||
"Error distributing allocated buffers\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
dt3155_fbuffer[ m ]->frame_info[ index ].addr = rambuff_acm;
|
||||
push_empty( index, m );
|
||||
/* printk(" - Buffer : %lx\n",
|
||||
* dt3155_fbuffer[ m ]->frame_info[ index ].addr );
|
||||
*/
|
||||
dt3155_fbuffer[ m ]->nbuffers += 1;
|
||||
rambuff_acm += bufsize;
|
||||
}
|
||||
|
||||
/* Make sure there is an active buffer there. */
|
||||
dt3155_fbuffer[ m ]->active_buf = pop_empty( m );
|
||||
dt3155_fbuffer[ m ]->even_happened = 0;
|
||||
dt3155_fbuffer[ m ]->even_stopped = 0;
|
||||
|
||||
/* make sure there is no locked_buf JML 2/28/00 */
|
||||
dt3155_fbuffer[ m ]->locked_buf = -1;
|
||||
|
||||
dt3155_status[ m ].mem_size =
|
||||
rambuff_acm - dt3155_status[ m ].mem_addr;
|
||||
|
||||
/* setup the ready queue */
|
||||
dt3155_fbuffer[ m ]->ready_head = 0;
|
||||
dt3155_fbuffer[ m ]->ready_len = 0;
|
||||
printk("Available buffers for device %d: %d\n",
|
||||
m, dt3155_fbuffer[ m ]->nbuffers);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*****************************************************
|
||||
* internal_release_locked_buffer
|
||||
*
|
||||
* The internal function for releasing a locked buffer.
|
||||
* It assumes interrupts are turned off.
|
||||
*
|
||||
* m is minor number of device
|
||||
*****************************************************/
|
||||
static inline void internal_release_locked_buffer( int m )
|
||||
{
|
||||
/* Pointer into global structure for handling buffers */
|
||||
if ( dt3155_fbuffer[ m ]->locked_buf >= 0 )
|
||||
{
|
||||
push_empty( dt3155_fbuffer[ m ]->locked_buf, m );
|
||||
dt3155_fbuffer[ m ]->locked_buf = -1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************
|
||||
* dt3155_release_locked_buffer()
|
||||
* m is minor # of device
|
||||
*
|
||||
* The user function of the above.
|
||||
*
|
||||
*****************************************************/
|
||||
inline void dt3155_release_locked_buffer( int m )
|
||||
{
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
|
||||
unsigned long int flags;
|
||||
local_save_flags(flags);
|
||||
local_irq_disable();
|
||||
internal_release_locked_buffer(m);
|
||||
local_irq_restore(flags);
|
||||
#else
|
||||
int flags;
|
||||
|
||||
save_flags( flags );
|
||||
cli();
|
||||
internal_release_locked_buffer( m );
|
||||
restore_flags( flags );
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************
|
||||
* dt3155_flush()
|
||||
* m is minor # of device
|
||||
*
|
||||
*****************************************************/
|
||||
inline int dt3155_flush( int m )
|
||||
{
|
||||
int index;
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
|
||||
unsigned long int flags;
|
||||
local_save_flags(flags);
|
||||
local_irq_disable();
|
||||
#else
|
||||
int flags;
|
||||
save_flags( flags );
|
||||
cli();
|
||||
#endif
|
||||
|
||||
internal_release_locked_buffer( m );
|
||||
dt3155_fbuffer[ m ]->empty_len = 0;
|
||||
|
||||
for ( index = 0; index < dt3155_fbuffer[ m ]->nbuffers; index++ )
|
||||
push_empty( index, m );
|
||||
|
||||
/* Make sure there is an active buffer there. */
|
||||
dt3155_fbuffer[ m ]->active_buf = pop_empty( m );
|
||||
|
||||
dt3155_fbuffer[ m ]->even_happened = 0;
|
||||
dt3155_fbuffer[ m ]->even_stopped = 0;
|
||||
|
||||
/* setup the ready queue */
|
||||
dt3155_fbuffer[ m ]->ready_head = 0;
|
||||
dt3155_fbuffer[ m ]->ready_len = 0;
|
||||
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
|
||||
local_irq_restore(flags);
|
||||
#else
|
||||
restore_flags( flags );
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*****************************************************
|
||||
* dt3155_get_ready_buffer()
|
||||
* m is minor # of device
|
||||
*
|
||||
* get_ready_buffer will grab the next chunk of data
|
||||
* if it is already there, otherwise it returns 0.
|
||||
* If the user has a buffer locked it will unlock
|
||||
* that buffer before returning the new one.
|
||||
*****************************************************/
|
||||
inline int dt3155_get_ready_buffer( int m )
|
||||
{
|
||||
int frame_index;
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
|
||||
unsigned long int flags;
|
||||
local_save_flags(flags);
|
||||
local_irq_disable();
|
||||
#else
|
||||
int flags;
|
||||
save_flags( flags );
|
||||
cli();
|
||||
#endif
|
||||
|
||||
#ifdef DEBUG_QUES_A
|
||||
printques( m );
|
||||
#endif
|
||||
|
||||
internal_release_locked_buffer( m );
|
||||
|
||||
if (is_ready_buf_empty( m ))
|
||||
frame_index = -1;
|
||||
else
|
||||
{
|
||||
frame_index = pop_ready( m );
|
||||
dt3155_fbuffer[ m ]->locked_buf = frame_index;
|
||||
}
|
||||
|
||||
#ifdef DEBUG_QUES_B
|
||||
printques( m );
|
||||
#endif
|
||||
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
|
||||
local_irq_restore(flags);
|
||||
#else
|
||||
restore_flags( flags );
|
||||
#endif
|
||||
|
||||
return frame_index;
|
||||
}
|
|
@ -0,0 +1,77 @@
|
|||
/*
|
||||
|
||||
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
|
|
@ -0,0 +1,97 @@
|
|||
|
||||
/* 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_ */
|
|
@ -0,0 +1,820 @@
|
|||
/*
|
||||
* sysdep.h -- centralizing compatibility issues between 2.0, 2.2, 2.4
|
||||
*
|
||||
* Copyright (C) 2001 Alessandro Rubini and Jonathan Corbet
|
||||
* Copyright (C) 2001 O'Reilly & Associates
|
||||
*
|
||||
* The source code in this file can be freely used, adapted,
|
||||
* and redistributed in source or binary form, so long as an
|
||||
* acknowledgment appears in derived source files. The citation
|
||||
* should list that the code comes from the book "Linux Device
|
||||
* Drivers" by Alessandro Rubini and Jonathan Corbet, published
|
||||
* by O'Reilly & Associates. No warranty is attached;
|
||||
* we cannot take responsibility for errors or fitness for use.
|
||||
*
|
||||
* $Id: sysdep.h,v 1.2 2005/08/09 06:08:51 ssmedley Exp $
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _SYSDEP_H_
|
||||
#define _SYSDEP_H_
|
||||
|
||||
#ifndef LINUX_VERSION_CODE
|
||||
# include <linux/version.h>
|
||||
#endif
|
||||
|
||||
#ifndef KERNEL_VERSION /* pre-2.1.90 didn't have it */
|
||||
# define KERNEL_VERSION(vers,rel,seq) ( ((vers)<<16) | ((rel)<<8) | (seq) )
|
||||
#endif
|
||||
|
||||
/* only allow 2.0.x 2.2.y and 2.4.z */
|
||||
|
||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,0,0) /* not < 2.0 */
|
||||
# error "This kernel is too old: not supported by this file"
|
||||
#endif
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,7,0) /* not > 2.7, by now */
|
||||
# error "This kernel is too recent: not supported by this file"
|
||||
#endif
|
||||
#if (LINUX_VERSION_CODE & 0xff00) == 1 /* not 2.1 */
|
||||
# error "Please don't use linux-2.1, use 2.2, 2.4 or 2.6 instead"
|
||||
#endif
|
||||
#if (LINUX_VERSION_CODE & 0xff00) == 3 /* not 2.3 */
|
||||
# error "Please don't use linux-2.3, use 2.4 or 2.6 instead"
|
||||
#endif
|
||||
|
||||
/* remember about the current version */
|
||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,0)
|
||||
# define LINUX_20
|
||||
#elif LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0)
|
||||
# define LINUX_22
|
||||
#else
|
||||
# define LINUX_24
|
||||
#endif
|
||||
|
||||
/* we can't support versioning in pre-2.4 because we #define some functions */
|
||||
#if !defined(LINUX_24) && defined(CONFIG_MODVERSIONS)
|
||||
# error "This sysdep.h can't support CONFIG_MODVERSIONS"
|
||||
# error "and old kernels at the same time."
|
||||
# error "Either use 2.4 or avoid using versioning"
|
||||
#endif
|
||||
|
||||
#ifndef LINUX_20 /* include vmalloc.h if this is 2.2/2.4 */
|
||||
# ifdef VM_READ /* a typical flag defined by mm.h */
|
||||
# include <linux/vmalloc.h>
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#include <linux/sched.h>
|
||||
|
||||
/* Modularization issues */
|
||||
#ifdef LINUX_20
|
||||
# define __USE_OLD_SYMTAB__
|
||||
# define EXPORT_NO_SYMBOLS register_symtab(NULL);
|
||||
# define REGISTER_SYMTAB(tab) register_symtab(tab)
|
||||
#else
|
||||
# define REGISTER_SYMTAB(tab) /* nothing */
|
||||
#endif
|
||||
|
||||
#ifdef __USE_OLD_SYMTAB__
|
||||
# define __MODULE_STRING(s) /* nothing */
|
||||
# define MODULE_PARM(v,t) /* nothing */
|
||||
# define MODULE_PARM_DESC(v,t) /* nothing */
|
||||
# define MODULE_AUTHOR(n) /* nothing */
|
||||
# define MODULE_DESCRIPTION(d) /* nothing */
|
||||
# define MODULE_SUPPORTED_DEVICE(n) /* nothing */
|
||||
#endif
|
||||
|
||||
/*
|
||||
* In version 2.2 (up to 2.2.19, at least), the macro for request_module()
|
||||
* when no kmod is there is wrong. It's a "do {} while 0" but it shouldbe int
|
||||
*/
|
||||
#ifdef LINUX_22
|
||||
# ifndef CONFIG_KMOD
|
||||
# undef request_module
|
||||
# define request_module(name) -ENOSYS
|
||||
# endif
|
||||
#endif
|
||||
|
||||
|
||||
#ifndef LINUX_20
|
||||
# include <linux/init.h> /* module_init/module_exit */
|
||||
#endif
|
||||
|
||||
#ifndef module_init
|
||||
# define module_init(x) int init_module(void) { return x(); }
|
||||
# define module_exit(x) void cleanup_module(void) { x(); }
|
||||
#endif
|
||||
|
||||
#ifndef SET_MODULE_OWNER
|
||||
# define SET_MODULE_OWNER(structure) /* nothing */
|
||||
#endif
|
||||
|
||||
/*
|
||||
* "select" changed in 2.1.23. The implementation is twin, but this
|
||||
* header is new
|
||||
*
|
||||
*/
|
||||
#ifdef LINUX_20
|
||||
# define __USE_OLD_SELECT__
|
||||
#else
|
||||
# include <linux/poll.h>
|
||||
#endif
|
||||
|
||||
#ifdef LINUX_20
|
||||
# define INODE_FROM_F(filp) ((filp)->f_inode)
|
||||
#else
|
||||
# define INODE_FROM_F(filp) ((filp)->f_dentry->d_inode)
|
||||
#endif
|
||||
|
||||
/* Other changes in the fops are solved using wrappers */
|
||||
|
||||
/*
|
||||
* Wait queues changed with 2.3
|
||||
*/
|
||||
#ifndef DECLARE_WAIT_QUEUE_HEAD
|
||||
# define DECLARE_WAIT_QUEUE_HEAD(head) struct wait_queue *head = NULL
|
||||
typedef struct wait_queue *wait_queue_head_t;
|
||||
# define init_waitqueue_head(head) (*(head)) = NULL
|
||||
|
||||
/* offer wake_up_sync as an alias for wake_up */
|
||||
# define wake_up_sync(head) wake_up(head)
|
||||
# define wake_up_interruptible_sync(head) wake_up_interruptible(head)
|
||||
|
||||
/* Pretend we have add_wait_queue_exclusive */
|
||||
# define add_wait_queue_exclusive(q,entry) add_wait_queue ((q), (entry))
|
||||
|
||||
#endif /* no DECLARE_WAIT_QUEUE_HEAD */
|
||||
|
||||
/*
|
||||
* Define wait_event for 2.0 kernels. (This ripped off directly from
|
||||
* the 2.2.18 sched.h)
|
||||
*/
|
||||
#ifdef LINUX_20
|
||||
|
||||
#define __wait_event(wq, condition) \
|
||||
do { \
|
||||
struct wait_queue __wait; \
|
||||
\
|
||||
__wait.task = current; \
|
||||
add_wait_queue(&wq, &__wait); \
|
||||
for (;;) { \
|
||||
current->state = TASK_UNINTERRUPTIBLE; \
|
||||
mb(); \
|
||||
if (condition) \
|
||||
break; \
|
||||
schedule(); \
|
||||
} \
|
||||
current->state = TASK_RUNNING; \
|
||||
remove_wait_queue(&wq, &__wait); \
|
||||
} while (0)
|
||||
|
||||
#define wait_event(wq, condition) \
|
||||
do { \
|
||||
if (condition) \
|
||||
break; \
|
||||
__wait_event(wq, condition); \
|
||||
} while (0)
|
||||
|
||||
#define __wait_event_interruptible(wq, condition, ret) \
|
||||
do { \
|
||||
struct wait_queue __wait; \
|
||||
\
|
||||
__wait.task = current; \
|
||||
add_wait_queue(&wq, &__wait); \
|
||||
for (;;) { \
|
||||
current->state = TASK_INTERRUPTIBLE; \
|
||||
mb(); \
|
||||
if (condition) \
|
||||
break; \
|
||||
if (!signal_pending(current)) { \
|
||||
schedule(); \
|
||||
continue; \
|
||||
} \
|
||||
ret = -ERESTARTSYS; \
|
||||
break; \
|
||||
} \
|
||||
current->state = TASK_RUNNING; \
|
||||
remove_wait_queue(&wq, &__wait); \
|
||||
} while (0)
|
||||
|
||||
#define wait_event_interruptible(wq, condition) \
|
||||
({ \
|
||||
int __ret = 0; \
|
||||
if (!(condition)) \
|
||||
__wait_event_interruptible(wq, condition, __ret); \
|
||||
__ret; \
|
||||
})
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
* 2.3 added tasklets
|
||||
*/
|
||||
#ifdef LINUX_24
|
||||
# define HAVE_TASKLETS
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
/* FIXME: implement the other versions of wake_up etc */
|
||||
|
||||
|
||||
/*
|
||||
* access to user space: use the 2.2 functions,
|
||||
* and implement them as macros for 2.0
|
||||
*/
|
||||
|
||||
#ifdef LINUX_20
|
||||
# include <asm/segment.h>
|
||||
# define access_ok(t,a,sz) (verify_area((t),(void *) (a),(sz)) ? 0 : 1)
|
||||
# define verify_area_20 verify_area
|
||||
# define copy_to_user(t,f,n) (memcpy_tofs((t), (f), (n)), 0)
|
||||
# define copy_from_user(t,f,n) (memcpy_fromfs((t), (f), (n)), 0)
|
||||
# define __copy_to_user(t,f,n) copy_to_user((t), (f), (n))
|
||||
# define __copy_from_user(t,f,n) copy_from_user((t), (f), (n))
|
||||
|
||||
# define PUT_USER(val,add) (put_user((val),(add)), 0)
|
||||
# define __PUT_USER(val,add) PUT_USER((val),(add))
|
||||
|
||||
# define GET_USER(dest,add) ((dest)=get_user((add)), 0)
|
||||
# define __GET_USER(dest,add) GET_USER((dest),(add))
|
||||
#else
|
||||
# include <asm/uaccess.h>
|
||||
# include <asm/io.h>
|
||||
# define verify_area_20(t,a,sz) (0) /* == success */
|
||||
# define PUT_USER put_user
|
||||
# define __PUT_USER __put_user
|
||||
# define GET_USER get_user
|
||||
# define __GET_USER __get_user
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Allocation issues
|
||||
*/
|
||||
#ifdef GFP_USER /* only if mm.h has been included */
|
||||
# ifdef LINUX_20
|
||||
# define __GFP_DMA GFP_DMA /* 2.0 didn't have the leading __ */
|
||||
# endif
|
||||
# ifndef LINUX_24
|
||||
# define __GFP_HIGHMEM 0 /* was not there */
|
||||
# define GFP_HIGHUSER 0 /* idem */
|
||||
# endif
|
||||
|
||||
# ifdef LINUX_20
|
||||
# define __get_free_pages(a,b) __get_free_pages((a),(b),0)
|
||||
# endif
|
||||
# ifndef LINUX_24
|
||||
# define get_zeroed_page get_free_page
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/* ioremap */
|
||||
#if defined(LINUX_20) && defined(_LINUX_MM_H)
|
||||
# define ioremap_nocache ioremap
|
||||
# ifndef __i386__
|
||||
/* This simple approach works for non-PC platforms. */
|
||||
# define ioremap vremap
|
||||
# define iounmap vfree
|
||||
# else /* the PC has <expletive> ISA; 2.2 and 2.4 remap it, 2.0 needs not */
|
||||
extern inline void *ioremap(unsigned long phys_addr, unsigned long size)
|
||||
{
|
||||
if (phys_addr >= 0xA0000 && phys_addr + size <= 0x100000)
|
||||
return (void *)phys_addr;
|
||||
return vremap(phys_addr, size);
|
||||
}
|
||||
|
||||
extern inline void iounmap(void *addr)
|
||||
{
|
||||
if ((unsigned long)addr >= 0xA0000
|
||||
&& (unsigned long)addr < 0x100000)
|
||||
return;
|
||||
vfree(addr);
|
||||
}
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/* Also, define check_mem_region etc */
|
||||
#ifndef LINUX_24
|
||||
# define check_mem_region(a,b) 0 /* success */
|
||||
# define request_mem_region(a,b,c) /* nothing */
|
||||
# define release_mem_region(a,b) /* nothing */
|
||||
#endif
|
||||
|
||||
/* implement capable() for 2.0 */
|
||||
#ifdef LINUX_20
|
||||
# define capable(anything) suser()
|
||||
#endif
|
||||
|
||||
/* The use_count of exec_domain and binfmt changed in 2.1.23 */
|
||||
|
||||
#ifdef LINUX_20
|
||||
# define INCRCOUNT(p) ((p)->module ? __MOD_INC_USE_COUNT((p)->module) : 0)
|
||||
# define DECRCOUNT(p) ((p)->module ? __MOD_DEC_USE_COUNT((p)->module) : 0)
|
||||
# define CURRCOUNT(p) ((p)->module && (p)->module->usecount)
|
||||
#else
|
||||
# define INCRCOUNT(p) ((p)->use_count++)
|
||||
# define DECRCOUNT(p) ((p)->use_count--)
|
||||
# define CURRCOUNT(p) ((p)->use_count)
|
||||
#endif
|
||||
|
||||
/*
|
||||
* /proc has changed a lot across the versions...
|
||||
*/
|
||||
#ifdef LINUX_20
|
||||
# define USE_PROC_REGISTER
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
* 2.2 didn't have create_proc_{read|info}_entry yet.
|
||||
* And it looks like there are no other "interesting" entry point, as
|
||||
* the rest is somehow esotique (mknod, symlink, ...)
|
||||
*/
|
||||
#ifdef LINUX_22
|
||||
# ifdef PROC_SUPER_MAGIC /* Only if procfs is being used */
|
||||
extern inline struct proc_dir_entry *create_proc_read_entry(const char *name,
|
||||
mode_t mode, struct proc_dir_entry *base,
|
||||
read_proc_t *read_proc, void * data)
|
||||
{
|
||||
struct proc_dir_entry *res=create_proc_entry(name,mode,base);
|
||||
if (res) {
|
||||
res->read_proc=read_proc;
|
||||
res->data=data;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
# ifndef create_proc_info_entry /* added in 2.2.18 */
|
||||
typedef int (get_info_t)(char *, char **, off_t, int, int);
|
||||
extern inline struct proc_dir_entry *create_proc_info_entry(const char *name,
|
||||
mode_t mode, struct proc_dir_entry *base, get_info_t *get_info)
|
||||
{
|
||||
struct proc_dir_entry *res=create_proc_entry(name,mode,base);
|
||||
if (res) res->get_info=get_info;
|
||||
return res;
|
||||
}
|
||||
# endif /* no create_proc_info_entry */
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifdef LINUX_20
|
||||
# define test_and_set_bit(nr,addr) test_bit((nr),(addr))
|
||||
# define test_and_clear_bit(nr,addr) clear_bit((nr),(addr))
|
||||
# define test_and_change_bit(nr,addr) change_bit((nr),(addr))
|
||||
#endif
|
||||
|
||||
|
||||
/* 2.0 had no read and write memory barriers, and 2.2 lacks the
|
||||
set_ functions */
|
||||
#ifndef LINUX_24
|
||||
# ifdef LINUX_20
|
||||
# define wmb() mb() /* this is a big penalty on non-reordering platfs */
|
||||
# define rmb() mb() /* this is a big penalty on non-reordering platfs */
|
||||
# endif /* LINUX_20 */
|
||||
|
||||
#define set_mb() do { var = value; mb(); } while (0)
|
||||
#define set_wmb() do { var = value; wmb(); } while (0)
|
||||
#endif /* ! LINUX_24 */
|
||||
|
||||
|
||||
|
||||
/* 2.1.30 removed these functions. Let's define them, just in case */
|
||||
#ifndef LINUX_20
|
||||
# define queue_task_irq queue_task
|
||||
# define queue_task_irq_off queue_task
|
||||
#endif
|
||||
|
||||
/* 2.1.10 and 2.1.43 introduced new functions. They are worth using */
|
||||
|
||||
#ifdef LINUX_20
|
||||
|
||||
# include <asm/byteorder.h>
|
||||
# ifdef __LITTLE_ENDIAN
|
||||
# define cpu_to_le16(x) (x)
|
||||
# define cpu_to_le32(x) (x)
|
||||
# define cpu_to_be16(x) htons((x))
|
||||
# define cpu_to_be32(x) htonl((x))
|
||||
# else
|
||||
# define cpu_to_be16(x) (x)
|
||||
# define cpu_to_be32(x) (x)
|
||||
extern inline __u16 cpu_to_le16(__u16 x) { return (x<<8) | (x>>8);}
|
||||
extern inline __u32 cpu_to_le32(__u32 x) { return (x>>24) |
|
||||
((x>>8)&0xff00) | ((x<<8)&0xff0000) | (x<<24);}
|
||||
# endif
|
||||
|
||||
# define le16_to_cpu(x) cpu_to_le16(x)
|
||||
# define le32_to_cpu(x) cpu_to_le32(x)
|
||||
# define be16_to_cpu(x) cpu_to_be16(x)
|
||||
# define be32_to_cpu(x) cpu_to_be32(x)
|
||||
|
||||
# define cpu_to_le16p(addr) (cpu_to_le16(*(addr)))
|
||||
# define cpu_to_le32p(addr) (cpu_to_le32(*(addr)))
|
||||
# define cpu_to_be16p(addr) (cpu_to_be16(*(addr)))
|
||||
# define cpu_to_be32p(addr) (cpu_to_be32(*(addr)))
|
||||
|
||||
extern inline void cpu_to_le16s(__u16 *a) {*a = cpu_to_le16(*a);}
|
||||
extern inline void cpu_to_le32s(__u16 *a) {*a = cpu_to_le32(*a);}
|
||||
extern inline void cpu_to_be16s(__u16 *a) {*a = cpu_to_be16(*a);}
|
||||
extern inline void cpu_to_be32s(__u16 *a) {*a = cpu_to_be32(*a);}
|
||||
|
||||
# define le16_to_cpup(x) cpu_to_le16p(x)
|
||||
# define le32_to_cpup(x) cpu_to_le32p(x)
|
||||
# define be16_to_cpup(x) cpu_to_be16p(x)
|
||||
# define be32_to_cpup(x) cpu_to_be32p(x)
|
||||
|
||||
# define le16_to_cpus(x) cpu_to_le16s(x)
|
||||
# define le32_to_cpus(x) cpu_to_le32s(x)
|
||||
# define be16_to_cpus(x) cpu_to_be16s(x)
|
||||
# define be32_to_cpus(x) cpu_to_be32s(x)
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef LINUX_20
|
||||
# define __USE_OLD_REBUILD_HEADER__
|
||||
#endif
|
||||
|
||||
/*
|
||||
* 2.0 didn't include sema_init, so we make our own - but only if it
|
||||
* looks like semaphore.h got included.
|
||||
*/
|
||||
#ifdef LINUX_20
|
||||
# ifdef MUTEX_LOCKED /* Only if semaphore.h included */
|
||||
extern inline void sema_init (struct semaphore *sem, int val)
|
||||
{
|
||||
sem->count = val;
|
||||
sem->waking = sem->lock = 0;
|
||||
sem->wait = NULL;
|
||||
}
|
||||
# endif
|
||||
#endif /* LINUX_20 */
|
||||
|
||||
/*
|
||||
* In 2.0, there is no real need for spinlocks, and they weren't really
|
||||
* implemented anyway.
|
||||
*
|
||||
* XXX the _irqsave variant should be defined eventually to do the
|
||||
* right thing.
|
||||
*/
|
||||
#ifdef LINUX_20
|
||||
typedef int spinlock_t;
|
||||
# define spin_lock(lock)
|
||||
# define spin_unlock(lock)
|
||||
# define spin_lock_init(lock)
|
||||
|
||||
# define spin_lock_irqsave(lock,flags) do { \
|
||||
save_flags(flags); cli(); } while (0);
|
||||
# define spin_unlock_irqrestore(lock,flags) restore_flags(flags);
|
||||
#endif
|
||||
|
||||
/*
|
||||
* 2.1 stuffed the "flush" method into the middle of the file_operations
|
||||
* structure. The FOP_NO_FLUSH symbol is for drivers that do not implement
|
||||
* flush (most of them), it can be inserted in initializers for all 2.x
|
||||
* kernel versions.
|
||||
*/
|
||||
#ifdef LINUX_20
|
||||
# define FOP_NO_FLUSH /* nothing */
|
||||
# define TAG_LLSEEK lseek
|
||||
# define TAG_POLL select
|
||||
#else
|
||||
# define FOP_NO_FLUSH NULL,
|
||||
# define TAG_LLSEEK llseek
|
||||
# define TAG_POLL poll
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* fasync changed in 2.2.
|
||||
*/
|
||||
#ifdef LINUX_20
|
||||
/* typedef struct inode *fasync_file; */
|
||||
# define fasync_file struct inode *
|
||||
#else
|
||||
typedef int fasync_file;
|
||||
#endif
|
||||
|
||||
/* kill_fasync had less arguments, and a different indirection in the first */
|
||||
#ifndef LINUX_24
|
||||
# define kill_fasync(ptrptr,sig,band) kill_fasync(*(ptrptr),(sig))
|
||||
#endif
|
||||
|
||||
/* other things that are virtualized: define the new functions for the old k */
|
||||
#ifdef LINUX_20
|
||||
# define in_interrupt() (intr_count!=0)
|
||||
# define mdelay(x) udelay((x)*1000)
|
||||
# define signal_pending(current) ((current)->signal & ~(current)->blocked)
|
||||
#endif
|
||||
|
||||
#ifdef LINUX_PCI_H /* only if PCI stuff is being used */
|
||||
# ifdef LINUX_20
|
||||
# include "pci-compat.h" /* a whole set of replacement functions */
|
||||
# else
|
||||
# define pci_release_device(d) /* placeholder, used in 2.0 to free stuff */
|
||||
# endif
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Some task state stuff
|
||||
*/
|
||||
|
||||
#ifndef set_current_state
|
||||
# define set_current_state(s) current->state = (s);
|
||||
#endif
|
||||
|
||||
#ifdef LINUX_20
|
||||
extern inline void schedule_timeout(int timeout)
|
||||
{
|
||||
current->timeout = jiffies + timeout;
|
||||
current->state = TASK_INTERRUPTIBLE;
|
||||
schedule();
|
||||
current->timeout = 0;
|
||||
}
|
||||
|
||||
extern inline long sleep_on_timeout(wait_queue_head_t *q, signed long timeout)
|
||||
{
|
||||
signed long early = 0;
|
||||
|
||||
current->timeout = jiffies + timeout;
|
||||
sleep_on (q);
|
||||
if (current->timeout > 0) {
|
||||
early = current->timeout - jiffies;
|
||||
current->timeout = 0;
|
||||
}
|
||||
return early;
|
||||
}
|
||||
|
||||
|
||||
extern inline long interruptible_sleep_on_timeout(wait_queue_head_t *q,
|
||||
signed long timeout)
|
||||
{
|
||||
signed long early = 0;
|
||||
|
||||
current->timeout = jiffies + timeout;
|
||||
interruptible_sleep_on (q);
|
||||
if (current->timeout > 0) {
|
||||
early = current->timeout - jiffies;
|
||||
current->timeout = 0;
|
||||
}
|
||||
return early;
|
||||
}
|
||||
|
||||
#endif /* LINUX_20 */
|
||||
|
||||
/*
|
||||
* Schedule_task was a late 2.4 addition.
|
||||
*/
|
||||
#ifndef LINUX_24
|
||||
extern inline int schedule_task(struct tq_struct *task)
|
||||
{
|
||||
queue_task(task, &tq_scheduler);
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
* Timing issues
|
||||
*/
|
||||
#ifdef LINUX_20
|
||||
# define get_fast_time do_gettimeofday
|
||||
#endif
|
||||
|
||||
#ifdef _LINUX_DELAY_H /* only if linux/delay.h is included */
|
||||
# ifndef mdelay /* linux-2.0 */
|
||||
# ifndef MAX_UDELAY_MS
|
||||
# define MAX_UDELAY_MS 5
|
||||
# endif
|
||||
# define mdelay(n) (\
|
||||
(__builtin_constant_p(n) && (n)<=MAX_UDELAY_MS) ? udelay((n)*1000) : \
|
||||
({unsigned long msec=(n); while (msec--) udelay(1000);}))
|
||||
# endif /* mdelay */
|
||||
#endif /* _LINUX_DELAY_H */
|
||||
|
||||
|
||||
/*
|
||||
* No del_timer_sync before 2.4
|
||||
*/
|
||||
#ifndef LINUX_24
|
||||
# define del_timer_sync(timer) del_timer(timer) /* and hope */
|
||||
#endif
|
||||
|
||||
/*
|
||||
* mod_timer wasn't present in 2.0
|
||||
*/
|
||||
#ifdef LINUX_20
|
||||
static inline int mod_timer(struct timer_list *timer, unsigned long expires)
|
||||
{
|
||||
int pending = del_timer(timer);
|
||||
if (pending) {
|
||||
timer->expires = expires;
|
||||
add_timer(timer);
|
||||
}
|
||||
return pending;
|
||||
}
|
||||
#endif
|
||||
/*
|
||||
* Various changes in mmap and friends.
|
||||
*/
|
||||
|
||||
#ifndef NOPAGE_SIGBUS
|
||||
# define NOPAGE_SIGBUS NULL /* return value of the nopage memory method */
|
||||
# define NOPAGE_OOM NULL /* No real equivalent in older kernels */
|
||||
#endif
|
||||
|
||||
#ifndef VM_RESERVED /* Added 2.4.0-test10 */
|
||||
# define VM_RESERVED 0
|
||||
#endif
|
||||
|
||||
#ifdef LINUX_24 /* use "vm_pgoff" to get an offset */
|
||||
#define VMA_OFFSET(vma) ((vma)->vm_pgoff << PAGE_SHIFT)
|
||||
#else /* use "vm_offset" */
|
||||
#define VMA_OFFSET(vma) ((vma)->vm_offset)
|
||||
#endif
|
||||
|
||||
#ifdef MAP_NR
|
||||
#define virt_to_page(page) (mem_map + MAP_NR(page))
|
||||
#endif
|
||||
|
||||
#ifndef get_page
|
||||
# define get_page(p) atomic_inc(&(p)->count)
|
||||
#endif
|
||||
|
||||
/*
|
||||
* No DMA lock in 2.0.
|
||||
*/
|
||||
#ifdef LINUX_20
|
||||
static inline unsigned long claim_dma_lock(void)
|
||||
{
|
||||
unsigned long flags;
|
||||
save_flags(flags);
|
||||
cli();
|
||||
return flags;
|
||||
}
|
||||
|
||||
static inline void release_dma_lock(unsigned long flags)
|
||||
{
|
||||
restore_flags(flags);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
* I/O memory was not managed by ealier kernels, define them as success
|
||||
*/
|
||||
|
||||
#if 0 /* FIXME: what is the right way to do request_mem_region? */
|
||||
#ifndef LINUX_24
|
||||
# define check_mem_region(start, len) 0
|
||||
# define request_mem_region(start, len, name) 0
|
||||
# define release_mem_region(start, len) 0
|
||||
|
||||
/*
|
||||
* Also, request_ and release_ region used to return void. Return 0 instead
|
||||
*/
|
||||
# define request_region(s, l, n) ({request_region((s),(l),(n));0;})
|
||||
# define release_region(s, l) ({release_region((s),(l));0;})
|
||||
|
||||
#endif /* not LINUX_24 */
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Block layer stuff.
|
||||
*/
|
||||
#ifndef LINUX_24
|
||||
|
||||
/* BLK_DEFAULT_QUEUE for use with these macros only!!!! */
|
||||
#define BLK_DEFAULT_QUEUE(major) blk_dev[(major)].request_fn
|
||||
#define blk_init_queue(where,request_fn) where = request_fn;
|
||||
#define blk_cleanup_queue(where) where = NULL;
|
||||
|
||||
/* No QUEUE_EMPTY in older kernels */
|
||||
#ifndef QUEUE_EMPTY /* Driver can redefine it too */
|
||||
# define QUEUE_EMPTY (CURRENT != NULL)
|
||||
#endif
|
||||
|
||||
#ifdef RO_IOCTLS
|
||||
static inline int blk_ioctl(kdev_t dev, unsigned int cmd, unsigned long arg)
|
||||
{
|
||||
int err;
|
||||
|
||||
switch (cmd) {
|
||||
case BLKRAGET: /* return the readahead value */
|
||||
if (!arg) return -EINVAL;
|
||||
err = ! access_ok(VERIFY_WRITE, arg, sizeof(long));
|
||||
if (err) return -EFAULT;
|
||||
PUT_USER(read_ahead[MAJOR(dev)],(long *) arg);
|
||||
return 0;
|
||||
|
||||
case BLKRASET: /* set the readahead value */
|
||||
if (!capable(CAP_SYS_ADMIN)) return -EACCES;
|
||||
if (arg > 0xff) return -EINVAL; /* limit it */
|
||||
read_ahead[MAJOR(dev)] = arg;
|
||||
return 0;
|
||||
|
||||
case BLKFLSBUF: /* flush */
|
||||
if (! capable(CAP_SYS_ADMIN)) return -EACCES; /* only root */
|
||||
fsync_dev(dev);
|
||||
invalidate_buffers(dev);
|
||||
return 0;
|
||||
|
||||
RO_IOCTLS(dev, arg);
|
||||
}
|
||||
return -ENOTTY;
|
||||
}
|
||||
#endif /* RO_IOCTLS */
|
||||
|
||||
#ifdef LINUX_EXTENDED_PARTITION /* defined in genhd.h */
|
||||
static inline void register_disk(struct gendisk *gdev, kdev_t dev,
|
||||
unsigned minors, struct file_operations *ops, long size)
|
||||
{
|
||||
if (! gdev)
|
||||
return;
|
||||
resetup_one_dev(gdev, MINOR(dev) >> gdev->minor_shift);
|
||||
}
|
||||
#endif /* LINUX_EXTENDED_PARTITION */
|
||||
|
||||
|
||||
#else /* it is Linux 2.4 */
|
||||
#define HAVE_BLKPG_H
|
||||
#endif /* LINUX_24 */
|
||||
|
||||
|
||||
|
||||
#ifdef LINUX_20 /* physical and virtual addresses had the same value */
|
||||
# define __pa(a) (a)
|
||||
# define __va(a) (a)
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Network driver compatibility
|
||||
*/
|
||||
|
||||
/*
|
||||
* 2.0 dev_kfree_skb had an extra arg. The following is a little dangerous
|
||||
* in that it assumes that FREE_WRITE is always wanted. Very few 2.0 drivers
|
||||
* use FREE_READ, but the number is *not* zero...
|
||||
*
|
||||
* Also: implement the non-checking versions of a couple skb functions -
|
||||
* but they still check in 2.0.
|
||||
*/
|
||||
#ifdef LINUX_20
|
||||
# define dev_kfree_skb(skb) dev_kfree_skb((skb), FREE_WRITE);
|
||||
|
||||
# define __skb_push(skb, len) skb_push((skb), (len))
|
||||
# define __skb_put(skb, len) skb_put((skb), (len))
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Softnet changes in 2.4
|
||||
*/
|
||||
#ifndef LINUX_24
|
||||
# ifdef _LINUX_NETDEVICE_H /* only if netdevice.h was included */
|
||||
# define netif_start_queue(dev) clear_bit(0, (void *) &(dev)->tbusy);
|
||||
# define netif_stop_queue(dev) set_bit(0, (void *) &(dev)->tbusy);
|
||||
|
||||
static inline void netif_wake_queue(struct device *dev)
|
||||
{
|
||||
clear_bit(0, (void *) &(dev)->tbusy);
|
||||
mark_bh(NET_BH);
|
||||
}
|
||||
|
||||
/* struct device became struct net_device */
|
||||
# define net_device device
|
||||
# endif /* netdevice.h */
|
||||
#endif /* ! LINUX_24 */
|
||||
|
||||
/*
|
||||
* Memory barrier stuff, define what's missing from older kernel versions
|
||||
*/
|
||||
#ifdef switch_to /* this is always a macro, defined in <asm/sysstem.h> */
|
||||
|
||||
# ifndef set_mb
|
||||
# define set_mb(var, value) do {(var) = (value); mb();} while 0
|
||||
# endif
|
||||
# ifndef set_rmb
|
||||
# define set_rmb(var, value) do {(var) = (value); rmb();} while 0
|
||||
# endif
|
||||
# ifndef set_wmb
|
||||
# define set_wmb(var, value) do {(var) = (value); wmb();} while 0
|
||||
# endif
|
||||
|
||||
/* The hw barriers are defined as sw barriers. A correct thing if this
|
||||
specific kernel/platform is supported but has no specific instruction */
|
||||
# ifndef mb
|
||||
# define mb barrier
|
||||
# endif
|
||||
# ifndef rmb
|
||||
# define rmb barrier
|
||||
# endif
|
||||
# ifndef wmb
|
||||
# define wmb barrier
|
||||
# endif
|
||||
|
||||
#endif /* switch to (i.e. <asm/system.h>) */
|
||||
|
||||
|
||||
#endif /* _SYSDEP_H_ */
|
Loading…
Reference in New Issue