tps/gnurabbit: first commit of the needed driver.

This version is the one uploaded in ohwr.org at the moment of this commit.
parent 6a8f19d8
This diff is collapsed.
DIRS = kernel user bench doc
all:
@for d in $(DIRS); do $(MAKE) -C $$d $@ || exit 1; done
clean:
@for d in $(DIRS); do $(MAKE) -C $$d $@ || exit 1; done
This work is part of the White Rabbit project at CERN (cern.ch).
The package includes the raw I/O driver and the GN4124 driver. The kernel
part lives in the kernel/ subdir of the package, while user-space utilities
are under user/
Documentation is under doc/ and is written in Texinfo, which though
old is simple enough to require little efforts on my side. Output is
pdf, text and info.
To compile, just "make". If you miss TeX or texinfo you won't have the
docs. If you miss the compiler or gmake you won't have anything.
To make clean just "make clean".
CFLAGS = -Wall -ggdb -I../kernel
AS = $(CROSS_COMPILE)as
LD = $(CROSS_COMPILE)ld
CC = $(CROSS_COMPILE)gcc
CPP = $(CC) -E
AR = $(CROSS_COMPILE)ar
NM = $(CROSS_COMPILE)nm
STRIP = $(CROSS_COMPILE)strip
OBJCOPY = $(CROSS_COMPILE)objcopy
OBJDUMP = $(CROSS_COMPILE)objdump
ALL = ioctl irq878 rdwr
all: $(ALL)
clean:
rm -f $(ALL) *.o *~
\ No newline at end of file
/*
* Trivial performance test for ioctl I/O
*
* Copyright (C) 2010 Alessandro Rubini <rubini@gnudd.com>
* Released according to the GNU GPL, version 2 or any later version.
*
* This work is part of the White Rabbit project and has been sponsored
* by CERN, the European Institute for Nuclear Research.
*/
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <fcntl.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include "rawrabbit.h"
#define DEVNAME "/dev/rawrabbit"
#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
struct rr_iocmd iocmd = {
.address = __RR_SET_BAR(4) | 0xa08,
.datasize = 4,
};
int main(int argc, char **argv)
{
int fd, count, count0, usec;
struct timeval tv1, tv2;
if (argc != 2) {
fprintf(stderr, "%s: use \"%s <count>\"\n", argv[0], argv[0]);
exit(1);
}
count0 = count = atoi(argv[1]);
if (!count) {
fprintf(stderr, "%s: not a number \"%s\"\n", argv[0], argv[1]);
exit(1);
}
fd = open(DEVNAME, O_RDWR);
if (fd < 0) {
fprintf(stderr, "%s: %s: %s\n", argv[0], DEVNAME,
strerror(errno));
exit(1);
}
gettimeofday(&tv1, NULL);
while (count--) {
static int values[] = {
/* These make a pwm signal on the leds */
0xf000, 0xf000, 0xf000, 0xf000,
0xe000, 0xc000, 0x8000, 0x0000
};
iocmd.data32 = values[ count % ARRAY_SIZE(values) ];
if (ioctl(fd, RR_WRITE, &iocmd) < 0) {
fprintf(stderr, "%s: %s: ioctl: %s\n", argv[0], DEVNAME,
strerror(errno));
exit(1);
}
}
gettimeofday(&tv2, NULL);
usec = (tv2.tv_sec - tv1.tv_sec) * 1000 * 1000
+ tv2.tv_usec - tv1.tv_usec;
printf("%i ioctls in %i usecs\n", count0, usec);
printf("%i ioctls per second\n",
(int)(count0 * 1000LL * 1000LL / usec));
exit(0);
}
/*
* Trivial performance test for irq management
*
* Copyright (C) 2010 Alessandro Rubini <rubini@gnudd.com>
* Released according to the GNU GPL, version 2 or any later version.
*
* This work is part of the White Rabbit project and has been sponsored
* by CERN, the European Institute for Nuclear Research.
*/
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <fcntl.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include "rawrabbit.h"
#define DEVNAME "/dev/rawrabbit"
#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
struct rr_devsel devsel = {
.vendor = 0x109e,
.device = 0x036e,
.subvendor = RR_DEVSEL_UNUSED,
.bus = RR_DEVSEL_UNUSED,
};
#define ENA_VAL 0x02
#define ENA_REG (__RR_SET_BAR(0) | 0x104)
#define ACK_REG (__RR_SET_BAR(0) | 0x100)
struct rr_iocmd iocmd = {
.datasize = 4,
};
int main(int argc, char **argv)
{
int fd, count, count0, nsec;
unsigned long long total = 0LL;
if (argc != 2) {
fprintf(stderr, "%s: use \"%s <count>\"\n", argv[0], argv[0]);
exit(1);
}
count0 = count = atoi(argv[1]);
if (!count) {
fprintf(stderr, "%s: not a number \"%s\"\n", argv[0], argv[1]);
exit(1);
}
fd = open(DEVNAME, O_RDWR);
if (fd < 0) {
fprintf(stderr, "%s: %s: %s\n", argv[0], DEVNAME,
strerror(errno));
exit(1);
}
/* choose the 878 device */
if (ioctl(fd, RR_DEVSEL, &devsel) < 0) {
fprintf(stderr, "%s: %s: ioctl: %s\n", argv[0], DEVNAME,
strerror(errno));
exit(1);
}
/* enable */
iocmd.address = ENA_REG;
iocmd.data32 = ENA_VAL;
if (ioctl(fd, RR_WRITE, &iocmd) < 0) {
fprintf(stderr, "%s: %s: ioctl: %s\n", argv[0], DEVNAME,
strerror(errno));
exit(1);
}
iocmd.address = ACK_REG;
while (count) {
nsec = ioctl(fd, RR_IRQWAIT);
if (nsec < 0) {
if (errno == EAGAIN) {
ioctl(fd, RR_IRQENA);
continue;
}
fprintf(stderr, "%s: %s: ioctl: %s\n", argv[0], DEVNAME,
strerror(errno));
exit(1); /* Argh! */
}
count--;
/* ack: this must work */
ioctl(fd, RR_WRITE, &iocmd);
nsec = ioctl(fd, RR_IRQENA, &iocmd);
if (nsec < 0) {
fprintf(stderr, "%s: %s: ioctl: %s\n", argv[0], DEVNAME,
strerror(errno));
/* Hmm... */
} else {
total += nsec;
}
}
/* now disable and then acknowledge */
iocmd.address = ENA_REG;
iocmd.data32 = 0;
ioctl(fd, RR_WRITE, &iocmd);
iocmd.address = ACK_REG;
iocmd.data32 = ~0;
ioctl(fd, RR_WRITE, &iocmd);
printf("got %i interrupts, average delay %lins\n", count0,
(long)(total / count0));
exit(0);
}
/*
* Trivial performance test for read(2)/write(2) I/O
*
* Copyright (C) 2010 Alessandro Rubini <rubini@gnudd.com>
* Released according to the GNU GPL, version 2 or any later version.
*
* This work is part of the White Rabbit project and has been sponsored
* by CERN, the European Institute for Nuclear Research.
*/
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <fcntl.h>
#include <stdint.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/stat.h>
#include "rawrabbit.h"
#define DEVNAME "/dev/rawrabbit"
int main(int argc, char **argv)
{
int fd, count, count0, usec;
struct timeval tv1, tv2;
if (argc != 2) {
fprintf(stderr, "%s: use \"%s <count>\"\n", argv[0], argv[0]);
exit(1);
}
count0 = count = atoi(argv[1]);
if (!count) {
fprintf(stderr, "%s: not a number \"%s\"\n", argv[0], argv[1]);
exit(1);
}
fd = open(DEVNAME, O_RDWR);
if (fd < 0) {
fprintf(stderr, "%s: %s: %s\n", argv[0], DEVNAME,
strerror(errno));
exit(1);
}
/* write */
lseek(fd, __RR_SET_BAR(4) | 0xa08, SEEK_SET);
gettimeofday(&tv1, NULL);
while (count--) {
static uint32_t values[] = {0x0000, 0xf000};
write(fd, values + (count & 1), sizeof(values[0]));
lseek(fd, -sizeof(values[0]), SEEK_CUR);
}
gettimeofday(&tv2, NULL);
usec = (tv2.tv_sec - tv1.tv_sec) * 1000 * 1000
+ tv2.tv_usec - tv1.tv_usec;
printf("%i writes in %i usecs\n", count0, usec);
printf("%i writes per second\n",
(int)(count0 * 1000LL * 1000LL / usec));
/* read: we cut and paste the code, oh so lazy */
count = count0;
lseek(fd, __RR_SET_BAR(4) | 0xa08, SEEK_SET);
gettimeofday(&tv1, NULL);
while (count--) {
static uint32_t value;
read(fd, &value, sizeof(value));
lseek(fd, -sizeof(value), SEEK_CUR);
}
gettimeofday(&tv2, NULL);
usec = (tv2.tv_sec - tv1.tv_sec) * 1000 * 1000
+ tv2.tv_usec - tv1.tv_usec;
printf("%i reads in %i usecs\n", count0, usec);
printf("%i reads per second\n",
(int)(count0 * 1000LL * 1000LL / usec));
exit(0);
}
#
# Makefile for the documentation directory
#
# Copyright 1994,2000,2010 Alessandro Rubini <rubini@linux.it>
#
#################
#
# BE CAREFUL in editing:
# due to the large number of index files, and my use of a non standard
# info input file, any file $(TARGET).* is removed by "make clean"
#
# I chose to use a prefix for the input file ("doc.$(TARGET)"), to ease
# makeing clean and applying my own rules.
#
###################################################################
TARGET = gnurabbit
# Assume makeinfo can do images and --html.
# In any case, MAKEINFO can be specified on the commandline
MAKEINFO = makeinfo
##############################################
INPUT = $(wildcard *.in)
TEXI = $(INPUT:.in=.texi)
.SUFFIXES: .in .texi .info .html .txt
.in.texi:
@rm -f $@ 2> /dev/null
sed -f ./infofilter $< > $@
chmod -w $@
# unfortuantely implicit rules are not concatenated, so force a make run
%.pdf: %.texi $(TEXI)
$(MAKE) $(TEXI)
texi2pdf --batch $<
%.info: %.texi $(TEXI)
$(MAKE) $(TEXI)
$(MAKEINFO) $< -o $@
%.html: %.texi $(TEXI)
$(MAKE) $(TEXI)
$(MAKEINFO) --html --no-split -o $@ $<
%.txt: %.texi $(TEXI)
$(MAKE) $(TEXI)
$(MAKEINFO) --no-headers $< > $@
##############################################
ALL = $(TARGET).info $(TARGET).txt $(TARGET).html $(TARGET).pdf
all: images $(TEXI) $(ALL)
images::
if [ -d images ]; then $(MAKE) -C images || exit 1; fi
info: $(TARGET).info
check: _err.ps
gs -sDEVICE=linux -r320x200x16 $<
terse:
for n in cp fn ky pg toc tp vr; do \
rm -f $(TARGET).$$n; \
done
rm -f *~
clean: terse
rm -f $(ALL) $(TEXI)
install:
@xrdef{Top-title}{Introduction}
@xrdef{Top-snt}{}
@xrdef{Driver for GN4124-title}{Driver for GN4124}
@xrdef{Driver for GN4124-snt}{Chapter@tie 1}
@xrdef{Raw PCI I/O-title}{Raw PCI I/O}
@xrdef{Raw PCI I/O-snt}{Chapter@tie 2}
@xrdef{General features of rawrabbit-title}{General features of rawrabbit}
@xrdef{General features of rawrabbit-snt}{Section@tie 2.1}
@xrdef{Top-pg}{1}
@xrdef{Driver for GN4124-pg}{1}
@xrdef{Raw PCI I/O-pg}{1}
@xrdef{General features of rawrabbit-pg}{1}
@xrdef{Interrupt management-title}{Interrupt management}
@xrdef{Interrupt management-snt}{Section@tie 2.2}
@xrdef{Bugs and misfeatures-title}{Bugs and misfeatures}
@xrdef{Bugs and misfeatures-snt}{Section@tie 2.3}
@xrdef{The DMA buffer-title}{The DMA buffer}
@xrdef{The DMA buffer-snt}{Section@tie 2.4}
@xrdef{Interrupt management-pg}{2}
@xrdef{Bugs and misfeatures-pg}{2}
@xrdef{The DMA buffer-pg}{2}
@xrdef{System calls implemented-title}{System calls implemented}
@xrdef{System calls implemented-snt}{Section@tie 2.5}
@xrdef{System calls implemented-pg}{3}
@xrdef{Ioctl commands-title}{Ioctl commands}
@xrdef{Ioctl commands-snt}{Section@tie 2.6}
@xrdef{Ioctl commands-pg}{4}
@xrdef{User space demo programs-title}{User space demo programs}
@xrdef{User space demo programs-snt}{Section@tie 2.7}
@xrdef{rrcmd-title}{rrcmd}
@xrdef{rrcmd-snt}{Section@tie 2.7.1}
@xrdef{User space demo programs-pg}{5}
@xrdef{rrcmd-pg}{5}
@xrdef{User space benchmarks-title}{User space benchmarks}
@xrdef{User space benchmarks-snt}{Section@tie 2.8}
@xrdef{bench/ioctl-title}{bench/ioctl}
@xrdef{bench/ioctl-snt}{Section@tie 2.8.1}
@xrdef{bench/irq878-title}{bench/irq878}
@xrdef{bench/irq878-snt}{Section@tie 2.8.2}
@xrdef{Benchmarking read and write-title}{Benchmarking read and write}
@xrdef{Benchmarking read and write-snt}{Section@tie 2.8.3}
@xrdef{User space benchmarks-pg}{7}
@xrdef{bench/ioctl-pg}{7}
@xrdef{bench/irq878-pg}{7}
@xrdef{Benchmarking read and write-pg}{7}
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This is pdfTeXk, Version 3.141592-1.40.3 (Web2C 7.5.6) (format=pdfetex 2010.3.10) 24 SEP 2010 18:06
entering extended mode
file:line:error style messages enabled.
%&-line parsing enabled.
**\nonstopmode \input ./gnurabbit.texi
(./gnurabbit.texi (/usr/share/texmf/tex/texinfo/texinfo.tex
Loading texinfo [version 2007-09-03.05]:
\bindingoffset=\dimen16
\normaloffset=\dimen17
\pagewidth=\dimen18
\pageheight=\dimen19
\outerhsize=\dimen20
\outervsize=\dimen21
\cornerlong=\dimen22
\cornerthick=\dimen23
\topandbottommargin=\dimen24
\headlinebox=\box16
\footlinebox=\box17
\margin=\insert252
\EMsimple=\toks13
\groupbox=\box18
\groupinvalidhelp=\toks14
\mil=\dimen25
\exdentamount=\skip18
\inmarginspacing=\skip19
pdf,
\tempnum=\count27
\lnkcount=\count28
\filename=\toks15
\filenamelength=\count29
\pgn=\count30
\toksA=\toks16
\toksB=\toks17
\toksC=\toks18
\toksD=\toks19
\boxA=\box19
\countA=\count31
\nopdfimagehelp=\toks20
fonts,
\sffam=\fam8
\textleading=\dimen26
\fontdepth=\count32
page headings,
\titlepagetopglue=\skip20
\titlepagebottomglue=\skip21
\evenheadline=\toks21
\oddheadline=\toks22
\evenfootline=\toks23
\oddfootline=\toks24
tables,
\tableindent=\dimen27
\itemindent=\dimen28
\itemmargin=\dimen29
\itemmax=\dimen30
\itemno=\count33
\multitableparskip=\skip22
\multitableparindent=\skip23
\multitablecolspace=\dimen31
\multitablelinespace=\skip24
\colcount=\count34
\everytab=\toks25
conditionals,
\doignorecount=\count35
indexing,
\whatsitskip=\skip25
\whatsitpenalty=\count36
\secondaryindent=\skip26
\partialpage=\box20
\doublecolumnhsize=\dimen32
sectioning,
\unnumberedno=\count37
\chapno=\count38
\secno=\count39
\subsecno=\count40
\subsubsecno=\count41
\appendixno=\count42
\absseclevel=\count43
\secbase=\count44
\chapheadingskip=\skip27
\secheadingskip=\skip28
\subsecheadingskip=\skip29
toc,
\tocfile=\write0
\contentsrightmargin=\skip30
\savepageno=\count45
\lastnegativepageno=\count46
\tocindent=\dimen33
environments,
\errorbox=\box21
\lispnarrowing=\skip31
\envskipamount=\skip32
\circthick=\dimen34
\cartouter=\dimen35
\cartinner=\dimen36
\normbskip=\skip33
\normpskip=\skip34
\normlskip=\skip35
\lskip=\skip36
\rskip=\skip37
\tabw=\dimen37
defuns,
\defbodyindent=\skip38
\defargsindent=\skip39
\deflastargmargin=\skip40
\defunpenalty=\count47
\parencount=\count48
\brackcount=\count49
macros,
\paramno=\count50
\macname=\toks26
cross references,
\auxfile=\write1
\savesfregister=\count51
insertions,
\footnoteno=\count52
\SAVEfootins=\box22
\SAVEmargin=\box23
(/usr/share/texmf-texlive/tex/generic/epsf/epsf.tex
This is `epsf.tex' v2.7.3 <23 July 2005>
\epsffilein=\read1
\epsfframemargin=\dimen38
\epsfframethickness=\dimen39
\epsfrsize=\dimen40
\epsftmp=\dimen41
\epsftsize=\dimen42
\epsfxsize=\dimen43
\epsfysize=\dimen44
\pspoints=\dimen45
)
\noepsfhelp=\toks27
localization,
\nolanghelp=\toks28
\countUTFx=\count53
\countUTFy=\count54
\countUTFz=\count55
formatting,
\defaultparindent=\dimen46
and turning on texinfo input format.)
(/usr/share/texmf/tex/texinfo/txi-en.tex) (./gnurabbit.aux)
\openout1 = `gnurabbit.aux'.
@cpindfile=@write2
@fnindfile=@write3
@vrindfile=@write4
@tpindfile=@write5
@kyindfile=@write6
@pgindfile=@write7
[1
\openout2 = `gnurabbit.cp'.
\openout3 = `gnurabbit.fn'.
\openout4 = `gnurabbit.vr'.
\openout5 = `gnurabbit.tp'.
\openout6 = `gnurabbit.ky'.
\openout7 = `gnurabbit.pg'.
{/var/lib/texmf/fonts/map/pdftex/updmap/pdftex.map}] (Introduction)
\openout0 = `gnurabbit.toc'.
Chapter 1 Chapter 2 [1]
[2] [3] [4] [5] [6] [7] [8] (./gnurabbit.toc) [-1] (./gnurabbit.toc)
(./gnurabbit.toc) )
Here is how much of TeX's memory you used:
1746 strings out of 97159
21344 string characters out of 1208396
54780 words of memory out of 1500000
2813 multiletter control sequences out of 10000+50000
32127 words of font info for 112 fonts, out of 1200000 for 2000
51 hyphenation exceptions out of 8191
11i,5n,17p,307b,340s stack positions out of 5000i,500n,6000p,200000b,5000s
</usr/share/texmf-texlive/fonts/type1/bluesky/cm/cmb10.pfb><
/usr/share/texmf-texlive/fonts/type1/bluesky/cm/cmbx12.pfb></usr/share/texmf-te
xlive/fonts/type1/bluesky/cm/cmmi10.pfb></usr/share/texmf-texlive/fonts/type1/b
luesky/cm/cmmi12.pfb></usr/share/texmf-texlive/fonts/type1/bluesky/cm/cmr10.pfb
></usr/share/texmf-texlive/fonts/type1/bluesky/cm/cmsltt10.pfb></usr/share/texm
f-texlive/fonts/type1/bluesky/cm/cmti10.pfb></usr/share/texmf-texlive/fonts/typ
e1/bluesky/cm/cmtt10.pfb></usr/share/texmf-texlive/fonts/type1/bluesky/cm/cmtt1
2.pfb></usr/share/texmf-texlive/fonts/type1/bluesky/cm/cmtt9.pfb>
Output written on gnurabbit.pdf (10 pages, 114969 bytes).
PDF statistics:
170 PDF objects out of 1000 (max. 8388607)
24 named destinations out of 1000 (max. 131072)
133 words of extra memory for PDF output out of 10000 (max. 10000000)
This diff is collapsed.
This diff is collapsed.
#! /usr/bin/sed -f
# allow "%" as a comment char, but only at the beginning of the line
s/^%/@c /
#s/[^\\]%.*$//
s/^\\%/%/
# turn accents into tex encoding (for Italian language)
s/a`//g
s/e`//g
s/E`//g
s/i`//g
s/o`//g
s/u`//g
s/erch/erch/g
s/oich/oich/g
s/n/n/g
s//@`a/g
s//@`e/g
s//@'e/g
s//@`i/g
s//@`o/g
s//@`E/g
s//@`u/g
#preserve blanks, braces and @ in @example and @smallexample blocks
/@example/,/@end example/ s/{/@{/g
/@example/,/@end example/ s/}/@}/g
/@example/,/@end example/ s/@/@@/g
s/^@@example/@example/
s/^@@end/@end/
/@example/,/@end example/ p
/@example/,/@end example/ d
/@smallexample/,/@end smallexample/ s/{/@{/g
/@smallexample/,/@end smallexample/ s/}/@}/g
/@smallexample/,/@end smallexample/ s/@/@@/g
s/^@@smallexample/@smallexample/
s/^@@end/@end/
/@smallexample/,/@end smallexample/ p
/@smallexample/,/@end smallexample/ d
# remove leading blanks
s/^[ ]*//
# fix include to include texi not in
s/^\(.include.*\).in$/\1.texi/
LINUX ?= /lib/modules/$(shell uname -r)/build
obj-m = rawrabbit.o
all modules:
$(MAKE) -C $(LINUX) M=$(shell /bin/pwd) modules
clean:
rm -rf *.o *~ .*.cmd *.ko *.mod.c .tmp_versions Module.symvers \
Module.markers modules.order
/* Simple compatibility macros */
#ifdef CONFIG_X86
/* Readq for IA32 introduced in 2.6.28-rc7 */
#ifndef readq
static inline __u64 readq(const volatile void __iomem *addr)
{
const volatile u32 __iomem *p = addr;
u32 low, high;
low = readl(p);
high = readl(p + 1);
return low + ((u64)high << 32);
}
static inline void writeq(__u64 val, volatile void __iomem *addr)
{
writel(val, addr);
writel(val >> 32, addr+4);
}
#endif
#endif /* X86 */
/* Hack... something I sometimes need */
static inline void dumpstruct(char *name, void *ptr, int size)
{
int i;
unsigned char *p = ptr;
printk("dump %s at %p (size 0x%x)\n", name, ptr, size);
for (i = 0; i < size; ) {
printk("%02x", p[i]);
i++;
printk(i & 3 ? " " : i & 0xf ? " " : "\n");
}
if (i & 0xf)
printk("\n");
}
This diff is collapsed.
/*
* Public header for the raw I/O interface for PCI or PCI express interfaces
*
* Copyright (C) 2010 Alessandro Rubini <rubini@gnudd.com>
* Released according to the GNU GPL, version 2 or any later version.
*
* This work is part of the White Rabbit project and has been sponsored
* by CERN, the European Institute for Nuclear Research.
*/
#ifndef __RAWRABBIT_H__
#define __RAWRABBIT_H__
#include <linux/types.h>
#include <linux/ioctl.h>
#ifdef __KERNEL__ /* The initial part of the file is driver-internal stuff */
#include <linux/pci.h>
#include <linux/spinlock.h>
#include <linux/completion.h>
#include <linux/wait.h>
struct rr_devsel;
struct rr_dev {
struct rr_devsel *devsel;
struct pci_driver *pci_driver;
struct pci_device_id *id_table;
struct pci_dev *pdev; /* non-null after pciprobe */
spinlock_t lock;
wait_queue_head_t q;
void *dmabuf;
struct timespec irqtime;
unsigned long irqcount;
struct completion complete;
struct resource *area[3]; /* bar 0, 2, 4 */
void *remap[3]; /* ioremap of bar 0, 2, 4 */
unsigned long flags;
int usecount;
};
#define RR_FLAG_REGISTERED 0x00000001
#define RR_FLAG_IRQDISABLE 0x00000002
#define RR_FLAG_IRQREQUEST 0x00000002
#define RR_PROBE_TIMEOUT (HZ/10) /* for pci_register_drv */
#endif /* __KERNEL__ */
/* By default, the driver registers for this vendor/devid */
#define RR_DEFAULT_VENDOR 0x1a39
#define RR_DEFAULT_DEVICE 0x0004
#define RR_DEFAULT_BUFSIZE (1<<20) /* 1MB */
#define RR_PLIST_SIZE 4096 /* no PAGE_SIZE in user space */
#define RR_PLIST_LEN (RR_PLIST_SIZE / sizeof(void *))
#define RR_MAX_BUFSIZE (RR_PLIST_SIZE * RR_PLIST_LEN)
/* This structure is used to select the device to be accessed, via ioctl */
struct rr_devsel {
__u16 vendor;
__u16 device;
__u16 subvendor; /* RR_DEVSEL_UNUSED to ignore subvendor/dev */
__u16 subdevice;
__u16 bus; /* RR_DEVSEL_UNUSED to ignore bus and devfn */
__u16 devfn;
};
#define RR_DEVSEL_UNUSED 0xffff
/* Offsets for BAR areas in llseek() and/or ioctl */
#define RR_BAR_0 0x00000000
#define RR_BAR_2 0x20000000
#define RR_BAR_4 0x40000000
#define RR_BAR_BUF 0xc0000000 /* The DMA buffer */
#define RR_IS_DMABUF(addr) ((addr) >= RR_BAR_BUF)
#define __RR_GET_BAR(x) ((x) >> 28)
#define __RR_SET_BAR(x) ((x) << 28)
#define __RR_GET_OFF(x) ((x) & 0x0fffffff)
static inline int rr_is_valid_bar(unsigned long address)
{
int bar = __RR_GET_BAR(address);
return bar == 0 || bar == 2 || bar == 4 || bar == 0x0c;
}
static inline int rr_is_dmabuf_bar(unsigned long address)
{
int bar = __RR_GET_BAR(address);
return bar == 0x0c;
}
struct rr_iocmd {
__u32 address; /* bar and offset */
__u32 datasize; /* 1 or 2 or 4 or 8 */
union {
__u8 data8;
__u16 data16;
__u32 data32;
__u64 data64;
};
};
/* ioctl commands */
#define __RR_IOC_MAGIC '4' /* random or so */
#define RR_DEVSEL _IOW(__RR_IOC_MAGIC, 0, struct rr_devsel)
#define RR_DEVGET _IOR(__RR_IOC_MAGIC, 1, struct rr_devsel)
#define RR_READ _IOWR(__RR_IOC_MAGIC, 2, struct rr_iocmd)
#define RR_WRITE _IOW(__RR_IOC_MAGIC, 3, struct rr_iocmd)
#define RR_IRQWAIT _IO(__RR_IOC_MAGIC, 4)
#define RR_IRQENA _IO(__RR_IOC_MAGIC, 5)
#define RR_GETDMASIZE _IO(__RR_IOC_MAGIC, 6)
/* #define RR_SETDMASIZE _IO(__RR_IOC_MAGIC, 7, unsigned long) */
#define RR_GETPLIST _IO(__RR_IOC_MAGIC, 8) /* returns a whole page */
#define VFAT_IOCTL_READDIR_BOTH _IOR('r', 1, struct dirent [2])
#endif /* __RAWRABBIT_H__ */
CFLAGS = -Wall -ggdb -I../kernel
AS = $(CROSS_COMPILE)as
LD = $(CROSS_COMPILE)ld
CC = $(CROSS_COMPILE)gcc
CPP = $(CC) -E
AR = $(CROSS_COMPILE)ar
NM = $(CROSS_COMPILE)nm
STRIP = $(CROSS_COMPILE)strip
OBJCOPY = $(CROSS_COMPILE)objcopy
OBJDUMP = $(CROSS_COMPILE)objdump
ALL = rrcmd
all: $(ALL)
clean:
rm -f $(ALL) *.o *~
\ No newline at end of file
/*
* User space frontend (command line) for the raw I/O interface
*
* Copyright (C) 2010 Alessandro Rubini <rubini@gnudd.com>
* Released according to the GNU GPL, version 2 or any later version.
*
* This work is part of the White Rabbit project and has been sponsored
* by CERN, the European Institute for Nuclear Research.
*/
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <fcntl.h>
#include <stdint.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include "rawrabbit.h"
#define DEVNAME "/dev/rawrabbit"
char *prgname;
void help(void)
{
fprintf(stderr, "%s: use like this (all numbers are hex):\n"
" %s [<vendor:device>[/<subvendor>:<subdev>]"
"[@<bus>:<devfn>]] <cmd>\n", prgname, prgname);
fprintf(stderr, " <cmd> = info\n");
fprintf(stderr, " <cmd> = irqwait\n");
fprintf(stderr, " <cmd> = irqena\n");
fprintf(stderr, " <cmd> = getdmasize\n");
fprintf(stderr, " <cmd> = getplist\n");
fprintf(stderr, " <cmd> = r[<sz>] <bar>:<addr>\n");
fprintf(stderr, " <cmd> = w[<sz>] <bar>:<addr> <val>\n");
fprintf(stderr, " <sz> = 1, 2, 4, 8 (default = 4)\n");
fprintf(stderr, " <bar> = 0, 2, 4, c (c == dma buffer)\n");
exit(1);
}
int parse_devsel(int fd, char *arg)
{
struct rr_devsel devsel;
int n;
devsel.subvendor = RR_DEVSEL_UNUSED;
devsel.bus = RR_DEVSEL_UNUSED;
if (strlen(arg) > 32) /* to prevent overflow with strtol */
return -EINVAL;
n = sscanf(arg, "%hx:%hx/%hx:%hx@%hx:%hx",
&devsel.vendor, &devsel.device,
&devsel.subvendor, &devsel.subdevice,
&devsel.bus, &devsel.devfn);
switch(n) {
case 6: /* all info */
case 4: /* id/subid but no busdev */
break;
case 2:
/* check if bus/dev is there */
n = sscanf(arg, "%hx:%hx@%hx:%hx",
&devsel.vendor, &devsel.device,
&devsel.bus, &devsel.devfn);
if (n == 4 || n == 2)
break;
/* fall through */
default:
printf("%s: can't parse \"%s\"\n", prgname, arg);
return -EINVAL;
}
/* Now try to do the change */
if (ioctl(fd, RR_DEVSEL, &devsel) < 0) {
fprintf(stderr, "%s: %s: ioctl(DEVSEL): %s\n", prgname, DEVNAME,
strerror(errno));
return -EIO;
}
return 0;
}
int do_iocmd(int fd, char *cmdname, char *addr, char *datum)
{
char rest[32];
struct rr_iocmd iocmd;
int i, ret;
unsigned bar;
__u64 d;
char cmd;
if (strlen(cmdname) >= sizeof(rest))
return -EINVAL;
if (strlen(addr) >= sizeof(rest))
return -EINVAL;
if (datum && strlen(addr) >= sizeof(rest))
return -EINVAL;
/* parse command and size */
i = sscanf(cmdname, "%c%i%s\n", &cmd, &iocmd.datasize, rest);
if (cmd != 'r' && cmd != 'w')
return -EINVAL;
if (i == 3)
return -EINVAL;
if (i == 1)
iocmd.datasize = 4;
/* parse address */
i = sscanf(addr, "%x:%x%s", &bar, &iocmd.address, rest);
if (i != 2)
return -EINVAL;
iocmd.address |= __RR_SET_BAR(bar);
if (!rr_is_valid_bar(iocmd.address))
return -EINVAL;
/* parse datum */
if (datum) {
i = sscanf(datum, "%llx%s", &d, rest);
if (i == 2)
return -EINVAL;
switch(iocmd.datasize) {
case 1:
iocmd.data8 = d;
break;
case 2:
iocmd.data16 = d;
break;
case 4:
iocmd.data32 = d;
break;
case 8:
iocmd.data64 = d;
break;
default:
return -EINVAL;
}
}
if (datum)
ret = ioctl(fd, RR_WRITE, &iocmd);
else
ret = ioctl(fd, RR_READ, &iocmd);
if (ret < 0)
return -errno;
if (!datum && !ret) {
switch(iocmd.datasize) {
case 1:
printf("0x%02x\n", (unsigned int)iocmd.data8);
break;
case 2:
printf("0x%04x\n", (unsigned int)iocmd.data16);
break;
case 4:
printf("0x%08lx\n", (unsigned long)iocmd.data32);
break;
case 8:
printf("0x%016llx\n", (unsigned long long)iocmd.data64);
break;
default:
return -EINVAL;
}
}
return ret;
}
int do_getplist(int fd)
{
uintptr_t plist[RR_PLIST_LEN];
int i, size;
size = ioctl(fd, RR_GETDMASIZE);
if (size < 0)
return -errno;
i = ioctl(fd, RR_GETPLIST, plist);
if (i < 0)
return -errno;
for (i = 0; i < size/RR_PLIST_SIZE; i++)
printf("buf 0x%08x: pfn 0x%08x, addr 0x%012llx\n",
i * RR_PLIST_SIZE, plist[i],
(unsigned long long)plist[i] << 12);
return 0;
}
int main(int argc, char **argv)
{
struct rr_devsel devsel;
int fd, ret = -EINVAL;
prgname = argv[0];
fd = open(DEVNAME, O_RDWR);
if (fd < 0) {
fprintf(stderr, "%s: %s: %s\n", prgname, DEVNAME,
strerror(errno));
exit(1);
}
/* parse argv[1] for devsel */
if (argc > 1 && strchr(argv[1], ':')) {
ret = parse_devsel(fd, argv[1]);
if (!ret) {
argc--, argv++;
}
}
if (argc > 1 && !strcmp(argv[1], "info")) {
if (ioctl(fd, RR_DEVGET, &devsel) < 0) {
if (errno == ENODEV) {
printf("%s: not bound\n", DEVNAME);
exit(0);
}
fprintf(stderr, "%s: %s: ioctl(DEVGET): %s\n", prgname,
DEVNAME, strerror(errno));
exit(1);
}
printf("%s: bound to %04x:%04x/%04x:%04x@%04x:%04x\n", DEVNAME,
devsel.vendor, devsel.device,
devsel.subvendor, devsel.subdevice,
devsel.bus, devsel.devfn);
ret = 0;
} else if (argc > 1 && !strcmp(argv[1], "irqwait")) {
ret = ioctl(fd, RR_IRQWAIT);
if (ret < 0)
fprintf(stderr, "%s: ioctl(IRQWAIT): %s\n", argv[0],
strerror(errno));
} else if (argc > 1 && !strcmp(argv[1], "irqena")) {
ret = ioctl(fd, RR_IRQENA);
if (ret < 0) {
fprintf(stderr, "%s: ioctl(IRQENA): %s\n", argv[0],
strerror(errno));
} else {
printf("delay: %i ns\n", ret);
ret = 0;
}
} else if (argc > 1 && !strcmp(argv[1], "getdmasize")) {
ret = ioctl(fd, RR_GETDMASIZE);
printf("dmasize: %i (0x%x -- %g MB)\n", ret, ret,
ret / (double)(1024*1024));
ret = 0;
} else if (argc > 1 && !strcmp(argv[1], "getplist")) {
ret = do_getplist(fd);
} else if (argc == 3 || argc == 4) {
ret = do_iocmd(fd, argv[1], argv[2], argv[3] /* may be NULL */);
} else if (argc > 4) {
ret = -EINVAL;
}
/* subroutines return "invalid argument" to ask for help */
if (ret == -EINVAL)
help();
if (ret) {
fprintf(stderr, "%s: command returned \"%s\"\n", prgname,
strerror(errno));
exit(1);
}
return 0;
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment